<commit_before>//== BasicStore.cpp - Basic map from Locations to Values --------*- C++ -*--==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defined the BasicStore and BasicStoreManager classes.
//
//===----------------------------------------------------------------------===//

#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/PathSensitive/GRState.h"
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Streams.h"

using namespace clang;

typedef llvm::ImmutableMap<const VarDecl*,RVal> VarBindingsTy;

namespace {

class VISIBILITY_HIDDEN BasicStoreManager : public StoreManager {
  VarBindingsTy::Factory VBFactory;
  GRStateManager& StateMgr;
  MemRegionManager MRMgr;

public:
  BasicStoreManager(GRStateManager& mgr)
    : StateMgr(mgr), MRMgr(StateMgr.getAllocator()) {}

  virtual ~BasicStoreManager() {}

  virtual RVal GetRVal(Store St, LVal LV, QualType T);
  virtual Store SetRVal(Store St, LVal LV, RVal V);
  virtual Store Remove(Store St, LVal LV);

  virtual Store getInitialStore();

  virtual MemRegionManager& getRegionManager() { return MRMgr; }

  // FIXME: Investigate what is using this. This method should be removed.
  virtual LVal getLVal(const VarDecl* VD) {
    return lval::MemRegionVal(MRMgr.getVarRegion(VD));
  }

  RVal getLValueVar(const GRState* St, const VarDecl* VD);
  RVal getLValueIvar(const GRState* St, const ObjCIvarDecl* D, RVal Base);
  RVal getLValueField(const GRState* St, const FieldDecl* D, RVal Base);
  RVal getLValueElement(const GRState* St, RVal Base, RVal Offset);

  virtual Store
  RemoveDeadBindings(Store store, Stmt* Loc, const LiveVariables& Live,
                     llvm::SmallVectorImpl<const MemRegion*>& RegionRoots,
                     LiveSymbolsTy& LSymbols, DeadSymbolsTy& DSymbols);

  virtual void iterBindings(Store store, BindingsHandler& f);

  virtual Store AddDecl(Store store,
                        const VarDecl* VD, Expr* Ex,
                        RVal InitVal = UndefinedVal(), unsigned Count = 0);

  static inline VarBindingsTy GetVarBindings(Store store) {
    return VarBindingsTy(static_cast<const VarBindingsTy::TreeTy*>(store));
  }

  virtual void print(Store store, std::ostream& Out,
                     const char* nl, const char *sep);

};

} // end anonymous namespace

StoreManager* clang::CreateBasicStoreManager(GRStateManager& StMgr) {
  return new BasicStoreManager(StMgr);
}
RVal BasicStoreManager::getLValueVar(const GRState* St, const VarDecl* VD) {
  QualType T = VD->getType();
  assert(!T->isArrayType() && "Array and struct variable have no lvalue.");
  return lval::MemRegionVal(MRMgr.getVarRegion(VD));
}

RVal BasicStoreManager::getLValueIvar(const GRState* St, const ObjCIvarDecl* D,
                                      RVal Base) {
  return UnknownVal();
}

RVal BasicStoreManager::getLValueField(const GRState* St, const FieldDecl* D,
                                       RVal Base) {
  return UnknownVal();
}

RVal BasicStoreManager::getLValueElement(const GRState* St, RVal Base,
                                         RVal Offset) {
  return UnknownVal();
}

RVal BasicStoreManager::GetRVal(Store St, LVal LV, QualType T) {

  if (isa<UnknownVal>(LV))
    return UnknownVal();

  assert (!isa<UndefinedVal>(LV));

  switch (LV.getSubKind()) {

    case lval::MemRegionKind: {
      VarRegion* R =
        dyn_cast<VarRegion>(cast<lval::MemRegionVal>(LV).getRegion());

      if (!R)
        return UnknownVal();

      VarBindingsTy B(static_cast<const VarBindingsTy::TreeTy*>(St));
      VarBindingsTy::data_type* T = B.lookup(R->getDecl());
      return T ? *T : UnknownVal();
    }

    case lval::SymbolValKind:
      return UnknownVal();

    case lval::ConcreteIntKind:
      // Some clients may call GetRVal with such an option simply because
      // they are doing a quick scan through their LVals (potentially to
      // invalidate their bindings).  Just return Undefined.
      return UndefinedVal();
    case lval::FuncValKind:
      return LV;

    case lval::StringLiteralValKind:
      // FIXME: Implement better support for fetching characters from strings.
      return UnknownVal();

    default:
      assert (false && "Invalid LVal.");
      break;
  }

  return UnknownVal();
}

Store BasicStoreManager::SetRVal(Store store, LVal LV, RVal V) {
  switch (LV.getSubKind()) {
    case lval::MemRegionKind: {
      VarRegion* R =
        dyn_cast<VarRegion>(cast<lval::MemRegionVal>(LV).getRegion());

      if (!R)
        return store;

      VarBindingsTy B = GetVarBindings(store);
      return V.isUnknown()
        ? VBFactory.Remove(B, R->getDecl()).getRoot()
        : VBFactory.Add(B, R->getDecl(), V).getRoot();
    }
    default:
      assert ("SetRVal for given LVal type not yet implemented.");
      return store;
  }
}

Store BasicStoreManager::Remove(Store store, LVal LV) {
  switch (LV.getSubKind()) {
    case lval::MemRegionKind: {
      VarRegion* R =
      dyn_cast<VarRegion>(cast<lval::MemRegionVal>(LV).getRegion());

      if (!R)
        return store;

      VarBindingsTy B = GetVarBindings(store);
      return VBFactory.Remove(B,R->getDecl()).getRoot();
    }
    default:
      assert ("Remove for given LVal type not yet implemented.");
      return store;
  }
}

Store
BasicStoreManager::RemoveDeadBindings(Store store, Stmt* Loc,
                          const LiveVariables& Liveness,
                          llvm::SmallVectorImpl<const MemRegion*>& RegionRoots,
                          LiveSymbolsTy& LSymbols, DeadSymbolsTy& DSymbols) {

  VarBindingsTy B = GetVarBindings(store);
  typedef RVal::symbol_iterator symbol_iterator;

  // Iterate over the variable bindings.
  for (VarBindingsTy::iterator I=B.begin(), E=B.end(); I!=E ; ++I)
    if (Liveness.isLive(Loc, I.getKey())) {
      RegionRoots.push_back(MRMgr.getVarRegion(I.getKey()));
      RVal X = I.getData();

      for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI)
        LSymbols.insert(*SI);
    }

  // Scan for live variables and live symbols.
  llvm::SmallPtrSet<const VarRegion*, 10> Marked;

  while (!RegionRoots.empty()) {
    const VarRegion* R = cast<VarRegion>(RegionRoots.back());
    RegionRoots.pop_back();

    if (Marked.count(R))
      continue;

    Marked.insert(R);
    // FIXME: Do we need the QualType here, since regions are partially
    // typed?
    RVal X = GetRVal(store, lval::MemRegionVal(R), QualType());

    for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI)
      LSymbols.insert(*SI);

    if (!isa<lval::MemRegionVal>(X))
      continue;

    const lval::MemRegionVal& LVD = cast<lval::MemRegionVal>(X);
    RegionRoots.push_back(cast<VarRegion>(LVD.getRegion()));
  }

  // Remove dead variable bindings.
  for (VarBindingsTy::iterator I=B.begin(), E=B.end(); I!=E ; ++I) {
    const VarRegion* R = cast<VarRegion>(MRMgr.getVarRegion(I.getKey()));

    if (!Marked.count(R)) {
      store = Remove(store, lval::MemRegionVal(R));
      RVal X = I.getData();

      for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI)
        if (!LSymbols.count(*SI)) DSymbols.insert(*SI);
    }
  }

  return store;
}

Store BasicStoreManager::getInitialStore() {
  // The LiveVariables information already has a compilation of all VarDecls
  // used in the function.  Iterate through this set, and "symbolicate"
  // any VarDecl whose value originally comes from outside the function.

  typedef LiveVariables::AnalysisDataTy LVDataTy;
  LVDataTy& D = StateMgr.getLiveVariables().getAnalysisData();

  Store St = VBFactory.GetEmptyMap().getRoot();

  for (LVDataTy::decl_iterator I=D.begin_decl(), E=D.end_decl(); I != E; ++I) {
    ScopedDecl* SD = const_cast<ScopedDecl*>(I->first);

    if (VarDecl* VD = dyn_cast<VarDecl>(SD)) {
      // Punt on static variables for now.
      if (VD->getStorageClass() == VarDecl::Static)
        continue;

      // Only handle pointers and integers for now.
      QualType T = VD->getType();
      if (LVal::IsLValType(T) || T->isIntegerType()) {
        // Initialize globals and parameters to symbolic values.
        // Initialize local variables to undefined.
        RVal X = (VD->hasGlobalStorage() || isa<ParmVarDecl>(VD) ||
                  isa<ImplicitParamDecl>(VD))
                 ? RVal::GetSymbolValue(StateMgr.getSymbolManager(), VD)
                 : UndefinedVal();

        St = SetRVal(St, lval::MemRegionVal(MRMgr.getVarRegion(VD)), X);
      }
    }
  }
  return St;
}

Store BasicStoreManager::AddDecl(Store store,
                                 const VarDecl* VD, Expr* Ex,
                                 RVal InitVal, unsigned Count) {

  BasicValueFactory& BasicVals = StateMgr.getBasicVals();
  SymbolManager& SymMgr = StateMgr.getSymbolManager();

  // BasicStore does not model arrays and structs.
  if (VD->getType()->isArrayType() || VD->getType()->isStructureType())
    return store;

  if (VD->hasGlobalStorage()) {
    // Handle variables with global storage: extern, static, PrivateExtern.

    // FIXME:: static variables may have an initializer, but the second time a
    // function is called those values may not be current. Currently, a function
    // will not be called more than once.

    // Static global variables should not be visited here.
    assert(!(VD->getStorageClass() == VarDecl::Static &&
             VD->isFileVarDecl()));

    // Process static variables.
    if (VD->getStorageClass() == VarDecl::Static) {
      // C99: 6.7.8 Initialization
      //  If an object that has static storage duration is not initialized
      //  explicitly, then:
      //   —if it has pointer type, it is initialized to a null pointer;
      //   —if it has arithmetic type, it is initialized to (positive or
      //     unsigned) zero;
      if (!Ex) {
        QualType T = VD->getType();
        if (LVal::IsLValType(T))
          store = SetRVal(store, getLVal(VD),
                          lval::ConcreteInt(BasicVals.getValue(0, T)));
        else if (T->isIntegerType())
          store = SetRVal(store, getLVal(VD),
                          nonlval::ConcreteInt(BasicVals.getValue(0, T)));
        else {
          // assert(0 && "ignore other types of variables");
        }
      } else {
        store = SetRVal(store, getLVal(VD), InitVal);
      }
    }
  } else {
    // Process local scalar variables.
    QualType T = VD->getType();
    if (LVal::IsLValType(T) || T->isIntegerType()) {
      RVal V = Ex ? InitVal : UndefinedVal();

      if (Ex && InitVal.isUnknown()) {
        // EXPERIMENTAL: "Conjured" symbols.
        SymbolID Sym = SymMgr.getConjuredSymbol(Ex, Count);

        V = LVal::IsLValType(Ex->getType())
          ? cast<RVal>(lval::SymbolVal(Sym))
          : cast<RVal>(nonlval::SymbolVal(Sym));
      }

      store = SetRVal(store, getLVal(VD), V);
    }
  }

  return store;
}

void BasicStoreManager::print(Store store, std::ostream& Out,
                              const char* nl, const char *sep) {

  VarBindingsTy B = GetVarBindings(store);
  Out << "Variables:" << nl;

  bool isFirst = true;

  for (VarBindingsTy::iterator I=B.begin(), E=B.end(); I != E; ++I) {
    if (isFirst) isFirst = false;
    else Out << nl;

    Out << ' ' << I.getKey()->getName() << " : ";
    I.getData().print(Out);
  }
}

void BasicStoreManager::iterBindings(Store store, BindingsHandler& f) {
  VarBindingsTy B = GetVarBindings(store);

  for (VarBindingsTy::iterator I=B.begin(), E=B.end(); I != E; ++I) {

    f.HandleBinding(*this, store, MRMgr.getVarRegion(I.getKey()),I.getData());
  }
}

