<commit_before>/* ---------------------------------------------------------------------
 * Numenta Platform for Intelligent Computing (NuPIC)
 * Copyright (C) 2013, Numenta, Inc.  Unless you have an agreement
 * with Numenta, Inc., for a separate license for this software code, the
 * following terms and conditions apply:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see http://www.gnu.org/licenses.
 *
 * http://numenta.org/licenses/
 * ---------------------------------------------------------------------
 */

/** @file
Implementation of the Region class

Methods related to parameters are in Region_parameters.cpp
Methods related to inputs and outputs are in Region_io.cpp

*/

#include <iostream>
#include <stdexcept>
#include <set>
#include <string>
#include <nupic/engine/Region.hpp>
#include <nupic/engine/RegionImpl.hpp>
#include <nupic/engine/RegionImplFactory.hpp>
#include <nupic/engine/Spec.hpp>
#include <nupic/utils/Log.hpp>
#include <nupic/engine/Input.hpp>
#include <nupic/engine/Output.hpp>
#include <nupic/engine/Link.hpp>
#include <nupic/ntypes/NodeSet.hpp>
#include <nupic/os/Timer.hpp>
#include <nupic/proto/RegionProto.capnp.h>

namespace nupic
{

  class GenericRegisteredRegionImpl;

  // Create region from parameter spec
  Region::Region(std::string name,
                 const std::string& nodeType,
                 const std::string& nodeParams,
                 Network * network) :
    name_(std::move(name)),
    type_(nodeType),
    initialized_(false),
    enabledNodes_(nullptr),
    network_(network)
  {
    // Set region info before creating the RegionImpl so that the
    // Impl has access to the region info in its constructor.
    RegionImplFactory & factory = RegionImplFactory::getInstance();
    spec_ = factory.getSpec(nodeType);

    // Dimensions start off as unspecified, but if
    // the RegionImpl only supports a single node, we
    // can immediately set the dimensions.
    if (spec_->singleNodeOnly)
      dims_.push_back(1);
    // else dims_ = []

    impl_ = factory.createRegionImpl(nodeType, nodeParams, this);
    createInputsAndOutputs_();

  }

  // Deserialize region
  Region::Region(std::string name,
                 const std::string& nodeType,
                 const Dimensions& dimensions,
                 BundleIO& bundle,
                 Network * network) :
    name_(std::move(name)),
    type_(nodeType),
    initialized_(false),
    enabledNodes_(nullptr),
    network_(network)
  {
    // Set region info before creating the RegionImpl so that the
    // Impl has access to the region info in its constructor.
    RegionImplFactory & factory = RegionImplFactory::getInstance();
    spec_ = factory.getSpec(nodeType);

    // Dimensions start off as unspecified, but if
    // the RegionImpl only supports a single node, we
    // can immediately set the dimensions.
    if (spec_->singleNodeOnly)
      if (!dimensions.isDontcare() && !dimensions.isUnspecified() &&
          !dimensions.isOnes())
        NTA_THROW << "Attempt to deserialize region of type " << nodeType
                  << " with dimensions " << dimensions
                  << " but region supports exactly one node.";

    dims_ = dimensions;

    impl_ = factory.deserializeRegionImpl(nodeType, bundle, this);
    createInputsAndOutputs_();
  }

  Region::Region(std::string name, RegionProto::Reader& proto,
                 Network* network) :
    name_(std::move(name)),
    type_(proto.getNodeType().cStr()),
    initialized_(false),
    enabledNodes_(nullptr),
    network_(network)
  {
    read(proto);
  }

  Network * Region::getNetwork()
  {
    return network_;
  }

  void Region::createInputsAndOutputs_()
  {

    // Create all the outputs for this node type. By default outputs are zero size
    for (size_t i = 0; i < spec_->outputs.getCount(); ++i)
    {
      const std::pair<std::string, OutputSpec> & p = spec_->outputs.getByIndex(i);
      std::string outputName = p.first;
      const OutputSpec & os = p.second;
      auto output = new Output(*this, os.dataType, os.regionLevel);
      outputs_[outputName] = output;
      // keep track of name in the output also -- see note in Region.hpp
      output->setName(outputName);
    }

    // Create all the inputs for this node type.
    for (size_t i = 0; i < spec_->inputs.getCount(); ++i)
    {
      const std::pair<std::string, InputSpec> & p = spec_->inputs.getByIndex(i);
      std::string inputName = p.first;
      const InputSpec &is = p.second;

      auto input = new Input(*this, is.dataType, is.regionLevel);
      inputs_[inputName] = input;
      // keep track of name in the input also -- see note in Region.hpp
      input->setName(inputName);
    }
  }

  bool Region::hasOutgoingLinks() const
  {
    for (const auto & elem : outputs_)
    {
      if (elem.second->hasOutgoingLinks())
      {
        return true;
      }
    }
    return false;
  }

  Region::~Region()
  {
    // If there are any links connected to our outputs, this will fail.
    // We should catch this error in the Network class and give the
    // user a good error message (regions may be removed either in
    // Network::removeRegion or Network::~Network())
    for (auto & elem : outputs_)
    {
      delete elem.second;
      elem.second = nullptr;
    }

    for (auto & elem : inputs_)
    {
      delete elem.second;
      elem.second = nullptr;
    }

    delete impl_;
    delete enabledNodes_;

  }

  void
  Region::initialize()
  {

    if (initialized_)
      return;

    impl_->initialize();
    initialized_ = true;
  }

  bool
  Region::isInitialized() const
  {
    return initialized_;
  }

  const std::string&
  Region::getName() const
  {
    return name_;
  }

  const std::string&
  Region::getType() const
  {
    return type_;
  }

  const Spec*
  Region::getSpec() const
  {
    return spec_;
  }

  const Spec*
  Region::getSpecFromType(const std::string& nodeType)
  {
    RegionImplFactory & factory = RegionImplFactory::getInstance();
    return factory.getSpec(nodeType);
  }

  void
  Region::registerPyRegion(const std::string module, const std::string className)
  {
    RegionImplFactory::registerPyRegion(module, className);
  }

  void
  Region::registerCPPRegion(const std::string name, GenericRegisteredRegionImpl* wrapper)
  {
    RegionImplFactory::registerCPPRegion(name, wrapper);
  }

  const Dimensions&
  Region::getDimensions() const
  {
    return dims_;
  }

  void
  Region::enable()
  {
    NTA_THROW << "Region::enable not implemented (region name: " << getName() << ")";
  }

  void
  Region::disable()
  {
    NTA_THROW << "Region::disable not implemented (region name: " << getName() << ")";
  }

  std::string
  Region::executeCommand(const std::vector<std::string>& args)
  {
    std::string retVal;
    if (args.size() < 1)
    {
      NTA_THROW << "Invalid empty command specified";
    }

    if (profilingEnabled_)
      executeTimer_.start();

    retVal = impl_->executeCommand(args, (UInt64)(-1));

    if (profilingEnabled_)
      executeTimer_.stop();

    return retVal;
  }

  void
  Region::compute()
  {
    if (!initialized_)
      NTA_THROW << "Region " << getName() << " unable to compute because not initialized";

    if (profilingEnabled_)
      computeTimer_.start();

    impl_->compute();

    if (profilingEnabled_)
      computeTimer_.stop();

    return;
  }

  /**
   * These internal methods are called by Network as
   * part of initialization.
   */

  size_t
  Region::evaluateLinks()
  {
    int nIncompleteLinks = 0;
    for (auto & elem : inputs_)
    {
      nIncompleteLinks += (elem.second)->evaluateLinks();
    }
    return nIncompleteLinks;
  }

  std::string
  Region::getLinkErrors() const
  {

    std::stringstream ss;
    for (const auto & elem : inputs_)
    {
      const std::vector<Link*>& links = elem.second->getLinks();
      for (const auto & link : links)
      {
        if ( (link)->getSrcDimensions().isUnspecified() ||
             (link)->getDestDimensions().isUnspecified())
        {
          ss << (link)->toString() << "\n";
        }
      }
    }

    return ss.str();
  }

  size_t Region::getNodeOutputElementCount(const std::string& name)
  {
    // Use output count if specified in nodespec, otherwise
    // ask the Impl
    NTA_CHECK(spec_->outputs.contains(name));
    size_t count = spec_->outputs.getByName(name).count;
    if(count == 0)
    {
      try
      {
        count = impl_->getNodeOutputElementCount(name);
      } catch(Exception& e) {
        NTA_THROW << "Internal error -- the size for the output " << name <<
                     "is unknown. : " << e.what();
      }
    }

    return count;
  }

  void Region::initOutputs()
  {
    // Some outputs are optional. These outputs will have 0 elementCount in the node
    // spec and also return 0 from impl->getNodeOutputElementCount(). These outputs still
    // appear in the output map, but with an array size of 0.

    for (auto & elem : outputs_)
    {
      const std::string& name = elem.first;

      size_t count = 0;
      try
      {
        count = getNodeOutputElementCount(name);
      } catch (nupic::Exception& e) {
        NTA_THROW << "Internal error -- unable to get size of output "
                  << name << " : " << e.what();
      }
      elem.second->initialize(count);
    }
  }

  void Region::initInputs() const
  {
    auto i = inputs_.begin();
    for (; i != inputs_.end(); i++)
    {
      i->second->initialize();
    }
  }

  void
  Region::setDimensions(Dimensions& newDims)
  {
    // Can only set dimensions one time
    if (dims_ == newDims)
      return;

    if (dims_.isUnspecified())
    {
      if (newDims.isDontcare())
      {
        NTA_THROW << "Invalid attempt to set region dimensions to dontcare value";
      }

      if (! newDims.isValid())
      {
        NTA_THROW << "Attempt to set region dimensions to invalid value:"
                  << newDims.toString();
      }

      dims_ = newDims;
      dimensionInfo_ = "Specified explicitly in setDimensions()";
    } else {
      NTA_THROW << "Attempt to set dimensions of region " << getName()
                << " to " << newDims.toString()
                << " but region already has dimensions " << dims_.toString();
    }

    // can only create the enabled node set after we know the number of dimensions
    setupEnabledNodeSet();

  }

  void Region::setupEnabledNodeSet()
  {
    NTA_CHECK(dims_.isValid());

    if (enabledNodes_ != nullptr)
    {
      delete enabledNodes_;
    }

    size_t nnodes = dims_.getCount();
    enabledNodes_ = new NodeSet(nnodes);

    enabledNodes_->allOn();
  }

