<commit_before>// @(#)root/tree:$Name:  $:$Id: TTreeCache.cxx,v 1.5 2006/08/11 20:17:26 brun Exp $
// Author: Rene Brun   04/06/2006

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TTreeCache                                                           //
//                                                                      //
//  A specialized TFileCacheRead object for a TTree                     //
//  This class acts as a file cache, registering automatically the      //
//  baskets from the branches being processed (TTree::Draw or           //
//  TTree::Process and TSelectors) when in the learning phase.          //
//  The learning phase is by default 100 entries.                       //
//  It can be changed via TTreeCache::SetLearnEntries.                  //
//                                                                      //
//  This cache speeds-up considerably the performance, in particular    //
//  when the Tree is accessed remotely via a high latency network.      //
//                                                                      //
//  The default cache size (10 Mbytes) may be changed via the function  //
//      TTreeCache::SetCacheSize                                        //
//                                                                      //
//  Only the baskets for the requested entry range are put in the cache //
//                                                                      //
//  For each Tree being processed a TTreeCache object is created.       //
//  This object is automatically deleted when the Tree is deleted or    //
//  when the file is deleted.                                           //
//                                                                      //
//  -Special case of a TChain                                           //
//   Once the training is done on the first Tree, the list of branches  //
//   in the cache is kept for the following files.                      //
//                                                                      //
//  -Special case of a TEventlist                                       //
//   if the Tree or TChain has a TEventlist, only the buffers           //
//   referenced by the list are put in the cache.                       //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TTreeCache.h"
#include "TChain.h"
#include "TBranch.h"
#include "TEventList.h"
#include "TObjString.h"

Int_t TTreeCache::fgLearnEntries = 100;

ClassImp(TTreeCache)

//______________________________________________________________________________
TTreeCache::TTreeCache() : TFileCacheRead(),
   fEntryMin(0),
   fEntryMax(1),
   fEntryNext(1),
   fZipBytes(0),
   fNbranches(0),
   fNReadOk(0),
   fNReadMiss(0),
   fNReadPref(0),
   fBranches(0),
   fBrNames(0),
   fOwner(0),
   fTree(0),
   fIsLearning(kTRUE)
{
   // Default Constructor.
}

//______________________________________________________________________________
TTreeCache::TTreeCache(TTree *tree, Int_t buffersize) : TFileCacheRead(tree->GetCurrentFile(),buffersize),
   fEntryMin(0),
   fEntryMax(tree->GetEntriesFast()),
   fEntryNext(0),
   fZipBytes(0),
   fNbranches(0),
   fNReadOk(0),
   fNReadMiss(0),
   fNReadPref(0),
   fBranches(0),
   fBrNames(new TList),
   fOwner(tree),
   fTree(0),
   fIsLearning(kTRUE)
{
   // Constructor.

   fEntryNext = fEntryMin + fgLearnEntries;
   Int_t nleaves = tree->GetListOfLeaves()->GetEntries();
   fBranches = new TBranch*[nleaves+10]; //add a margin just in case in a TChain?
}

//______________________________________________________________________________
TTreeCache::TTreeCache(const TTreeCache &pf) : TFileCacheRead(pf)
{
   // Copy Constructor.
}

//______________________________________________________________________________
TTreeCache::~TTreeCache()
{
   // destructor. (in general called by the TFile destructor

   delete [] fBranches;
   if (fBrNames) {fBrNames->Delete(); delete fBrNames;}
}

//______________________________________________________________________________
TTreeCache& TTreeCache::operator=(const TTreeCache& pf)
{
   // Assignment.

   if (this != &pf) TFileCacheRead::operator=(pf);
   return *this;
}

//_____________________________________________________________________________
void TTreeCache::AddBranch(TBranch *b)
{
   //add a branch to the list of branches to be stored in the cache
   //this function is called by TBranch::GetBasket

   if (!fIsLearning) return;

   //Is branch already in the cache?
   Bool_t isNew = kTRUE;
   for (int i=0;i<fNbranches;i++) {
      if (fBranches[i] == b) {isNew = kFALSE; break;}
   }
   if (isNew) {
      fTree = b->GetTree();
      fBranches[fNbranches] = b;
      fBrNames->Add(new TObjString(b->GetName()));
      fZipBytes += b->GetZipBytes();
      fNbranches++;
      if (gDebug > 0) printf("Entry: %lld, registering branch: %s\n",b->GetTree()->GetReadEntry(),b->GetName());
   }
}

//_____________________________________________________________________________
Bool_t TTreeCache::FillBuffer()
{
   //Fill the cache buffer with the branches in the cache

   if (fNbranches <= 0) return kFALSE;
   TTree *tree = fBranches[0]->GetTree();
   Long64_t entry = tree->GetReadEntry();
   if (entry < fEntryNext) return kFALSE;

   // estimate number of entries that can fit in the cache
   // compare it to the original value of fBufferSize not
   // to the real one
   fEntryNext = entry + tree->GetEntries()*fBufferSizeMin/fZipBytes;

   if (fEntryNext > fEntryMax) fEntryNext = fEntryMax+1;

   //check if owner has a TEventList set. If yes we optimize for this special case
   //reading only the baskets containing entries in the list
   TEventList *elist = fOwner->GetEventList();
   Long64_t chainOffset = 0;
   if (elist) {
      fEntryNext = fTree->GetEntries();
      if (fOwner->IsA() ==TChain::Class()) {
         TChain *chain = (TChain*)fOwner;
         Int_t t = chain->GetTreeNumber();
         chainOffset = chain->GetTreeOffset()[t];
      }
   }

   //clear cache buffer
   TFileCacheRead::Prefetch(0,0);
   //store baskets
   Bool_t mustBreak = kFALSE;
   for (Int_t i=0;i<fNbranches;i++) {
      if (mustBreak) break;
      TBranch *b = fBranches[i];
      Int_t nb = b->GetMaxBaskets();
      Int_t *lbaskets   = b->GetBasketBytes();
      Long64_t *entries = b->GetBasketEntry();
      if (!lbaskets || !entries) continue;
      //we have found the branch. We now register all its baskets
      //from the requested offset to the basket below fEntrymax
      for (Int_t j=0;j<nb;j++) {
         Long64_t pos = b->GetBasketSeek(j);
         Int_t len = lbaskets[j];
         if (pos <= 0 || len <= 0) continue;
         if (entries[j] > fEntryNext) continue;
         if (entries[j] < entry && (j<nb-1 && entries[j+1] < entry)) continue;
         if (elist) {
            Long64_t emax = fEntryMax;
            if (j<nb-1) emax = entries[j+1]-1;
            if (!elist->ContainsRange(entries[j]+chainOffset,emax+chainOffset)) continue;
         }
         fNReadPref++;
         TFileCacheRead::Prefetch(pos,len);
         //we allow up to twice the default buffer size. When using eventlist in particular
         //it may happen that the evaluation of fEntryNext is bad, hence this protection
         if (fNtot > 2*fBufferSizeMin) {TFileCacheRead::Prefetch(0,0);mustBreak = kTRUE; break;}
      }
      if (gDebug > 0) printf("Entry: %lld, registering baskets branch %s, fEntryNext=%lld, fNseek=%d, fNtot=%d\n",entry,fBranches[i]->GetName(),fEntryNext,fNseek,fNtot);
   }
   fIsLearning = kFALSE;
   if (mustBreak) return kFALSE;
   return kTRUE;
}

//_____________________________________________________________________________
Double_t TTreeCache::GetEfficiency()
{
   // Give the total efficiency of the cache... defined as the ratio
   // of blocks found in the cache vs. the number of blocks prefetched
   // ( it could be more than 1 if we read the same block from the cache more
   //   than once )
   // Note: This should eb used at the end of the processing or we will
   //       get uncomplete stats

   if ( !fNReadPref )
      return 0;

   return ((Double_t)fNReadOk / (Double_t)fNReadPref);
}

//_____________________________________________________________________________
Double_t TTreeCache::GetEfficiencyRel()
{
   // This will indicate a sort of relative efficiency... a ratio of the
   // reads found in the cache to the number of reads so far

   if ( !fNReadOk && !fNReadMiss )
      return 0;

   return ((Double_t)fNReadOk / (Double_t)(fNReadOk + fNReadMiss));
}

//_____________________________________________________________________________
Int_t TTreeCache::GetLearnEntries()
{
   //static function returning the number of entries used to train the cache
   //see SetLearnEntries

   return fgLearnEntries;
}

//_____________________________________________________________________________
TTree *TTreeCache::GetTree() const
{
   //return Tree in the cache
   if (fNbranches <= 0) return 0;
   return fBranches[0]->GetTree();
}

//_____________________________________________________________________________
Int_t TTreeCache::ReadBuffer(char *buf, Long64_t pos, Int_t len)
{
   // Read buffer at position pos.
   // If pos is in the list of prefetched blocks read from fBuffer,
   // then try to fill the cache from the list of selected branches,
   // otherwise normal read from file. Returns -1 in case of read
   // failure, 0 in case not in cache and 1 in case read from cache.
   // This function overloads TFileCacheRead::ReadBuffer.

   //Is request already in the cache?
   if (TFileCacheRead::ReadBuffer(buf,pos,len) == 1){
      fNReadOk++;
      return 1;
   }

   //not found in cache. Do we need to fill the cache?
   Bool_t bufferFilled = FillBuffer();
   if (bufferFilled) {
      Int_t res = TFileCacheRead::ReadBuffer(buf,pos,len);

      if (res == 1)
	 fNReadOk++;
      else if (res == 0)
	 fNReadMiss++;

      return res;
   }
   fNReadMiss++;

   return 0;
}

//_____________________________________________________________________________
void TTreeCache::SetEntryRange(Long64_t emin, Long64_t emax)
{
   // Set the minimum and maximum entry number to be processed
   // this information helps to optimize the number of baskets to read
   // when prefetching the branch buffers.

   fEntryMin  = emin;
   fEntryMax  = emax;
   fEntryNext  = fEntryMin + fgLearnEntries;
   fIsLearning = kTRUE;
   fNbranches  = 0;
   fZipBytes   = 0;
   if (fBrNames) fBrNames->Delete();
   if (gDebug > 0) printf("SetEntryRange: fEntryMin=%lld, fEntryMax=%lld, fEntryNext=%lld\n",fEntryMin,fEntryMax,fEntryNext);

}

//_____________________________________________________________________________
void TTreeCache::SetLearnEntries(Int_t n)
{
   // Static function to set the number of entries to be used in learning mode
   // The default value for n is 10. n must be >= 1

   if (n < 1) n = 1;
   fgLearnEntries = n;
}

//_____________________________________________________________________________
void TTreeCache::UpdateBranches(TTree *tree)
{
   //update pointer to current Tree and recompute pointers to the branches in the cache

   fTree = tree;
   Prefetch(0,0);

   fEntryMin  = 0;
   fEntryMax  = fTree->GetEntries();
   fEntryNext = fEntryMin + fgLearnEntries;
   fZipBytes  = 0;
   fNbranches = 0;
   TIter next(fBrNames);
   TObjString *os;
   while ((os = (TObjString*)next())) {
      TBranch *b = fTree->GetBranch(os->GetName());
      if (!b) continue;
      fBranches[fNbranches] = b;
      fZipBytes   += b->GetZipBytes();
      fNbranches++;
   }
}
<commit_msg>Fix coding conventions violation.<commit_after>// @(#)root/tree:$Name:  $:$Id: TTreeCache.cxx,v 1.6 2006/08/14 08:55:30 brun Exp $
// Author: Rene Brun   04/06/2006