StoreManager::BindingsHandler::~BindingsHandler() {}
<commit_msg>Array and struct variables do have lvalue. For example, struct s {}; void f() {   int a[10];   int (*p)[10];   p = &a;   (*p)[3] =1;<commit_after>//== BasicStore.cpp - Basic map from Locations to Values --------*- C++ -*--==//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defined the BasicStore and BasicStoreManager classes.
//
//===----------------------------------------------------------------------===//

#include "clang/Analysis/Analyses/LiveVariables.h"
#include "clang/Analysis/PathSensitive/GRState.h"
#include "llvm/ADT/ImmutableMap.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Streams.h"

using namespace clang;

typedef llvm::ImmutableMap<const VarDecl*,RVal> VarBindingsTy;

namespace {

class VISIBILITY_HIDDEN BasicStoreManager : public StoreManager {
  VarBindingsTy::Factory VBFactory;
  GRStateManager& StateMgr;
  MemRegionManager MRMgr;

public:
  BasicStoreManager(GRStateManager& mgr)
    : StateMgr(mgr), MRMgr(StateMgr.getAllocator()) {}

  virtual ~BasicStoreManager() {}

  virtual RVal GetRVal(Store St, LVal LV, QualType T);
  virtual Store SetRVal(Store St, LVal LV, RVal V);
  virtual Store Remove(Store St, LVal LV);

  virtual Store getInitialStore();

  virtual MemRegionManager& getRegionManager() { return MRMgr; }

  // FIXME: Investigate what is using this. This method should be removed.
  virtual LVal getLVal(const VarDecl* VD) {
    return lval::MemRegionVal(MRMgr.getVarRegion(VD));
  }

  RVal getLValueVar(const GRState* St, const VarDecl* VD);
  RVal getLValueIvar(const GRState* St, const ObjCIvarDecl* D, RVal Base);
  RVal getLValueField(const GRState* St, const FieldDecl* D, RVal Base);
  RVal getLValueElement(const GRState* St, RVal Base, RVal Offset);

  virtual Store
  RemoveDeadBindings(Store store, Stmt* Loc, const LiveVariables& Live,
                     llvm::SmallVectorImpl<const MemRegion*>& RegionRoots,
                     LiveSymbolsTy& LSymbols, DeadSymbolsTy& DSymbols);

  virtual void iterBindings(Store store, BindingsHandler& f);

  virtual Store AddDecl(Store store,
                        const VarDecl* VD, Expr* Ex,
                        RVal InitVal = UndefinedVal(), unsigned Count = 0);

  static inline VarBindingsTy GetVarBindings(Store store) {
    return VarBindingsTy(static_cast<const VarBindingsTy::TreeTy*>(store));
  }

  virtual void print(Store store, std::ostream& Out,
                     const char* nl, const char *sep);

};

} // end anonymous namespace

StoreManager* clang::CreateBasicStoreManager(GRStateManager& StMgr) {
  return new BasicStoreManager(StMgr);
}
RVal BasicStoreManager::getLValueVar(const GRState* St, const VarDecl* VD) {
  return lval::MemRegionVal(MRMgr.getVarRegion(VD));
}

RVal BasicStoreManager::getLValueIvar(const GRState* St, const ObjCIvarDecl* D,
                                      RVal Base) {
  return UnknownVal();
}

RVal BasicStoreManager::getLValueField(const GRState* St, const FieldDecl* D,
                                       RVal Base) {
  return UnknownVal();
}

RVal BasicStoreManager::getLValueElement(const GRState* St, RVal Base,
                                         RVal Offset) {
  return UnknownVal();
}

RVal BasicStoreManager::GetRVal(Store St, LVal LV, QualType T) {

  if (isa<UnknownVal>(LV))
    return UnknownVal();

  assert (!isa<UndefinedVal>(LV));

  switch (LV.getSubKind()) {

    case lval::MemRegionKind: {
      VarRegion* R =
        dyn_cast<VarRegion>(cast<lval::MemRegionVal>(LV).getRegion());

      if (!R)
        return UnknownVal();

      VarBindingsTy B(static_cast<const VarBindingsTy::TreeTy*>(St));
      VarBindingsTy::data_type* T = B.lookup(R->getDecl());
      return T ? *T : UnknownVal();
    }

    case lval::SymbolValKind:
      return UnknownVal();

    case lval::ConcreteIntKind:
      // Some clients may call GetRVal with such an option simply because
      // they are doing a quick scan through their LVals (potentially to
      // invalidate their bindings).  Just return Undefined.
      return UndefinedVal();
    case lval::FuncValKind:
      return LV;

    case lval::StringLiteralValKind:
      // FIXME: Implement better support for fetching characters from strings.
      return UnknownVal();

    default:
      assert (false && "Invalid LVal.");
      break;
  }

  return UnknownVal();
}

Store BasicStoreManager::SetRVal(Store store, LVal LV, RVal V) {
  switch (LV.getSubKind()) {
    case lval::MemRegionKind: {
      VarRegion* R =
        dyn_cast<VarRegion>(cast<lval::MemRegionVal>(LV).getRegion());

      if (!R)
        return store;

      VarBindingsTy B = GetVarBindings(store);
      return V.isUnknown()
        ? VBFactory.Remove(B, R->getDecl()).getRoot()
        : VBFactory.Add(B, R->getDecl(), V).getRoot();
    }
    default:
      assert ("SetRVal for given LVal type not yet implemented.");
      return store;
  }
}

Store BasicStoreManager::Remove(Store store, LVal LV) {
  switch (LV.getSubKind()) {
    case lval::MemRegionKind: {
      VarRegion* R =
      dyn_cast<VarRegion>(cast<lval::MemRegionVal>(LV).getRegion());

      if (!R)
        return store;

      VarBindingsTy B = GetVarBindings(store);
      return VBFactory.Remove(B,R->getDecl()).getRoot();
    }
    default:
      assert ("Remove for given LVal type not yet implemented.");
      return store;
  }
}

Store
BasicStoreManager::RemoveDeadBindings(Store store, Stmt* Loc,
                          const LiveVariables& Liveness,
                          llvm::SmallVectorImpl<const MemRegion*>& RegionRoots,
                          LiveSymbolsTy& LSymbols, DeadSymbolsTy& DSymbols) {

  VarBindingsTy B = GetVarBindings(store);
  typedef RVal::symbol_iterator symbol_iterator;

  // Iterate over the variable bindings.
  for (VarBindingsTy::iterator I=B.begin(), E=B.end(); I!=E ; ++I)
    if (Liveness.isLive(Loc, I.getKey())) {
      RegionRoots.push_back(MRMgr.getVarRegion(I.getKey()));
      RVal X = I.getData();

      for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI)
        LSymbols.insert(*SI);
    }

  // Scan for live variables and live symbols.
  llvm::SmallPtrSet<const VarRegion*, 10> Marked;

  while (!RegionRoots.empty()) {
    const VarRegion* R = cast<VarRegion>(RegionRoots.back());
    RegionRoots.pop_back();

    if (Marked.count(R))
      continue;

    Marked.insert(R);
    // FIXME: Do we need the QualType here, since regions are partially
    // typed?
    RVal X = GetRVal(store, lval::MemRegionVal(R), QualType());

    for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI)
      LSymbols.insert(*SI);

    if (!isa<lval::MemRegionVal>(X))
      continue;

    const lval::MemRegionVal& LVD = cast<lval::MemRegionVal>(X);
    RegionRoots.push_back(cast<VarRegion>(LVD.getRegion()));
  }

  // Remove dead variable bindings.
  for (VarBindingsTy::iterator I=B.begin(), E=B.end(); I!=E ; ++I) {
    const VarRegion* R = cast<VarRegion>(MRMgr.getVarRegion(I.getKey()));

    if (!Marked.count(R)) {
      store = Remove(store, lval::MemRegionVal(R));
      RVal X = I.getData();

      for (symbol_iterator SI=X.symbol_begin(), SE=X.symbol_end(); SI!=SE; ++SI)
        if (!LSymbols.count(*SI)) DSymbols.insert(*SI);
    }
  }

  return store;
}

Store BasicStoreManager::getInitialStore() {
  // The LiveVariables information already has a compilation of all VarDecls
  // used in the function.  Iterate through this set, and "symbolicate"
  // any VarDecl whose value originally comes from outside the function.

  typedef LiveVariables::AnalysisDataTy LVDataTy;
  LVDataTy& D = StateMgr.getLiveVariables().getAnalysisData();

  Store St = VBFactory.GetEmptyMap().getRoot();

  for (LVDataTy::decl_iterator I=D.begin_decl(), E=D.end_decl(); I != E; ++I) {
    ScopedDecl* SD = const_cast<ScopedDecl*>(I->first);

    if (VarDecl* VD = dyn_cast<VarDecl>(SD)) {
      // Punt on static variables for now.
      if (VD->getStorageClass() == VarDecl::Static)
        continue;

      // Only handle pointers and integers for now.
      QualType T = VD->getType();
      if (LVal::IsLValType(T) || T->isIntegerType()) {
        // Initialize globals and parameters to symbolic values.
        // Initialize local variables to undefined.
        RVal X = (VD->hasGlobalStorage() || isa<ParmVarDecl>(VD) ||
                  isa<ImplicitParamDecl>(VD))
                 ? RVal::GetSymbolValue(StateMgr.getSymbolManager(), VD)
                 : UndefinedVal();

        St = SetRVal(St, lval::MemRegionVal(MRMgr.getVarRegion(VD)), X);
      }
    }
  }
  return St;
}

Store BasicStoreManager::AddDecl(Store store,
                                 const VarDecl* VD, Expr* Ex,
                                 RVal InitVal, unsigned Count) {

  BasicValueFactory& BasicVals = StateMgr.getBasicVals();
  SymbolManager& SymMgr = StateMgr.getSymbolManager();

  // BasicStore does not model arrays and structs.
  if (VD->getType()->isArrayType() || VD->getType()->isStructureType())
    return store;

  if (VD->hasGlobalStorage()) {
    // Handle variables with global storage: extern, static, PrivateExtern.

    // FIXME:: static variables may have an initializer, but the second time a
    // function is called those values may not be current. Currently, a function
    // will not be called more than once.

    // Static global variables should not be visited here.
    assert(!(VD->getStorageClass() == VarDecl::Static &&
             VD->isFileVarDecl()));

    // Process static variables.
    if (VD->getStorageClass() == VarDecl::Static) {
      // C99: 6.7.8 Initialization
      //  If an object that has static storage duration is not initialized
      //  explicitly, then:
      //   —if it has pointer type, it is initialized to a null pointer;
      //   —if it has arithmetic type, it is initialized to (positive or
      //     unsigned) zero;
      if (!Ex) {
        QualType T = VD->getType();
        if (LVal::IsLValType(T))
          store = SetRVal(store, getLVal(VD),
                          lval::ConcreteInt(BasicVals.getValue(0, T)));
        else if (T->isIntegerType())
          store = SetRVal(store, getLVal(VD),
                          nonlval::ConcreteInt(BasicVals.getValue(0, T)));
        else {
          // assert(0 && "ignore other types of variables");
        }
      } else {
        store = SetRVal(store, getLVal(VD), InitVal);
      }
    }
  } else {
    // Process local scalar variables.
    QualType T = VD->getType();
    if (LVal::IsLValType(T) || T->isIntegerType()) {
      RVal V = Ex ? InitVal : UndefinedVal();

      if (Ex && InitVal.isUnknown()) {
        // EXPERIMENTAL: "Conjured" symbols.
        SymbolID Sym = SymMgr.getConjuredSymbol(Ex, Count);

        V = LVal::IsLValType(Ex->getType())
          ? cast<RVal>(lval::SymbolVal(Sym))
          : cast<RVal>(nonlval::SymbolVal(Sym));
      }

      store = SetRVal(store, getLVal(VD), V);
    }
  }

  return store;
}

void BasicStoreManager::print(Store store, std::ostream& Out,
                              const char* nl, const char *sep) {

  VarBindingsTy B = GetVarBindings(store);
  Out << "Variables:" << nl;

  bool isFirst = true;

  for (VarBindingsTy::iterator I=B.begin(), E=B.end(); I != E; ++I) {
    if (isFirst) isFirst = false;
    else Out << nl;

    Out << ' ' << I.getKey()->getName() << " : ";
    I.getData().print(Out);
  }
}