  const NodeSet& Region::getEnabledNodes() const
  {
    if (enabledNodes_ == nullptr)
    {
      NTA_THROW << "Attempt to access enabled nodes set before region has been initialized";
    }
    return *enabledNodes_;
  }

  void
  Region::setDimensionInfo(const std::string& info)
  {
    dimensionInfo_ = info;
  }

  const std::string&
  Region::getDimensionInfo() const
  {
    return dimensionInfo_;
  }

  void
  Region::removeAllIncomingLinks()
  {
    InputMap::const_iterator i = inputs_.begin();
    for (; i != inputs_.end(); i++)
    {
      std::vector<Link*> links = i->second->getLinks();
      for (auto & links_link : links)
      {
        i->second->removeLink(links_link);

      }
    }

  }

  void
  Region::uninitialize()
  {
    initialized_ = false;
  }

  void
  Region::setPhases(std::set<UInt32>& phases)
  {
    phases_ = phases;
  }

  std::set<UInt32>&
  Region::getPhases()
  {
    return phases_;
  }

  void
  Region::serializeImpl(BundleIO& bundle)
  {
    impl_->serialize(bundle);
  }

  void Region::write(RegionProto::Builder& proto) const
  {
    auto dimensionsProto = proto.initDimensions(dims_.size());
    for (UInt i = 0; i < dims_.size(); ++i)
    {
      dimensionsProto.set(i, dims_[i]);
    }
    auto phasesProto = proto.initPhases(phases_.size());
    UInt i = 0;
    for (auto elem : phases_)
    {
      phasesProto.set(i++, elem);
    }
    proto.setNodeType(type_);
    auto implProto = proto.getRegionImpl();
    impl_->write(implProto);
  }

  void Region::read(RegionProto::Reader& proto)
  {
    dims_.clear();
    for (auto elem : proto.getDimensions())
    {
      dims_.push_back(elem);
    }

    phases_.clear();
    for (auto elem : proto.getPhases())
    {
      phases_.insert(elem);
    }

    auto implProto = proto.getRegionImpl();
    RegionImplFactory& factory = RegionImplFactory::getInstance();
    impl_ = factory.deserializeRegionImpl(
        proto.getNodeType().cStr(), implProto, this);
  }

  void
  Region::enableProfiling()
  {
    profilingEnabled_ = true;
  }

  void
  Region::disableProfiling()
  {
    profilingEnabled_ = false;
  }

  void
  Region::resetProfiling()
  {
    computeTimer_.reset();
    executeTimer_.reset();
  }

  const Timer& Region::getComputeTimer() const
  {
    return computeTimer_;
  }

  const Timer& Region::getExecuteTimer() const
  {
    return executeTimer_;
  }

}
<commit_msg>More string fixes for Windoes.<commit_after>/* ---------------------------------------------------------------------
 * Numenta Platform for Intelligent Computing (NuPIC)
 * Copyright (C) 2013, Numenta, Inc.  Unless you have an agreement
 * with Numenta, Inc., for a separate license for this software code, the
 * following terms and conditions apply:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 * See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see http://www.gnu.org/licenses.
 *
 * http://numenta.org/licenses/
 * ---------------------------------------------------------------------
 */

/** @file
Implementation of the Region class

Methods related to parameters are in Region_parameters.cpp
Methods related to inputs and outputs are in Region_io.cpp

*/

#include <iostream>
#include <stdexcept>
#include <set>
#include <string>
#include <nupic/engine/Region.hpp>
#include <nupic/engine/RegionImpl.hpp>
#include <nupic/engine/RegionImplFactory.hpp>
#include <nupic/engine/Spec.hpp>
#include <nupic/utils/Log.hpp>
#include <nupic/engine/Input.hpp>
#include <nupic/engine/Output.hpp>
#include <nupic/engine/Link.hpp>
#include <nupic/ntypes/NodeSet.hpp>
#include <nupic/os/Timer.hpp>
#include <nupic/proto/RegionProto.capnp.h>

namespace nupic
{

  class GenericRegisteredRegionImpl;

  // Create region from parameter spec
  Region::Region(std::string name,
                 const std::string& nodeType,
                 const std::string& nodeParams,
                 Network * network) :
    name_(std::move(name)),
    type_(nodeType),
    initialized_(false),
    enabledNodes_(nullptr),
    network_(network)
  {
    // Set region info before creating the RegionImpl so that the
    // Impl has access to the region info in its constructor.
    RegionImplFactory & factory = RegionImplFactory::getInstance();
    spec_ = factory.getSpec(nodeType);

    // Dimensions start off as unspecified, but if
    // the RegionImpl only supports a single node, we
    // can immediately set the dimensions.
    if (spec_->singleNodeOnly)
      dims_.push_back(1);
    // else dims_ = []

    impl_ = factory.createRegionImpl(nodeType, nodeParams, this);
    createInputsAndOutputs_();

  }

  // Deserialize region
  Region::Region(std::string name,
                 const std::string& nodeType,
                 const Dimensions& dimensions,
                 BundleIO& bundle,
                 Network * network) :
    name_(std::move(name)),
    type_(nodeType),
    initialized_(false),
    enabledNodes_(nullptr),
    network_(network)
  {
    // Set region info before creating the RegionImpl so that the
    // Impl has access to the region info in its constructor.
    RegionImplFactory & factory = RegionImplFactory::getInstance();
    spec_ = factory.getSpec(nodeType);

    // Dimensions start off as unspecified, but if
    // the RegionImpl only supports a single node, we
    // can immediately set the dimensions.
    if (spec_->singleNodeOnly)
      if (!dimensions.isDontcare() && !dimensions.isUnspecified() &&
          !dimensions.isOnes())
        NTA_THROW << "Attempt to deserialize region of type " << nodeType
                  << " with dimensions " << dimensions
                  << " but region supports exactly one node.";

    dims_ = dimensions;

    impl_ = factory.deserializeRegionImpl(nodeType, bundle, this);
    createInputsAndOutputs_();
  }

  Region::Region(std::string name, RegionProto::Reader& proto,
                 Network* network) :
    name_(std::move(name)),
    type_(proto.getNodeType().cStr()),
    initialized_(false),
    enabledNodes_(nullptr),
    network_(network)
  {
    read(proto);
  }

  Network * Region::getNetwork()
  {
    return network_;
  }

  void Region::createInputsAndOutputs_()
  {

    // Create all the outputs for this node type. By default outputs are zero size
    for (size_t i = 0; i < spec_->outputs.getCount(); ++i)
    {
      const std::pair<std::string, OutputSpec> & p = spec_->outputs.getByIndex(i);
      std::string outputName = p.first;
      const OutputSpec & os = p.second;
      auto output = new Output(*this, os.dataType, os.regionLevel);
      outputs_[outputName] = output;
      // keep track of name in the output also -- see note in Region.hpp
      output->setName(outputName);
    }

    // Create all the inputs for this node type.
    for (size_t i = 0; i < spec_->inputs.getCount(); ++i)
    {
      const std::pair<std::string, InputSpec> & p = spec_->inputs.getByIndex(i);
      std::string inputName = p.first;
      const InputSpec &is = p.second;

      auto input = new Input(*this, is.dataType, is.regionLevel);
      inputs_[inputName] = input;
      // keep track of name in the input also -- see note in Region.hpp
      input->setName(inputName);
    }
  }

  bool Region::hasOutgoingLinks() const
  {
    for (const auto & elem : outputs_)
    {
      if (elem.second->hasOutgoingLinks())
      {
        return true;
      }
    }
    return false;
  }

  Region::~Region()
  {
    // If there are any links connected to our outputs, this will fail.
    // We should catch this error in the Network class and give the
    // user a good error message (regions may be removed either in
    // Network::removeRegion or Network::~Network())
    for (auto & elem : outputs_)
    {
      delete elem.second;
      elem.second = nullptr;
    }

    for (auto & elem : inputs_)
    {
      delete elem.second;
      elem.second = nullptr;
    }

    delete impl_;
    delete enabledNodes_;

  }

  void
  Region::initialize()
  {

    if (initialized_)
      return;

    impl_->initialize();
    initialized_ = true;
  }

  bool
  Region::isInitialized() const
  {
    return initialized_;
  }

  const std::string&
  Region::getName() const
  {
    return name_;
  }

  const std::string&
  Region::getType() const
  {
    return type_;
  }

  const Spec*
  Region::getSpec() const
  {
    return spec_;
  }

  const Spec*
  Region::getSpecFromType(const std::string& nodeType)
  {
    RegionImplFactory & factory = RegionImplFactory::getInstance();
    return factory.getSpec(nodeType);
  }

  void
  Region::registerPyRegion(const std::string module, const std::string className)
  {
    RegionImplFactory::registerPyRegion(module, className);
  }

  void
  Region::registerCPPRegion(const std::string name, GenericRegisteredRegionImpl* wrapper)
  {
    RegionImplFactory::registerCPPRegion(name, wrapper);
  }

  const Dimensions&
  Region::getDimensions() const
  {
    return dims_;
  }

  void
  Region::enable()
  {
    NTA_THROW << "Region::enable not implemented (region name: " << getName() << ")";
  }

  void
  Region::disable()
  {
    NTA_THROW << "Region::disable not implemented (region name: " << getName() << ")";
  }

  std::string
  Region::executeCommand(const std::vector<std::string>& args)
  {
    std::string retVal;
    if (args.size() < 1)
    {
      NTA_THROW << "Invalid empty command specified";
    }

    if (profilingEnabled_)
      executeTimer_.start();

    retVal = impl_->executeCommand(args, (UInt64)(-1));

    if (profilingEnabled_)
      executeTimer_.stop();

    return retVal;
  }

  void
  Region::compute()
  {
    if (!initialized_)
      NTA_THROW << "Region " << getName() << " unable to compute because not initialized";

    if (profilingEnabled_)
      computeTimer_.start();

    impl_->compute();

    if (profilingEnabled_)
      computeTimer_.stop();

    return;
  }

  /**
   * These internal methods are called by Network as
   * part of initialization.
   */

  size_t
  Region::evaluateLinks()
  {
    int nIncompleteLinks = 0;
    for (auto & elem : inputs_)
    {
      nIncompleteLinks += (elem.second)->evaluateLinks();
    }
    return nIncompleteLinks;
  }

  std::string
  Region::getLinkErrors() const
  {

    std::stringstream ss;
    for (const auto & elem : inputs_)
    {
      const std::vector<Link*>& links = elem.second->getLinks();
      for (const auto & link : links)
      {
        if ( (link)->getSrcDimensions().isUnspecified() ||
             (link)->getDestDimensions().isUnspecified())
        {
          ss << (link)->toString() << "\n";
        }
      }
    }

    return ss.str();
  }