/*************************************************************************
 * Copyright (C) 1995-2000, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TTreeCache                                                           //
//                                                                      //
//  A specialized TFileCacheRead object for a TTree                     //
//  This class acts as a file cache, registering automatically the      //
//  baskets from the branches being processed (TTree::Draw or           //
//  TTree::Process and TSelectors) when in the learning phase.          //
//  The learning phase is by default 100 entries.                       //
//  It can be changed via TTreeCache::SetLearnEntries.                  //
//                                                                      //
//  This cache speeds-up considerably the performance, in particular    //
//  when the Tree is accessed remotely via a high latency network.      //
//                                                                      //
//  The default cache size (10 Mbytes) may be changed via the function  //
//      TTreeCache::SetCacheSize                                        //
//                                                                      //
//  Only the baskets for the requested entry range are put in the cache //
//                                                                      //
//  For each Tree being processed a TTreeCache object is created.       //
//  This object is automatically deleted when the Tree is deleted or    //
//  when the file is deleted.                                           //
//                                                                      //
//  -Special case of a TChain                                           //
//   Once the training is done on the first Tree, the list of branches  //
//   in the cache is kept for the following files.                      //
//                                                                      //
//  -Special case of a TEventlist                                       //
//   if the Tree or TChain has a TEventlist, only the buffers           //
//   referenced by the list are put in the cache.                       //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TTreeCache.h"
#include "TChain.h"
#include "TBranch.h"
#include "TEventList.h"
#include "TObjString.h"

Int_t TTreeCache::fgLearnEntries = 100;

ClassImp(TTreeCache)

//______________________________________________________________________________
TTreeCache::TTreeCache() : TFileCacheRead(),
   fEntryMin(0),
   fEntryMax(1),
   fEntryNext(1),
   fZipBytes(0),
   fNbranches(0),
   fNReadOk(0),
   fNReadMiss(0),
   fNReadPref(0),
   fBranches(0),
   fBrNames(0),
   fOwner(0),
   fTree(0),
   fIsLearning(kTRUE)
{
   // Default Constructor.
}

//______________________________________________________________________________
TTreeCache::TTreeCache(TTree *tree, Int_t buffersize) : TFileCacheRead(tree->GetCurrentFile(),buffersize),
   fEntryMin(0),
   fEntryMax(tree->GetEntriesFast()),
   fEntryNext(0),
   fZipBytes(0),
   fNbranches(0),
   fNReadOk(0),
   fNReadMiss(0),
   fNReadPref(0),
   fBranches(0),
   fBrNames(new TList),
   fOwner(tree),
   fTree(0),
   fIsLearning(kTRUE)
{
   // Constructor.

   fEntryNext = fEntryMin + fgLearnEntries;
   Int_t nleaves = tree->GetListOfLeaves()->GetEntries();
   fBranches = new TBranch*[nleaves+10]; //add a margin just in case in a TChain?
}

//______________________________________________________________________________
TTreeCache::TTreeCache(const TTreeCache &pf) : TFileCacheRead(pf)
{
   // Copy Constructor.
}

//______________________________________________________________________________
TTreeCache::~TTreeCache()
{
   // destructor. (in general called by the TFile destructor

   delete [] fBranches;
   if (fBrNames) {fBrNames->Delete(); delete fBrNames;}
}

//______________________________________________________________________________
TTreeCache& TTreeCache::operator=(const TTreeCache& pf)
{
   // Assignment.

   if (this != &pf) TFileCacheRead::operator=(pf);
   return *this;
}

//_____________________________________________________________________________
void TTreeCache::AddBranch(TBranch *b)
{
   //add a branch to the list of branches to be stored in the cache
   //this function is called by TBranch::GetBasket

   if (!fIsLearning) return;

   //Is branch already in the cache?
   Bool_t isNew = kTRUE;
   for (int i=0;i<fNbranches;i++) {
      if (fBranches[i] == b) {isNew = kFALSE; break;}
   }
   if (isNew) {
      fTree = b->GetTree();
      fBranches[fNbranches] = b;
      fBrNames->Add(new TObjString(b->GetName()));
      fZipBytes += b->GetZipBytes();
      fNbranches++;
      if (gDebug > 0) printf("Entry: %lld, registering branch: %s\n",b->GetTree()->GetReadEntry(),b->GetName());
   }
}

//_____________________________________________________________________________
Bool_t TTreeCache::FillBuffer()
{
   //Fill the cache buffer with the branches in the cache

   if (fNbranches <= 0) return kFALSE;
   TTree *tree = fBranches[0]->GetTree();
   Long64_t entry = tree->GetReadEntry();
   if (entry < fEntryNext) return kFALSE;

   // estimate number of entries that can fit in the cache
   // compare it to the original value of fBufferSize not
   // to the real one
   fEntryNext = entry + tree->GetEntries()*fBufferSizeMin/fZipBytes;

   if (fEntryNext > fEntryMax) fEntryNext = fEntryMax+1;

   //check if owner has a TEventList set. If yes we optimize for this special case
   //reading only the baskets containing entries in the list
   TEventList *elist = fOwner->GetEventList();
   Long64_t chainOffset = 0;
   if (elist) {
      fEntryNext = fTree->GetEntries();
      if (fOwner->IsA() ==TChain::Class()) {
         TChain *chain = (TChain*)fOwner;
         Int_t t = chain->GetTreeNumber();
         chainOffset = chain->GetTreeOffset()[t];
      }
   }

   //clear cache buffer
   TFileCacheRead::Prefetch(0,0);
   //store baskets
   Bool_t mustBreak = kFALSE;
   for (Int_t i=0;i<fNbranches;i++) {
      if (mustBreak) break;
      TBranch *b = fBranches[i];
      Int_t nb = b->GetMaxBaskets();
      Int_t *lbaskets   = b->GetBasketBytes();
      Long64_t *entries = b->GetBasketEntry();
      if (!lbaskets || !entries) continue;
      //we have found the branch. We now register all its baskets
      //from the requested offset to the basket below fEntrymax
      for (Int_t j=0;j<nb;j++) {
         Long64_t pos = b->GetBasketSeek(j);
         Int_t len = lbaskets[j];
         if (pos <= 0 || len <= 0) continue;
         if (entries[j] > fEntryNext) continue;
         if (entries[j] < entry && (j<nb-1 && entries[j+1] < entry)) continue;
         if (elist) {
            Long64_t emax = fEntryMax;
            if (j<nb-1) emax = entries[j+1]-1;
            if (!elist->ContainsRange(entries[j]+chainOffset,emax+chainOffset)) continue;
         }
         fNReadPref++;
         TFileCacheRead::Prefetch(pos,len);
         //we allow up to twice the default buffer size. When using eventlist in particular
         //it may happen that the evaluation of fEntryNext is bad, hence this protection
         if (fNtot > 2*fBufferSizeMin) {TFileCacheRead::Prefetch(0,0);mustBreak = kTRUE; break;}
      }
      if (gDebug > 0) printf("Entry: %lld, registering baskets branch %s, fEntryNext=%lld, fNseek=%d, fNtot=%d\n",entry,fBranches[i]->GetName(),fEntryNext,fNseek,fNtot);
   }
   fIsLearning = kFALSE;
   if (mustBreak) return kFALSE;
   return kTRUE;
}

//_____________________________________________________________________________
Double_t TTreeCache::GetEfficiency()
{
   // Give the total efficiency of the cache... defined as the ratio
   // of blocks found in the cache vs. the number of blocks prefetched
   // ( it could be more than 1 if we read the same block from the cache more
   //   than once )
   // Note: This should eb used at the end of the processing or we will
   //       get uncomplete stats

   if ( !fNReadPref )
      return 0;

   return ((Double_t)fNReadOk / (Double_t)fNReadPref);
}

//_____________________________________________________________________________
Double_t TTreeCache::GetEfficiencyRel()
{
   // This will indicate a sort of relative efficiency... a ratio of the
   // reads found in the cache to the number of reads so far

   if ( !fNReadOk && !fNReadMiss )
      return 0;

   return ((Double_t)fNReadOk / (Double_t)(fNReadOk + fNReadMiss));
}

//_____________________________________________________________________________
Int_t TTreeCache::GetLearnEntries()
{
   //static function returning the number of entries used to train the cache
   //see SetLearnEntries

   return fgLearnEntries;
}

//_____________________________________________________________________________
TTree *TTreeCache::GetTree() const
{
   //return Tree in the cache
   if (fNbranches <= 0) return 0;
   return fBranches[0]->GetTree();
}

//_____________________________________________________________________________
Int_t TTreeCache::ReadBuffer(char *buf, Long64_t pos, Int_t len)
{
   // Read buffer at position pos.
   // If pos is in the list of prefetched blocks read from fBuffer,
   // then try to fill the cache from the list of selected branches,
   // otherwise normal read from file. Returns -1 in case of read
   // failure, 0 in case not in cache and 1 in case read from cache.
   // This function overloads TFileCacheRead::ReadBuffer.

   //Is request already in the cache?
   if (TFileCacheRead::ReadBuffer(buf,pos,len) == 1){
      fNReadOk++;
      return 1;
   }

   //not found in cache. Do we need to fill the cache?
   Bool_t bufferFilled = FillBuffer();
   if (bufferFilled) {
      Int_t res = TFileCacheRead::ReadBuffer(buf,pos,len);

      if (res == 1)
         fNReadOk++;
      else if (res == 0)
         fNReadMiss++;

      return res;
   }
   fNReadMiss++;

   return 0;
}

//_____________________________________________________________________________
void TTreeCache::SetEntryRange(Long64_t emin, Long64_t emax)
{
   // Set the minimum and maximum entry number to be processed
   // this information helps to optimize the number of baskets to read
   // when prefetching the branch buffers.

   fEntryMin  = emin;
   fEntryMax  = emax;
   fEntryNext  = fEntryMin + fgLearnEntries;
   fIsLearning = kTRUE;
   fNbranches  = 0;
   fZipBytes   = 0;
   if (fBrNames) fBrNames->Delete();
   if (gDebug > 0) printf("SetEntryRange: fEntryMin=%lld, fEntryMax=%lld, fEntryNext=%lld\n",fEntryMin,fEntryMax,fEntryNext);

}

//_____________________________________________________________________________
void TTreeCache::SetLearnEntries(Int_t n)
{
   // Static function to set the number of entries to be used in learning mode
   // The default value for n is 10. n must be >= 1

   if (n < 1) n = 1;
   fgLearnEntries = n;
}

//_____________________________________________________________________________
void TTreeCache::UpdateBranches(TTree *tree)
{
   //update pointer to current Tree and recompute pointers to the branches in the cache

   fTree = tree;
   Prefetch(0,0);

   fEntryMin  = 0;
   fEntryMax  = fTree->GetEntries();
   fEntryNext = fEntryMin + fgLearnEntries;
   fZipBytes  = 0;
   fNbranches = 0;
   TIter next(fBrNames);
   TObjString *os;
   while ((os = (TObjString*)next())) {
      TBranch *b = fTree->GetBranch(os->GetName());
      if (!b) continue;
      fBranches[fNbranches] = b;
      fZipBytes   += b->GetZipBytes();
      fNbranches++;
   }
}
<|endoftext|>


<commit_before>#pragma once

#include <sstream>
#include <mimosa/init.hh>
#include <mimosa/http/server.hh>
#include <mimosa/http/response-writer.hh>
#include <mimosa/http/request-reader.hh>
#include <silicon/symbols.hh>

#include <iod/json.hh>

namespace iod
{
  namespace mh = mimosa::http;

  using s::_Secure;
  using s::_Path;
  using s::_Http_only;
  using s::_Expires;

  struct request
  {
    request(mh::RequestReader& rr) : rr_(rr) {
      int n;
      char buf[1024];
      while ((n = rr_.read(buf, 1024))) { body_string.append(buf, n); }

      body_stream.str(body_string);
      body_stream.seekg(0);
      body_stream.clear();
    }

    auto get_body_string() const { return body_stream.str(); }
    auto& get_body_stream() { return body_stream; }

    auto& get_params_string() { return params_string; }
    auto& get_tail_string() { return tail_string; }

    bool get_cookie(const std::string& key, std::string& value)
    {
      auto it = rr_.cookies().find(key);
      if (it != rr_.cookies().end())
      {
        value = it->second;
        return true;
      }
      else return false;
    }

    void set_params_position(int pos) {
      params_string.str = body_string.c_str() + pos;
      params_string.len = body_string.size() - pos;
      tail_string = params_string;
    }

    void set_tail_position(int pos) {
      tail_string.str = params_string.data() + pos;
      tail_string.len = params_string.size() - pos;
    }

    std::istringstream body_stream;
    std::string body_string;
    stringview params_string;
    stringview tail_string;
    mh::RequestReader& rr_;
  };

  struct response
  {
    response(mh::ResponseWriter& rw) : rw_(rw) {}

    auto get_body_string() const { return body_stream_.str(); }
    auto& get_body_stream() { return body_stream_; }

    template <typename T>
    auto operator<<(const T& t)
    {
      body_stream_ << t;
    }

    template <typename... T>
    auto operator<<(const iod::sio<T...>& t)
    {
      json_encode(t, body_stream_);
    }

    void write(const char* str, int len) {
      rw_.write(str, len);
    }

    void write_body() {
      std::string s = body_stream_.str();
      rw_.write(s.c_str(), s.size());
    }

    template <typename... O>
    void set_cookie(const std::string& key, const std::string& value, O&&... _options)
    {
      auto options = D(_options...);
      auto* cookie = new mimosa::http::Cookie;
      cookie->setKey(key);
      cookie->setValue(value);
      cookie->setSecure(options.has(_Secure));
      cookie->setHttpOnly(options.has(_Http_only));
      if (options.has(_Expires)) cookie->setExpires(options.get(_Expires, ""));
      cookie->setPath(options.get(_Path, "/"));
      rw_.addCookie(cookie);
    }

    void set_header(const std::string& key, const std::string& value) { rw_.addHeader(key, value); }

    void set_status(int s) { rw_.setStatus(s); }

    std::ostringstream body_stream_;
    mh::ResponseWriter& rw_;
  };

  template <typename F>
  struct mimosa_handler : public mh::Handler
  {
    mimosa_handler(F f) : fun_(f) {}

    bool handle(mh::RequestReader & request_,
                mh::ResponseWriter & response_) const
    {
      request request(request_);
      response response(response_);
      // std::cout << "before" << std::endl;
      // std::cout << &request_ << std::endl;
      // std::cout << &response_ << std::endl;
      fun_(request, response);
      // std::cout << "after" << std::endl;
      response.rw_.setContentLength(response.get_body_string().size());
      // std::cout << response.get_body_string().size() << std::endl;
      response.write_body();
      return true;
    }
    F fun_;
  };

  struct mimosa_backend
  {
    mimosa_backend(int argc, char* argv[]) { mimosa::init(argc, argv); }
    mimosa_backend() { mimosa::deinit(); }

    template <typename F>
    void serve(F f);
  };

  typedef mimosa_backend backend;

}

#include <silicon/mimosa_backend.hpp>
<commit_msg>mimosa backend: Access to the location and take the port as argument.<commit_after>#pragma once

#include <sstream>
#include <mimosa/init.hh>
#include <mimosa/http/server.hh>
#include <mimosa/http/response-writer.hh>
#include <mimosa/http/request-reader.hh>
#include <silicon/symbols.hh>

#include <iod/json.hh>

namespace iod
{
  namespace mh = mimosa::http;

  using s::_Secure;
  using s::_Path;
  using s::_Http_only;
  using s::_Expires;

  struct request
  {
    request(mh::RequestReader& rr) : rr_(rr) {
      int n;
      char buf[1024];
      while ((n = rr_.read(buf, 1024))) { body_string.append(buf, n); }

      body_stream.str(body_string);
      body_stream.seekg(0);
      body_stream.clear();
    }

    auto get_body_string() const { return body_stream.str(); }
    auto& get_body_stream() { return body_stream; }

    auto& get_params_string() { return params_string; }
    auto& get_tail_string() { return tail_string; }

    bool get_cookie(const std::string& key, std::string& value)
    {
      auto it = rr_.cookies().find(key);
      if (it != rr_.cookies().end())
      {
        value = it->second;
        return true;
      }
      else return false;
    }

    void set_params_position(int pos) {
      params_string.str = body_string.c_str() + pos;
      params_string.len = body_string.size() - pos;
      tail_string = params_string;
    }

    void set_tail_position(int pos) {
      tail_string.str = params_string.data() + pos;
      tail_string.len = params_string.size() - pos;
    }

    const std::string& location() { return rr_.location(); }

    std::istringstream body_stream;
    std::string body_string;
    stringview params_string;
    stringview tail_string;
    mh::RequestReader& rr_;
  };

  struct response
  {
    response(mh::ResponseWriter& rw) : rw_(rw) {}

    auto get_body_string() const { return body_stream_.str(); }
    auto& get_body_stream() { return body_stream_; }

    template <typename T>
    auto operator<<(const T& t)
    {
      body_stream_ << t;
    }

    template <typename... T>
    auto operator<<(const iod::sio<T...>& t)
    {
      json_encode(t, body_stream_);
    }

    void write(const char* str, int len) {
      rw_.write(str, len);
    }

    void write_body() {
      std::string s = body_stream_.str();
      rw_.write(s.c_str(), s.size());
    }

    template <typename... O>
    void set_cookie(const std::string& key, const std::string& value, O&&... _options)
    {
      auto options = D(_options...);
      auto* cookie = new mimosa::http::Cookie;
      cookie->setKey(key);
      cookie->setValue(value);
      cookie->setSecure(options.has(_Secure));
      cookie->setHttpOnly(options.has(_Http_only));
      if (options.has(_Expires)) cookie->setExpires(options.get(_Expires, ""));
      cookie->setPath(options.get(_Path, "/"));
      rw_.addCookie(cookie);
    }

    void set_header(const std::string& key, const std::string& value) { rw_.addHeader(key, value); }

    void set_status(int s) { rw_.setStatus(s); }

    std::ostringstream body_stream_;
    mh::ResponseWriter& rw_;
  };

  template <typename F>
  struct mimosa_handler : public mh::Handler
  {
    mimosa_handler(F f) : fun_(f) {}

    bool handle(mh::RequestReader & request_,
                mh::ResponseWriter & response_) const
    {
      request request(request_);
      response response(response_);
      // std::cout << "before" << std::endl;
      // std::cout << &request_ << std::endl;
      // std::cout << &response_ << std::endl;
      fun_(request, response);
      // std::cout << "after" << std::endl;
      response.rw_.setContentLength(response.get_body_string().size());
      // std::cout << response.get_body_string().size() << std::endl;
      response.write_body();
      return true;
    }
    F fun_;
  };

  struct mimosa_backend
  {
    mimosa_backend(int argc, char* argv[]) { mimosa::init(argc, argv); }
    mimosa_backend() { mimosa::deinit(); }

    template <typename F>
    void serve(int port, F f);
  };

  typedef mimosa_backend backend;

}

#include <silicon/mimosa_backend.hpp>
<|endoftext|>


<commit_before>// serial.cxx -- Unix serial I/O support
//
// Written by Curtis Olson, started November 1998.
//
// Copyright (C) 1998  Curtis L. Olson - curt@flightgear.org
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
// Boston, MA  02111-1307, USA.
//
// $Id$

#include <simgear/compiler.h>

#include STL_IOSTREAM

#ifdef SG_HAVE_STD_INCLUDE
#  include <cerrno>
#else
#  include <errno.h>
#endif

#if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
  // maybe include something???
#else
#  include <termios.h>
#  include <sys/types.h>
#  include <sys/stat.h>
#  include <fcntl.h>
#  include <unistd.h>
#endif

#include <simgear/debug/logstream.hxx>

#include "serial.hxx"

SGSerialPort::SGSerialPort()
    : dev_open(false)
{
    // empty
}

SGSerialPort::SGSerialPort(const string& device, int baud) {
    open_port(device);

    if ( dev_open ) {
	set_baud(baud);
    }
}

SGSerialPort::~SGSerialPort() {
    // closing the port here screws us up because if we would even so
    // much as make a copy of an SGSerialPort object and then delete it,
    // the file descriptor gets closed.  Doh!!!
}

bool SGSerialPort::open_port(const string& device) {

#if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )

    fd = CreateFile( device.c_str(),
        GENERIC_READ | GENERIC_WRITE,
        0, // dwShareMode
        NULL, // lpSecurityAttributes
        OPEN_EXISTING,
        FILE_FLAG_OVERLAPPED,
        NULL );
    if ( fd == INVALID_HANDLE_VALUE )
    {
        LPVOID lpMsgBuf;
        FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER |
            FORMAT_MESSAGE_FROM_SYSTEM |
            FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL,
            GetLastError(),
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
            (LPTSTR) &lpMsgBuf,
            0,
            NULL );

        SG_LOG( SG_IO, SG_ALERT, "Error opening serial device \""
            << device << "\" " << (const char*) lpMsgBuf );
        LocalFree( lpMsgBuf );
        return false;
    }

    dev_open = true;
    return true;

#else

    struct termios config;

    fd = open(device.c_str(), O_RDWR | O_NONBLOCK);
    SG_LOG( SG_EVENT, SG_DEBUG, "Serial fd created = " << fd);

    if ( fd  == -1 ) {
	SG_LOG( SG_IO, SG_ALERT, "Cannot open " << device
		<< " for serial I/O" );
	return false;
    } else {
	dev_open = true;
    }

    // set required port parameters
    if ( tcgetattr( fd, &config ) != 0 ) {
	SG_LOG( SG_IO, SG_ALERT, "Unable to poll port settings" );
	return false;
    }

    // cfmakeraw( &config );

    // cout << "config.c_iflag = " << config.c_iflag << endl;

    // software flow control on
    config.c_iflag |= IXON;
    // config.c_iflag |= IXOFF;

    // config.c_cflag |= CLOCAL;

#if ! defined( sgi )
    // disable hardware flow control
    config.c_cflag &= ~(CRTSCTS);
#endif

    // cout << "config.c_iflag = " << config.c_iflag << endl;

    if ( tcsetattr( fd, TCSANOW, &config ) != 0 ) {
	SG_LOG( SG_IO, SG_ALERT, "Unable to update port settings" );
	return false;
    }

    return true;
#endif
}

bool SGSerialPort::close_port() {
#if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
    CloseHandle( fd );
#else
    close(fd);
#endif

    dev_open = false;

    return true;
}

bool SGSerialPort::set_baud(int baud) {

#if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )

    return true;

#else

    struct termios config;
    speed_t speed = B9600;

    if ( tcgetattr( fd, &config ) != 0 ) {
	SG_LOG( SG_IO, SG_ALERT, "Unable to poll port settings" );
	return false;
    }

    if ( baud == 300 ) {
	speed = B300;
    } else if ( baud == 1200 ) {
	speed = B1200;
    } else if ( baud == 2400 ) {
	speed = B2400;
    } else if ( baud == 4800 ) {
	speed = B4800;
    } else if ( baud == 9600 ) {
	speed = B9600;
    } else if ( baud == 19200 ) {
	speed = B19200;
    } else if ( baud == 38400 ) {
	speed = B38400;
    } else if ( baud == 57600 ) {
	speed = B57600;
    } else if ( baud == 115200 ) {
	speed = B115200;
#if defined( linux ) || defined( __FreeBSD__ )
    } else if ( baud == 230400 ) {
	speed = B230400;
#endif
    } else {
	SG_LOG( SG_IO, SG_ALERT, "Unsupported baud rate " << baud );
	return false;
    }

    if ( cfsetispeed( &config, speed ) != 0 ) {
	SG_LOG( SG_IO, SG_ALERT, "Problem setting input baud rate" );
	return false;
    }

    if ( cfsetospeed( &config, speed ) != 0 ) {
	SG_LOG( SG_IO, SG_ALERT, "Problem setting output baud rate" );
	return false;
    }

    if ( tcsetattr( fd, TCSANOW, &config ) != 0 ) {
	SG_LOG( SG_IO, SG_ALERT, "Unable to update port settings" );
	return false;
    }

    return true;

#endif

}

string SGSerialPort::read_port() {

#if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )

    string result = "";
    return result;

#else

    const int max_count = 1024;
    char buffer[max_count+1];
    int count;
    string result;

    count = read(fd, buffer, max_count);
    // cout << "read " << count << " bytes" << endl;

    if ( count < 0 ) {
	// error condition
	if ( errno != EAGAIN ) {
	    SG_LOG( SG_IO, SG_ALERT,
		    "Serial I/O on read, error number = " << errno );
	}

	return "";
    } else {
	buffer[count] = '\0';
	result = buffer;

	return result;
    }

#endif

}

int SGSerialPort::read_port(char *buf, int len) {

#if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )

    buf[0] = '\0';
    return 0;

#else

    string result;

    int count = read(fd, buf, len);
    // cout << "read " << count << " bytes" << endl;

    if ( count < 0 ) {
	// error condition
	if ( errno != EAGAIN ) {
	    SG_LOG( SG_IO, SG_ALERT,
		    "Serial I/O on read, error number = " << errno );
	}

	buf[0] = '\0';
	return 0;
    } else {
	buf[count] = '\0';

	return count;
    }

#endif

}

int SGSerialPort::write_port(const string& value) {

#if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )

    LPCVOID lpBuffer = value.c_str();
    DWORD nNumberOfBytesToWrite = value.length();
    DWORD lpNumberOfBytesWritten;
    OVERLAPPED lpOverlapped;

    if ( WriteFile( fd,
        lpBuffer,
        nNumberOfBytesToWrite,
        &lpNumberOfBytesWritten,
        &lpOverlapped ) == 0 )
    {
        LPVOID lpMsgBuf;
        FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER |
            FORMAT_MESSAGE_FROM_SYSTEM |
            FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL,
            GetLastError(),
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
            (LPTSTR) &lpMsgBuf,
            0,
            NULL );

        SG_LOG( SG_IO, SG_ALERT, "Serial I/O write error: "
             << (const char*) lpMsgBuf );
        LocalFree( lpMsgBuf );
        return int(lpNumberOfBytesWritten);
    }

    return int(lpNumberOfBytesWritten);

#else

    static bool error = false;
    int count;

    if ( error ) {
        SG_LOG( SG_IO, SG_ALERT, "attempting serial write error recovery" );
	// attempt some sort of error recovery
	count = write(fd, "\n", 1);
	if ( count == 1 ) {
	    // cout << "Serial error recover successful!\n";
	    error = false;
	} else {
	    return 0;
	}
    }

    count = write(fd, value.c_str(), value.length());
    // cout << "write '" << value << "'  " << count << " bytes" << endl;

    if ( (int)count == (int)value.length() ) {
	error = false;
    } else {
	if ( errno == EAGAIN ) {
	    // ok ... in our context we don't really care if we can't
	    // write a string, we'll just get it the next time around
	    error = false;
	} else {
	    error = true;
	    SG_LOG( SG_IO, SG_ALERT,
		    "Serial I/O on write, error number = " << errno );
	}
    }

    return count;

#endif

}

int SGSerialPort::write_port(const char* buf, int len) {
#if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )

    LPCVOID lpBuffer = buf;
    DWORD nNumberOfBytesToWrite = len;
    DWORD lpNumberOfBytesWritten;
    OVERLAPPED lpOverlapped;

    if ( WriteFile( fd,
        lpBuffer,
        nNumberOfBytesToWrite,
        &lpNumberOfBytesWritten,
        &lpOverlapped ) == 0 )
    {
        LPVOID lpMsgBuf;
        FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER |
            FORMAT_MESSAGE_FROM_SYSTEM |
            FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL,
            GetLastError(),
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
            (LPTSTR) &lpMsgBuf,
            0,
            NULL );

        SG_LOG( SG_IO, SG_ALERT, "Serial I/O write error: "
             << (const char*) lpMsgBuf );
        LocalFree( lpMsgBuf );
        return int(lpNumberOfBytesWritten);
    }

    return int(lpNumberOfBytesWritten);

#else

    static bool error = false;
    int count;

    if ( error ) {
	// attempt some sort of error recovery
	count = write(fd, "\n", 1);
	if ( count == 1 ) {
	    // cout << "Serial error recover successful!\n";
	    error = false;
	} else {
	    return 0;
	}
    }

    count = write(fd, buf, len);
    // cout << "write '" << buf << "'  " << count << " bytes" << endl;

    if ( (int)count == len ) {
	error = false;
    } else {
	error = true;
	if ( errno == EAGAIN ) {
	    // ok ... in our context we don't really care if we can't
	    // write a string, we'll just get it the next time around
	} else {
	    SG_LOG( SG_IO, SG_ALERT,
		    "Serial I/O on write, error number = " << errno );
	}
    }

    return count;

#endif

}
<commit_msg>Frederic BOUVIER:<commit_after>// serial.cxx -- Unix serial I/O support
//
// Written by Curtis Olson, started November 1998.
//
// Copyright (C) 1998  Curtis L. Olson - curt@flightgear.org
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the
// Free Software Foundation, Inc., 59 Temple Place - Suite 330,
// Boston, MA  02111-1307, USA.
//
// $Id$

#include <simgear/compiler.h>

#include STL_IOSTREAM

#ifdef SG_HAVE_STD_INCLUDE
#  include <cerrno>
#else
#  include <errno.h>
#endif

#if !defined( WIN32 ) || defined( __CYGWIN__) || defined( __CYGWIN32__ )
#  include <termios.h>
#  include <sys/types.h>
#  include <sys/stat.h>
#  include <fcntl.h>
#  include <unistd.h>
#endif

#include <simgear/debug/logstream.hxx>

#include "serial.hxx"

SGSerialPort::SGSerialPort()
    : dev_open(false)
{
    // empty
}

SGSerialPort::SGSerialPort(const string& device, int baud) {
    open_port(device);

    if ( dev_open ) {
	set_baud(baud);
    }
}

SGSerialPort::~SGSerialPort() {
    // closing the port here screws us up because if we would even so
    // much as make a copy of an SGSerialPort object and then delete it,
    // the file descriptor gets closed.  Doh!!!
}

bool SGSerialPort::open_port(const string& device) {

#if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )

    fd = CreateFile( device.c_str(),
        GENERIC_READ | GENERIC_WRITE,
        0, // dwShareMode
        NULL, // lpSecurityAttributes
        OPEN_EXISTING,
        0,
        NULL );
    if ( fd == INVALID_HANDLE_VALUE )
    {
        LPVOID lpMsgBuf;
        FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER |
            FORMAT_MESSAGE_FROM_SYSTEM |
            FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL,
            GetLastError(),
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
            (LPTSTR) &lpMsgBuf,
            0,
            NULL );

        SG_LOG( SG_IO, SG_ALERT, "Error opening serial device \""
            << device << "\" " << (const char*) lpMsgBuf );
        LocalFree( lpMsgBuf );
        return false;
    }

    dev_open = true;
    return true;

#else

    struct termios config;

    fd = open(device.c_str(), O_RDWR | O_NONBLOCK);
    SG_LOG( SG_EVENT, SG_DEBUG, "Serial fd created = " << fd);

    if ( fd  == -1 ) {
	SG_LOG( SG_IO, SG_ALERT, "Cannot open " << device
		<< " for serial I/O" );
	return false;
    } else {
	dev_open = true;
    }

    // set required port parameters
    if ( tcgetattr( fd, &config ) != 0 ) {
	SG_LOG( SG_IO, SG_ALERT, "Unable to poll port settings" );
	return false;
    }

    // cfmakeraw( &config );

    // cout << "config.c_iflag = " << config.c_iflag << endl;

    // software flow control on
    config.c_iflag |= IXON;
    // config.c_iflag |= IXOFF;

    // config.c_cflag |= CLOCAL;

#if ! defined( sgi )
    // disable hardware flow control
    config.c_cflag &= ~(CRTSCTS);
#endif

    // cout << "config.c_iflag = " << config.c_iflag << endl;

    if ( tcsetattr( fd, TCSANOW, &config ) != 0 ) {
	SG_LOG( SG_IO, SG_ALERT, "Unable to update port settings" );
	return false;
    }

    return true;
#endif
}

bool SGSerialPort::close_port() {
#if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )
    CloseHandle( fd );
#else
    close(fd);
#endif

    dev_open = false;

    return true;
}

bool SGSerialPort::set_baud(int baud) {

#if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )

    DCB dcb;
    if ( GetCommState( fd, &dcb ) ) {
        dcb.BaudRate = baud;
        dcb.fOutxCtsFlow = FALSE;
        dcb.fOutxDsrFlow = FALSE;
        dcb.fOutX = TRUE;
        dcb.fInX = TRUE;

        if ( !SetCommState( fd, &dcb ) ) {
            LPVOID lpMsgBuf;
            FormatMessage(
                FORMAT_MESSAGE_ALLOCATE_BUFFER |
                FORMAT_MESSAGE_FROM_SYSTEM |
                FORMAT_MESSAGE_IGNORE_INSERTS,
                NULL,
                GetLastError(),
                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
                (LPTSTR) &lpMsgBuf,
                0,
                NULL );

            SG_LOG( SG_IO, SG_ALERT, "Unable to update port settings: "
                << (const char*) lpMsgBuf );
            LocalFree( lpMsgBuf );
	    return false;
        }
    } else {
        LPVOID lpMsgBuf;
        FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER |
            FORMAT_MESSAGE_FROM_SYSTEM |
            FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL,
            GetLastError(),
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
            (LPTSTR) &lpMsgBuf,
            0,
            NULL );

        SG_LOG( SG_IO, SG_ALERT, "Unable to poll port settings: "
             << (const char*) lpMsgBuf );
        LocalFree( lpMsgBuf );
	return false;
    }

    return true;

#else

    struct termios config;
    speed_t speed = B9600;

    if ( tcgetattr( fd, &config ) != 0 ) {
	SG_LOG( SG_IO, SG_ALERT, "Unable to poll port settings" );
	return false;
    }

    if ( baud == 300 ) {
	speed = B300;
    } else if ( baud == 1200 ) {
	speed = B1200;
    } else if ( baud == 2400 ) {
	speed = B2400;
    } else if ( baud == 4800 ) {
	speed = B4800;
    } else if ( baud == 9600 ) {
	speed = B9600;
    } else if ( baud == 19200 ) {
	speed = B19200;
    } else if ( baud == 38400 ) {
	speed = B38400;
    } else if ( baud == 57600 ) {
	speed = B57600;
    } else if ( baud == 115200 ) {
	speed = B115200;
#if defined( linux ) || defined( __FreeBSD__ )
    } else if ( baud == 230400 ) {
	speed = B230400;
#endif
    } else {
	SG_LOG( SG_IO, SG_ALERT, "Unsupported baud rate " << baud );
	return false;
    }

    if ( cfsetispeed( &config, speed ) != 0 ) {
	SG_LOG( SG_IO, SG_ALERT, "Problem setting input baud rate" );
	return false;
    }

    if ( cfsetospeed( &config, speed ) != 0 ) {
	SG_LOG( SG_IO, SG_ALERT, "Problem setting output baud rate" );
	return false;
    }

    if ( tcsetattr( fd, TCSANOW, &config ) != 0 ) {
	SG_LOG( SG_IO, SG_ALERT, "Unable to update port settings" );
	return false;
    }

    return true;

#endif

}

string SGSerialPort::read_port() {

    const int max_count = 1024;
    char buffer[max_count+1];
    string result;

#if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )

    DWORD count;
    if ( ReadFile( fd, buffer, max_count, &count, 0 ) ) {
	buffer[count] = '\0';
        result = buffer;
    } else {
        LPVOID lpMsgBuf;
        FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER |
            FORMAT_MESSAGE_FROM_SYSTEM |
            FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL,
            GetLastError(),
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
            (LPTSTR) &lpMsgBuf,
            0,
            NULL );

        SG_LOG( SG_IO, SG_ALERT, "Serial I/O read error: "
             << (const char*) lpMsgBuf );
        LocalFree( lpMsgBuf );
    }

    return result;

#else

    int count = read(fd, buffer, max_count);
    // cout << "read " << count << " bytes" << endl;

    if ( count < 0 ) {
	// error condition
	if ( errno != EAGAIN ) {
	    SG_LOG( SG_IO, SG_ALERT,
		    "Serial I/O on read, error number = " << errno );
	}

	return "";
    } else {
	buffer[count] = '\0';
	result = buffer;

	return result;
    }

#endif

}

int SGSerialPort::read_port(char *buf, int len) {

#if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )

    DWORD count;
    if ( ReadFile( fd, buf, len, &count, 0 ) ) {
	buf[count] = '\0';

        return count;
    } else {
        LPVOID lpMsgBuf;
        FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER |
            FORMAT_MESSAGE_FROM_SYSTEM |
            FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL,
            GetLastError(),
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
            (LPTSTR) &lpMsgBuf,
            0,
            NULL );

        SG_LOG( SG_IO, SG_ALERT, "Serial I/O read error: "
             << (const char*) lpMsgBuf );
        LocalFree( lpMsgBuf );

	buf[0] = '\0';
	return 0;
    }

#else

    string result;

    int count = read(fd, buf, len);
    // cout << "read " << count << " bytes" << endl;

    if ( count < 0 ) {
	// error condition
	if ( errno != EAGAIN ) {
	    SG_LOG( SG_IO, SG_ALERT,
		    "Serial I/O on read, error number = " << errno );
	}

	buf[0] = '\0';
	return 0;
    } else {
	buf[count] = '\0';

	return count;
    }

#endif

}

int SGSerialPort::write_port(const string& value) {

#if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )

    LPCVOID lpBuffer = value.data();
    DWORD nNumberOfBytesToWrite = value.length();
    DWORD lpNumberOfBytesWritten;

    if ( WriteFile( fd,
        lpBuffer,
        nNumberOfBytesToWrite,
        &lpNumberOfBytesWritten,
        0 ) == 0 )
    {
        LPVOID lpMsgBuf;
        FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER |
            FORMAT_MESSAGE_FROM_SYSTEM |
            FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL,
            GetLastError(),
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
            (LPTSTR) &lpMsgBuf,
            0,
            NULL );

        SG_LOG( SG_IO, SG_ALERT, "Serial I/O write error: "
             << (const char*) lpMsgBuf );
        LocalFree( lpMsgBuf );
        return int(lpNumberOfBytesWritten);
    }

    return int(lpNumberOfBytesWritten);

#else

    static bool error = false;
    int count;

    if ( error ) {
        SG_LOG( SG_IO, SG_ALERT, "attempting serial write error recovery" );
	// attempt some sort of error recovery
	count = write(fd, "\n", 1);
	if ( count == 1 ) {
	    // cout << "Serial error recover successful!\n";
	    error = false;
	} else {
	    return 0;
	}
    }

    count = write(fd, value.c_str(), value.length());
    // cout << "write '" << value << "'  " << count << " bytes" << endl;

    if ( (int)count == (int)value.length() ) {
	error = false;
    } else {
	if ( errno == EAGAIN ) {
	    // ok ... in our context we don't really care if we can't
	    // write a string, we'll just get it the next time around
	    error = false;
	} else {
	    error = true;
	    SG_LOG( SG_IO, SG_ALERT,
		    "Serial I/O on write, error number = " << errno );
	}
    }

    return count;

#endif

}

int SGSerialPort::write_port(const char* buf, int len) {
#if defined( WIN32 ) && !defined( __CYGWIN__) && !defined( __CYGWIN32__ )

    LPCVOID lpBuffer = buf;
    DWORD nNumberOfBytesToWrite = len;
    DWORD lpNumberOfBytesWritten;

    if ( WriteFile( fd,
        lpBuffer,
        nNumberOfBytesToWrite,
        &lpNumberOfBytesWritten,
        0 ) == 0 )
    {
        LPVOID lpMsgBuf;
        FormatMessage(
            FORMAT_MESSAGE_ALLOCATE_BUFFER |
            FORMAT_MESSAGE_FROM_SYSTEM |
            FORMAT_MESSAGE_IGNORE_INSERTS,
            NULL,
            GetLastError(),
            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
            (LPTSTR) &lpMsgBuf,
            0,
            NULL );

        SG_LOG( SG_IO, SG_ALERT, "Serial I/O write error: "
             << (const char*) lpMsgBuf );
        LocalFree( lpMsgBuf );
        return int(lpNumberOfBytesWritten);
    }

    return int(lpNumberOfBytesWritten);

#else

    static bool error = false;
    int count;

    if ( error ) {
	// attempt some sort of error recovery
	count = write(fd, "\n", 1);
	if ( count == 1 ) {
	    // cout << "Serial error recover successful!\n";
	    error = false;
	} else {
	    return 0;
	}
    }

    count = write(fd, buf, len);
    // cout << "write '" << buf << "'  " << count << " bytes" << endl;

    if ( (int)count == len ) {
	error = false;
    } else {
	error = true;
	if ( errno == EAGAIN ) {
	    // ok ... in our context we don't really care if we can't
	    // write a string, we'll just get it the next time around
	} else {
	    SG_LOG( SG_IO, SG_ALERT,
		    "Serial I/O on write, error number = " << errno );
	}
    }

    return count;

#endif

}
<|endoftext|>


<commit_before>#include "renderwidget.h"

static const char vertex_shader[] = "       \
attribute vec2 position;                    \
attribute vec2 tex_coord;                   \
                                            \
varying vec2 texc;                          \
                                            \
void main()                                 \
{                                           \
   texc = tex_coord;                        \
   gl_Position = vec4(position, 0, 1);      \
}";

static const char fragment_shader[] = "                             \
uniform sampler2D samp;                                             \
uniform sampler2D samp2;                                            \
                                                                    \
varying vec2 texc;                                                  \
                                                                    \
void main()                                                         \
{                                                                   \
    vec3 current_color = texture2D(samp, texc).bgr;                 \
    vec3 prev_color = texture2D(samp2, texc).bgr;                   \
                                                                    \
    gl_FragColor = vec4(mix(current_color, prev_color, 0.5), 1);    \
}";

RenderWidget::RenderWidget(QWidget* parent) : QOpenGLWidget(parent)
{
    timer = new QTimer(this);

    connect(timer, SIGNAL(timeout()), this, SLOT(update()));
    timer->start(1000.0 / 60.0);
}

RenderWidget::~RenderWidget()
{
    makeCurrent();

    glDeleteBuffers(1, &vbo);
    glDeleteBuffers(1, &ibo);
    glDeleteTextures(2, textures);

    doneCurrent();
}

void RenderWidget::update_frame(u32* new_frame)
{
    makeCurrent();

    current_texture = (current_texture + 1) % 2;

    glBindTexture(GL_TEXTURE_2D, textures[current_texture]);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 160, 144, GL_RGBA, /*GL_UNSIGNED_SHORT_1_5_5_5_REV*/ GL_UNSIGNED_INT_8_8_8_8_REV, new_frame);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, textures[current_texture]);

    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, textures[(current_texture + 1) % 2]);

    glBindTexture(GL_TEXTURE_2D, 0);

    doneCurrent();
}