void BasicStoreManager::iterBindings(Store store, BindingsHandler& f) {
  VarBindingsTy B = GetVarBindings(store);

  for (VarBindingsTy::iterator I=B.begin(), E=B.end(); I != E; ++I) {

    f.HandleBinding(*this, store, MRMgr.getVarRegion(I.getKey()),I.getData());
  }
}

StoreManager::BindingsHandler::~BindingsHandler() {}
<|endoftext|>


<commit_before>/**
 * @file classify-test.cpp
 */

#include <vector>
#include <string>
#include <memory>
#include <iostream>

#include "index/document.h"
#include "io/config_reader.h"
#include "tokenizers/tokenizers.h"
#include "util/invertible_map.h"
#include "classify/classifier/all.h"

using std::vector;
using std::unordered_map;
using std::pair;
using std::cout;
using std::cerr;
using std::endl;
using std::string;

using namespace meta;
using namespace meta::index;
using namespace meta::util;
using namespace meta::tokenizers;

/**
 * Tokenizes testing and training docs.
 */
void tokenize(vector<document> & docs, const cpptoml::toml_group & config)
{
    std::shared_ptr<tokenizer> tok = io::config_reader::create_tokenizer(config);

    size_t i = 0;
    for(auto & d: docs)
    {
        common::show_progress(i++, docs.size(), 20, "  tokenizing ");
        tok->tokenize(d, nullptr);
    }
    common::end_progress("  tokenizing ");
}

classify::confusion_matrix cv( classify::classifier & c, const vector<document> & train_docs ) {
    classify::confusion_matrix matrix = c.cross_validate(train_docs, 5);
    matrix.print();
    matrix.print_stats();
    return matrix;
}

/**
 *
 */
int main(int argc, char* argv[])
{
    if(argc != 2)
    {
        cerr << "Usage:\t" << argv[0] << " config.ini" << endl;
        return 1;
    }

    auto config = io::config_reader::read(argv[1]);
    string prefix = *cpptoml::get_as<std::string>( config, "prefix" )
        + *cpptoml::get_as<std::string>( config, "dataset" );;
    string corpus_file = prefix
        + "/"
        + *cpptoml::get_as<std::string>( config, "list" )
        + "-full-corpus.txt";
    vector<document> train_docs = document::load_docs(corpus_file, prefix);
    //vector<document> test_docs = document::loadDocs(prefix + "/test.txt", prefix);

    tokenize(train_docs, config);
    //tokenize(test_docs, config);

    classify::liblinear_svm svm{ *cpptoml::get_as<std::string>( config, "liblinear" ) };
    classify::linear_svm l2svm;
    classify::linear_svm l1svm{ classify::linear_svm::loss_function::L1 };
    classify::perceptron p;
    classify::naive_bayes nb;
    auto m1 = cv( svm, train_docs );
    auto m2 = cv( l2svm, train_docs );
    std::cout << "(liblinear) Significant? " << std::boolalpha << classify::confusion_matrix::mcnemar_significant( m1, m2 ) << std::endl;
    auto m3 = cv( l1svm, train_docs );
    std::cout << "(liblinear) Significant? " << std::boolalpha << classify::confusion_matrix::mcnemar_significant( m1, m3 ) << std::endl;
    auto m4 = cv( p, train_docs );
    std::cout << "(liblinear) Significant? " << std::boolalpha << classify::confusion_matrix::mcnemar_significant( m1, m4 ) << std::endl;
    std::cout << "(lsvm) Significant? " << std::boolalpha << classify::confusion_matrix::mcnemar_significant( m2, m4 ) << std::endl;
    cv( nb, train_docs );
    //svm.train(train_docs);

    return 0;
}
<commit_msg>fix few small typos<commit_after>/**
 * @file classify-test.cpp
 */

#include <vector>
#include <string>
#include <memory>
#include <iostream>

#include "index/document.h"
#include "io/config_reader.h"
#include "tokenizers/tokenizers.h"
#include "util/invertible_map.h"
#include "classify/classifier/all.h"

using std::vector;
using std::unordered_map;
using std::pair;
using std::cout;
using std::cerr;
using std::endl;
using std::string;

using namespace meta;
using namespace meta::index;
using namespace meta::util;
using namespace meta::tokenizers;

/**
 * Tokenizes testing and training docs.
 */
void tokenize(vector<document> & docs, const cpptoml::toml_group & config)
{
    std::shared_ptr<tokenizer> tok = io::config_reader::create_tokenizer(config);

    size_t i = 0;
    for(auto & d: docs)
    {
        common::show_progress(i++, docs.size(), 20, "  tokenizing ");
        tok->tokenize(d, nullptr);
    }
    common::end_progress("  tokenizing ");
}

classify::confusion_matrix cv( classify::classifier & c, const vector<document> & train_docs ) {
    classify::confusion_matrix matrix = c.cross_validate(train_docs, 5);
    matrix.print();
    matrix.print_stats();
    return matrix;
}

/**
 *
 */
int main(int argc, char* argv[])
{
    if(argc != 2)
    {
        cerr << "Usage:\t" << argv[0] << " config.toml" << endl;
        return 1;
    }

    auto config = io::config_reader::read(argv[1]);
    string prefix = *cpptoml::get_as<std::string>( config, "prefix" )
        + *cpptoml::get_as<std::string>( config, "dataset" );
    string corpus_file = prefix
        + "/"
        + *cpptoml::get_as<std::string>( config, "list" )
        + "-full-corpus.txt";
    vector<document> train_docs = document::load_docs(corpus_file, prefix);
    //vector<document> test_docs = document::loadDocs(prefix + "/test.txt", prefix);

    tokenize(train_docs, config);
    //tokenize(test_docs, config);

    classify::liblinear_svm svm{ *cpptoml::get_as<std::string>( config, "liblinear" ) };
    classify::linear_svm l2svm;
    classify::linear_svm l1svm{ classify::linear_svm::loss_function::L1 };
    classify::perceptron p;
    classify::naive_bayes nb;
    auto m1 = cv( svm, train_docs );
    auto m2 = cv( l2svm, train_docs );
    std::cout << "(liblinear) Significant? " << std::boolalpha << classify::confusion_matrix::mcnemar_significant( m1, m2 ) << std::endl;
    auto m3 = cv( l1svm, train_docs );
    std::cout << "(liblinear) Significant? " << std::boolalpha << classify::confusion_matrix::mcnemar_significant( m1, m3 ) << std::endl;
    auto m4 = cv( p, train_docs );
    std::cout << "(liblinear) Significant? " << std::boolalpha << classify::confusion_matrix::mcnemar_significant( m1, m4 ) << std::endl;
    std::cout << "(lsvm) Significant? " << std::boolalpha << classify::confusion_matrix::mcnemar_significant( m2, m4 ) << std::endl;
    cv( nb, train_docs );
    //svm.train(train_docs);

    return 0;
}
<|endoftext|>


<commit_before><commit_msg>fix text of commands to create B-spline curves<commit_after><|endoftext|>


<commit_before>#ifndef KARM_UTILITY_H
#define KARM_UTILITY_H

#include "karmutility.h"

QString formatTime( long minutes )
{
  QString time;
  time.sprintf("%ld:%02ld", minutes / 60, labs(minutes % 60));
  return time;
}

#endif // KARM_UTILITY_H
<commit_msg><commit_after>#ifndef KARM_UTILITY_H
#define KARM_UTILITY_H

#include <stdlib.h>

#include "karmutility.h"

QString formatTime( long minutes )
{
  QString time;
  time.sprintf("%ld:%02ld", minutes / 60, labs(minutes % 60));
  return time;
}

#endif // KARM_UTILITY_H
<|endoftext|>


<commit_before>//=======================================================================
// Copyright Baptiste Wicht 2013-2016.
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://www.opensource.org/licenses/MIT)
//=======================================================================

#include <array.hpp>

#include "drivers/keyboard.hpp"

#include "stdio.hpp"
#include "terminal.hpp"
#include "terminal_driver.hpp"
#include "console.hpp"
#include "assert.hpp"
#include "logging.hpp"
#include "scheduler.hpp"

namespace {

stdio::terminal_driver terminal_driver_impl;
stdio::terminal_driver* tty_driver = &terminal_driver_impl;

constexpr const size_t MAX_TERMINALS = 3;
size_t active_terminal;

std::array<stdio::virtual_terminal, MAX_TERMINALS> terminals;

void input_thread(void* data) {
    auto& terminal = *reinterpret_cast<stdio::virtual_terminal*>(data);

    auto pid = scheduler::get_pid();

    logging::logf(logging::log_level::TRACE, "stdio: Input Thread for terminal %u started (pid:%u)\n", terminal.id, pid);

    bool shift = false;
    bool alt   = false;

    while (true) {
        // Wait for some input
        scheduler::block_process(pid);

        // Handle keyboard input
        while (!terminal.keyboard_buffer.empty()) {
            auto key = terminal.keyboard_buffer.pop();

            if (terminal.canonical) {
                //Key released
                if (key & 0x80) {
                    key &= ~(0x80);

                    if (alt && key == keyboard::KEY_F1) {
                        stdio::switch_terminal(0);
                    } else if (alt && key == keyboard::KEY_F2) {
                        stdio::switch_terminal(1);
                    } else if (alt && key == keyboard::KEY_F3) {
                        stdio::switch_terminal(2);
                    }

                    if (key == keyboard::KEY_LEFT_SHIFT || key == keyboard::KEY_RIGHT_SHIFT) {
                        shift = false;
                    }

                    if (key == keyboard::KEY_ALT) {
                        alt = false;
                    }
                }
                //Key pressed
                else {
                    if (key == keyboard::KEY_LEFT_SHIFT || key == keyboard::KEY_RIGHT_SHIFT) {
                        shift = true;
                    } else if (key == keyboard::KEY_ALT) {
                        alt = true;
                    } else if (key == keyboard::KEY_BACKSPACE) {
                        if (!terminal.input_buffer.empty()) {
                            terminal.input_buffer.pop_last();
                            terminal.print('\b');
                        }
                    } else {
                        auto qwertz_key =
                            shift
                                ? keyboard::shift_key_to_ascii(key)
                                : keyboard::key_to_ascii(key);

                        if (qwertz_key) {
                            terminal.input_buffer.push(qwertz_key);

                            terminal.print(qwertz_key);

                            if (qwertz_key == '\n') {
                                // Transfer current line to the canonical buffer
                                while (!terminal.input_buffer.empty()) {
                                    terminal.canonical_buffer.push(terminal.input_buffer.pop());
                                }

                                terminal.input_queue.notify_one();
                            }
                        }
                    }
                }
            } else {
                // The complete processing of the key will be done by the
                // userspace program
                auto code = keyboard::raw_key_to_keycode(key);
                terminal.raw_buffer.push(static_cast<size_t>(code));

                terminal.input_queue.notify_one();

                thor_assert(!terminal.raw_buffer.full(), "raw buffer is full!");
            }
        }

        // Handle mouse input
        while (!terminal.mouse_buffer.empty()) {
            auto key = terminal.mouse_buffer.pop();

            if (!terminal.canonical && terminal.is_mouse()) {
                terminal.raw_buffer.push(key);

                terminal.input_queue.notify_one();

                thor_assert(!terminal.raw_buffer.full(), "raw buffer is full!");
            }
        }
    }
}

} //end of anonymous namespace

void stdio::init_terminals() {
    size_t id = 0;

    for (auto& terminal : terminals) {
        terminal.id        = id++;
        terminal.active    = false;
        terminal.canonical = true;
        terminal.mouse     = false;
    }

    // Initialize the active terminal

    active_terminal                   = 0;
    terminals[active_terminal].active = true;
    terminals[active_terminal].get_console().set_active(true);
}

void stdio::register_devices() {
    for (auto& terminal : terminals) {
        std::string name = std::string("tty") + std::to_string(terminal.id);

        devfs::register_device("/dev/", name, devfs::device_type::CHAR_DEVICE, tty_driver, &terminal);
    }
}

void stdio::finalize() {
    for (auto& terminal : terminals) {
        auto* user_stack   = new char[scheduler::user_stack_size];
        auto* kernel_stack = new char[scheduler::kernel_stack_size];

        auto& input_process    = scheduler::create_kernel_task_args("tty_input", user_stack, kernel_stack, &input_thread, &terminal);
        input_process.ppid     = 1;
        input_process.priority = scheduler::DEFAULT_PRIORITY;

        scheduler::queue_system_process(input_process.pid);

        terminal.input_thread_pid = input_process.pid;

        // Save the initial image of the terminal
        terminal.get_console().init();
        terminal.get_console().save();
    }
}