  size_t Region::getNodeOutputElementCount(const std::string& name)
  {
    // Use output count if specified in nodespec, otherwise
    // ask the Impl
    NTA_CHECK(spec_->outputs.contains(name));
    size_t count = spec_->outputs.getByName(name).count;
    if(count == 0)
    {
      try
      {
        count = impl_->getNodeOutputElementCount(name);
      } catch(Exception& e) {
        NTA_THROW << "Internal error -- the size for the output " << name <<
                     "is unknown. : " << e.what();
      }
    }

    return count;
  }

  void Region::initOutputs()
  {
    // Some outputs are optional. These outputs will have 0 elementCount in the node
    // spec and also return 0 from impl->getNodeOutputElementCount(). These outputs still
    // appear in the output map, but with an array size of 0.

    for (auto & elem : outputs_)
    {
      const std::string& name = elem.first;

      size_t count = 0;
      try
      {
        count = getNodeOutputElementCount(name);
      } catch (nupic::Exception& e) {
        NTA_THROW << "Internal error -- unable to get size of output "
                  << name << " : " << e.what();
      }
      elem.second->initialize(count);
    }
  }

  void Region::initInputs() const
  {
    auto i = inputs_.begin();
    for (; i != inputs_.end(); i++)
    {
      i->second->initialize();
    }
  }

  void
  Region::setDimensions(Dimensions& newDims)
  {
    // Can only set dimensions one time
    if (dims_ == newDims)
      return;

    if (dims_.isUnspecified())
    {
      if (newDims.isDontcare())
      {
        NTA_THROW << "Invalid attempt to set region dimensions to dontcare value";
      }

      if (! newDims.isValid())
      {
        NTA_THROW << "Attempt to set region dimensions to invalid value:"
                  << newDims.toString();
      }

      dims_ = newDims;
      dimensionInfo_ = "Specified explicitly in setDimensions()";
    } else {
      NTA_THROW << "Attempt to set dimensions of region " << getName()
                << " to " << newDims.toString()
                << " but region already has dimensions " << dims_.toString();
    }

    // can only create the enabled node set after we know the number of dimensions
    setupEnabledNodeSet();

  }

  void Region::setupEnabledNodeSet()
  {
    NTA_CHECK(dims_.isValid());

    if (enabledNodes_ != nullptr)
    {
      delete enabledNodes_;
    }

    size_t nnodes = dims_.getCount();
    enabledNodes_ = new NodeSet(nnodes);

    enabledNodes_->allOn();
  }

  const NodeSet& Region::getEnabledNodes() const
  {
    if (enabledNodes_ == nullptr)
    {
      NTA_THROW << "Attempt to access enabled nodes set before region has been initialized";
    }
    return *enabledNodes_;
  }

  void
  Region::setDimensionInfo(const std::string& info)
  {
    dimensionInfo_ = info;
  }

  const std::string&
  Region::getDimensionInfo() const
  {
    return dimensionInfo_;
  }

  void
  Region::removeAllIncomingLinks()
  {
    InputMap::const_iterator i = inputs_.begin();
    for (; i != inputs_.end(); i++)
    {
      std::vector<Link*> links = i->second->getLinks();
      for (auto & links_link : links)
      {
        i->second->removeLink(links_link);

      }
    }

  }

  void
  Region::uninitialize()
  {
    initialized_ = false;
  }

  void
  Region::setPhases(std::set<UInt32>& phases)
  {
    phases_ = phases;
  }

  std::set<UInt32>&
  Region::getPhases()
  {
    return phases_;
  }

  void
  Region::serializeImpl(BundleIO& bundle)
  {
    impl_->serialize(bundle);
  }

  void Region::write(RegionProto::Builder& proto) const
  {
    auto dimensionsProto = proto.initDimensions(dims_.size());
    for (UInt i = 0; i < dims_.size(); ++i)
    {
      dimensionsProto.set(i, dims_[i]);
    }
    auto phasesProto = proto.initPhases(phases_.size());
    UInt i = 0;
    for (auto elem : phases_)
    {
      phasesProto.set(i++, elem);
    }
    proto.setNodeType(type_.c_str());
    auto implProto = proto.getRegionImpl();
    impl_->write(implProto);
  }

  void Region::read(RegionProto::Reader& proto)
  {
    dims_.clear();
    for (auto elem : proto.getDimensions())
    {
      dims_.push_back(elem);
    }

    phases_.clear();
    for (auto elem : proto.getPhases())
    {
      phases_.insert(elem);
    }

    auto implProto = proto.getRegionImpl();
    RegionImplFactory& factory = RegionImplFactory::getInstance();
    impl_ = factory.deserializeRegionImpl(
        proto.getNodeType().cStr(), implProto, this);
  }

  void
  Region::enableProfiling()
  {
    profilingEnabled_ = true;
  }

  void
  Region::disableProfiling()
  {
    profilingEnabled_ = false;
  }

  void
  Region::resetProfiling()
  {
    computeTimer_.reset();
    executeTimer_.reset();
  }

  const Timer& Region::getComputeTimer() const
  {
    return computeTimer_;
  }

  const Timer& Region::getExecuteTimer() const
  {
    return executeTimer_;
  }

}
<|endoftext|>


<commit_before>#include <map>
#include <iostream>

#include "Core.hpp"
#include "FileSystem.hpp"
#include "Util.hpp"
#include "Index.hpp"

#ifdef WIN32
#include <Windows.h>
#endif

namespace Sit {
namespace Core {

void Init()
{
	using namespace boost::filesystem;
	try {
		create_directories(".sit/");
#ifdef WIN32
		SetFileAttributes(L".sit", FILE_ATTRIBUTE_HIDDEN);
#endif
		create_directories(".sit/hook");
		create_directories(".sit/objects");
		create_directories(".sit/info");
		create_directories(".sit/log");
		create_directories(".sit/objects");
		create_directories(".sit/objects/info");
		create_directories(".sit/objects/pack");
		create_directories(".sit/refs");
		create_directories(".sit/refs/heads");
		create_directories(".sit/refs/tags");

		ofstream HEAD(".sit/HEAD");
		HEAD << "refs/heads/master" << std::endl;
		HEAD.close();
	} catch (const boost::filesystem::filesystem_error &fe) {
		std::cerr << fe.what() << std::endl;
	} catch (const std::exception &stdEc) {
		std::cerr << stdEc.what() << std::endl;
	}
}

std::string AddFile(const boost::filesystem::path &file)
{
	if (FileSystem::IsDirectory(file)) {
		return "";
	}
	try {
		auto fileSize = boost::filesystem::file_size(file);
		if (fileSize > 102400) {
			std::cerr << "Warning : Try to add a file larger than 100MB" << std::endl;
		}
		if (fileSize > 204800) {
			throw Sit::Util::SitException("Fatal: Try to add a file larger than 200MB", file.string());
		}
		std::string sha1Value = Sit::Util::SHA1sum(FileSystem::Read(file));
		boost::filesystem::path dstFile(FileSystem::OBJECTS_DIR / sha1Value.substr(0, 2) / sha1Value.substr(2));
		FileSystem::SafeCopyFile(file, dstFile);
		std::cout << file << " added." << std::endl;
		return sha1Value;
	} catch (const boost::filesystem::filesystem_error &fe) {
		std::cerr << fe.what() << std::endl;
	} catch (const std::exception &stdEc) {
		std::cerr << stdEc.what() << std::endl;
	}
	return std::string("");
}

void Add(const boost::filesystem::path &path)
{
	Index::Load();

	auto fileList = FileSystem::ListRecursive(path);
	for (auto &file : fileList) {
		if (FileSystem::IsDirectory(file)) {
			continue;
		}
		Index::Insert(file, AddFile(file));
	}

	Index::Save();
}

void Rm(const boost::filesystem::path &path)
{
	Index::Load();
	std::cout << "Removed " << Index::Remove(path) << " files" << std::endl;
	Index::Save();
}
}
}<commit_msg>fix a bug when check file size<commit_after>#include <map>
#include <iostream>

#include "Core.hpp"
#include "FileSystem.hpp"
#include "Util.hpp"
#include "Index.hpp"

#ifdef WIN32
#include <Windows.h>
#endif

namespace Sit {
namespace Core {

void Init()
{
	using namespace boost::filesystem;
	try {
		create_directories(".sit/");
#ifdef WIN32
		SetFileAttributes(L".sit", FILE_ATTRIBUTE_HIDDEN);
#endif
		create_directories(".sit/hook");
		create_directories(".sit/objects");
		create_directories(".sit/info");
		create_directories(".sit/log");
		create_directories(".sit/objects");
		create_directories(".sit/objects/info");
		create_directories(".sit/objects/pack");
		create_directories(".sit/refs");
		create_directories(".sit/refs/heads");
		create_directories(".sit/refs/tags");

		ofstream HEAD(".sit/HEAD");
		HEAD << "refs/heads/master" << std::endl;
		HEAD.close();
	} catch (const boost::filesystem::filesystem_error &fe) {
		std::cerr << fe.what() << std::endl;
	} catch (const std::exception &stdEc) {
		std::cerr << stdEc.what() << std::endl;
	}
}

std::string AddFile(const boost::filesystem::path &file)
{
	if (FileSystem::IsDirectory(file)) {
		return "";
	}
	try {
		auto fileSize = boost::filesystem::file_size(file);
		if (fileSize > (100 << 20)) {
			std::cerr << "Warning : Try to add a file larger than 100MB" << std::endl;
		}
		if (fileSize > (200 << 20)) {
			throw Sit::Util::SitException("Fatal: Try to add a file larger than 200MB", file.string());
		}
		std::string sha1Value = Sit::Util::SHA1sum(FileSystem::Read(file));
		boost::filesystem::path dstFile(FileSystem::OBJECTS_DIR / sha1Value.substr(0, 2) / sha1Value.substr(2));
		FileSystem::SafeCopyFile(file, dstFile);
		std::cout << file << " added." << std::endl;
		return sha1Value;
	} catch (const boost::filesystem::filesystem_error &fe) {
		std::cerr << fe.what() << std::endl;
	} catch (const std::exception &stdEc) {
		std::cerr << stdEc.what() << std::endl;
	}
	return std::string("");
}

void Add(const boost::filesystem::path &path)
{
	Index::Load();

	auto fileList = FileSystem::ListRecursive(path);
	for (auto &file : fileList) {
		if (FileSystem::IsDirectory(file)) {
			continue;
		}
		Index::Insert(file, AddFile(file));
	}

	Index::Save();
}

void Rm(const boost::filesystem::path &path)
{
	Index::Load();
	std::cout << "Removed " << Index::Remove(path) << " files" << std::endl;
	Index::Save();
}
}
}<|endoftext|>