void RenderWidget::initializeGL()
{
    initializeOpenGLFunctions();
    makeCurrent();

    glClearColor(0,0,0,1);
    glClear(GL_COLOR_BUFFER_BIT);

    shaders.addShaderFromSourceCode(QOpenGLShader::Vertex, vertex_shader);
    shaders.addShaderFromSourceCode(QOpenGLShader::Fragment, fragment_shader);

    shaders.link();
    shaders.bind();

    vertex_location = shaders.attributeLocation("position");
    texc_location = shaders.attributeLocation("tex_coord");
    int sampler_location1 = shaders.uniformLocation("samp");
    int sampler_location2 = shaders.uniformLocation("samp2");

    shaders.setUniformValue(sampler_location1, 0);
    shaders.setUniformValue(sampler_location2, 1);

    shaders.release();

    float vbo_data[] = {
         //vertex data
        -1, 1,  //top left
        1, 1,   //top right
        1, -1,  //bottom right
        -1, -1,  //bottom left

        //texture coords data
        0, 1,   //tl
        1, 1,   //tr
        1, 0,   //br
        0, 0    //bl
    };

    GLubyte indexes[] = {0,1,2, 0,2,3};

    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vbo_data), vbo_data, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glGenBuffers(1, &ibo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexes), indexes, GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

    //generate our "frame buffers"
    glGenTextures(2, textures);

    for (auto tex : textures)
    {
        glBindTexture(GL_TEXTURE_2D, tex);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, /*GL_UNSIGNED_SHORT_1_5_5_5_REV*/ GL_UNSIGNED_INT_8_8_8_8_REV, nullptr);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    }

    glBindTexture(GL_TEXTURE_2D, 0);

    //set up everything and leave on forever (we only change textures, so why even bother with state changes?)
    shaders.bind();

    glBindBuffer(GL_ARRAY_BUFFER, vbo);

    //load vertices
    glEnableVertexAttribArray(vertex_location);
    glVertexAttribPointer(vertex_location, 2, GL_FLOAT, GL_FALSE, 0, 0);

    //load texture coords
    glEnableVertexAttribArray(texc_location);
    glVertexAttribPointer(texc_location, 2, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<void*>(8));

    //enable indexing
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);

    doneCurrent();
}