size_t stdio::terminals_count() {
    return MAX_TERMINALS;
}

stdio::virtual_terminal& stdio::get_active_terminal() {
    return terminals[active_terminal];
}

stdio::virtual_terminal& stdio::get_terminal(size_t id) {
    thor_assert(id < MAX_TERMINALS, "Out of bound tty");

    return terminals[id];
}

void stdio::switch_terminal(size_t id) {
    if (active_terminal != id) {
        logging::logf(logging::log_level::TRACE, "stdio: Switch activate virtual terminal %u\n", id);

        // Effectively switch the terminal
        terminals[active_terminal].set_active(false);
        terminals[id].set_active(true);

        active_terminal = id;
    }
}
<commit_msg>Lower number of terminals in low memory systems<commit_after>//=======================================================================
// Copyright Baptiste Wicht 2013-2016.
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://www.opensource.org/licenses/MIT)
//=======================================================================

#include <array.hpp>

#include "drivers/keyboard.hpp"

#include "stdio.hpp"
#include "terminal.hpp"
#include "terminal_driver.hpp"
#include "console.hpp"
#include "assert.hpp"
#include "logging.hpp"
#include "scheduler.hpp"
#include "physical_allocator.hpp"

namespace {

stdio::terminal_driver terminal_driver_impl;
stdio::terminal_driver* tty_driver = &terminal_driver_impl;

constexpr const size_t MAX_TERMINALS = 3;

size_t _terminals_count;
size_t active_terminal;

std::array<stdio::virtual_terminal, MAX_TERMINALS> terminals;

void input_thread(void* data) {
    auto& terminal = *reinterpret_cast<stdio::virtual_terminal*>(data);

    auto pid = scheduler::get_pid();

    logging::logf(logging::log_level::TRACE, "stdio: Input Thread for terminal %u started (pid:%u)\n", terminal.id, pid);

    bool shift = false;
    bool alt   = false;

    while (true) {
        // Wait for some input
        scheduler::block_process(pid);

        // Handle keyboard input
        while (!terminal.keyboard_buffer.empty()) {
            auto key = terminal.keyboard_buffer.pop();

            if (terminal.canonical) {
                //Key released
                if (key & 0x80) {
                    key &= ~(0x80);

                    if (alt && key == keyboard::KEY_F1) {
                        stdio::switch_terminal(0);
                    } else if (alt && key == keyboard::KEY_F2) {
                        stdio::switch_terminal(1);
                    } else if (alt && key == keyboard::KEY_F3) {
                        stdio::switch_terminal(2);
                    }

                    if (key == keyboard::KEY_LEFT_SHIFT || key == keyboard::KEY_RIGHT_SHIFT) {
                        shift = false;
                    }

                    if (key == keyboard::KEY_ALT) {
                        alt = false;
                    }
                }
                //Key pressed
                else {
                    if (key == keyboard::KEY_LEFT_SHIFT || key == keyboard::KEY_RIGHT_SHIFT) {
                        shift = true;
                    } else if (key == keyboard::KEY_ALT) {
                        alt = true;
                    } else if (key == keyboard::KEY_BACKSPACE) {
                        if (!terminal.input_buffer.empty()) {
                            terminal.input_buffer.pop_last();
                            terminal.print('\b');
                        }
                    } else {
                        auto qwertz_key =
                            shift
                                ? keyboard::shift_key_to_ascii(key)
                                : keyboard::key_to_ascii(key);

                        if (qwertz_key) {
                            terminal.input_buffer.push(qwertz_key);

                            terminal.print(qwertz_key);

                            if (qwertz_key == '\n') {
                                // Transfer current line to the canonical buffer
                                while (!terminal.input_buffer.empty()) {
                                    terminal.canonical_buffer.push(terminal.input_buffer.pop());
                                }

                                terminal.input_queue.notify_one();
                            }
                        }
                    }
                }
            } else {
                // The complete processing of the key will be done by the
                // userspace program
                auto code = keyboard::raw_key_to_keycode(key);
                terminal.raw_buffer.push(static_cast<size_t>(code));

                terminal.input_queue.notify_one();

                thor_assert(!terminal.raw_buffer.full(), "raw buffer is full!");
            }
        }

        // Handle mouse input
        while (!terminal.mouse_buffer.empty()) {
            auto key = terminal.mouse_buffer.pop();

            if (!terminal.canonical && terminal.is_mouse()) {
                terminal.raw_buffer.push(key);

                terminal.input_queue.notify_one();

                thor_assert(!terminal.raw_buffer.full(), "raw buffer is full!");
            }
        }
    }
}

} //end of anonymous namespace

void stdio::init_terminals() {
    size_t id = 0;

    if(physical_allocator::available() < 64 * 1024 * 1024){
        _terminals_count = 1;
    } else {
        _terminals_count = MAX_TERMINALS;
    }

    logging::logf(logging::log_level::DEBUG, "stdio: using %u terminals\n", _terminals_count);

    for (size_t i = 0; i < _terminals_count; ++i){
        auto& terminal = terminals[i];

        terminal.id        = id++;
        terminal.active    = false;
        terminal.canonical = true;
        terminal.mouse     = false;
    }

    // Initialize the active terminal

    active_terminal                   = 0;
    terminals[active_terminal].active = true;
    terminals[active_terminal].get_console().set_active(true);
}

void stdio::register_devices() {
    for (size_t i = 0; i < _terminals_count; ++i){
        auto& terminal = terminals[i];

        std::string name = std::string("tty") + std::to_string(terminal.id);

        devfs::register_device("/dev/", name, devfs::device_type::CHAR_DEVICE, tty_driver, &terminal);
    }
}

void stdio::finalize() {
    for (size_t i = 0; i < _terminals_count; ++i){
        auto& terminal = terminals[i];

        auto* user_stack   = new char[scheduler::user_stack_size];
        auto* kernel_stack = new char[scheduler::kernel_stack_size];

        auto& input_process    = scheduler::create_kernel_task_args("tty_input", user_stack, kernel_stack, &input_thread, &terminal);
        input_process.ppid     = 1;
        input_process.priority = scheduler::DEFAULT_PRIORITY;

        scheduler::queue_system_process(input_process.pid);

        terminal.input_thread_pid = input_process.pid;

        // Save the initial image of the terminal
        terminal.get_console().init();
        terminal.get_console().save();
    }
}

size_t stdio::terminals_count() {
    return _terminals_count;
}

stdio::virtual_terminal& stdio::get_active_terminal() {
    return terminals[active_terminal];
}

stdio::virtual_terminal& stdio::get_terminal(size_t id) {
    thor_assert(id < _terminals_count, "Out of bound tty");

    return terminals[id];
}

void stdio::switch_terminal(size_t id) {
    if (active_terminal != id) {
        logging::logf(logging::log_level::TRACE, "stdio: Switch activate virtual terminal %u\n", id);

        // Effectively switch the terminal
        terminals[active_terminal].set_active(false);
        terminals[id].set_active(true);

        active_terminal = id;
    }
}
<|endoftext|>


<commit_before><commit_msg>[REF] Simpler symbol_set::enough_terminals method<commit_after><|endoftext|>


<commit_before>// @(#)root/base:$Name:  $:$Id: TStorage.cxx,v 1.5 2000/09/14 17:41:44 rdm Exp $
// Author: Fons Rademakers   29/07/95