<commit_before>/*
* The MIT License (MIT)
*
* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/

#include "nan.h"
#include "Core.h"

#include "talk/app/webrtc/peerconnectionfactoryproxy.h"
#include "talk/app/webrtc/proxy.h"

#include "webrtc/base/cpumonitor.h"

#ifdef WIN32
#include "webrtc/base/win32socketinit.h"
#include "webrtc/base/win32socketserver.h"
#else
#include "webrtc/base/physicalsocketserver.h"
#endif

using namespace v8;
using namespace WebRTC;

class ThreadPool {
  public:
    static void Init() {
      rtc::CpuSampler info;

      if (info.Init()) {
        _instances = info.GetCurrentCpus();
      } else {
        _instances = 1;
      }

      _pool = new ThreadPool[_instances];
    }

    static void Dispose() {
      delete [] _pool;
    }

    static ThreadPool *GetPool() {
      int selected = _instances - 1;
      size_t count = _pool[_instances - 1]._count;

      for (int index = 0; index < _instances; index++) {
        if (count >= _pool[index]._count) {
          selected = index;
          count = _pool[index]._count;
        }
      }

      return &_pool[selected];
    }

    rtc::Thread *GetWorker() {
      return _worker;
    }

    void Inc() {
      _count++;
    }

    void Dec() {
      _count--;
    }

  private:
    ThreadPool() : _count(0), _worker(new rtc::Thread()) {
      _worker->Start();
    }

    virtual ~ThreadPool() {
      _worker->Stop();
      delete _worker;
    }

  protected:
    size_t _count;
    rtc::Thread* _worker;
    static ThreadPool* _pool;
    static int _instances;
};

ThreadPool* ThreadPool::_pool;
int ThreadPool::_instances;

class ThreadConstructor {
  public:
    ThreadConstructor() : _pool(ThreadPool::GetPool()) {
      _pool->Inc();
    }

    virtual ~ThreadConstructor() {
      _pool->Dec();
    }

    rtc::Thread *Current() const {
      return _pool->GetWorker();
    }

  protected:
    ThreadPool* _pool;
};

class PeerConnectionFactory : public ThreadConstructor, public webrtc::PeerConnectionFactory {
  public:
    PeerConnectionFactory() :
      webrtc::PeerConnectionFactory(rtc::Thread::Current(), ThreadConstructor::Current(), NULL, NULL, NULL)
    { }
};

#ifdef WIN32
  rtc::Win32Thread* _signal;
#else
  rtc::Thread* _signal;
#endif

rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> _factory;
rtc::scoped_ptr<cricket::DeviceManagerInterface> _manager;

void Core::Init() {
  LOG(LS_INFO) << __PRETTY_FUNCTION__;

#ifdef WIN32
  rtc::EnsureWinsockInit();
#endif
  rtc::InitializeSSL();

#ifdef WIN32
  _signal = new rtc::Win32Thread();
#else
  _signal = new rtc::Thread();
#endif
  _signal->Start();

  rtc::ThreadManager::Instance()->SetCurrentThread(_signal);

  if (rtc::ThreadManager::Instance()->CurrentThread() != _signal) {
    LOG(LS_ERROR) << "Internal Thread Error!";
    abort();
  }

  ThreadPool::Init();

  _factory = Core::CreateFactory();
  _manager.reset(cricket::DeviceManagerFactory::Create());

  if (!_manager->Init()) {
    _manager.release();
  }
}

void Core::Dispose() {
  LOG(LS_INFO) << __PRETTY_FUNCTION__;

#if (NODE_MODULE_VERSION < NODE_0_12_MODULE_VERSION)
  V8::LowMemoryNotification();
#else
  Isolate* isolate = Isolate::GetCurrent();
  isolate->LowMemoryNotification();
#endif

  _factory.release();

  if (_manager.get()) {
    _manager->Terminate();
  }

  _manager.release();

  ThreadPool::Dispose();

  _signal->Stop();
  delete _signal;
}

rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> Core::CreateFactory() {
  rtc::scoped_refptr<PeerConnectionFactory> factory(new rtc::RefCountedObject<PeerConnectionFactory>());

  webrtc::MethodCall0<PeerConnectionFactory, bool> call(factory.get(), &webrtc::PeerConnectionFactory::Initialize);
  bool result = call.Marshal(factory->signaling_thread());

  if (!result) {
    return NULL;
  }

  return webrtc::PeerConnectionFactoryProxy::Create(factory->signaling_thread(), factory);
}

webrtc::PeerConnectionFactoryInterface* Core::GetFactory() {
  LOG(LS_INFO) << __PRETTY_FUNCTION__;

  return _factory.get();
}

cricket::DeviceManagerInterface* Core::GetManager() {
  LOG(LS_INFO) << __PRETTY_FUNCTION__;

  return _manager.get();
}<commit_msg>Update Core<commit_after>/*
* The MIT License (MIT)
*
* Copyright (c) 2015 vmolsa <ville.molsa@gmail.com> (http://github.com/vmolsa)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/

#include "nan.h"
#include "Core.h"

#include "talk/app/webrtc/peerconnectionfactoryproxy.h"
#include "talk/app/webrtc/proxy.h"

#include "webrtc/base/cpumonitor.h"

#ifdef WIN32
#include "webrtc/base/win32socketinit.h"
#include "webrtc/base/win32socketserver.h"
#else
#include "webrtc/base/physicalsocketserver.h"
#endif

using namespace v8;
using namespace WebRTC;

class ThreadPool {
  public:
    static void Init() {
      rtc::CpuSampler info;

      if (info.Init()) {
        _instances = info.GetCurrentCpus();
      } else {
        _instances = 1;
      }

      _pool = new ThreadPool[_instances];
    }

    static void Dispose() {
      delete [] _pool;
    }

    static ThreadPool *GetPool() {
      int selected = _instances - 1;
      size_t count = _pool[_instances - 1]._count;

      for (int index = 0; index < _instances; index++) {
        if (count >= _pool[index]._count) {
          selected = index;
          count = _pool[index]._count;
        }
      }

      return &_pool[selected];
    }

    rtc::Thread *GetWorker() {
      return _worker;
    }

    void Inc() {
      _count++;
    }

    void Dec() {
      _count--;
    }

  private:
    ThreadPool() : _count(0), _worker(new rtc::Thread()) {
      _worker->Start();
    }

    virtual ~ThreadPool() {
      _worker->Stop();
      delete _worker;
    }

  protected:
    size_t _count;
    rtc::Thread* _worker;
    static ThreadPool* _pool;
    static int _instances;
};

ThreadPool* ThreadPool::_pool;
int ThreadPool::_instances;

class ThreadConstructor {
  public:
    ThreadConstructor() : _pool(ThreadPool::GetPool()) {
      _pool->Inc();
    }

    virtual ~ThreadConstructor() {
      _pool->Dec();
    }

    rtc::Thread *Current() const {
      return _pool->GetWorker();
    }

  protected:
    ThreadPool* _pool;
};

class PeerConnectionFactory : public ThreadConstructor, public webrtc::PeerConnectionFactory {
  public:
    PeerConnectionFactory() :
      webrtc::PeerConnectionFactory(rtc::Thread::Current(), ThreadConstructor::Current(), NULL, NULL, NULL)
    { }
};

rtc::Thread* _signal;
rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> _factory;
rtc::scoped_ptr<cricket::DeviceManagerInterface> _manager;

void Core::Init() {
  LOG(LS_INFO) << __PRETTY_FUNCTION__;

#ifdef WIN32
  rtc::EnsureWinsockInit();
#endif
  rtc::InitializeSSL();

  _signal = new rtc::Thread();
  _signal->Start();

  rtc::ThreadManager::Instance()->SetCurrentThread(_signal);

  if (rtc::ThreadManager::Instance()->CurrentThread() != _signal) {
    LOG(LS_ERROR) << "Internal Thread Error!";
    abort();
  }

  ThreadPool::Init();

  _factory = Core::CreateFactory();
  _manager.reset(cricket::DeviceManagerFactory::Create());

  if (!_manager->Init()) {
    _manager.release();
  }
}

void Core::Dispose() {
  LOG(LS_INFO) << __PRETTY_FUNCTION__;

#if (NODE_MODULE_VERSION < NODE_0_12_MODULE_VERSION)
  V8::LowMemoryNotification();
#else
  Isolate* isolate = Isolate::GetCurrent();
  isolate->LowMemoryNotification();
#endif

  _factory.release();

  if (_manager.get()) {
    _manager->Terminate();
  }

  _manager.release();

  ThreadPool::Dispose();

  _signal->Stop();
  delete _signal;
}

rtc::scoped_refptr<webrtc::PeerConnectionFactoryInterface> Core::CreateFactory() {
  rtc::scoped_refptr<PeerConnectionFactory> factory(new rtc::RefCountedObject<PeerConnectionFactory>());

  webrtc::MethodCall0<PeerConnectionFactory, bool> call(factory.get(), &webrtc::PeerConnectionFactory::Initialize);
  bool result = call.Marshal(factory->signaling_thread());

  if (!result) {
    return NULL;
  }

  return webrtc::PeerConnectionFactoryProxy::Create(factory->signaling_thread(), factory);
}

webrtc::PeerConnectionFactoryInterface* Core::GetFactory() {
  LOG(LS_INFO) << __PRETTY_FUNCTION__;

  return _factory.get();
}

cricket::DeviceManagerInterface* Core::GetManager() {
  LOG(LS_INFO) << __PRETTY_FUNCTION__;

  return _manager.get();
}<|endoftext|>


<commit_before>/*++
Copyright (c) 2013 Microsoft Corporation

Module Name:

    weighted_maxsat.cpp

Abstract:
    Weighted MAXSAT module

Author:

    Anh-Dung Phan (t-anphan) 2013-10-16

Notes:

--*/

#include "weighted_maxsat.h"
#include "smt_theory.h"
#include "smt_context.h"
#include "ast_pp.h"

namespace smt {