void RenderWidget::resizeGL(int w, int h)
{

}

void RenderWidget::paintGL()
{
    makeCurrent();

    glClear(GL_COLOR_BUFFER_BIT);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0);

    doneCurrent();
}
<commit_msg>fixed 2nd texture bug (it`s no longer black)<commit_after>#include "renderwidget.h"

static const char vertex_shader[] = "       \
attribute vec2 position;                    \
attribute vec2 tex_coord;                   \
                                            \
varying vec2 texc;                          \
                                            \
void main()                                 \
{                                           \
   texc = tex_coord;                        \
   gl_Position = vec4(position, 0, 1);      \
}";

static const char fragment_shader[] = "                             \
uniform sampler2D samp;                                             \
uniform sampler2D samp2;                                            \
                                                                    \
varying vec2 texc;                                                  \
                                                                    \
void main()                                                         \
{                                                                   \
    vec3 current_color = texture2D(samp, texc).bgr;                 \
    vec3 prev_color = texture2D(samp2, texc).bgr;                   \
                                                                    \
    gl_FragColor = vec4(mix(current_color, prev_color, 0.5), 1);    \
}";

RenderWidget::RenderWidget(QWidget* parent) : QOpenGLWidget(parent)
{
    timer = new QTimer(this);

    connect(timer, SIGNAL(timeout()), this, SLOT(update()));
    timer->start(1000.0 / 60.0);
}

RenderWidget::~RenderWidget()
{
    makeCurrent();

    glDeleteBuffers(1, &vbo);
    glDeleteBuffers(1, &ibo);
    glDeleteTextures(2, textures);

    doneCurrent();
}

void RenderWidget::update_frame(u32* new_frame)
{
    makeCurrent();

    current_texture = (current_texture + 1) % 2;

    glBindTexture(GL_TEXTURE_2D, textures[current_texture]);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 160, 144, GL_RGBA, /*GL_UNSIGNED_SHORT_1_5_5_5_REV*/ GL_UNSIGNED_INT_8_8_8_8_REV, new_frame);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, textures[current_texture]);

    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, textures[(current_texture + 1) % 2]);

    doneCurrent();
}

void RenderWidget::initializeGL()
{
    initializeOpenGLFunctions();
    makeCurrent();

    glClearColor(0,0,0,1);
    glClear(GL_COLOR_BUFFER_BIT);

    shaders.addShaderFromSourceCode(QOpenGLShader::Vertex, vertex_shader);
    shaders.addShaderFromSourceCode(QOpenGLShader::Fragment, fragment_shader);

    shaders.link();
    shaders.bind();

    vertex_location = shaders.attributeLocation("position");
    texc_location = shaders.attributeLocation("tex_coord");
    int sampler_location1 = shaders.uniformLocation("samp");
    int sampler_location2 = shaders.uniformLocation("samp2");

    shaders.setUniformValue(sampler_location1, 0);
    shaders.setUniformValue(sampler_location2, 1);

    shaders.release();

    float vbo_data[] = {
         //vertex data
        -1, 1,  //top left
        1, 1,   //top right
        1, -1,  //bottom right
        -1, -1,  //bottom left

        //texture coords data
        0, 1,   //tl
        1, 1,   //tr
        1, 0,   //br
        0, 0    //bl
    };

    GLubyte indexes[] = {0,1,2, 0,2,3};

    glGenBuffers(1, &vbo);
    glBindBuffer(GL_ARRAY_BUFFER, vbo);
    glBufferData(GL_ARRAY_BUFFER, sizeof(vbo_data), vbo_data, GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glGenBuffers(1, &ibo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indexes), indexes, GL_STATIC_DRAW);

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);

    //generate our "frame buffers"
    glGenTextures(2, textures);

    for (auto tex : textures)
    {
        glBindTexture(GL_TEXTURE_2D, tex);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, /*GL_UNSIGNED_SHORT_1_5_5_5_REV*/ GL_UNSIGNED_INT_8_8_8_8_REV, nullptr);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    }

    glBindTexture(GL_TEXTURE_2D, 0);

    //set up everything and leave on forever (we only change textures, so why even bother with state changes?)
    shaders.bind();

    glBindBuffer(GL_ARRAY_BUFFER, vbo);

    //load vertices
    glEnableVertexAttribArray(vertex_location);
    glVertexAttribPointer(vertex_location, 2, GL_FLOAT, GL_FALSE, 0, 0);

    //load texture coords
    glEnableVertexAttribArray(texc_location);
    glVertexAttribPointer(texc_location, 2, GL_FLOAT, GL_FALSE, 0, reinterpret_cast<void*>(8));

    //enable indexing
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);

    doneCurrent();
}

void RenderWidget::resizeGL(int w, int h)
{

}

void RenderWidget::paintGL()
{
    makeCurrent();

    glClear(GL_COLOR_BUFFER_BIT);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_BYTE, 0);

    doneCurrent();
}
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/modules/video_coding/main/interface/video_coding.h"
#include "webrtc/modules/video_coding/main/source/generic_decoder.h"
#include "webrtc/modules/video_coding/main/source/internal_defines.h"
#include "webrtc/system_wrappers/interface/clock.h"
#include "webrtc/system_wrappers/interface/logging.h"

namespace webrtc {

VCMDecodedFrameCallback::VCMDecodedFrameCallback(VCMTiming& timing,
                                                 Clock* clock)
:
_critSect(CriticalSectionWrapper::CreateCriticalSection()),
_clock(clock),
_receiveCallback(NULL),
_timing(timing),
_timestampMap(kDecoderFrameMemoryLength),
_lastReceivedPictureID(0)
{
}

VCMDecodedFrameCallback::~VCMDecodedFrameCallback()
{
    delete _critSect;
}

void VCMDecodedFrameCallback::SetUserReceiveCallback(
    VCMReceiveCallback* receiveCallback)
{
    CriticalSectionScoped cs(_critSect);
    _receiveCallback = receiveCallback;
}

VCMReceiveCallback* VCMDecodedFrameCallback::UserReceiveCallback()
{
    CriticalSectionScoped cs(_critSect);
    return _receiveCallback;
}

int32_t VCMDecodedFrameCallback::Decoded(I420VideoFrame& decodedImage)
{
    // TODO(holmer): We should improve this so that we can handle multiple
    // callbacks from one call to Decode().
    VCMFrameInformation* frameInfo;
    VCMReceiveCallback* callback;
    {
        CriticalSectionScoped cs(_critSect);
        frameInfo = static_cast<VCMFrameInformation*>(
            _timestampMap.Pop(decodedImage.timestamp()));
        callback = _receiveCallback;
    }
    assert(frameInfo != NULL);

    _timing.StopDecodeTimer(
        decodedImage.timestamp(),
        frameInfo->decodeStartTimeMs,
        _clock->TimeInMilliseconds());

    if (callback != NULL)
    {
        decodedImage.set_render_time_ms(frameInfo->renderTimeMs);
        callback->FrameToRender(decodedImage);
    }
    return WEBRTC_VIDEO_CODEC_OK;
}

int32_t
VCMDecodedFrameCallback::ReceivedDecodedReferenceFrame(
    const uint64_t pictureId)
{
    CriticalSectionScoped cs(_critSect);
    if (_receiveCallback != NULL)
    {
        return _receiveCallback->ReceivedDecodedReferenceFrame(pictureId);
    }
    return -1;
}

int32_t
VCMDecodedFrameCallback::ReceivedDecodedFrame(const uint64_t pictureId)
{
    _lastReceivedPictureID = pictureId;
    return 0;
}

uint64_t VCMDecodedFrameCallback::LastReceivedPictureID() const
{
    return _lastReceivedPictureID;
}

int32_t VCMDecodedFrameCallback::Map(uint32_t timestamp, VCMFrameInformation* frameInfo)
{
    CriticalSectionScoped cs(_critSect);
    return _timestampMap.Add(timestamp, frameInfo);
}

int32_t VCMDecodedFrameCallback::Pop(uint32_t timestamp)
{
    CriticalSectionScoped cs(_critSect);
    if (_timestampMap.Pop(timestamp) == NULL)
    {
        return VCM_GENERAL_ERROR;
    }
    return VCM_OK;
}

VCMGenericDecoder::VCMGenericDecoder(VideoDecoder& decoder, bool isExternal)
:
_callback(NULL),
_frameInfos(),
_nextFrameInfoIdx(0),
_decoder(decoder),
_codecType(kVideoCodecUnknown),
_isExternal(isExternal),
_keyFrameDecoded(false)
{
}

VCMGenericDecoder::~VCMGenericDecoder()
{
}

int32_t VCMGenericDecoder::InitDecode(const VideoCodec* settings,
                                      int32_t numberOfCores)
{
    _codecType = settings->codecType;

    return _decoder.InitDecode(settings, numberOfCores);
}

int32_t VCMGenericDecoder::Decode(const VCMEncodedFrame& frame,
                                        int64_t nowMs)
{
    _frameInfos[_nextFrameInfoIdx].decodeStartTimeMs = nowMs;
    _frameInfos[_nextFrameInfoIdx].renderTimeMs = frame.RenderTimeMs();
    _callback->Map(frame.TimeStamp(), &_frameInfos[_nextFrameInfoIdx]);

    _nextFrameInfoIdx = (_nextFrameInfoIdx + 1) % kDecoderFrameMemoryLength;
    int32_t ret = _decoder.Decode(frame.EncodedImage(),
                                        frame.MissingFrame(),
                                        frame.FragmentationHeader(),
                                        frame.CodecSpecific(),
                                        frame.RenderTimeMs());

    if (ret < WEBRTC_VIDEO_CODEC_OK)
    {
        LOG(LS_WARNING) << "Failed to decode frame with timestamp "
                        << frame.TimeStamp() << ", error code: " << ret;
        _callback->Pop(frame.TimeStamp());
        return ret;
    }
    else if (ret == WEBRTC_VIDEO_CODEC_NO_OUTPUT ||
             ret == WEBRTC_VIDEO_CODEC_REQUEST_SLI)
    {
        // No output
        _callback->Pop(frame.TimeStamp());
    }
    return ret;
}

int32_t
VCMGenericDecoder::Release()
{
    return _decoder.Release();
}

int32_t VCMGenericDecoder::Reset()
{
    return _decoder.Reset();
}

int32_t VCMGenericDecoder::SetCodecConfigParameters(const uint8_t* buffer, int32_t size)
{
    return _decoder.SetCodecConfigParameters(buffer, size);
}

int32_t VCMGenericDecoder::RegisterDecodeCompleteCallback(VCMDecodedFrameCallback* callback)
{
    _callback = callback;
    return _decoder.RegisterDecodeCompleteCallback(callback);
}

bool VCMGenericDecoder::External() const
{
    return _isExternal;
}

}  // namespace
<commit_msg>Don't crash if a frame returned from the decoder is too old.<commit_after>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

#include "webrtc/modules/video_coding/main/interface/video_coding.h"
#include "webrtc/modules/video_coding/main/source/generic_decoder.h"
#include "webrtc/modules/video_coding/main/source/internal_defines.h"
#include "webrtc/system_wrappers/interface/clock.h"
#include "webrtc/system_wrappers/interface/logging.h"

namespace webrtc {

VCMDecodedFrameCallback::VCMDecodedFrameCallback(VCMTiming& timing,
                                                 Clock* clock)
:
_critSect(CriticalSectionWrapper::CreateCriticalSection()),
_clock(clock),
_receiveCallback(NULL),
_timing(timing),
_timestampMap(kDecoderFrameMemoryLength),
_lastReceivedPictureID(0)
{
}

VCMDecodedFrameCallback::~VCMDecodedFrameCallback()
{
    delete _critSect;
}

void VCMDecodedFrameCallback::SetUserReceiveCallback(
    VCMReceiveCallback* receiveCallback)
{
    CriticalSectionScoped cs(_critSect);
    _receiveCallback = receiveCallback;
}

VCMReceiveCallback* VCMDecodedFrameCallback::UserReceiveCallback()
{
    CriticalSectionScoped cs(_critSect);
    return _receiveCallback;
}

int32_t VCMDecodedFrameCallback::Decoded(I420VideoFrame& decodedImage)
{
    // TODO(holmer): We should improve this so that we can handle multiple
    // callbacks from one call to Decode().
    VCMFrameInformation* frameInfo;
    VCMReceiveCallback* callback;
    {
        CriticalSectionScoped cs(_critSect);
        frameInfo = static_cast<VCMFrameInformation*>(
            _timestampMap.Pop(decodedImage.timestamp()));
        callback = _receiveCallback;
    }

    if (frameInfo == NULL) {
      LOG(LS_WARNING) << "Too many frames backed up in the decoder, dropping "
                         "this one.";
      return WEBRTC_VIDEO_CODEC_OK;
    }

    _timing.StopDecodeTimer(
        decodedImage.timestamp(),
        frameInfo->decodeStartTimeMs,
        _clock->TimeInMilliseconds());

    if (callback != NULL)
    {
        decodedImage.set_render_time_ms(frameInfo->renderTimeMs);
        callback->FrameToRender(decodedImage);
    }
    return WEBRTC_VIDEO_CODEC_OK;
}

int32_t
VCMDecodedFrameCallback::ReceivedDecodedReferenceFrame(
    const uint64_t pictureId)
{
    CriticalSectionScoped cs(_critSect);
    if (_receiveCallback != NULL)
    {
        return _receiveCallback->ReceivedDecodedReferenceFrame(pictureId);
    }
    return -1;
}

int32_t
VCMDecodedFrameCallback::ReceivedDecodedFrame(const uint64_t pictureId)
{
    _lastReceivedPictureID = pictureId;
    return 0;
}

uint64_t VCMDecodedFrameCallback::LastReceivedPictureID() const
{
    return _lastReceivedPictureID;
}

int32_t VCMDecodedFrameCallback::Map(uint32_t timestamp, VCMFrameInformation* frameInfo)
{
    CriticalSectionScoped cs(_critSect);
    return _timestampMap.Add(timestamp, frameInfo);
}

int32_t VCMDecodedFrameCallback::Pop(uint32_t timestamp)
{
    CriticalSectionScoped cs(_critSect);
    if (_timestampMap.Pop(timestamp) == NULL)
    {
        return VCM_GENERAL_ERROR;
    }
    return VCM_OK;
}

VCMGenericDecoder::VCMGenericDecoder(VideoDecoder& decoder, bool isExternal)
:
_callback(NULL),
_frameInfos(),
_nextFrameInfoIdx(0),
_decoder(decoder),
_codecType(kVideoCodecUnknown),
_isExternal(isExternal),
_keyFrameDecoded(false)
{
}

VCMGenericDecoder::~VCMGenericDecoder()
{
}

int32_t VCMGenericDecoder::InitDecode(const VideoCodec* settings,
                                      int32_t numberOfCores)
{
    _codecType = settings->codecType;

    return _decoder.InitDecode(settings, numberOfCores);
}

int32_t VCMGenericDecoder::Decode(const VCMEncodedFrame& frame,
                                        int64_t nowMs)
{
    _frameInfos[_nextFrameInfoIdx].decodeStartTimeMs = nowMs;
    _frameInfos[_nextFrameInfoIdx].renderTimeMs = frame.RenderTimeMs();
    _callback->Map(frame.TimeStamp(), &_frameInfos[_nextFrameInfoIdx]);

    _nextFrameInfoIdx = (_nextFrameInfoIdx + 1) % kDecoderFrameMemoryLength;
    int32_t ret = _decoder.Decode(frame.EncodedImage(),
                                        frame.MissingFrame(),
                                        frame.FragmentationHeader(),
                                        frame.CodecSpecific(),
                                        frame.RenderTimeMs());

    if (ret < WEBRTC_VIDEO_CODEC_OK)
    {
        LOG(LS_WARNING) << "Failed to decode frame with timestamp "
                        << frame.TimeStamp() << ", error code: " << ret;
        _callback->Pop(frame.TimeStamp());
        return ret;
    }
    else if (ret == WEBRTC_VIDEO_CODEC_NO_OUTPUT ||
             ret == WEBRTC_VIDEO_CODEC_REQUEST_SLI)
    {
        // No output
        _callback->Pop(frame.TimeStamp());
    }
    return ret;
}

int32_t
VCMGenericDecoder::Release()
{
    return _decoder.Release();
}

int32_t VCMGenericDecoder::Reset()
{
    return _decoder.Reset();
}

int32_t VCMGenericDecoder::SetCodecConfigParameters(const uint8_t* buffer, int32_t size)
{
    return _decoder.SetCodecConfigParameters(buffer, size);
}

int32_t VCMGenericDecoder::RegisterDecodeCompleteCallback(VCMDecodedFrameCallback* callback)
{
    _callback = callback;
    return _decoder.RegisterDecodeCompleteCallback(callback);
}

bool VCMGenericDecoder::External() const
{
    return _isExternal;
}

}  // namespace
<|endoftext|>


<commit_before>#include <config.h>
// dune-multiscale
// Copyright Holders: Patrick Henning, Rene Milk
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#include "localoperator.hh"

#include <assert.h>
#include <boost/assert.hpp>
#include <dune/common/fmatrix.hh>
#include <dune/common/exceptions.hh>
#include <dune/stuff/common/filesystem.hh>
#include <dune/stuff/common/exceptions.hh>
#include <dune/stuff/common/configuration.hh>
#include <dune/multiscale/common/heterogenous.hh>
#include <dune/multiscale/tools/misc.hh>
#include <dune/multiscale/problems/selector.hh>
#include <dune/multiscale/msfem/localproblems/localproblemsolver.hh>
#include <dune/multiscale/msfem/msfem_traits.hh>
#include <dune/multiscale/common/traits.hh>
#include <dune/multiscale/msfem/localproblems/localproblemsolver.hh>
#include <dune/gdt/operators/projections.hh>
#include <dune/gdt/operators/prolongations.hh>
#include <dune/gdt/spaces/constraints.hh>
#include <dune/gdt/functionals/l2.hh>

namespace Dune {
namespace Multiscale {

//! holds functionals,etc for boundary correctors to make conditional usage simpler
template <class LocalNeumann>
class BoundaryValueHelper {
  typedef GDT::Functionals::L2Face<LocalNeumann, CommonTraits::GdtVectorType, MsFEMTraits::LocalSpaceType>
      NeumannFunctional;
  typedef GDT::Functionals::L2Volume<Problem::LocalDiffusionType, CommonTraits::GdtVectorType,
                                     MsFEMTraits::LocalSpaceType, MsFEMTraits::LocalGridViewType,
                                     DirichletProduct> DirichletCorrectorFunctionalType;

public:
  BoundaryValueHelper(const DMP::ProblemContainer& problem, const MsFEMTraits::LocalSpaceType& localSpace,
                      const Problem::LocalDiffusionType& local_diffusion_operator,
                      MsFEMTraits::LocalSolutionVectorType& allLocalRHS, std::size_t coarseBaseFunc)
    : localSpace_(localSpace)
    , dirichletExtensionLocal(localSpace_, "dirichletExtension")
    , local_neumann(problem.getNeumannData().transfer<MsFEMTraits::LocalEntityType>())
    , neumann_functional(local_neumann, allLocalRHS[coarseBaseFunc]->vector(), localSpace_)
    , dl_corrector_functional(problem.getDiffusion(), dirichletExtensionLocal, local_diffusion_operator)
    , dirichlet_corrector(local_diffusion_operator, allLocalRHS[++coarseBaseFunc]->vector(), localSpace_,
                          dl_corrector_functional)
    , problem_(problem) {}

  void dirichlet_projection(const CommonTraits::SpaceType& coarse_space) {
    GDT::SystemAssembler<CommonTraits::SpaceType> coarse_system_assembler(coarse_space);
    const auto& dirichlet_data = problem_.getDirichletData();
    CommonTraits::DiscreteFunctionType dirichletExtensionCoarse(coarse_space, "Dirichlet Extension Coarse");
    GDT::Operators::DirichletProjectionLocalizable<CommonTraits::GridViewType, Problem::DirichletDataBase,
                                                   CommonTraits::DiscreteFunctionType>
        coarse_dirichlet_projection_operator(coarse_space.grid_view(), problem_.getModelData().boundaryInfo(),
                                             dirichlet_data, dirichletExtensionCoarse);
    coarse_system_assembler.add(coarse_dirichlet_projection_operator,
                                new DSG::ApplyOn::BoundaryEntities<CommonTraits::GridViewType>());
    coarse_system_assembler.assemble();
    GDT::Operators::LagrangeProlongation<MsFEMTraits::LocalGridViewType> projection(localSpace_.grid_view());
    projection.apply(dirichletExtensionCoarse, dirichletExtensionLocal);
  }

  void add_to(GDT::SystemAssembler<MsFEMTraits::LocalSpaceType>& system_assembler) {
    system_assembler.add(neumann_functional);
    system_assembler.add(dirichlet_corrector);
  }

private:
  const MsFEMTraits::LocalSpaceType& localSpace_;
  MsFEMTraits::LocalGridDiscreteFunctionType dirichletExtensionLocal;
  LocalNeumann local_neumann;
  NeumannFunctional neumann_functional;
  GDT::LocalFunctional::Codim0Integral<DirichletProduct> dl_corrector_functional;
  DirichletCorrectorFunctionalType dirichlet_corrector;
  const DMP::ProblemContainer& problem_;
};

LocalProblemOperator::LocalProblemOperator(const DMP::ProblemContainer& problem,
                                           const CommonTraits::SpaceType& coarse_space,
                                           const MsFEMTraits::LocalSpaceType& space)
  : localSpace_(space)
  , local_diffusion_operator_(problem.getDiffusion())
  , coarse_space_(coarse_space)
  , system_matrix_(localSpace_.mapper().size(), localSpace_.mapper().size(), EllipticOperatorType::pattern(localSpace_))
  , system_assembler_(localSpace_)
  , elliptic_operator_(local_diffusion_operator_, system_matrix_, localSpace_)
  , dirichletConstraints_(problem.getModelData().subBoundaryInfo(), localSpace_.mapper().maxNumDofs(),
                          localSpace_.mapper().maxNumDofs())
#if HAVE_UMFPACK
  , use_umfpack_(problem.config().get("msfem.localproblemsolver_type", std::string("umfpack")) ==
                 std::string("umfpack"))
#else
  , use_umfpack_(false)
#endif
  , problem_(problem) {
  system_assembler_.add(elliptic_operator_);
}

void LocalProblemOperator::assemble_all_local_rhs(const MsFEMTraits::CoarseEntityType& coarseEntity,
                                                  MsFEMTraits::LocalSolutionVectorType& allLocalRHS) {
  BOOST_ASSERT_MSG(allLocalRHS.size() > 0, "You need to preallocate the necessary space outside this function!");

  const bool is_simplex_grid = DSG::is_simplex_grid(coarse_space_);
  if (is_simplex_grid)
    DUNE_THROW(NotImplemented, "special treatment for simplicial grids missing");

  const auto numBoundaryCorrectors = is_simplex_grid ? 1u : 2u;
  const auto numInnerCorrectors = allLocalRHS.size() - numBoundaryCorrectors;

  typedef BoundaryValueHelper<decltype(problem_.getNeumannData().transfer<MsFEMTraits::LocalEntityType>())> BVHelper;
  std::unique_ptr<BVHelper> bv_helper(nullptr);
  if (coarseEntity.hasBoundaryIntersections()) {
    bv_helper =
        DSC::make_unique<BVHelper>(problem_, localSpace_, local_diffusion_operator_, allLocalRHS, numInnerCorrectors);
    bv_helper->dirichlet_projection(coarse_space_);
  }

  typedef GDT::Functionals::L2Volume<Problem::LocalDiffusionType, CommonTraits::GdtVectorType,
                                     MsFEMTraits::LocalSpaceType, MsFEMTraits::LocalGridViewType,
                                     CoarseBasisProduct> RhsFunctionalType;
  std::vector<std::unique_ptr<RhsFunctionalType>> rhs_functionals(numInnerCorrectors);
  std::size_t coarseBaseFunc = 0;
  const auto coarseBaseFunctionSet = coarse_space_.base_function_set(coarseEntity);
  for (; coarseBaseFunc < numInnerCorrectors; ++coarseBaseFunc) {
    assert(allLocalRHS[coarseBaseFunc]);
    GDT::LocalFunctional::Codim0Integral<CoarseBasisProduct> local_rhs_functional(
        problem_.getDiffusion(), coarseBaseFunctionSet, local_diffusion_operator_, coarseBaseFunc);
    auto& rhs_vector = allLocalRHS[coarseBaseFunc]->vector();
    rhs_functionals[coarseBaseFunc] =
        DSC::make_unique<RhsFunctionalType>(local_diffusion_operator_, rhs_vector, localSpace_, local_rhs_functional);
    system_assembler_.add(*rhs_functionals[coarseBaseFunc]);
  }

  if (coarseEntity.hasBoundaryIntersections())
    bv_helper->add_to(system_assembler_);
  system_assembler_.assemble();

  // dirichlet-0 for all rhs
  typedef DSG::ApplyOn::BoundaryEntities<MsFEMTraits::LocalGridViewType> OnLocalBoundaryEntities;
  system_assembler_.add(dirichletConstraints_, system_matrix_, new OnLocalBoundaryEntities());
  for (auto& rhs : allLocalRHS)
    system_assembler_.add(dirichletConstraints_, rhs->vector(), new OnLocalBoundaryEntities());

  system_assembler_.assemble();
#if HAVE_UMFPACK
  if (use_umfpack_)
    local_direct_inverse_ = DSC::make_unique<LocalDirectInverseType>(
        system_matrix_.backend(), problem_.config().get("msfem.localproblemsolver_verbose", 0));
#endif
}

void LocalProblemOperator::apply_inverse(const MsFEMTraits::LocalGridDiscreteFunctionType& current_rhs,
                                         MsFEMTraits::LocalGridDiscreteFunctionType& current_solution) {
  if (!current_rhs.dofs_valid())
    DUNE_THROW(Dune::InvalidStateException, "Local MsFEM Problem RHS invalid.");

  typedef BackendChooser<MsFEMTraits::LocalSpaceType>::InverseOperatorType LocalInverseOperatorType;
  const LocalInverseOperatorType local_inverse(system_matrix_, current_rhs.space().communicator());

  auto options = local_inverse.options(problem_.config().get("msfem.localproblemsolver_type", "umfpack"));
  options["precision"] = 1;
  assert(false);
  options["verbose"] = problem_.config().get("msfem.localproblemsolver_verbose", "0");
  {
    InverseOperatorResult stat;
    auto writable_rhs = current_rhs.vector().copy();
#if HAVE_UMFPACK
    if (use_umfpack_)
      local_direct_inverse_->apply(current_solution.vector().backend(), writable_rhs.backend(), stat);
    else
#endif
      local_inverse.apply(current_solution.vector(), writable_rhs, options);
  }
  if (!current_solution.dofs_valid())
    DUNE_THROW(Dune::InvalidStateException, "Current solution of the local msfem problem invalid!");
}

} // namespace Multiscale {
} // namespace Dune {
<commit_msg>missing fix local problem solve precision<commit_after>#include <config.h>
// dune-multiscale
// Copyright Holders: Patrick Henning, Rene Milk
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#include "localoperator.hh"

#include <assert.h>
#include <boost/assert.hpp>
#include <dune/common/fmatrix.hh>
#include <dune/common/exceptions.hh>
#include <dune/stuff/common/filesystem.hh>
#include <dune/stuff/common/exceptions.hh>
#include <dune/stuff/common/configuration.hh>
#include <dune/multiscale/common/heterogenous.hh>
#include <dune/multiscale/tools/misc.hh>
#include <dune/multiscale/problems/selector.hh>
#include <dune/multiscale/msfem/localproblems/localproblemsolver.hh>
#include <dune/multiscale/msfem/msfem_traits.hh>
#include <dune/multiscale/common/traits.hh>
#include <dune/multiscale/msfem/localproblems/localproblemsolver.hh>
#include <dune/gdt/operators/projections.hh>
#include <dune/gdt/operators/prolongations.hh>
#include <dune/gdt/spaces/constraints.hh>
#include <dune/gdt/functionals/l2.hh>

namespace Dune {
namespace Multiscale {

//! holds functionals,etc for boundary correctors to make conditional usage simpler
template <class LocalNeumann>
class BoundaryValueHelper {
  typedef GDT::Functionals::L2Face<LocalNeumann, CommonTraits::GdtVectorType, MsFEMTraits::LocalSpaceType>
      NeumannFunctional;
  typedef GDT::Functionals::L2Volume<Problem::LocalDiffusionType, CommonTraits::GdtVectorType,
                                     MsFEMTraits::LocalSpaceType, MsFEMTraits::LocalGridViewType,
                                     DirichletProduct> DirichletCorrectorFunctionalType;

public:
  BoundaryValueHelper(const DMP::ProblemContainer& problem, const MsFEMTraits::LocalSpaceType& localSpace,
                      const Problem::LocalDiffusionType& local_diffusion_operator,
                      MsFEMTraits::LocalSolutionVectorType& allLocalRHS, std::size_t coarseBaseFunc)
    : localSpace_(localSpace)
    , dirichletExtensionLocal(localSpace_, "dirichletExtension")
    , local_neumann(problem.getNeumannData().transfer<MsFEMTraits::LocalEntityType>())
    , neumann_functional(local_neumann, allLocalRHS[coarseBaseFunc]->vector(), localSpace_)
    , dl_corrector_functional(problem.getDiffusion(), dirichletExtensionLocal, local_diffusion_operator)
    , dirichlet_corrector(local_diffusion_operator, allLocalRHS[++coarseBaseFunc]->vector(), localSpace_,
                          dl_corrector_functional)
    , problem_(problem) {}

  void dirichlet_projection(const CommonTraits::SpaceType& coarse_space) {
    GDT::SystemAssembler<CommonTraits::SpaceType> coarse_system_assembler(coarse_space);
    const auto& dirichlet_data = problem_.getDirichletData();
    CommonTraits::DiscreteFunctionType dirichletExtensionCoarse(coarse_space, "Dirichlet Extension Coarse");
    GDT::Operators::DirichletProjectionLocalizable<CommonTraits::GridViewType, Problem::DirichletDataBase,
                                                   CommonTraits::DiscreteFunctionType>
        coarse_dirichlet_projection_operator(coarse_space.grid_view(), problem_.getModelData().boundaryInfo(),
                                             dirichlet_data, dirichletExtensionCoarse);
    coarse_system_assembler.add(coarse_dirichlet_projection_operator,
                                new DSG::ApplyOn::BoundaryEntities<CommonTraits::GridViewType>());
    coarse_system_assembler.assemble();
    GDT::Operators::LagrangeProlongation<MsFEMTraits::LocalGridViewType> projection(localSpace_.grid_view());
    projection.apply(dirichletExtensionCoarse, dirichletExtensionLocal);
  }

  void add_to(GDT::SystemAssembler<MsFEMTraits::LocalSpaceType>& system_assembler) {
    system_assembler.add(neumann_functional);
    system_assembler.add(dirichlet_corrector);
  }

private:
  const MsFEMTraits::LocalSpaceType& localSpace_;
  MsFEMTraits::LocalGridDiscreteFunctionType dirichletExtensionLocal;
  LocalNeumann local_neumann;
  NeumannFunctional neumann_functional;
  GDT::LocalFunctional::Codim0Integral<DirichletProduct> dl_corrector_functional;
  DirichletCorrectorFunctionalType dirichlet_corrector;
  const DMP::ProblemContainer& problem_;
};

LocalProblemOperator::LocalProblemOperator(const DMP::ProblemContainer& problem,
                                           const CommonTraits::SpaceType& coarse_space,
                                           const MsFEMTraits::LocalSpaceType& space)
  : localSpace_(space)
  , local_diffusion_operator_(problem.getDiffusion())
  , coarse_space_(coarse_space)
  , system_matrix_(localSpace_.mapper().size(), localSpace_.mapper().size(), EllipticOperatorType::pattern(localSpace_))
  , system_assembler_(localSpace_)
  , elliptic_operator_(local_diffusion_operator_, system_matrix_, localSpace_)
  , dirichletConstraints_(problem.getModelData().subBoundaryInfo(), localSpace_.mapper().maxNumDofs(),
                          localSpace_.mapper().maxNumDofs())
#if HAVE_UMFPACK
  , use_umfpack_(problem.config().get("msfem.localproblemsolver_type", std::string("umfpack")) ==
                 std::string("umfpack"))
#else
  , use_umfpack_(false)
#endif
  , problem_(problem) {
  system_assembler_.add(elliptic_operator_);
}

void LocalProblemOperator::assemble_all_local_rhs(const MsFEMTraits::CoarseEntityType& coarseEntity,
                                                  MsFEMTraits::LocalSolutionVectorType& allLocalRHS) {
  BOOST_ASSERT_MSG(allLocalRHS.size() > 0, "You need to preallocate the necessary space outside this function!");

  const bool is_simplex_grid = DSG::is_simplex_grid(coarse_space_);
  if (is_simplex_grid)
    DUNE_THROW(NotImplemented, "special treatment for simplicial grids missing");

  const auto numBoundaryCorrectors = is_simplex_grid ? 1u : 2u;
  const auto numInnerCorrectors = allLocalRHS.size() - numBoundaryCorrectors;

  typedef BoundaryValueHelper<decltype(problem_.getNeumannData().transfer<MsFEMTraits::LocalEntityType>())> BVHelper;
  std::unique_ptr<BVHelper> bv_helper(nullptr);
  if (coarseEntity.hasBoundaryIntersections()) {
    bv_helper =
        DSC::make_unique<BVHelper>(problem_, localSpace_, local_diffusion_operator_, allLocalRHS, numInnerCorrectors);
    bv_helper->dirichlet_projection(coarse_space_);
  }

  typedef GDT::Functionals::L2Volume<Problem::LocalDiffusionType, CommonTraits::GdtVectorType,
                                     MsFEMTraits::LocalSpaceType, MsFEMTraits::LocalGridViewType,
                                     CoarseBasisProduct> RhsFunctionalType;
  std::vector<std::unique_ptr<RhsFunctionalType>> rhs_functionals(numInnerCorrectors);
  std::size_t coarseBaseFunc = 0;
  const auto coarseBaseFunctionSet = coarse_space_.base_function_set(coarseEntity);
  for (; coarseBaseFunc < numInnerCorrectors; ++coarseBaseFunc) {
    assert(allLocalRHS[coarseBaseFunc]);
    GDT::LocalFunctional::Codim0Integral<CoarseBasisProduct> local_rhs_functional(
        problem_.getDiffusion(), coarseBaseFunctionSet, local_diffusion_operator_, coarseBaseFunc);
    auto& rhs_vector = allLocalRHS[coarseBaseFunc]->vector();
    rhs_functionals[coarseBaseFunc] =
        DSC::make_unique<RhsFunctionalType>(local_diffusion_operator_, rhs_vector, localSpace_, local_rhs_functional);
    system_assembler_.add(*rhs_functionals[coarseBaseFunc]);
  }

  if (coarseEntity.hasBoundaryIntersections())
    bv_helper->add_to(system_assembler_);
  system_assembler_.assemble();

  // dirichlet-0 for all rhs
  typedef DSG::ApplyOn::BoundaryEntities<MsFEMTraits::LocalGridViewType> OnLocalBoundaryEntities;
  system_assembler_.add(dirichletConstraints_, system_matrix_, new OnLocalBoundaryEntities());
  for (auto& rhs : allLocalRHS)
    system_assembler_.add(dirichletConstraints_, rhs->vector(), new OnLocalBoundaryEntities());

  system_assembler_.assemble();
#if HAVE_UMFPACK
  if (use_umfpack_)
    local_direct_inverse_ = DSC::make_unique<LocalDirectInverseType>(
        system_matrix_.backend(), problem_.config().get("msfem.localproblemsolver_verbose", 0));
#endif
}

void LocalProblemOperator::apply_inverse(const MsFEMTraits::LocalGridDiscreteFunctionType& current_rhs,
                                         MsFEMTraits::LocalGridDiscreteFunctionType& current_solution) {
  if (!current_rhs.dofs_valid())
    DUNE_THROW(Dune::InvalidStateException, "Local MsFEM Problem RHS invalid.");

  typedef BackendChooser<MsFEMTraits::LocalSpaceType>::InverseOperatorType LocalInverseOperatorType;
  const LocalInverseOperatorType local_inverse(system_matrix_, current_rhs.space().communicator());

  auto options = local_inverse.options(problem_.config().get("msfem.localproblemsolver_type", "umfpack"));
  options["precision"] = problem_.config().get("msfem.localproblemsolver_precision", 1e-5);
  options["verbose"] = problem_.config().get("msfem.localproblemsolver_verbose", "0");
  {
    InverseOperatorResult stat;
    auto writable_rhs = current_rhs.vector().copy();
#if HAVE_UMFPACK
    if (use_umfpack_)
      local_direct_inverse_->apply(current_solution.vector().backend(), writable_rhs.backend(), stat);
    else
#endif
      local_inverse.apply(current_solution.vector(), writable_rhs, options);
  }
  if (!current_solution.dofs_valid())
    DUNE_THROW(Dune::InvalidStateException, "Current solution of the local msfem problem invalid!");
}

} // namespace Multiscale {
} // namespace Dune {
<|endoftext|>