/*************************************************************************
 * 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.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TStorage                                                             //
//                                                                      //
// Storage manager. The storage manager works best in conjunction with  //
// the custom ROOT new and delete operators defined in the file         //
// NewDelete.cxx (libNew.so). Only when using the custom allocation     //
// operators will memory usage statistics be gathered using the         //
// TStorage EnterStat(), RemoveStat(), etc. functions.                  //
// Memory checking is by default enabled (when using libNew.so) and     //
// usage statistics is gathered. Using the resource (in .rootrc):       //
// Root.MemStat one can toggle statistics gathering on or off. More     //
// specifically on can trap the allocation of a block of memory of a    //
// certain size. This can be specified using the resource:              //
// Root.MemStat.size, using the resource Root.MemStat.cnt one can       //
// specify after how many allocations of this size the trap should      //
// occur.                                                               //
// Set the compile option R__NOSTATS to de-activate all memory checking //
// and statistics gathering in the system.                              //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include <stdlib.h>

#include "TObjectTable.h"
#include "TError.h"
#include "TMath.h"
#include "TString.h"

#if !defined(R__NOSTATS)
#   define MEM_DEBUG
#   define MEM_STAT
#   define MEM_CHECKOBJECTPOINTERS
#endif

#if defined(MEM_STAT) && !defined(MEM_DEBUG)
#   define MEM_DEBUG
#endif

#ifdef MEM_DEBUG
#   ifdef R__B64
#      define storage_size(p) ((size_t)(((size_t*)p)[-1]))
#   else
#      define storage_size(p) ((size_t)(((int*)p)[-2]))
#   endif
#else
#   define storage_size(p) ((size_t)0)
#endif

#ifndef NOCINT
#define G__PVOID (-1)
#ifndef WIN32
extern long G__globalvarpointer;
#else
#include "G__ci.h"
#endif
#endif

ULong_t       TStorage::fgHeapBegin = (ULong_t)-1L;
ULong_t       TStorage::fgHeapEnd;
size_t        TStorage::fgMaxBlockSize;
FreeHookFun_t TStorage::fgFreeHook;
void         *TStorage::fgFreeHookData;
ReAllocFun_t  TStorage::fgReAllocHook;
ReAllocCFun_t TStorage::fgReAllocCHook;
Bool_t        TStorage::fgHasCustomNewDelete;

ClassImp(TStorage)

//------------------------------------------------------------------------------

static const char *spaceErr = "storage exhausted";

const size_t kObjMaxSize = 10024;

static Bool_t   memStatistics;
static Int_t    allocated[kObjMaxSize], freed[kObjMaxSize];
static Int_t    allocatedTotal, freedTotal;
static void   **traceArray = 0;
static Int_t    traceCapacity = 10, traceIndex = 0, memSize = -1, memIndex = -1;

//______________________________________________________________________________
void TStorage::EnterStat(size_t size, void *p)
{
   // Register a memory allocation operation. If desired one can trap an
   // allocation of a certain size in case one tries to find a memory
   // leak of that particular size. This function is only called via
   // the ROOT custom new operators.

   TStorage::SetMaxBlockSize(TMath::Max(TStorage::GetMaxBlockSize(), size));

   if (!memStatistics) return;

   if ((Int_t)size == memSize) {
      if (traceIndex == memIndex)
         Fatal("EnterStat", "trapped allocation %d", memIndex);

      if (!traceArray) traceArray = (void**) malloc(sizeof(void*)*traceCapacity);

      if (traceIndex >= traceCapacity) {
         traceCapacity = traceCapacity*2;
         traceArray = (void**) realloc(traceArray, sizeof(void*)*traceCapacity);
      }
      traceArray[traceIndex++] = p;
   }
   if (size >= kObjMaxSize)
      allocated[kObjMaxSize-1]++;
   else
      allocated[size]++;
   allocatedTotal += size;
}

//______________________________________________________________________________
void TStorage::RemoveStat(void *vp)
{
   // Register a memory free operation. This function is only called via
   // the custom ROOT delete operator.

   if (!memStatistics) return;

   size_t size = storage_size(vp);
   if ((Int_t)size == memSize) {
      for (int i = 0; i < traceIndex; i++)
         if (traceArray[i] == vp) {
            traceArray[i] = 0;
            break;
         }
   }
   if (size >= kObjMaxSize)
      freed[kObjMaxSize-1]++;
   else
      freed[size]++;
   freedTotal += size;
}

//______________________________________________________________________________
void *TStorage::ReAlloc(void *ovp, size_t size)
{
   // Reallocate (i.e. resize) block of memory.

   if (fgReAllocHook && fgHasCustomNewDelete)
      return (*fgReAllocHook)(ovp, size);

   static const char *where = "TStorage::ReAlloc";

   void *vp;
   if (ovp == 0) {
      vp = ::operator new(size);
      if (vp == 0)
         Fatal(where, spaceErr);
      return vp;
   }

   vp = ::operator new(size);
   if (vp == 0)
      Fatal(where, spaceErr);
   memmove(vp, ovp, size);
   ::operator delete(ovp);
   return vp;
}

//______________________________________________________________________________
void *TStorage::ReAlloc(void *ovp, size_t size, size_t oldsize)
{
   // Reallocate (i.e. resize) block of memory. Checks if current size is
   // equal to oldsize. If not memory was overwritten.

   if (fgReAllocCHook && fgHasCustomNewDelete)
      return (*fgReAllocCHook)(ovp, size, oldsize);

   static const char *where = "TStorage::ReAlloc";

   void *vp;
   if (ovp == 0) {
     vp = ::operator new(size);
     if (vp == 0)
        Fatal(where, spaceErr);
     return vp;
   }
   if (oldsize == size)
      return ovp;

   vp = ::operator new(size);
   if (vp == 0)
      Fatal(where, spaceErr);
   if (size > oldsize) {
      memcpy(vp, ovp, oldsize);
      memset((char*)vp+oldsize, 0, size-oldsize);
   } else
      memcpy(vp, ovp, size);
   ::operator delete(ovp);
   return vp;
}

//______________________________________________________________________________
void *TStorage::ObjectAlloc(size_t sz)
{
   // Used to allocate a TObject on the heap (via TObject::operator new()).
   // Directly after this routine one can call (in the TObject ctor)
   // TStorage::IsOnHeap() to find out if the just created object is on
   // the heap.

   ULong_t space;

#ifndef NOCINT
   // to handle new with placement called via CINT
#ifndef WIN32
   if (G__globalvarpointer != G__PVOID) {
      space = G__globalvarpointer;
      G__globalvarpointer = G__PVOID;
   } else
#else
   space = G__getgvp();
   if ((long)space != G__PVOID) {
      G__setgvp(G__PVOID);
   } else
#endif
#endif
   space = (ULong_t) ::operator new(sz);
   AddToHeap(space, space+sz);
   return (void*) space;
}

//______________________________________________________________________________
void *TStorage::ObjectAlloc(size_t , void *vp)
{
   // Used to allocate a TObject on the heap (via TObject::operator new(size_t,void*))
   // in position vp. vp is already allocated (maybe on heap, maybe on
   // stack) so just return.

   return vp;
}

//______________________________________________________________________________
void TStorage::ObjectDealloc(void *vp)
{
   // Used to deallocate a TObject on the heap (via TObject::operator delete()).

#ifndef NOCINT
   // to handle delete with placement called via CINT
#ifndef WIN32
   if ((long)vp == G__globalvarpointer && G__globalvarpointer != G__PVOID)
      return;
#else
   long gvp = G__getgvp();
   if ((long)vp == gvp && gvp != G__PVOID)
      return;
#endif
#endif
   ::operator delete(vp);
}

//______________________________________________________________________________
void TStorage::ObjectDealloc(void *vp, void *ptr)
{
   // Used to deallocate a TObject on the heap (via TObject::operator delete(void*,void*)).

   if (vp && ptr) { }
}

//______________________________________________________________________________
void TStorage::SetFreeHook(FreeHookFun_t fh, void *data)
{
   // Set a free handler.

   fgFreeHook     = fh;
   fgFreeHookData = data;
}

//______________________________________________________________________________
void TStorage::SetReAllocHooks(ReAllocFun_t rh1, ReAllocCFun_t rh2)
{
   // Set a custom ReAlloc handlers. This function is typically
   // called via a static object in the ROOT libNew.so shared library.

   fgReAllocHook  = rh1;
   fgReAllocCHook = rh2;
}

//______________________________________________________________________________
void TStorage::PrintStatistics()
{
   // Print memory usage statistics.

#if defined(MEM_DEBUG) && defined(MEM_STAT)

   if (!memStatistics || !HasCustomNewDelete())
      return;

   //Printf("");
   Printf("Heap statistics");
   Printf("%12s%12s%12s%12s", "size", "alloc", "free", "diff");
   Printf("================================================");

   int i;
   for (i = 0; i < (int)kObjMaxSize; i++)
      if (allocated[i] != freed[i])
      //if (allocated[i])
         Printf("%12d%12d%12d%12d", i, allocated[i], freed[i],
                allocated[i]-freed[i]);

   if (allocatedTotal != freedTotal) {
      Printf("------------------------------------------------");
      Printf("Total:      %12d%12d%12d", allocatedTotal, freedTotal,
              allocatedTotal-freedTotal);
   }

   if (memSize != -1) {
      Printf("------------------------------------------------");
      for (i= 0; i < traceIndex; i++)
         if (traceArray[i])
            Printf("block %d of size %d not freed", i, memSize);
   }
   Printf("================================================");
   Printf("");
#endif
}

//______________________________________________________________________________
void TStorage::EnableStatistics(int size, int ix)
{
   // Enable memory usage statistics gathering. Size is the size of the memory
   // block that should be trapped and ix is after how many such allocations
   // the trap should happen.

#ifdef MEM_STAT
   memSize       = size;
   memIndex      = ix;
   memStatistics = kTRUE;
#else
   int idum = size; int iidum = ix;
#endif
}

//______________________________________________________________________________
ULong_t TStorage::GetHeapBegin()
{
   return fgHeapBegin;
}

//______________________________________________________________________________
ULong_t TStorage::GetHeapEnd()
{
   return fgHeapEnd;
}

//______________________________________________________________________________
void *TStorage::GetFreeHookData()
{
   return fgFreeHookData;
}

//______________________________________________________________________________
Bool_t TStorage::HasCustomNewDelete()
{
   return fgHasCustomNewDelete;
}

//______________________________________________________________________________
void TStorage::SetCustomNewDelete()
{
   fgHasCustomNewDelete = kTRUE;
}

#ifdef WIN32

//______________________________________________________________________________
void TStorage::AddToHeap(ULong_t begin, ULong_t end)
{
   if (begin < fgHeapBegin) fgHeapBegin = begin;
   if (end   > fgHeapEnd)   fgHeapEnd   = end;
}

//______________________________________________________________________________
Bool_t TStorage::IsOnHeap(void *p)
{
   return (ULong_t)p >= fgHeapBegin && (ULong_t)p < fgHeapEnd;
}

//______________________________________________________________________________
size_t TStorage::GetMaxBlockSize()
{
   return fgMaxBlockSize;
}

//______________________________________________________________________________
void TStorage::SetMaxBlockSize(size_t size)
{
   fgMaxBlockSize = size;
}

//______________________________________________________________________________
FreeHookFun_t TStorage::GetFreeHook()
{
   return fgFreeHook;
}

#endif
<commit_msg>add case for new memory checker.<commit_after>// @(#)root/base:$Name:  $:$Id: TStorage.cxx,v 1.6 2000/10/13 18:57:45 rdm Exp $
// Author: Fons Rademakers   29/07/95

/*************************************************************************
 * 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.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TStorage                                                             //
//                                                                      //
// Storage manager. The storage manager works best in conjunction with  //
// the custom ROOT new and delete operators defined in the file         //
// NewDelete.cxx (libNew.so). Only when using the custom allocation     //
// operators will memory usage statistics be gathered using the         //
// TStorage EnterStat(), RemoveStat(), etc. functions.                  //
// Memory checking is by default enabled (when using libNew.so) and     //
// usage statistics is gathered. Using the resource (in .rootrc):       //
// Root.MemStat one can toggle statistics gathering on or off. More     //
// specifically on can trap the allocation of a block of memory of a    //
// certain size. This can be specified using the resource:              //
// Root.MemStat.size, using the resource Root.MemStat.cnt one can       //
// specify after how many allocations of this size the trap should      //
// occur.                                                               //
// Set the compile option R__NOSTATS to de-activate all memory checking //
// and statistics gathering in the system.                              //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include <stdlib.h>

#include "TROOT.h"
#include "TObjectTable.h"
#include "TError.h"
#include "TMath.h"
#include "TString.h"

#if !defined(R__NOSTATS)
#   define MEM_DEBUG
#   define MEM_STAT
#   define MEM_CHECKOBJECTPOINTERS
#endif

#if defined(MEM_STAT) && !defined(MEM_DEBUG)
#   define MEM_DEBUG
#endif

#ifdef MEM_DEBUG
#   ifdef R__B64
#      define storage_size(p) ((size_t)(((size_t*)p)[-1]))
#   else
#      define storage_size(p) ((size_t)(((int*)p)[-2]))
#   endif
#else
#   define storage_size(p) ((size_t)0)
#endif

#ifndef NOCINT
#define G__PVOID (-1)
#ifndef WIN32
extern long G__globalvarpointer;
#else
#include "G__ci.h"
#endif
#endif

ULong_t       TStorage::fgHeapBegin = (ULong_t)-1L;
ULong_t       TStorage::fgHeapEnd;
size_t        TStorage::fgMaxBlockSize;
FreeHookFun_t TStorage::fgFreeHook;
void         *TStorage::fgFreeHookData;
ReAllocFun_t  TStorage::fgReAllocHook;
ReAllocCFun_t TStorage::fgReAllocCHook;
Bool_t        TStorage::fgHasCustomNewDelete;

ClassImp(TStorage)

//------------------------------------------------------------------------------

static const char *spaceErr = "storage exhausted";

const size_t kObjMaxSize = 10024;

static Bool_t   memStatistics;
static Int_t    allocated[kObjMaxSize], freed[kObjMaxSize];
static Int_t    allocatedTotal, freedTotal;
static void   **traceArray = 0;
static Int_t    traceCapacity = 10, traceIndex = 0, memSize = -1, memIndex = -1;

//______________________________________________________________________________
void TStorage::EnterStat(size_t size, void *p)
{
   // Register a memory allocation operation. If desired one can trap an
   // allocation of a certain size in case one tries to find a memory
   // leak of that particular size. This function is only called via
   // the ROOT custom new operators.

   TStorage::SetMaxBlockSize(TMath::Max(TStorage::GetMaxBlockSize(), size));

   if (!memStatistics) return;

   if ((Int_t)size == memSize) {
      if (traceIndex == memIndex)
         Fatal("EnterStat", "trapped allocation %d", memIndex);

      if (!traceArray) traceArray = (void**) malloc(sizeof(void*)*traceCapacity);

      if (traceIndex >= traceCapacity) {
         traceCapacity = traceCapacity*2;
         traceArray = (void**) realloc(traceArray, sizeof(void*)*traceCapacity);
      }
      traceArray[traceIndex++] = p;
   }
   if (size >= kObjMaxSize)
      allocated[kObjMaxSize-1]++;
   else
      allocated[size]++;
   allocatedTotal += size;
}

//______________________________________________________________________________
void TStorage::RemoveStat(void *vp)
{
   // Register a memory free operation. This function is only called via
   // the custom ROOT delete operator.

   if (!memStatistics) return;

   size_t size = storage_size(vp);
   if ((Int_t)size == memSize) {
      for (int i = 0; i < traceIndex; i++)
         if (traceArray[i] == vp) {
            traceArray[i] = 0;
            break;
         }
   }
   if (size >= kObjMaxSize)
      freed[kObjMaxSize-1]++;
   else
      freed[size]++;
   freedTotal += size;
}

//______________________________________________________________________________
void *TStorage::ReAlloc(void *ovp, size_t size)
{
   // Reallocate (i.e. resize) block of memory.

   if (fgReAllocHook && fgHasCustomNewDelete && !TROOT::MemCheck())
      return (*fgReAllocHook)(ovp, size);

   static const char *where = "TStorage::ReAlloc";

   void *vp;
   if (ovp == 0) {
      vp = ::operator new(size);
      if (vp == 0)
         Fatal(where, spaceErr);
      return vp;
   }

   vp = ::operator new(size);
   if (vp == 0)
      Fatal(where, spaceErr);
   memmove(vp, ovp, size);
   ::operator delete(ovp);
   return vp;
}

//______________________________________________________________________________
void *TStorage::ReAlloc(void *ovp, size_t size, size_t oldsize)
{
   // Reallocate (i.e. resize) block of memory. Checks if current size is
   // equal to oldsize. If not memory was overwritten.

   if (fgReAllocCHook && fgHasCustomNewDelete && !TROOT::MemCheck())
      return (*fgReAllocCHook)(ovp, size, oldsize);

   static const char *where = "TStorage::ReAlloc";

   void *vp;
   if (ovp == 0) {
     vp = ::operator new(size);
     if (vp == 0)
        Fatal(where, spaceErr);
     return vp;
   }
   if (oldsize == size)
      return ovp;

   vp = ::operator new(size);
   if (vp == 0)
      Fatal(where, spaceErr);
   if (size > oldsize) {
      memcpy(vp, ovp, oldsize);
      memset((char*)vp+oldsize, 0, size-oldsize);
   } else
      memcpy(vp, ovp, size);
   ::operator delete(ovp);
   return vp;
}

//______________________________________________________________________________
void *TStorage::ObjectAlloc(size_t sz)
{
   // Used to allocate a TObject on the heap (via TObject::operator new()).
   // Directly after this routine one can call (in the TObject ctor)
   // TStorage::IsOnHeap() to find out if the just created object is on
   // the heap.

   ULong_t space;

#ifndef NOCINT
   // to handle new with placement called via CINT
#ifndef WIN32
   if (G__globalvarpointer != G__PVOID) {
      space = G__globalvarpointer;
      G__globalvarpointer = G__PVOID;
   } else
#else
   space = G__getgvp();
   if ((long)space != G__PVOID) {
      G__setgvp(G__PVOID);
   } else
#endif
#endif
   space = (ULong_t) ::operator new(sz);
   AddToHeap(space, space+sz);
   return (void*) space;
}

//______________________________________________________________________________
void *TStorage::ObjectAlloc(size_t , void *vp)
{
   // Used to allocate a TObject on the heap (via TObject::operator new(size_t,void*))
   // in position vp. vp is already allocated (maybe on heap, maybe on
   // stack) so just return.

   return vp;
}

//______________________________________________________________________________
void TStorage::ObjectDealloc(void *vp)
{
   // Used to deallocate a TObject on the heap (via TObject::operator delete()).

#ifndef NOCINT
   // to handle delete with placement called via CINT
#ifndef WIN32
   if ((long)vp == G__globalvarpointer && G__globalvarpointer != G__PVOID)
      return;
#else
   long gvp = G__getgvp();
   if ((long)vp == gvp && gvp != G__PVOID)
      return;
#endif
#endif
   ::operator delete(vp);
}

//______________________________________________________________________________
void TStorage::ObjectDealloc(void *vp, void *ptr)
{
   // Used to deallocate a TObject on the heap (via TObject::operator delete(void*,void*)).

   if (vp && ptr) { }
}

//______________________________________________________________________________
void TStorage::SetFreeHook(FreeHookFun_t fh, void *data)
{
   // Set a free handler.

   fgFreeHook     = fh;
   fgFreeHookData = data;
}

//______________________________________________________________________________
void TStorage::SetReAllocHooks(ReAllocFun_t rh1, ReAllocCFun_t rh2)
{
   // Set a custom ReAlloc handlers. This function is typically
   // called via a static object in the ROOT libNew.so shared library.

   fgReAllocHook  = rh1;
   fgReAllocCHook = rh2;
}

//______________________________________________________________________________
void TStorage::PrintStatistics()
{
   // Print memory usage statistics.

#if defined(MEM_DEBUG) && defined(MEM_STAT)

   if (!memStatistics || !HasCustomNewDelete())
      return;

   //Printf("");
   Printf("Heap statistics");
   Printf("%12s%12s%12s%12s", "size", "alloc", "free", "diff");
   Printf("================================================");

   int i;
   for (i = 0; i < (int)kObjMaxSize; i++)
      if (allocated[i] != freed[i])
      //if (allocated[i])
         Printf("%12d%12d%12d%12d", i, allocated[i], freed[i],
                allocated[i]-freed[i]);

   if (allocatedTotal != freedTotal) {
      Printf("------------------------------------------------");
      Printf("Total:      %12d%12d%12d", allocatedTotal, freedTotal,
              allocatedTotal-freedTotal);
   }

   if (memSize != -1) {
      Printf("------------------------------------------------");
      for (i= 0; i < traceIndex; i++)
         if (traceArray[i])
            Printf("block %d of size %d not freed", i, memSize);
   }
   Printf("================================================");
   Printf("");
#endif
}

//______________________________________________________________________________
void TStorage::EnableStatistics(int size, int ix)
{
   // Enable memory usage statistics gathering. Size is the size of the memory
   // block that should be trapped and ix is after how many such allocations
   // the trap should happen.

#ifdef MEM_STAT
   memSize       = size;
   memIndex      = ix;
   memStatistics = kTRUE;
#else
   int idum = size; int iidum = ix;
#endif
}

//______________________________________________________________________________
ULong_t TStorage::GetHeapBegin()
{
   return fgHeapBegin;
}

//______________________________________________________________________________
ULong_t TStorage::GetHeapEnd()
{
   return fgHeapEnd;
}

//______________________________________________________________________________
void *TStorage::GetFreeHookData()
{
   return fgFreeHookData;
}

//______________________________________________________________________________
Bool_t TStorage::HasCustomNewDelete()
{
   return fgHasCustomNewDelete;
}

//______________________________________________________________________________
void TStorage::SetCustomNewDelete()
{
   fgHasCustomNewDelete = kTRUE;
}

#ifdef WIN32

//______________________________________________________________________________
void TStorage::AddToHeap(ULong_t begin, ULong_t end)
{
   if (begin < fgHeapBegin) fgHeapBegin = begin;
   if (end   > fgHeapEnd)   fgHeapEnd   = end;
}

//______________________________________________________________________________
Bool_t TStorage::IsOnHeap(void *p)
{
   return (ULong_t)p >= fgHeapBegin && (ULong_t)p < fgHeapEnd;
}

//______________________________________________________________________________
size_t TStorage::GetMaxBlockSize()
{
   return fgMaxBlockSize;
}

//______________________________________________________________________________
void TStorage::SetMaxBlockSize(size_t size)
{
   fgMaxBlockSize = size;
}

//______________________________________________________________________________
FreeHookFun_t TStorage::GetFreeHook()
{
   return fgFreeHook;
}

#endif
<|endoftext|>


<commit_before>#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <Channel.h>

namespace test {

using ::testing::_;
using ::testing::Return;
using ::testing::AtLeast;

struct ChannelTestSuite : public ::testing::Test{
  using Events     = Transformer::Events;
  using EventTypes = Transformer::EventTypes;
  using TransPtr   = Transformation::TransPtr;

  struct TestTransformer : public SimpleTransformer {
    TestTransformer() : SimpleTransformer(EventType(), EventType()) {}
    MOCK_CONST_METHOD1(check, bool(const MetaEvent&));
    MOCK_CONST_METHOD1(execute, MetaEvent(const MetaEvent&));
    MOCK_CONST_METHOD1(print, void(std::ostream&));
  };

  struct TestChannel : public Channel {
    TestChannel() : Channel(TransPtr(new TestTransformer())) { }

    MOCK_CONST_METHOD1(publishEvent, void(const MetaEvent& e));
    void handleEvent() { Channel::handleEvent(MetaEvent()); }
    Transformer* trans() { return mTrans.get(); }
  } c;
};

TEST_F(ChannelTestSuite, failedSingleTransformTest) {
  ASSERT_TRUE(c.trans());
	EXPECT_CALL(dynamic_cast<TestTransformer&>(*c.trans()), execute(_))
		.Times(0);
  EXPECT_CALL(dynamic_cast<const TestTransformer&>(*c.trans()), check(_))
    .Times(AtLeast(1))
    .WillRepeatedly(Return(false));
  EXPECT_CALL(c, publishEvent(_))
    .Times(0);
  c.handleEvent();
}

TEST_F(ChannelTestSuite, succededTransformTest) {
	MetaEvent e;
	MetaAttribute a;
	e.add(a);
  ASSERT_TRUE(c.trans());
	EXPECT_CALL(dynamic_cast<TestTransformer&>(*c.trans()), execute(_))
		.Times(1)
		.WillRepeatedly(Return(e));
  EXPECT_CALL(dynamic_cast<const TestTransformer&>(*c.trans()), check(_))
    .Times(AtLeast(1))
    .WillRepeatedly(Return(true));
  EXPECT_CALL(c, publishEvent(_))
    .Times(1);
  c.handleEvent();
}

}
<commit_msg>UnitTest: fix channel test to fulfil new checks<commit_after>#include <gtest/gtest.h>
#include <gmock/gmock.h>
#include <Channel.h>
#include <BaseEvent.h>

namespace test {

using ::testing::_;
using ::testing::Return;
using ::testing::AtLeast;

struct ChannelTestSuite : public ::testing::Test{
  using Events     = Transformer::Events;
  using EventTypes = Transformer::EventTypes;
  using TransPtr   = Transformation::TransPtr;

  struct TestTransformer : public SimpleTransformer {
    TestTransformer() : SimpleTransformer(EventType(), EventType()) {}
    MOCK_CONST_METHOD1(check, bool(const MetaEvent&));
    MOCK_CONST_METHOD1(execute, MetaEvent(const MetaEvent&));
    MOCK_CONST_METHOD1(print, void(std::ostream&));
  };

  struct TestChannel : public Channel {
    TestChannel() : Channel(TransPtr(new TestTransformer())) { }

    MOCK_CONST_METHOD1(publishEvent, void(const MetaEvent& e));
    MOCK_CONST_METHOD2(error, void(Errors, const MetaEvent&));
    void handleEvent() { Channel::handleEvent(MetaEvent()); }
    Transformer* trans() { return mTrans.get(); }
  } c;
};

TEST_F(ChannelTestSuite, failedSingleTransformTest) {
  ASSERT_TRUE(c.trans());
	EXPECT_CALL(c, error(_,_)).Times(0);
	EXPECT_CALL(dynamic_cast<TestTransformer&>(*c.trans()), execute(_))
		.Times(0);
  EXPECT_CALL(dynamic_cast<const TestTransformer&>(*c.trans()), check(_))
    .Times(AtLeast(1))
    .WillRepeatedly(Return(false));
  EXPECT_CALL(c, publishEvent(_))
    .Times(0);
  c.handleEvent();
}

TEST_F(ChannelTestSuite, succededTransformTest) {
	MetaEvent e((EventType)BaseEvent<>());
  ASSERT_TRUE(c.trans());
	EXPECT_CALL(c, error(_,_)).Times(0);
	EXPECT_CALL(dynamic_cast<TestTransformer&>(*c.trans()), execute(_))
		.Times(1)
		.WillRepeatedly(Return(e));
  EXPECT_CALL(dynamic_cast<const TestTransformer&>(*c.trans()), check(_))
    .Times(AtLeast(1))
    .WillRepeatedly(Return(true));
  EXPECT_CALL(c, publishEvent(_))
    .Times(1);
  c.handleEvent();
}

}
<|endoftext|>


<commit_before><commit_msg>Fix for osx Lanzcos scale test.<commit_after><|endoftext|>


<commit_before>#include <glibmm/i18n.h>

#include "siteeditor.h"
using namespace AhoViewer;
using namespace AhoViewer::Booru;

#include "settings.h"

// Fixes issue with winnt.h
#ifdef DELETE
#undef DELETE
#endif

SiteEditor::SiteEditor(BaseObjectType *cobj, const Glib::RefPtr<Gtk::Builder> &bldr)
  : Gtk::TreeView(cobj),
    m_Model(Gtk::ListStore::create(m_Columns)),
    m_NameColumn(Gtk::manage(new Gtk::TreeView::Column(_("Name"), m_Columns.name))),
    m_UrlColumn(Gtk::manage(new Gtk::TreeView::Column(_("Url"), m_Columns.url))),
    m_Sites(Settings.get_sites()),
    m_ErrorPixbuf(Gtk::Invisible().render_icon(Gtk::Stock::DELETE, Gtk::ICON_SIZE_MENU)),
    m_SiteCheckEdit(false),
    m_SiteCheckEditSuccess(false)
{
    bldr->get_widget("BooruRegisterLinkButton", m_RegisterButton);
    bldr->get_widget("BooruUsernameEntry", m_UsernameEntry);
    bldr->get_widget("BooruPasswordEntry", m_PasswordEntry);
    bldr->get_widget("BooruPasswordLabel", m_PasswordLabel);

    m_SignalSiteChecked.connect(sigc::mem_fun(*this, &SiteEditor::on_site_checked));

    for (const std::shared_ptr<Site> &s : m_Sites)
    {
        Gtk::TreeIter iter = m_Model->append();
        iter->set_value(m_Columns.icon, s->get_icon_pixbuf());
        s->signal_icon_downloaded().connect([ this, iter, s ]()
                { iter->set_value(m_Columns.icon, s->get_icon_pixbuf()); });
        iter->set_value(m_Columns.name, s->get_name());
        iter->set_value(m_Columns.url,  s->get_url());
        iter->set_value(m_Columns.site, s);
    }

    CellRendererIcon *iconRenderer = Gtk::manage(new CellRendererIcon(this));
    iconRenderer->property_xpad() = 2;
    iconRenderer->property_ypad() = 2;
    append_column("", *iconRenderer);
    get_column(0)->add_attribute(iconRenderer->property_loading(), m_Columns.loading);
    get_column(0)->add_attribute(iconRenderer->property_pulse(), m_Columns.pulse);
    get_column(0)->add_attribute(iconRenderer->property_pixbuf(), m_Columns.icon);

    Gtk::CellRendererText *textRenderer = nullptr;

    textRenderer = static_cast<Gtk::CellRendererText*>(m_NameColumn->get_first_cell());
    textRenderer->property_editable() = true;
    textRenderer->signal_edited().connect(sigc::mem_fun(*this, &SiteEditor::on_name_edited));
    append_column(*m_NameColumn);

    textRenderer = static_cast<Gtk::CellRendererText*>(m_UrlColumn->get_first_cell());
    textRenderer->property_editable() = true;
    textRenderer->signal_edited().connect(sigc::mem_fun(*this, &SiteEditor::on_url_edited));
    append_column(*m_UrlColumn);

    set_model(m_Model);
    get_selection()->select(m_Model->get_iter("0"));

    Gtk::ToolButton *toolButton = nullptr;
    bldr->get_widget("DeleteSiteButton", toolButton);
    toolButton->signal_clicked().connect(sigc::mem_fun(*this, &SiteEditor::delete_site));

    bldr->get_widget("AddSiteButton", toolButton);
    toolButton->signal_clicked().connect(sigc::mem_fun(*this, &SiteEditor::add_row));

    m_UsernameConn = m_UsernameEntry->signal_changed().connect(
            sigc::mem_fun(*this, &SiteEditor::on_username_edited));
    m_PasswordConn = m_PasswordEntry->signal_changed().connect(
            sigc::mem_fun(*this, &SiteEditor::on_password_edited));

#ifdef HAVE_LIBSECRET
    // Make sure the initially selected site's password gets set in the entry once it's loaded
    const std::shared_ptr<Site> &s = get_selection()->get_selected()->get_value(m_Columns.site);
    if (s)
        s->signal_password_lookup().connect([ this, s ]() { m_PasswordEntry->set_text(s->get_password()); });

    m_PasswordEntry->set_visibility(false);
#endif // HAVE_LIBSECRET

    // Set initial values for entries and linkbutton
    on_cursor_changed();
}

SiteEditor::~SiteEditor()
{
    if (m_SiteCheckThread.joinable())
        m_SiteCheckThread.join();
}

bool SiteEditor::on_key_release_event(GdkEventKey *e)
{
    if (e->keyval == GDK_Return || e->keyval == GDK_ISO_Enter
     || e->keyval == GDK_KP_Enter || e->keyval == GDK_Tab)
    {
        Gtk::TreeIter iter = get_selection()->get_selected();
        Gtk::TreePath p(iter);

        if (iter->get_value(m_Columns.url).empty())
            set_cursor(p, *m_UrlColumn, true);
        else if (iter->get_value(m_Columns.name).empty())
            set_cursor(p, *m_NameColumn, true);
    }

    return false;
}

void SiteEditor::on_cursor_changed()
{
    Gtk::TreeView::on_cursor_changed();

    const std::shared_ptr<Site> &s = get_selection()->get_selected()->get_value(m_Columns.site);

    m_UsernameConn.block();
    m_PasswordConn.block();

    if (s)
    {
        m_RegisterButton->set_label(_("Register account on ") + s->get_name());
        m_RegisterButton->set_uri(s->get_register_uri());

        m_UsernameEntry->set_text(s->get_username());
        m_PasswordEntry->set_text(s->get_password());
    }
    else
    {
        m_RegisterButton->set_label(_("Register account"));

        m_UsernameEntry->set_text("");
        m_PasswordEntry->set_text("");
    }

    m_UsernameConn.unblock();
    m_PasswordConn.unblock();

    m_RegisterButton->set_sensitive(!!s);
    m_UsernameEntry->set_sensitive(!!s);
    m_PasswordEntry->set_sensitive(!!s);

    if (!s || s->get_type() == Site::Type::GELBOORU)
        m_PasswordLabel->set_text(_("Password:"));
    else
        m_PasswordLabel->set_text(_("API Key:"));
}

void SiteEditor::add_row()
{
    Gtk::TreePath path(m_Model->append());
    set_cursor(path, *m_NameColumn, true);
    scroll_to_row(path);
}

void SiteEditor::delete_site()
{
    Gtk::TreeIter o = get_selection()->get_selected();

    if (o)
    {
        m_Sites.erase(std::remove(m_Sites.begin(), m_Sites.end(), o->get_value(m_Columns.site)), m_Sites.end());
        m_SignalEdited();

        Gtk::TreeIter n = m_Model->erase(o);
        if (m_Model->children().size())
        {
            get_selection()->select(n ? n : --n);
            on_cursor_changed();
        }
    }
}

void SiteEditor::on_name_edited(const std::string &p, const std::string &text)
{
    Gtk::TreePath path(p);
    Gtk::TreeIter iter = m_Model->get_iter(path);
    std::string name = text;

    // make sure the site name is unique
    for (size_t i = 1; !is_name_unique(iter, name); ++i)
        name = text + std::to_string(i);

    iter->set_value(m_Columns.name, name);

    if (!iter->get_value(m_Columns.url).empty())
        add_edit_site(iter);
}

void SiteEditor::on_url_edited(const std::string &p, const std::string &text)
{
    Gtk::TreePath path(p);
    Gtk::TreeIter iter = m_Model->get_iter(path);
    std::string url = text;

    if (url.back() == '/')
        url = text.substr(0, text.size() - 1);

    iter->set_value(m_Columns.url, url);
    add_edit_site(iter);
}

bool SiteEditor::is_name_unique(const Gtk::TreeIter &iter, const std::string &name) const
{
    for (const Gtk::TreeIter &i : m_Model->children())
        if (i->get_value(m_Columns.name) == name && iter != i)
            return false;

    return true;
}

void SiteEditor::add_edit_site(const Gtk::TreeIter &iter)
{
    std::string name = iter->get_value(m_Columns.name),
                url(iter->get_value(m_Columns.url));

    if (name.empty() || url.empty())
    {
        iter->set_value(m_Columns.icon, m_ErrorPixbuf);
        return;
    }

    if (m_SiteCheckThread.joinable())
        m_SiteCheckThread.join();

    m_SiteCheckIter = iter;

    std::vector<std::shared_ptr<Site>>::iterator i =
        std::find(m_Sites.begin(), m_Sites.end(), iter->get_value(m_Columns.site));
    std::shared_ptr<Site> site = i != m_Sites.end() ? *i : nullptr;

    // editting
    if (site)
    {
        if (name == site->get_name() && url == site->get_url())
        {
            if (iter->get_value(m_Columns.icon) == m_ErrorPixbuf)
                iter->set_value(m_Columns.icon, site->get_icon_pixbuf());

            return;
        }

        m_SiteCheckEdit = true;
        m_SiteCheckSite = site;
        m_SiteCheckIter->set_value(m_Columns.loading, true);
        m_SiteCheckThread = std::thread([ this, name, url ]()
        {
            m_SiteCheckSite->set_name(name);
            m_SiteCheckEditSuccess = m_SiteCheckSite->set_url(url);

            if (m_SiteCheckEditSuccess)
                update_edited_site_icon();

            m_SignalSiteChecked();
        });
    }
    else
    {
        m_SiteCheckEdit = false;
        m_SiteCheckIter->set_value(m_Columns.loading, true);
        m_SiteCheckThread = std::thread([ this, name, url ]()
        {
            m_SiteCheckSite = Site::create(name, url);

            if (m_SiteCheckSite)
                update_edited_site_icon();

            m_SignalSiteChecked();
        });
    }
}

void SiteEditor::update_edited_site_icon()
{
    m_SiteCheckIter->set_value(m_Columns.icon, m_SiteCheckSite->get_icon_pixbuf(true));
    m_SiteCheckIter->set_value(m_Columns.loading, false);
}

void SiteEditor::on_site_checked()
{
    if ((m_SiteCheckEdit && !m_SiteCheckEditSuccess) || (!m_SiteCheckEdit && !m_SiteCheckSite))
    {
        m_SiteCheckIter->set_value(m_Columns.icon, m_ErrorPixbuf);
        m_SiteCheckIter->set_value(m_Columns.loading, false);
    }
    else if (m_SiteCheckSite && !m_SiteCheckEdit)
    {
        m_Sites.push_back(m_SiteCheckSite);
        m_SiteCheckIter->set_value(m_Columns.site, m_SiteCheckSite);
        on_cursor_changed();
    }

    if (m_SiteCheckEdit || m_SiteCheckSite)
        m_SignalEdited();

    if (m_SiteCheckThread.joinable())
        m_SiteCheckThread.join();
}

void SiteEditor::on_username_edited()
{
    const std::shared_ptr<Site> &s = get_selection()->get_selected()->get_value(m_Columns.site);
    if (s) s->set_username(m_UsernameEntry->get_text());
}

void SiteEditor::on_password_edited()
{
    const std::shared_ptr<Site> &s = get_selection()->get_selected()->get_value(m_Columns.site);
    if (s) s->set_password(m_PasswordEntry->get_text());
}
<commit_msg>siteeditor: Handle deleting all sites better<commit_after>#include <glibmm/i18n.h>

#include "siteeditor.h"
using namespace AhoViewer;
using namespace AhoViewer::Booru;

#include "settings.h"

// Fixes issue with winnt.h
#ifdef DELETE
#undef DELETE
#endif

SiteEditor::SiteEditor(BaseObjectType *cobj, const Glib::RefPtr<Gtk::Builder> &bldr)
  : Gtk::TreeView(cobj),
    m_Model(Gtk::ListStore::create(m_Columns)),
    m_NameColumn(Gtk::manage(new Gtk::TreeView::Column(_("Name"), m_Columns.name))),
    m_UrlColumn(Gtk::manage(new Gtk::TreeView::Column(_("Url"), m_Columns.url))),
    m_Sites(Settings.get_sites()),
    m_ErrorPixbuf(Gtk::Invisible().render_icon(Gtk::Stock::DELETE, Gtk::ICON_SIZE_MENU)),
    m_SiteCheckEdit(false),
    m_SiteCheckEditSuccess(false)
{
    bldr->get_widget("BooruRegisterLinkButton", m_RegisterButton);
    bldr->get_widget("BooruUsernameEntry", m_UsernameEntry);
    bldr->get_widget("BooruPasswordEntry", m_PasswordEntry);
    bldr->get_widget("BooruPasswordLabel", m_PasswordLabel);

    m_SignalSiteChecked.connect(sigc::mem_fun(*this, &SiteEditor::on_site_checked));

    for (const std::shared_ptr<Site> &s : m_Sites)
    {
        Gtk::TreeIter iter = m_Model->append();
        iter->set_value(m_Columns.icon, s->get_icon_pixbuf());
        s->signal_icon_downloaded().connect([ this, iter, s ]()
                { iter->set_value(m_Columns.icon, s->get_icon_pixbuf()); });
        iter->set_value(m_Columns.name, s->get_name());
        iter->set_value(m_Columns.url,  s->get_url());
        iter->set_value(m_Columns.site, s);
    }

    CellRendererIcon *iconRenderer = Gtk::manage(new CellRendererIcon(this));
    iconRenderer->property_xpad() = 2;
    iconRenderer->property_ypad() = 2;
    append_column("", *iconRenderer);
    get_column(0)->add_attribute(iconRenderer->property_loading(), m_Columns.loading);
    get_column(0)->add_attribute(iconRenderer->property_pulse(), m_Columns.pulse);
    get_column(0)->add_attribute(iconRenderer->property_pixbuf(), m_Columns.icon);

    Gtk::CellRendererText *textRenderer = nullptr;

    textRenderer = static_cast<Gtk::CellRendererText*>(m_NameColumn->get_first_cell());
    textRenderer->property_editable() = true;
    textRenderer->signal_edited().connect(sigc::mem_fun(*this, &SiteEditor::on_name_edited));
    append_column(*m_NameColumn);

    textRenderer = static_cast<Gtk::CellRendererText*>(m_UrlColumn->get_first_cell());
    textRenderer->property_editable() = true;
    textRenderer->signal_edited().connect(sigc::mem_fun(*this, &SiteEditor::on_url_edited));
    append_column(*m_UrlColumn);

    set_model(m_Model);
    get_selection()->select(m_Model->get_iter("0"));

    Gtk::ToolButton *toolButton = nullptr;
    bldr->get_widget("DeleteSiteButton", toolButton);
    toolButton->signal_clicked().connect(sigc::mem_fun(*this, &SiteEditor::delete_site));

    bldr->get_widget("AddSiteButton", toolButton);
    toolButton->signal_clicked().connect(sigc::mem_fun(*this, &SiteEditor::add_row));

    m_UsernameConn = m_UsernameEntry->signal_changed().connect(
            sigc::mem_fun(*this, &SiteEditor::on_username_edited));
    m_PasswordConn = m_PasswordEntry->signal_changed().connect(
            sigc::mem_fun(*this, &SiteEditor::on_password_edited));

#ifdef HAVE_LIBSECRET
    // Make sure the initially selected site's password gets set in the entry once it's loaded
    const std::shared_ptr<Site> &s = get_selection()->get_selected()->get_value(m_Columns.site);
    if (s)
        s->signal_password_lookup().connect([ this, s ]() { m_PasswordEntry->set_text(s->get_password()); });

    m_PasswordEntry->set_visibility(false);
#endif // HAVE_LIBSECRET

    // Set initial values for entries and linkbutton
    on_cursor_changed();
}

SiteEditor::~SiteEditor()
{
    if (m_SiteCheckThread.joinable())
        m_SiteCheckThread.join();
}

bool SiteEditor::on_key_release_event(GdkEventKey *e)
{
    if (e->keyval == GDK_Return || e->keyval == GDK_ISO_Enter
     || e->keyval == GDK_KP_Enter || e->keyval == GDK_Tab)
    {
        Gtk::TreeIter iter = get_selection()->get_selected();
        Gtk::TreePath p(iter);

        if (iter->get_value(m_Columns.url).empty())
            set_cursor(p, *m_UrlColumn, true);
        else if (iter->get_value(m_Columns.name).empty())
            set_cursor(p, *m_NameColumn, true);
    }

    return false;
}

void SiteEditor::on_cursor_changed()
{
    Gtk::TreeView::on_cursor_changed();
    std::shared_ptr<Site> s = nullptr;

    if (get_selection()->get_selected())
        s = get_selection()->get_selected()->get_value(m_Columns.site);

    m_UsernameConn.block();
    m_PasswordConn.block();

    if (s)
    {
        m_RegisterButton->set_label(_("Register account on ") + s->get_name());
        m_RegisterButton->set_uri(s->get_register_uri());

        m_UsernameEntry->set_text(s->get_username());
        m_PasswordEntry->set_text(s->get_password());
    }
    else
    {
        m_RegisterButton->set_label(_("Register account"));

        m_UsernameEntry->set_text("");
        m_PasswordEntry->set_text("");
    }

    m_UsernameConn.unblock();
    m_PasswordConn.unblock();

    m_RegisterButton->set_sensitive(!!s);
    m_UsernameEntry->set_sensitive(!!s);
    m_PasswordEntry->set_sensitive(!!s);

    if (!s || s->get_type() == Site::Type::GELBOORU)
        m_PasswordLabel->set_text(_("Password:"));
    else
        m_PasswordLabel->set_text(_("API Key:"));
}

void SiteEditor::add_row()
{
    Gtk::TreePath path(m_Model->append());
    set_cursor(path, *m_NameColumn, true);
    scroll_to_row(path);
}

void SiteEditor::delete_site()
{
    Gtk::TreeIter o = get_selection()->get_selected();

    if (o)
    {
        m_Sites.erase(std::remove(m_Sites.begin(), m_Sites.end(), o->get_value(m_Columns.site)), m_Sites.end());
        m_SignalEdited();

        Gtk::TreeIter n = m_Model->erase(o);
        if (m_Model->children().size())
            get_selection()->select(n ? n : --n);
        on_cursor_changed();
    }
}

void SiteEditor::on_name_edited(const std::string &p, const std::string &text)
{
    Gtk::TreePath path(p);
    Gtk::TreeIter iter = m_Model->get_iter(path);
    std::string name = text;

    // make sure the site name is unique
    for (size_t i = 1; !is_name_unique(iter, name); ++i)
        name = text + std::to_string(i);

    iter->set_value(m_Columns.name, name);

    if (!iter->get_value(m_Columns.url).empty())
        add_edit_site(iter);
}

void SiteEditor::on_url_edited(const std::string &p, const std::string &text)
{
    Gtk::TreePath path(p);
    Gtk::TreeIter iter = m_Model->get_iter(path);
    std::string url = text;

    if (url.back() == '/')
        url = text.substr(0, text.size() - 1);

    iter->set_value(m_Columns.url, url);
    add_edit_site(iter);
}

bool SiteEditor::is_name_unique(const Gtk::TreeIter &iter, const std::string &name) const
{
    for (const Gtk::TreeIter &i : m_Model->children())
        if (i->get_value(m_Columns.name) == name && iter != i)
            return false;

    return true;
}

void SiteEditor::add_edit_site(const Gtk::TreeIter &iter)
{
    std::string name = iter->get_value(m_Columns.name),
                url(iter->get_value(m_Columns.url));

    if (name.empty() || url.empty())
    {
        iter->set_value(m_Columns.icon, m_ErrorPixbuf);
        return;
    }

    if (m_SiteCheckThread.joinable())
        m_SiteCheckThread.join();

    m_SiteCheckIter = iter;

    std::vector<std::shared_ptr<Site>>::iterator i =
        std::find(m_Sites.begin(), m_Sites.end(), iter->get_value(m_Columns.site));
    std::shared_ptr<Site> site = i != m_Sites.end() ? *i : nullptr;

    // editting
    if (site)
    {
        if (name == site->get_name() && url == site->get_url())
        {
            if (iter->get_value(m_Columns.icon) == m_ErrorPixbuf)
                iter->set_value(m_Columns.icon, site->get_icon_pixbuf());

            return;
        }

        m_SiteCheckEdit = true;
        m_SiteCheckSite = site;
        m_SiteCheckIter->set_value(m_Columns.loading, true);
        m_SiteCheckThread = std::thread([ this, name, url ]()
        {
            m_SiteCheckSite->set_name(name);
            m_SiteCheckEditSuccess = m_SiteCheckSite->set_url(url);

            if (m_SiteCheckEditSuccess)
                update_edited_site_icon();

            m_SignalSiteChecked();
        });
    }
    else
    {
        m_SiteCheckEdit = false;
        m_SiteCheckIter->set_value(m_Columns.loading, true);
        m_SiteCheckThread = std::thread([ this, name, url ]()
        {
            m_SiteCheckSite = Site::create(name, url);

            if (m_SiteCheckSite)
                update_edited_site_icon();

            m_SignalSiteChecked();
        });
    }
}

void SiteEditor::update_edited_site_icon()
{
    m_SiteCheckIter->set_value(m_Columns.icon, m_SiteCheckSite->get_icon_pixbuf(true));
    m_SiteCheckIter->set_value(m_Columns.loading, false);
}

void SiteEditor::on_site_checked()
{
    if ((m_SiteCheckEdit && !m_SiteCheckEditSuccess) || (!m_SiteCheckEdit && !m_SiteCheckSite))
    {
        m_SiteCheckIter->set_value(m_Columns.icon, m_ErrorPixbuf);
        m_SiteCheckIter->set_value(m_Columns.loading, false);
    }
    else if (m_SiteCheckSite && !m_SiteCheckEdit)
    {
        m_Sites.push_back(m_SiteCheckSite);
        m_SiteCheckIter->set_value(m_Columns.site, m_SiteCheckSite);
        on_cursor_changed();
    }

    if (m_SiteCheckEdit || m_SiteCheckSite)
        m_SignalEdited();

    if (m_SiteCheckThread.joinable())
        m_SiteCheckThread.join();
}

void SiteEditor::on_username_edited()
{
    const std::shared_ptr<Site> &s = get_selection()->get_selected()->get_value(m_Columns.site);
    if (s) s->set_username(m_UsernameEntry->get_text());
}

void SiteEditor::on_password_edited()
{
    const std::shared_ptr<Site> &s = get_selection()->get_selected()->get_value(m_Columns.site);
    if (s) s->set_password(m_PasswordEntry->get_text());
}
<|endoftext|>


<commit_before>#pragma once
#include <algorithm>
#include <iterator>

namespace archie
{
  template <typename Range, typename Pred>
  auto filter(Range&, Pred);

  namespace detail
  {
    template <typename ForwardIt, typename Pred>
    class filter_impl {
      class filter_iterator {
        friend class filter_impl;
        ForwardIt first_;
        ForwardIt last_;
        Pred pred_;

        explicit filter_iterator(ForwardIt first, ForwardIt last, Pred pred)
            : first_(first), last_(last), pred_(pred)
        {
        }

      public:
        auto& operator*() const { return *first_; }
        filter_iterator& operator++()
        {
          first_ = std::find_if(++first_, last_, pred_);
          return *this;
        }
        bool operator==(filter_iterator const& rhs) const { return first_ == rhs.first_; }
        bool operator!=(filter_iterator const& rhs) const { return !(*this == rhs); }
      };

      ForwardIt first_;
      ForwardIt last_;
      Pred pred_;

      template <typename Range, typename P>
      friend auto archie::filter(Range&, P);

      explicit filter_impl(ForwardIt first, ForwardIt last, Pred pred)
          : first_(std::find_if(first, last, pred)), last_(last), pred_(pred)
      {
      }

    public:
      filter_iterator begin() const { return filter_iterator(first_, last_, pred_); }
      filter_iterator end() const { return filter_iterator(last_, last_, pred_); }
    };
  }

  template <typename Range, typename Pred>
  auto filter(Range& r, Pred pred)
  {
    return detail::filter_impl<decltype(std::begin(r)), Pred>(std::begin(r), std::end(r), pred);
  }
}
<commit_msg>clang compilation fix to lazy filter<commit_after>#pragma once
#include <algorithm>
#include <iterator>

namespace archie
{
  namespace detail
  {
    template <typename, typename>
    class filter_impl;
  }
  template <typename Range, typename Pred>
  auto filter(Range& r, Pred) -> detail::filter_impl<decltype(std::begin(r)), Pred>;

  namespace detail
  {
    template <typename ForwardIt, typename Pred>
    class filter_impl {
      class filter_iterator {
        friend class filter_impl;
        ForwardIt first_;
        ForwardIt last_;
        Pred pred_;

        explicit filter_iterator(ForwardIt first, ForwardIt last, Pred pred)
            : first_(first), last_(last), pred_(pred)
        {
        }

      public:
        auto& operator*() const { return *first_; }
        filter_iterator& operator++()
        {
          first_ = std::find_if(++first_, last_, pred_);
          return *this;
        }
        bool operator==(filter_iterator const& rhs) const { return first_ == rhs.first_; }
        bool operator!=(filter_iterator const& rhs) const { return !(*this == rhs); }
      };

      ForwardIt first_;
      ForwardIt last_;
      Pred pred_;

      template <typename Range, typename P>
      friend auto archie::filter(Range& r, P) -> filter_impl<decltype(std::begin(r)), P>;

      explicit filter_impl(ForwardIt first, ForwardIt last, Pred pred)
          : first_(std::find_if(first, last, pred)), last_(last), pred_(pred)
      {
      }

    public:
      filter_iterator begin() const { return filter_iterator(first_, last_, pred_); }
      filter_iterator end() const { return filter_iterator(last_, last_, pred_); }
    };
  }

  template <typename Range, typename Pred>
  auto filter(Range& r, Pred pred) -> detail::filter_impl<decltype(std::begin(r)), Pred>
  {
    return detail::filter_impl<decltype(std::begin(r)), Pred>(std::begin(r), std::end(r), pred);
  }
}
<|endoftext|>