    class theory_weighted_maxsat : public theory {
        app_ref_vector           m_vars;       // Auxiliary variables per soft clause
        expr_ref_vector          m_fmls;       // Formulas per soft clause
        app_ref                  m_min_cost_atom; // atom tracking modified lower bound
        bool_var                 m_min_cost_bv;   // max cost Boolean variable
        vector<rational>         m_weights;    // weights of theory variables.
        svector<theory_var>      m_costs;      // set of asserted theory variables
        svector<theory_var>      m_cost_save;  // set of asserted theory variables
        rational                 m_cost;       // current sum of asserted costs
        rational                 m_min_cost;   // current maximal cost assignment.
        u_map<theory_var>        m_bool2var;   // bool_var -> theory_var
        svector<bool_var>        m_var2bool;   // theory_var -> bool_var
    public:
        theory_weighted_maxsat(ast_manager& m):
            theory(m.mk_family_id("weighted_maxsat")),
            m_vars(m),
            m_fmls(m),
            m_min_cost_atom(m)
        {}

        /**
           \brief return the complement of variables that are currently assigned.
        */
        void get_assignment(expr_ref_vector& result) {
            result.reset();
            std::sort(m_cost_save.begin(), m_cost_save.end());
            for (unsigned i = 0, j = 0; i < m_vars.size(); ++i) {
                if (j < m_cost_save.size() && m_cost_save[j] == i) {
                    ++j;
                }
                else {
                    result.push_back(m_fmls[i].get());
                }
            }
        }

        virtual void init_search_eh() {
            context & ctx = get_context();
            ast_manager& m = get_manager();
            m_var2bool.reset();
            for (unsigned i = 0; i < m_vars.size(); ++i) {
                app* var = m_vars[i].get();
                bool_var bv;
                enode* x;
                if (!ctx.e_internalized(var)) {
                    x = ctx.mk_enode(var, false, true, true);
                }
                else {
                    x = ctx.get_enode(var);
                }
                if (ctx.b_internalized(var)) {
                    bv = ctx.get_bool_var(var);
                }
                else {
                    bv = ctx.mk_bool_var(var);
                }
                ctx.set_var_theory(bv, get_id());
                ctx.set_enode_flag(bv, true);
                theory_var v = mk_var(x);
                ctx.attach_th_var(x, this, v);
                m_bool2var.insert(bv, v);
                SASSERT(v == m_var2bool.size());
                m_var2bool.push_back(bv);
                SASSERT(ctx.bool_var2enode(bv));
            }
            if (m_min_cost_atom) {
                app* var = m_min_cost_atom;
                if (!ctx.e_internalized(var)) {
                    ctx.mk_enode(var, false, true, true);
                }
                if (ctx.b_internalized(var)) {
                    m_min_cost_bv = ctx.get_bool_var(var);
                }
                else {
                    m_min_cost_bv = ctx.mk_bool_var(var);
                }
                ctx.set_enode_flag(m_min_cost_bv, true);
            }
        }

        void assert_weighted(expr* fml, rational const& w) {
            context & ctx = get_context();
            ast_manager& m = get_manager();
            app_ref var(m), wfml(m);
            var = m.mk_fresh_const("w", m.mk_bool_sort());
            wfml = m.mk_or(var, fml);
            ctx.assert_expr(wfml);
            m_weights.push_back(w);
            m_vars.push_back(var);
            m_fmls.push_back(fml);
            m_min_cost += w;
        }

        rational const& get_min_cost() const {
            return m_min_cost;
        }

        expr* set_min_cost(rational const& c) {
            ast_manager& m = get_manager();
            std::ostringstream strm;
            strm << "cost <= " << c;
            m_min_cost = c;
            m_min_cost_atom = m.mk_fresh_const(strm.str().c_str(), m.mk_bool_sort());
            return m_min_cost_atom;
        }

        bool found_solution() const {
            return !m_cost_save.empty();
        }

        virtual void assign_eh(bool_var v, bool is_true) {
            IF_VERBOSE(3, verbose_stream() << "Assign " << v << " " << is_true << "\n";);
            if (is_true) {
                context& ctx = get_context();
                theory_var tv = m_bool2var[v];
                rational const& w = m_weights[tv];
                ctx.push_trail(value_trail<context, rational>(m_cost));
                ctx.push_trail(push_back_vector<context, svector<theory_var> >(m_costs));
                m_cost += w;
                m_costs.push_back(tv);
                if (m_cost > m_min_cost) {
                    block(false);
                }
            }
        }

        virtual final_check_status final_check_eh() {
            if (block(true)) {
                return FC_DONE;
            }
            return FC_CONTINUE;
        }

        virtual bool use_diseqs() const {
            return false;
        }

        virtual bool build_models() const {
            return false;
        }

        void reset() {
            reset_eh();
        }

        virtual void reset_eh() {
            theory::reset_eh();
            m_vars.reset();
            m_fmls.reset();
            m_weights.reset();
            m_costs.reset();
            m_min_cost.reset();
            m_cost.reset();
            m_cost_save.reset();
            m_bool2var.reset();
            m_var2bool.reset();
            m_min_cost_atom = 0;
        }

        virtual theory * mk_fresh(context * new_ctx) { return alloc(theory_weighted_maxsat, new_ctx->get_manager()); }
        virtual bool internalize_atom(app * atom, bool gate_ctx) { return false; }
        virtual bool internalize_term(app * term) { return false; }
        virtual void new_eq_eh(theory_var v1, theory_var v2) { }
        virtual void new_diseq_eh(theory_var v1, theory_var v2) { }

    private:

        class compare_cost {
            theory_weighted_maxsat& m_th;
        public:
            compare_cost(theory_weighted_maxsat& t):m_th(t) {}
            bool operator() (theory_var v, theory_var w) const {
                return m_th.m_weights[v] > m_th.m_weights[w];
            }
        };

        bool block(bool is_final) {
            if (m_vars.empty()) {
                return true;
            }
            ast_manager& m = get_manager();
            context& ctx = get_context();
            literal_vector lits;
            compare_cost compare_cost(*this);
            svector<theory_var> costs(m_costs);
            std::sort(costs.begin(), costs.end(), compare_cost);
            rational weight(0);
            for (unsigned i = 0; i < costs.size() && weight < m_min_cost; ++i) {
                weight += m_weights[costs[i]];
                lits.push_back(~literal(m_var2bool[costs[i]]));
            }
            if (m_min_cost_atom) {
                lits.push_back(~literal(m_min_cost_bv));
            }
            IF_VERBOSE(2,
                       verbose_stream() << "block: ";
                       for (unsigned i = 0; i < lits.size(); ++i) {
                           expr_ref tmp(m);
                           ctx.literal2expr(lits[i], tmp);
                           verbose_stream() << tmp << " ";
                       }
                       verbose_stream() << "\n";
                       );

            ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr());
            if (is_final && m_cost < m_min_cost) {
                m_min_cost = weight;
                m_cost_save.reset();
                m_cost_save.append(m_costs);
            }
            return false;
        }
    };

}

namespace opt {

    /**
       Iteratively increase cost until there is an assignment during
       final_check that satisfies min_cost.

       Takes: log (n / log(n)) iterations
    */

    static lbool iterative_weighted_maxsat(opt_solver& s, smt::theory_weighted_maxsat& wth) {
        ast_manager& m = s.get_context().get_manager();
        rational cost = wth.get_min_cost();
        rational log_cost(1), tmp(1);
        while (tmp < cost) {
            ++log_cost;
            tmp *= rational(2);
        }
        expr_ref_vector bounds(m);
        expr_ref bound(m);
        lbool result = l_false;
        while (log_cost <= cost && !wth.found_solution() && result != l_undef) {
            std::cout << "cost: " << log_cost << "\n";
            bound = wth.set_min_cost(log_cost);
            bounds.push_back(bound);
            result = s.check_sat_core(1,bounds.c_ptr()+bounds.size()-1);
            log_cost *= rational(2);
        }
        return result;
    }

    struct wmaxsmt::imp {
        ast_manager&     m;
        opt_solver&      s;
        expr_ref_vector  m_soft;
        expr_ref_vector  m_assignment;
        vector<rational> m_weights;
        rational         m_upper;

        imp(ast_manager& m, opt_solver& s, expr_ref_vector& soft_constraints, vector<rational> const& weights):
            m(m), s(s), m_soft(soft_constraints), m_assignment(m), m_weights(weights)
        {}
        ~imp() {}

        smt::theory_weighted_maxsat* get_theory() const {
            smt::context& ctx = s.get_context();
            smt::theory_id th_id = m.get_family_id("weighted_maxsat");
            smt::theory* th = ctx.get_theory(th_id);
            if (th) {
                return dynamic_cast<smt::theory_weighted_maxsat*>(th);
            }
            else {
                return 0;
            }
        }

        smt::theory_weighted_maxsat& ensure_theory() {
            smt::theory_weighted_maxsat* wth = get_theory();
            if (wth) {
                wth->reset();
            }
            else {
                wth = alloc(smt::theory_weighted_maxsat, m);
                s.get_context().register_plugin(wth);
            }
            return *wth;
        }

        /**
           Takes solver with hard constraints added.
           Returns a maximal satisfying subset of weighted soft_constraints
           that are still consistent with the solver state.
        */

        lbool operator()() {
            TRACE("opt", tout << "weighted maxsat\n";);
            smt::theory_weighted_maxsat& wth = ensure_theory();
            lbool result;
            {
                solver::scoped_push _s(s);
                for (unsigned i = 0; i < m_soft.size(); ++i) {
                    wth.assert_weighted(m_soft[i].get(), m_weights[i]);
                }
                result = s.check_sat_core(0,0);

                wth.get_assignment(m_assignment);
                if (!m_assignment.empty() && result == l_false) {
                    result = l_true;
                }
            }
            m_upper = wth.get_min_cost();
            TRACE("opt", tout << "min cost: " << m_upper << "\n";);
            wth.reset();
            return result;
        }

        rational get_lower() const {
            return rational(0);
        }

        rational get_upper() const {
            return m_upper;
        }
    };

    wmaxsmt::wmaxsmt(ast_manager& m, opt_solver& s, expr_ref_vector& soft_constraints, vector<rational> const& weights) {
        m_imp = alloc(imp, m, s, soft_constraints, weights);
    }

    wmaxsmt::~wmaxsmt() {
        dealloc(m_imp);
    }

    lbool wmaxsmt::operator()() {
        return (*m_imp)();
    }
    rational wmaxsmt::get_lower() const {
        return m_imp->get_lower();
    }
    rational wmaxsmt::get_upper() const {
        return m_imp->get_upper();
    }
    rational wmaxsmt::get_value() const {
        return m_imp->get_upper();
    }
    expr_ref_vector wmaxsmt::get_assignment() const {
        return m_imp->m_assignment;
    }
    void wmaxsmt::set_cancel(bool f) {
        // no-op
    }
    void wmaxsmt::collect_statistics(statistics& st) const {
        // no-op
    }

};

<commit_msg>fix bug exposed by lia2maxsmt4<commit_after>/*++
Copyright (c) 2013 Microsoft Corporation

Module Name:

    weighted_maxsat.cpp

Abstract:
    Weighted MAXSAT module

Author:

    Anh-Dung Phan (t-anphan) 2013-10-16

Notes:

--*/

#include "weighted_maxsat.h"
#include "smt_theory.h"
#include "smt_context.h"
#include "ast_pp.h"

namespace smt {

    class theory_weighted_maxsat : public theory {
        app_ref_vector           m_vars;       // Auxiliary variables per soft clause
        expr_ref_vector          m_fmls;       // Formulas per soft clause
        app_ref                  m_min_cost_atom; // atom tracking modified lower bound
        bool_var                 m_min_cost_bv;   // max cost Boolean variable
        vector<rational>         m_weights;    // weights of theory variables.
        svector<theory_var>      m_costs;      // set of asserted theory variables
        svector<theory_var>      m_cost_save;  // set of asserted theory variables
        rational                 m_cost;       // current sum of asserted costs
        rational                 m_min_cost;   // current maximal cost assignment.
        u_map<theory_var>        m_bool2var;   // bool_var -> theory_var
        svector<bool_var>        m_var2bool;   // theory_var -> bool_var
    public:
        theory_weighted_maxsat(ast_manager& m):
            theory(m.mk_family_id("weighted_maxsat")),
            m_vars(m),
            m_fmls(m),
            m_min_cost_atom(m)
        {}

        /**
           \brief return the complement of variables that are currently assigned.
        */
        void get_assignment(expr_ref_vector& result) {
            result.reset();
            std::sort(m_cost_save.begin(), m_cost_save.end());
            for (unsigned i = 0, j = 0; i < m_vars.size(); ++i) {
                if (j < m_cost_save.size() && m_cost_save[j] == i) {
                    ++j;
                }
                else {
                    result.push_back(m_fmls[i].get());
                }
            }
        }

        virtual void init_search_eh() {
            context & ctx = get_context();
            ast_manager& m = get_manager();
            m_var2bool.reset();
            for (unsigned i = 0; i < m_vars.size(); ++i) {
                app* var = m_vars[i].get();
                bool_var bv;
                enode* x;
                if (!ctx.e_internalized(var)) {
                    x = ctx.mk_enode(var, false, true, true);
                }
                else {
                    x = ctx.get_enode(var);
                }
                if (ctx.b_internalized(var)) {
                    bv = ctx.get_bool_var(var);
                }
                else {
                    bv = ctx.mk_bool_var(var);
                }
                ctx.set_var_theory(bv, get_id());
                ctx.set_enode_flag(bv, true);
                theory_var v = mk_var(x);
                ctx.attach_th_var(x, this, v);
                m_bool2var.insert(bv, v);
                SASSERT(v == m_var2bool.size());
                m_var2bool.push_back(bv);
                SASSERT(ctx.bool_var2enode(bv));

                lbool asgn = ctx.get_assignment(bv);
                if (asgn == l_true) {
                    assign_eh(bv, true);
                }

            }
            if (m_min_cost_atom) {
                app* var = m_min_cost_atom;
                if (!ctx.e_internalized(var)) {
                    ctx.mk_enode(var, false, true, true);
                }
                if (ctx.b_internalized(var)) {
                    m_min_cost_bv = ctx.get_bool_var(var);
                }
                else {
                    m_min_cost_bv = ctx.mk_bool_var(var);
                }
                ctx.set_enode_flag(m_min_cost_bv, true);
            }
        }

        void assert_weighted(expr* fml, rational const& w) {
            context & ctx = get_context();
            ast_manager& m = get_manager();
            app_ref var(m), wfml(m);
            var = m.mk_fresh_const("w", m.mk_bool_sort());
            wfml = m.mk_or(var, fml);
            ctx.assert_expr(wfml);
            m_weights.push_back(w);
            m_vars.push_back(var);
            m_fmls.push_back(fml);
            m_min_cost += w;
        }

        rational const& get_min_cost() const {
            return m_min_cost;
        }

        expr* set_min_cost(rational const& c) {
            ast_manager& m = get_manager();
            std::ostringstream strm;
            strm << "cost <= " << c;
            m_min_cost = c;
            m_min_cost_atom = m.mk_fresh_const(strm.str().c_str(), m.mk_bool_sort());
            return m_min_cost_atom;
        }

        bool found_solution() const {
            return !m_cost_save.empty();
        }

        virtual void assign_eh(bool_var v, bool is_true) {
            IF_VERBOSE(3, verbose_stream() << "Assign " << v << " " << is_true << "\n";);
            if (is_true) {
                context& ctx = get_context();
                theory_var tv = m_bool2var[v];
                rational const& w = m_weights[tv];
                ctx.push_trail(value_trail<context, rational>(m_cost));
                ctx.push_trail(push_back_vector<context, svector<theory_var> >(m_costs));
                m_cost += w;
                m_costs.push_back(tv);
                if (m_cost > m_min_cost) {
                    block(false);
                }
            }
        }

        virtual final_check_status final_check_eh() {
            if (block(true)) {
                return FC_DONE;
            }
            return FC_CONTINUE;
        }

        virtual bool use_diseqs() const {
            return false;
        }

        virtual bool build_models() const {
            return false;
        }

        void reset() {
            reset_eh();
        }

        virtual void reset_eh() {
            theory::reset_eh();
            m_vars.reset();
            m_fmls.reset();
            m_weights.reset();
            m_costs.reset();
            m_min_cost.reset();
            m_cost.reset();
            m_cost_save.reset();
            m_bool2var.reset();
            m_var2bool.reset();
            m_min_cost_atom = 0;
        }

        virtual theory * mk_fresh(context * new_ctx) { return alloc(theory_weighted_maxsat, new_ctx->get_manager()); }
        virtual bool internalize_atom(app * atom, bool gate_ctx) { return false; }
        virtual bool internalize_term(app * term) { return false; }
        virtual void new_eq_eh(theory_var v1, theory_var v2) { }
        virtual void new_diseq_eh(theory_var v1, theory_var v2) { }

    private:

        class compare_cost {
            theory_weighted_maxsat& m_th;
        public:
            compare_cost(theory_weighted_maxsat& t):m_th(t) {}
            bool operator() (theory_var v, theory_var w) const {
                return m_th.m_weights[v] > m_th.m_weights[w];
            }
        };

        bool block(bool is_final) {
            if (m_vars.empty()) {
                return true;
            }
            ast_manager& m = get_manager();
            context& ctx = get_context();
            literal_vector lits;
            compare_cost compare_cost(*this);
            svector<theory_var> costs(m_costs);
            std::sort(costs.begin(), costs.end(), compare_cost);
            rational weight(0);
            for (unsigned i = 0; i < costs.size() && weight < m_min_cost; ++i) {
                weight += m_weights[costs[i]];
                lits.push_back(~literal(m_var2bool[costs[i]]));
            }
            if (m_min_cost_atom) {
                lits.push_back(~literal(m_min_cost_bv));
            }
            IF_VERBOSE(2,
                       verbose_stream() << "block: ";
                       for (unsigned i = 0; i < lits.size(); ++i) {
                           expr_ref tmp(m);
                           ctx.literal2expr(lits[i], tmp);
                           verbose_stream() << tmp << " ";
                       }
                       verbose_stream() << "\n";
                       );

            ctx.mk_th_axiom(get_id(), lits.size(), lits.c_ptr());
            if (is_final && m_cost < m_min_cost) {
                m_min_cost = weight;
                m_cost_save.reset();
                m_cost_save.append(m_costs);
            }
            return false;
        }
    };

}

namespace opt {

    /**
       Iteratively increase cost until there is an assignment during
       final_check that satisfies min_cost.

       Takes: log (n / log(n)) iterations
    */

    static lbool iterative_weighted_maxsat(opt_solver& s, smt::theory_weighted_maxsat& wth) {
        ast_manager& m = s.get_context().get_manager();
        rational cost = wth.get_min_cost();
        rational log_cost(1), tmp(1);
        while (tmp < cost) {
            ++log_cost;
            tmp *= rational(2);
        }
        expr_ref_vector bounds(m);
        expr_ref bound(m);
        lbool result = l_false;
        while (log_cost <= cost && !wth.found_solution() && result != l_undef) {
            std::cout << "cost: " << log_cost << "\n";
            bound = wth.set_min_cost(log_cost);
            bounds.push_back(bound);
            result = s.check_sat_core(1,bounds.c_ptr()+bounds.size()-1);
            log_cost *= rational(2);
        }
        return result;
    }

    struct wmaxsmt::imp {
        ast_manager&     m;
        opt_solver&      s;
        expr_ref_vector  m_soft;
        expr_ref_vector  m_assignment;
        vector<rational> m_weights;
        rational         m_upper;

        imp(ast_manager& m, opt_solver& s, expr_ref_vector& soft_constraints, vector<rational> const& weights):
            m(m), s(s), m_soft(soft_constraints), m_assignment(m), m_weights(weights)
        {}
        ~imp() {}

        smt::theory_weighted_maxsat* get_theory() const {
            smt::context& ctx = s.get_context();
            smt::theory_id th_id = m.get_family_id("weighted_maxsat");
            smt::theory* th = ctx.get_theory(th_id);
            if (th) {
                return dynamic_cast<smt::theory_weighted_maxsat*>(th);
            }
            else {
                return 0;
            }
        }

        smt::theory_weighted_maxsat& ensure_theory() {
            smt::theory_weighted_maxsat* wth = get_theory();
            if (wth) {
                wth->reset();
            }
            else {
                wth = alloc(smt::theory_weighted_maxsat, m);
                s.get_context().register_plugin(wth);
            }
            return *wth;
        }

        /**
           Takes solver with hard constraints added.
           Returns a maximal satisfying subset of weighted soft_constraints
           that are still consistent with the solver state.
        */

        lbool operator()() {
            TRACE("opt", tout << "weighted maxsat\n";);
            smt::theory_weighted_maxsat& wth = ensure_theory();
            lbool result;
            {
                solver::scoped_push _s(s);
                for (unsigned i = 0; i < m_soft.size(); ++i) {
                    wth.assert_weighted(m_soft[i].get(), m_weights[i]);
                }
                result = s.check_sat_core(0,0);

                wth.get_assignment(m_assignment);
                if (!m_assignment.empty() && result == l_false) {
                    result = l_true;
                }
            }
            m_upper = wth.get_min_cost();
            TRACE("opt", tout << "min cost: " << m_upper << "\n";);
            wth.reset();
            return result;
        }

        rational get_lower() const {
            return rational(0);
        }

        rational get_upper() const {
            return m_upper;
        }
    };

    wmaxsmt::wmaxsmt(ast_manager& m, opt_solver& s, expr_ref_vector& soft_constraints, vector<rational> const& weights) {
        m_imp = alloc(imp, m, s, soft_constraints, weights);
    }

    wmaxsmt::~wmaxsmt() {
        dealloc(m_imp);
    }

    lbool wmaxsmt::operator()() {
        return (*m_imp)();
    }
    rational wmaxsmt::get_lower() const {
        return m_imp->get_lower();
    }
    rational wmaxsmt::get_upper() const {
        return m_imp->get_upper();
    }
    rational wmaxsmt::get_value() const {
        return m_imp->get_upper();
    }
    expr_ref_vector wmaxsmt::get_assignment() const {
        return m_imp->m_assignment;
    }
    void wmaxsmt::set_cancel(bool f) {
        // no-op
    }
    void wmaxsmt::collect_statistics(statistics& st) const {
        // no-op
    }

};

<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2014, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */

#include <osquery/filesystem.h>
#include <osquery/tables.h>

namespace fs = boost::filesystem;
namespace pt = boost::property_tree;

namespace osquery {
namespace tables {

/// Each home directory will include custom extensions.
#define kSafariExtensionsPath "/Library/Safari/Extensions/"

#define kSafariPluginsPath "/Library/Internet Plug-Ins/"

/// Safari extensions will not load unless they have the expected pattern.
#define kSafariExtensionsPattern "%.safariextz"

const std::map<std::string, std::string> kSafariPluginKeys = {
    {"WebPluginName", "name"},
    {"CFBundleIdentifier", "identifier"},
    {"CFBundleShortVersionString", "version"},
    {"DTPlatformBuild", "sdk"},
    {"WebPluginDescription", "description"},
    {"CFBundleDevelopmentRegion", "development_region"},
    {"LSRequiresNativeExecution", "native"},
};

void genSafariPlugin(const std::string& path, QueryData& results) {
  Row r;
  pt::ptree tree;
  if (osquery::parsePlist(path + "/Contents/Info.plist", tree).ok()) {
    // Plugin did not include an Info.plist, or it was invalid
    for (const auto& it : kSafariPluginKeys) {
      try {
        r[it.second] = tree.get<std::string>(it.first);
      } catch (const pt::ptree_error& e) {
        r[it.second] = "";
      }

      // Convert Plist bool-types to an integer.
      if (r[it.second] == "true" || r[it.second] == "YES" ||
          r[it.first] == "Yes") {
        r[it.second] = INTEGER(1);
      } else if (r[it.second] == "false" || r[it.second] == "NO" ||
                 r[it.second] == "No") {
        r[it.second] = INTEGER(0);
      }
    }
  }

  if (r.at("is_native").size() == 0) {
    // The default case for native execution is false.
    r["is_native"] = "0";
  }

  r["path"] = path;
  results.push_back(r);
}

QueryData genSafariPlugins(QueryContext& context) {
  QueryData results;

  std::vector<std::string> bundles;
  if (listDirectoriesInDirectory(kSafariPluginsPath, bundles).ok()) {
    for (const auto& dir : bundles) {
      genSafariPlugin(dir, results);
    }
  }

  auto homes = osquery::getHomeDirectories();
  for (const auto& home : homes) {
    bundles.clear();
    if (listDirectoriesInDirectory(home / kSafariPluginsPath, bundles).ok()) {
      for (const auto& dir : bundles) {
        genSafariPlugin(dir, results);
      }
    }
  }

  return results;
}

void genSafariExtension(const std::string& path, QueryData& results) {
  Row r;
  r["name"] = fs::path(path).stem().string();
  r["path"] = path;
  results.push_back(r);
}

QueryData genSafariExtensions(QueryContext& context) {
  QueryData results;

  auto homes = osquery::getHomeDirectories();
  for (const auto& home : homes) {
    auto dir = home / kSafariExtensionsPath;
    // Check that an extensions directory exists.
    if (!pathExists(dir).ok()) {
      continue;
    }

    // Glob the extension files.
    std::vector<std::string> paths;
    if (!resolveFilePattern(dir / kSafariExtensionsPattern, paths).ok()) {
      continue;
    }

    for (const auto& extension_path : paths) {
      genSafariExtension(extension_path, results);
    }
  }

  return results;
}
}
}
<commit_msg>[Fix #869] Rename safari_plugins is_native<commit_after>/*
 *  Copyright (c) 2014, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 *
 */

#include <osquery/filesystem.h>
#include <osquery/tables.h>

namespace fs = boost::filesystem;
namespace pt = boost::property_tree;

namespace osquery {
namespace tables {

/// Each home directory will include custom extensions.
#define kSafariExtensionsPath "/Library/Safari/Extensions/"

#define kSafariPluginsPath "/Library/Internet Plug-Ins/"

/// Safari extensions will not load unless they have the expected pattern.
#define kSafariExtensionsPattern "%.safariextz"

const std::map<std::string, std::string> kSafariPluginKeys = {
    {"WebPluginName", "name"},
    {"CFBundleIdentifier", "identifier"},
    {"CFBundleShortVersionString", "version"},
    {"DTPlatformBuild", "sdk"},
    {"WebPluginDescription", "description"},
    {"CFBundleDevelopmentRegion", "development_region"},
    {"LSRequiresNativeExecution", "native"},
};

void genSafariPlugin(const std::string& path, QueryData& results) {
  Row r;
  pt::ptree tree;
  if (osquery::parsePlist(path + "/Contents/Info.plist", tree).ok()) {
    // Plugin did not include an Info.plist, or it was invalid
    for (const auto& it : kSafariPluginKeys) {
      try {
        r[it.second] = tree.get<std::string>(it.first);
      } catch (const pt::ptree_error& e) {
        r[it.second] = "";
      }

      // Convert Plist bool-types to an integer.
      if (r[it.second] == "true" || r[it.second] == "YES" ||
          r[it.first] == "Yes") {
        r[it.second] = INTEGER(1);
      } else if (r[it.second] == "false" || r[it.second] == "NO" ||
                 r[it.second] == "No") {
        r[it.second] = INTEGER(0);
      }
    }
  }

  if (r.count("native") == 0 || r.at("native").size() == 0) {
    // The default case for native execution is false.
    r["native"] = "0";
  }

  r["path"] = path;
  results.push_back(r);
}

QueryData genSafariPlugins(QueryContext& context) {
  QueryData results;

  std::vector<std::string> bundles;
  if (listDirectoriesInDirectory(kSafariPluginsPath, bundles).ok()) {
    for (const auto& dir : bundles) {
      genSafariPlugin(dir, results);
    }
  }

  auto homes = osquery::getHomeDirectories();
  for (const auto& home : homes) {
    bundles.clear();
    if (listDirectoriesInDirectory(home / kSafariPluginsPath, bundles).ok()) {
      for (const auto& dir : bundles) {
        genSafariPlugin(dir, results);
      }
    }
  }

  return results;
}

void genSafariExtension(const std::string& path, QueryData& results) {
  Row r;
  r["name"] = fs::path(path).stem().string();
  r["path"] = path;
  results.push_back(r);
}

QueryData genSafariExtensions(QueryContext& context) {
  QueryData results;

  auto homes = osquery::getHomeDirectories();
  for (const auto& home : homes) {
    auto dir = home / kSafariExtensionsPath;
    // Check that an extensions directory exists.
    if (!pathExists(dir).ok()) {
      continue;
    }

    // Glob the extension files.
    std::vector<std::string> paths;
    if (!resolveFilePattern(dir / kSafariExtensionsPattern, paths).ok()) {
      continue;
    }

    for (const auto& extension_path : paths) {
      genSafariExtension(extension_path, results);
    }
  }

  return results;
}
}
}
<|endoftext|>


<commit_before>#include "ctext.h"

const ctext_config config_default = {
  .m_tabstop = CTEXT_DEFAULT_TABSTOP,
  .m_scrollback = CTEXT_DEFAULT_SCROLLBACK,
  .m_bounding_box = CTEXT_DEFAULT_BOUNDING_BOX,
  .m_do_wrap = CTEXT_DEFAULT_DO_WRAP,
  .m_append_top = CTEXT_DEFAULT_APPEND_TOP,
  .m_scroll_on_append = CTEXT_DEFAULT_APPEND_TOP,
  .m_on_event = CTEXT_DEFAULT_ON_EVENT
};

char really_large_buffer[64000] = {0};

ctext::ctext(WINDOW *win = 0, ctext_config *config = 0)
{
  this->m_win = win;

  if(config)
  {
    memcpy(&this->m_config, config, sizeof(ctext_config));
  }
  else
  {
    memcpy(&this->m_config, config_default, sizeof(ctext_config));
  }

  this->m_pos_x = 0;
  this->m_pos_y = 0;

  this->m_max_x = 0;
  this->m_max_y = 0;
}

int8_t ctext::set_config(ctext_config *config)
{
  memcpy(&this->m_config, config, sizeof(ctext_config));
  return this->render();
}

int8_t ctext::get_config(ctext_config *config)
{
  memcpy(&config, &this->m_config, sizeof(ctext_config));
  return 0;
}

int8_t ctext::attach_curses_window(WINDOW *win)
{
  this->m_win = win;
  return this->render();
}

size_t ctext::clear(size_t amount = 0)
{
  if(amount == 0)
  {
    this->m_buffer.clear();
  }
  else
  {
    this->m_buffer.erase(this->m_buffer.begin(), this->m_buffer.begin() + amount);
  }

  if (this->m_config.m_on_event)
  {
    this->m_config.m_on_event(this, ctext_event::CLEAR);
  }

  return this->render();
}

int8_t ctext::direct_scroll(size_t x, size_t y)
{
  if(this->m_config.m_bounding_box)
  {
    x = max(0, x);
    y = max(0, y);
    x = min(x, this->m_max_x);
    y = min(y, this->m_max_y);
  }

  this->m_pos_x = x;
  this->m_pos_y = y;

  if (this->m_config.m_on_event)
  {
    this->m_config.m_on_event(this, ctext_event::SCROLL);
  }

  return 0;
}

int8_t ctext::scroll_to(size_t x, size_t y)
{
  this->direct_scroll(x, y);
  return this->render();
}

int8_t ctext::get_offset(size_t*x, size_t*y)
{
  *x = this->m_pos_x;
  *y = this->m_pos_y;

  return 0;
}

int8_t get_size(size_t*x, size_t*y)
{
  *x = this->m_max_x;
  *y = this->m_max_y;
  return 0;
}

int8_t ctext::up(size_t amount = 1)
{
  return this->down(-amount);
}

int8_t ctext::down(size_t amount = 1)
{
  return this->scroll_to(this->m_pos_x, this->m_pos_y + amount);
}

int8_t ctext::left(size_t amount = 1)
{
  return this->right(-amount);
}

int8_t ctext:right(size_t amount = 1)
{
  return this->scroll_to(this->m_pos_x + amount, this->m_pos_y);
}

int8_t ctext::printf(const char*format, ...)
{
  this->render();
}

void ctext::get_win_size()
{
  int32_t width = 0, height = 0;

  if(this->m_win)
  {
    getmaxyx(this->m_win, height, width);
  }
  this->m_win_width = width;
  this->m_win_height = height;
}

int8_t ctext::rebuf()
{
  this->get_win_size();

  // The actual scroll back, which is what
  // people expect in this feature is the
  // configured scrollback + the window height.
  size_t actual_scroll_back = this->m_win_height + this->m_config.m_scrollback;

  if(this->m_buffer.size() > actual_scroll_back)
  {
    this->m_buffer.erase(this->m_buffer.begin(), this->m_buffer().size() - actual_scroll_back);
  }

  this->m_max_x = 0;
  // Now unfortunately we have to do a scan over everything in N time to find
  // the maximum length string --- but only if we care about the bounding
  // box
  if(this->m_config.m_bounding_box)
  {
    for(ctext_buffer::const_iterator it = this->m_buffer.begin(); it != this->m_buffer.end(); it++)
    {
      this->m_max_x = max(this->m_max_x, (*it).size());
    }
  }

  // this is practically free so we'll just do it.
  this->m_max_y = this->m_buffer().size();

  // Since we've changed the bounding box of the content we have to
  // issue a rescroll on exactly our previous parameters. This may
  // force us inward or may retain our position.
  return this->direct_scroll(this->m_pos_x, this->m_pos_y);
  return 0;
}

int8_t ctext::printf(const char*format, ...)
{
  va_list args;
  va_start(args, fmt);
  vsprintf(really_large_buffer, args);
  va_end(args);

  this->m_buffer.push_back(really_large_buffer);

  if (this->m_config.m_on_event)
  {
    this->m_config.m_on_event(this, ctext_event::DATA);
  }

  // Since we are adding content we need to see if we are
  // to force on scroll.
  if(this->m_config.m_scroll_on_append)
  {
    this->get_win_size();
    // now we force it.
    this->direct_scroll(this->m_buffer.size() - this->m_win_height, 0);
  }

  return this->render();
}

int8_t ctext::render()
{
  // Calculate the bounds of everything first.
  this->rebuf();

  if(!this->m_win)
  {
    // not doing anything without a window.
    return -1;
  }

  int32_t width = 0, height = 0;
  getmaxyx(this->m_win, height, width);

  // By this time, if we are bounded by a box,
}
<commit_msg>implementation complete, now time to compile<commit_after>#include "ctext.h"

const ctext_config config_default = {
  .m_tabstop = CTEXT_DEFAULT_TABSTOP,
  .m_scrollback = CTEXT_DEFAULT_SCROLLBACK,
  .m_bounding_box = CTEXT_DEFAULT_BOUNDING_BOX,
  .m_do_wrap = CTEXT_DEFAULT_DO_WRAP,
  .m_append_top = CTEXT_DEFAULT_APPEND_TOP,
  .m_scroll_on_append = CTEXT_DEFAULT_APPEND_TOP,
  .m_on_event = CTEXT_DEFAULT_ON_EVENT
};

char really_large_buffer[64000] = {0};

ctext::ctext(WINDOW *win = 0, ctext_config *config = 0)
{
  this->m_win = win;

  if(config)
  {
    memcpy(&this->m_config, config, sizeof(ctext_config));
  }
  else
  {
    memcpy(&this->m_config, config_default, sizeof(ctext_config));
  }

  this->m_pos_x = 0;
  this->m_pos_y = 0;

  this->m_max_x = 0;
  this->m_max_y = 0;
}

int8_t ctext::set_config(ctext_config *config)
{
  memcpy(&this->m_config, config, sizeof(ctext_config));
  return this->render();
}

int8_t ctext::get_config(ctext_config *config)
{
  memcpy(&config, &this->m_config, sizeof(ctext_config));
  return 0;
}

int8_t ctext::attach_curses_window(WINDOW *win)
{
  this->m_win = win;
  return this->render();
}

size_t ctext::clear(size_t amount = 0)
{
  if(amount == 0)
  {
    this->m_buffer.clear();
  }
  else
  {
    this->m_buffer.erase(this->m_buffer.begin(), this->m_buffer.begin() + amount);
  }

  if (this->m_config.m_on_event)
  {
    this->m_config.m_on_event(this, ctext_event::CLEAR);
  }

  return this->render();
}

int8_t ctext::direct_scroll(size_t x, size_t y)
{
  if(this->m_config.m_bounding_box)
  {
    x = max(0, x);
    y = max(0, y);
    x = min(x, this->m_max_x);
    y = min(y, this->m_max_y);
  }

  this->m_pos_x = x;
  this->m_pos_y = y;

  if (this->m_config.m_on_event)
  {
    this->m_config.m_on_event(this, ctext_event::SCROLL);
  }

  return 0;
}

int8_t ctext::scroll_to(size_t x, size_t y)
{
  this->direct_scroll(x, y);
  return this->render();
}

int8_t ctext::get_offset(size_t*x, size_t*y)
{
  *x = this->m_pos_x;
  *y = this->m_pos_y;

  return 0;
}

int8_t get_size(size_t*x, size_t*y)
{
  *x = this->m_max_x;
  *y = this->m_max_y;

  return 0;
}

int8_t ctext::up(size_t amount = 1)
{
  return this->down(-amount);
}

int8_t ctext::down(size_t amount = 1)
{
  return this->scroll_to(this->m_pos_x, this->m_pos_y + amount);
}

int8_t ctext::left(size_t amount = 1)
{
  return this->right(-amount);
}

int8_t ctext:right(size_t amount = 1)
{
  return this->scroll_to(this->m_pos_x + amount, this->m_pos_y);
}

int8_t ctext::printf(const char*format, ...)
{
  this->render();
}

void ctext::get_win_size()
{
  int32_t width = 0, height = 0;

  if(this->m_win)
  {
    getmaxyx(this->m_win, height, width);
  }
  this->m_win_width = width;
  this->m_win_height = height;
}

int8_t ctext::rebuf()
{
  this->get_win_size();

  // The actual scroll back, which is what
  // people expect in this feature is the
  // configured scrollback + the window height.
  size_t actual_scroll_back = this->m_win_height + this->m_config.m_scrollback;

  if(this->m_buffer.size() > actual_scroll_back)
  {
    this->m_buffer.erase(this->m_buffer.begin(), this->m_buffer().size() - actual_scroll_back);
  }

  this->m_max_x = 0;
  // Now unfortunately we have to do a scan over everything in N time to find
  // the maximum length string --- but only if we care about the bounding
  // box
  if(this->m_config.m_bounding_box)
  {
    for(ctext_buffer::const_iterator it = this->m_buffer.begin(); it != this->m_buffer.end(); it++)
    {
      this->m_max_x = max(this->m_max_x, (*it).size());
    }
  }

  // this is practically free so we'll just do it.
  this->m_max_y = this->m_buffer().size();

  // Since we've changed the bounding box of the content we have to
  // issue a rescroll on exactly our previous parameters. This may
  // force us inward or may retain our position.
  return this->direct_scroll(this->m_pos_x, this->m_pos_y);
}

int8_t ctext::printf(const char*format, ...)
{
  va_list args;
  va_start(args, fmt);
  vsprintf(really_large_buffer, args);
  va_end(args);

  this->m_buffer.push_back(really_large_buffer);

  if (this->m_config.m_on_event)
  {
    this->m_config.m_on_event(this, ctext_event::DATA);
  }

  // Since we are adding content we need to see if we are
  // to force on scroll.
  if(this->m_config.m_scroll_on_append)
  {
    this->get_win_size();
    // now we force it.
    this->direct_scroll(this->m_buffer.size() - this->m_win_height, 0);
  }

  return this->render();
}

int8_t ctext::render()
{
  // Calculate the bounds of everything first.
  this->rebuf();

  if(!this->m_win)
  {
    // Not doing anything without a window.
    return -1;
  }

  this->get_win_size();

  //
  // By this time, if we are bounded by a box,
  // it has been accounted for.
  //
  // Really our only point of interest is
  // whether we need to append to bottom
  // or append to top.
  //
  // We will assume that we can
  // populate the window quick enough
  // to avoid linear updating or paging.
  //  ... it's 2015 after all.
  //
  werase(this->m_win);

  // Regardless of whether this is append to top
  // or bottom we generate top to bottom.

  size_t start_char = max(0, this->m_pos_y);
  size_t offset = start_char;
  // the endchar will be in the substr

  // We start as m_pos_x in our list and move up to
  // m_pos_x + m_win_height except in the case of
  // wrap around.  Because of this special case,
  // we compute when to exit slightly differently.
  //
  // This is the current line of output, which stays
  // below m_win_height
  size_t line = 0;

  // start at the beginning of the buffer.
  size_t index = this->m_pos_x;
  size_t directionality = +1;

  // if we are appending to the top then we start
  // at the end and change our directionality.
  if(this->m_config.m_append_top)
  {
    directionality = -1;
    index = this->m_pos_x + this->m_win_height;
  }

  while(line < this->m_win_height)
  {
    // Reset the offset.
    offset = start_char;

    index += directionality;
    if(index < this->m_max_y || index >= 0)
    {
      // We only index into the object if we have the
      // data to do so.
      wstring to_add = this->m_buffer[index].substr(start_char, this->m_win_width);
      mvwaddwstr(this->m_win, line, 0, to_add);

      // if we are wrapping, then we do that here.
      while(
          this->m_config.m_do_wrap &&

          // if our string still exhausts our entire width
          to_add.size() == this->m_win_width &&

          // and we haven't hit the bottom
          line < this->m_win_height
        )
      {
        // move our line forward
        line++;

        // and the start_char
        start_char += this->m_win_width;

        // substring into this character now at this advanced position
        to_add = this->m_buffer[index].substr(start_char, this->m_win_width);

        // and add it to the screen
        mvwaddwstr(this->m_win, line, 0, to_add);
      }
    }
    line++;
  }

  wrefresh(this->m_win);
}
<|endoftext|>