text:
/*
 * GridMap.cpp
 *
 *  Created on: Jul 14, 2014
 *      Author: Péter Fankhauser
 *	 Institute: ETH Zurich, Autonomous Systems Lab
 */

#include "grid_map_core/GridMap.hpp"
#include "grid_map_core/GridMapMath.hpp"
#include "grid_map_core/SubmapGeometry.hpp"
#include "grid_map_core/iterators/GridMapIterator.hpp"

#include <Eigen/Dense>

#include <iostream>
#include <cassert>
#include <math.h>
#include <algorithm>
#include <stdexcept>

using namespace std;
using namespace grid_map;

namespace grid_map {

GridMap::GridMap(const std::vector<std::string>& layers)
{
  position_.setZero();
  length_.setZero();
  resolution_ = 0.0;
  size_.setZero();
  startIndex_.setZero();
  timestamp_ = 0;
  layers_ = layers;

  for (auto& layer : layers_) {
    data_.insert(std::pair<std::string, Matrix>(layer, Matrix()));
  }
}

GridMap::GridMap() :
    GridMap(std::vector<std::string>())
{
}

GridMap::~GridMap()
{
}

void GridMap::setGeometry(const Length& length, const double resolution,
                          const Position& position)
{
  assert(length(0) > 0.0);
  assert(length(1) > 0.0);
  assert(resolution > 0.0);

  Size size;
  size(0) = static_cast<int>(round(length(0) / resolution)); // There is no round() function in Eigen.
  size(1) = static_cast<int>(round(length(1) / resolution));
  resize(size);
  clearAll();

  resolution_ = resolution;
  length_ = (size_.cast<double>() * resolution_).matrix();
  position_ = position;
  startIndex_.setZero();

  return;
}

void GridMap::setGeometry(const SubmapGeometry& geometry)
{
  setGeometry(geometry.getLength(), geometry.getResolution(), geometry.getPosition());
}

void GridMap::setBasicLayers(const std::vector<std::string>& basicLayers)
{
  basicLayers_ = basicLayers;
}

const std::vector<std::string>& GridMap::getBasicLayers() const
{
  return basicLayers_;
}

bool GridMap::hasBasicLayers() const
{
  return basicLayers_.size() > 0;
}

bool GridMap::hasSameLayers(const GridMap& other) const
{
  for (const auto& layer : layers_) {
    if (!other.exists(layer)) return false;
  }
  return true;
}

void GridMap::add(const std::string& layer, const double value)
{
  add(layer, Matrix::Constant(size_(0), size_(1), value));
}

void GridMap::add(const std::string& layer, const Matrix& data)
{
  assert(size_(0) == data.rows());
  assert(size_(1) == data.cols());

  if (exists(layer)) {
    // Type exists already, overwrite its data.
    data_.at(layer) = data;
  } else {
    // Type does not exist yet, add type and data.
    data_.insert(std::pair<std::string, Matrix>(layer, data));
    layers_.push_back(layer);
  }
}

bool GridMap::exists(const std::string& layer) const
{
  return !(data_.find(layer) == data_.end());
}

const Matrix& GridMap::get(const std::string& layer) const
{
  try {
    return data_.at(layer);
  } catch (const std::out_of_range& exception) {
    throw std::out_of_range("GridMap::get(...) : No map layer '" + layer + "' available.");
  }
}

Matrix& GridMap::get(const std::string& layer)
{
  try {
    return data_.at(layer);
  } catch (const std::out_of_range& exception) {
    throw std::out_of_range("GridMap::get(...) : No map layer of type '" + layer + "' available.");
  }
}

const Matrix& GridMap::operator [](const std::string& layer) const
{
  return get(layer);
}

Matrix& GridMap::operator [](const std::string& layer)
{
  return get(layer);
}

bool GridMap::erase(const std::string& layer)
{
  const auto dataIterator = data_.find(layer);
  if (dataIterator == data_.end()) return false;
  data_.erase(dataIterator);

  const auto layerIterator = std::find(layers_.begin(), layers_.end(), layer);
  if (layerIterator == layers_.end()) return false;
  layers_.erase(layerIterator);

  const auto basicLayerIterator = std::find(basicLayers_.begin(), basicLayers_.end(), layer);
  if (basicLayerIterator != basicLayers_.end()) basicLayers_.erase(basicLayerIterator);

  return true;
}

const std::vector<std::string>& GridMap::getLayers() const
{
  return layers_;
}

float& GridMap::atPosition(const std::string& layer, const Position& position)
{
  Index index;
  if (getIndex(position, index)) {
    return at(layer, index);
  }
  throw std::out_of_range("GridMap::atPosition(...) : Position is out of range.");
}

float GridMap::atPosition(const std::string& layer, const Position& position, InterpolationMethods interpolationMethod) const
{
  switch (interpolationMethod) {
      case InterpolationMethods::INTER_LINEAR:
      {
        float value;
        if (atPositionLinearInterpolated(layer, position, value))
          return value;
        else
            interpolationMethod = InterpolationMethods::INTER_NEAREST;
      }
      case  InterpolationMethods::INTER_NEAREST:
      {
        Index index;
        if (getIndex(position, index)) {
        return at(layer, index);
        }
        else
        throw std::out_of_range("GridMap::atPosition(...) : Position is out of range.");
        break;
      }
      default:
        throw std::runtime_error("GridMap::atPosition(...) : Specified interpolation method not implemented.");
  }
}

float& GridMap::at(const std::string& layer, const Index& index)
{
  try {
    return data_.at(layer)(index(0), index(1));
  } catch (const std::out_of_range& exception) {
    throw std::out_of_range("GridMap::at(...) : No map layer '" + layer + "' available.");
  }
}

float GridMap::at(const std::string& layer, const Index& index) const
{
  try {
    return data_.at(layer)(index(0), index(1));
  } catch (const std::out_of_range& exception) {
    throw std::out_of_range("GridMap::at(...) : No map layer '" + layer + "' available.");
  }
}

bool GridMap::getIndex(const Position& position, Index& index) const
{
  return getIndexFromPosition(index, position, length_, position_, resolution_, size_, startIndex_);
}

bool GridMap::getPosition(const Index& index, Position& position) const
{
  return getPositionFromIndex(position, index, length_, position_, resolution_, size_, startIndex_);
}

bool GridMap::isInside(const Position& position) const
{
  return checkIfPositionWithinMap(position, length_, position_);
}

bool GridMap::isValid(const Index& index) const
{
  return isValid(index, basicLayers_);
}

bool GridMap::isValid(const Index& index, const std::string& layer) const
{
  if (!isfinite(at(layer, index))) return false;
  return true;
}

bool GridMap::isValid(const Index& index, const std::vector<std::string>& layers) const
{
  if (layers.empty()) return false;
  for (auto& layer : layers) {
    if (!isfinite(at(layer, index))) return false;
  }
  return true;
}

bool GridMap::getPosition3(const std::string& layer, const Index& index,
                           Position3& position) const
{
  if (!isValid(index, layer)) return false;
  Position position2d;
  getPosition(index, position2d);
  position.head(2) = position2d;
  position.z() = at(layer, index);
  return true;
}

bool GridMap::getVector(const std::string& layerPrefix, const Index& index,
                        Eigen::Vector3d& vector) const
{
  std::vector<std::string> layers;
  layers.push_back(layerPrefix + "x");
  layers.push_back(layerPrefix + "y");
  layers.push_back(layerPrefix + "z");
  if (!isValid(index, layers)) return false;
  for (size_t i = 0; i < 3; ++i) {
    vector(i) = at(layers[i], index);
  }
  return true;
}

GridMap GridMap::getSubmap(const Position& position, const Length& length,
                           bool& isSuccess) const
{
  Index index;
  return getSubmap(position, length, index, isSuccess);
}

GridMap GridMap::getSubmap(const Position& position, const Length& length,
                           Index& indexInSubmap, bool& isSuccess) const
{
  // Submap the generate.
  GridMap submap(layers_);
  submap.setBasicLayers(basicLayers_);
  submap.setTimestamp(timestamp_);
  submap.setFrameId(frameId_);

  // Get submap geometric information.
  SubmapGeometry submapInformation(*this, position, length, isSuccess);
  if (isSuccess == false) return GridMap(layers_);
  submap.setGeometry(submapInformation);
  submap.startIndex_.setZero(); // Because of the way we copy the data below.

  // Copy data.
  std::vector<BufferRegion> bufferRegions;

  if (!getBufferRegionsForSubmap(bufferRegions, submapInformation.getStartIndex(),
                                 submap.getSize(), size_, startIndex_)) {
    cout << "Cannot access submap of this size." << endl;
    isSuccess = false;
    return GridMap(layers_);
  }

  for (const auto& data : data_) {
    for (const auto& bufferRegion : bufferRegions) {
      Index index = bufferRegion.getStartIndex();
      Size size = bufferRegion.getSize();

      if (bufferRegion.getQuadrant() == BufferRegion::Quadrant::TopLeft) {
        submap.data_[data.first].topLeftCorner(size(0), size(1)) = data.second.block(index(0), index(1), size(0), size(1));
      } else if (bufferRegion.getQuadrant() == BufferRegion::Quadrant::TopRight) {
        submap.data_[data.first].topRightCorner(size(0), size(1)) = data.second.block(index(0), index(1), size(0), size(1));
      } else if (bufferRegion.getQuadrant() == BufferRegion::Quadrant::BottomLeft) {
        submap.data_[data.first].bottomLeftCorner(size(0), size(1)) = data.second.block(index(0), index(1), size(0), size(1));
      } else if (bufferRegion.getQuadrant() == BufferRegion::Quadrant::BottomRight) {
        submap.data_[data.first].bottomRightCorner(size(0), size(1)) = data.second.block(index(0), index(1), size(0), size(1));
      }

    }
  }

  isSuccess = true;
  return submap;
}

void GridMap::setPosition(const Position& position)
{
  position_ = position;
}

bool GridMap::move(const Position& position, std::vector<BufferRegion>& newRegions)
{
  Index indexShift;
  Position positionShift = position - position_;
  getIndexShiftFromPositionShift(indexShift, positionShift, resolution_);
  Position alignedPositionShift;
  getPositionShiftFromIndexShift(alignedPositionShift, indexShift, resolution_);

  // Delete fields that fall out of map (and become empty cells).
  for (int i = 0; i < indexShift.size(); i++) {
    if (indexShift(i) != 0) {
      if (abs(indexShift(i)) >= getSize()(i)) {
        // Entire map is dropped.
        clearAll();
        newRegions.push_back(BufferRegion(Index(0, 0), getSize(), BufferRegion::Quadrant::Undefined));
      } else {
        // Drop cells out of map.
        int sign = (indexShift(i) > 0 ? 1 : -1);
        int startIndex = startIndex_(i) - (sign < 0 ? 1 : 0);
        int endIndex = startIndex - sign + indexShift(i);
        int nCells = abs(indexShift(i));
        int index = (sign > 0 ? startIndex : endIndex);
        mapIndexWithinRange(index, getSize()(i));

        if (index + nCells <= getSize()(i)) {
          // One region to drop.
          if (i == 0) {
            clearRows(index, nCells);
            newRegions.push_back(BufferRegion(Index(index, 0), Size(nCells, getSize()(1)), BufferRegion::Quadrant::Undefined));
          } else if (i == 1) {
            clearCols(index, nCells);
            newRegions.push_back(BufferRegion(Index(0, index), Size(getSize()(0), nCells), BufferRegion::Quadrant::Undefined));
          }
        } else {
          // Two regions to drop.
          int firstIndex = index;
          int firstNCells = getSize()(i) - firstIndex;
          if (i == 0) {
            clearRows(firstIndex, firstNCells);
            newRegions.push_back(BufferRegion(Index(firstIndex, 0), Size(firstNCells, getSize()(1)), BufferRegion::Quadrant::Undefined));
          } else if (i == 1) {
            clearCols(firstIndex, firstNCells);
            newRegions.push_back(BufferRegion(Index(0, firstIndex), Size(getSize()(0), firstNCells), BufferRegion::Quadrant::Undefined));
          }

          int secondIndex = 0;
          int secondNCells = nCells - firstNCells;
          if (i == 0) {
            clearRows(secondIndex, secondNCells);
            newRegions.push_back(BufferRegion(Index(secondIndex, 0), Size(secondNCells, getSize()(1)), BufferRegion::Quadrant::Undefined));
          } else if (i == 1) {
            clearCols(secondIndex, secondNCells);
            newRegions.push_back(BufferRegion(Index(0, secondIndex), Size(getSize()(0), secondNCells), BufferRegion::Quadrant::Undefined));
          }
        }
      }
    }
  }

  // Update information.
  startIndex_ += indexShift;
  mapIndexWithinRange(startIndex_, getSize());
  position_ += alignedPositionShift;

  // Check if map has been moved at all.
  return (indexShift.any() != 0);
}

bool GridMap::move(const Position& position)
{
  std::vector<BufferRegion> newRegions;
  return move(position, newRegions);
}

bool GridMap::addDataFrom(const GridMap& other, bool extendMap, bool overwriteData,
                          bool copyAllLayers, std::vector<std::string> layers)
{
  // Set the layers to copy.
  if (copyAllLayers) layers = other.getLayers();

  // Resize map.
  if (extendMap) extendToInclude(other);

  // Check if all layers to copy exist and add missing layers.
  for (const auto& layer : layers) {
    if (std::find(layers_.begin(), layers_.end(), layer) == layers_.end()) {
      add(layer);
    }
  }
  // Copy data.
  for (GridMapIterator iterator(*this); !iterator.isPastEnd(); ++iterator) {
    if (isValid(*iterator) && !overwriteData) continue;
    Position position;
    getPosition(*iterator, position);
    Index index;
    if (!other.isInside(position)) continue;
    other.getIndex(position, index);
    for (const auto& layer : layers) {
      if (!other.isValid(index, layer)) continue;
      at(layer, *iterator) = other.at(layer, index);
    }
  }

  return true;
}

bool GridMap::extendToInclude(const GridMap& other)
{
  // Get dimension of maps.
  Position topLeftCorner(position_.x() + length_.x() / 2.0, position_.y() + length_.y() / 2.0);
  Position bottomRightCorner(position_.x() - length_.x() / 2.0, position_.y() - length_.y() / 2.0);
  Position topLeftCornerOther(other.getPosition().x() + other.getLength().x() / 2.0, other.getPosition().y() + other.getLength().y() / 2.0);
  Position bottomRightCornerOther(other.getPosition().x() - other.getLength().x() / 2.0, other.getPosition().y() - other.getLength().y() / 2.0);
  // Check if map needs to be resized.
  bool resizeMap = false;
  Position extendedMapPosition = position_;
  Length extendedMapLength = length_;
  if (topLeftCornerOther.x() > topLeftCorner.x()) {
    extendedMapPosition.x() += (topLeftCornerOther.x() - topLeftCorner.x()) / 2.0;
    extendedMapLength.x() += topLeftCornerOther.x() - topLeftCorner.x();
    resizeMap = true;
  }
  if (topLeftCornerOther.y() > topLeftCorner.y()) {
    extendedMapPosition.y() += (topLeftCornerOther.y() - topLeftCorner.y()) / 2.0;
    extendedMapLength.y() += topLeftCornerOther.y() - topLeftCorner.y();
    resizeMap = true;
  }
  if (bottomRightCornerOther.x() < bottomRightCorner.x()) {
    extendedMapPosition.x() -= (bottomRightCorner.x() - bottomRightCornerOther.x()) / 2.0;
    extendedMapLength.x() += bottomRightCorner.x() - bottomRightCornerOther.x();
    resizeMap = true;
  }
  if (bottomRightCornerOther.y() < bottomRightCorner.y()) {
    extendedMapPosition.y() -= (bottomRightCorner.y() - bottomRightCornerOther.y()) / 2.0;
    extendedMapLength.y() += bottomRightCorner.y() - bottomRightCornerOther.y();
    resizeMap = true;
  }
  // Resize map and copy data to new map.
  if (resizeMap) {
    GridMap mapCopy = *this;
    setGeometry(extendedMapLength, resolution_, extendedMapPosition);
    // Align new map with old one.
    Vector shift = position_ - mapCopy.getPosition();
    shift.x() = std::fmod(shift.x(), resolution_);
    shift.y() = std::fmod(shift.y(), resolution_);
    if (std::abs(shift.x()) < resolution_ / 2.0) {
      position_.x() -= shift.x();
    } else {
      position_.x() += resolution_ - shift.x();
    }
    if (size_.x() % 2 != mapCopy.getSize().x() % 2) {
      position_.x() += -std::copysign(resolution_ / 2.0, shift.x());
    }
    if (std::abs(shift.y()) < resolution_ / 2.0) {
      position_.y() -= shift.y();
    } else {
      position_.y() += resolution_ - shift.y();
    }
    if (size_.y() % 2 != mapCopy.getSize().y() % 2) {
      position_.y() += -std::copysign(resolution_ / 2.0, shift.y());
    }
    // Copy data.
    for (GridMapIterator iterator(*this); !iterator.isPastEnd(); ++iterator) {
      if (isValid(*iterator)) continue;
      Position position;
      getPosition(*iterator, position);
      Index index;
      if (!mapCopy.isInside(position)) continue;
      mapCopy.getIndex(position, index);
      for (const auto& layer : layers_) {
        at(layer, *iterator) = mapCopy.at(layer, index);
      }
    }
  }
  return true;
}

void GridMap::setTimestamp(const Time timestamp)
{
  timestamp_ = timestamp;
}

Time GridMap::getTimestamp() const
{
  return timestamp_;
}

void GridMap::resetTimestamp()
{
  timestamp_ = 0.0;
}

void GridMap::setFrameId(const std::string& frameId)
{
  frameId_ = frameId;
}

const std::string& GridMap::getFrameId() const
{
  return frameId_;
}

const Length& GridMap::getLength() const
{
  return length_;
}

const Position& GridMap::getPosition() const
{
  return position_;
}

double GridMap::getResolution() const
{
  return resolution_;
}

const Size& GridMap::getSize() const
{
  return size_;
}

void GridMap::setStartIndex(const Index& startIndex) {
  startIndex_ = startIndex;
}

const Index& GridMap::getStartIndex() const
{
  return startIndex_;
}

void GridMap::convertToDefaultStartIndex()
{
  if ((startIndex_ == 0).all()) return;

  std::vector<BufferRegion> bufferRegions;
  if (!getBufferRegionsForSubmap(bufferRegions, startIndex_, size_, size_, startIndex_)) {
    throw std::out_of_range("Cannot access submap of this size.");
  }

  for (auto& data : data_) {
    auto tempData(data.second);
    for (const auto& bufferRegion : bufferRegions) {
      Index index = bufferRegion.getStartIndex();
      Size size = bufferRegion.getSize();

      if (bufferRegion.getQuadrant() == BufferRegion::Quadrant::TopLeft) {
        tempData.topLeftCorner(size(0), size(1)) = data.second.block(index(0), index(1), size(0), size(1));
      } else if (bufferRegion.getQuadrant() == BufferRegion::Quadrant::TopRight) {
        tempData.topRightCorner(size(0), size(1)) = data.second.block(index(0), index(1), size(0), size(1));
      } else if (bufferRegion.getQuadrant() == BufferRegion::Quadrant::BottomLeft) {
        tempData.bottomLeftCorner(size(0), size(1)) = data.second.block(index(0), index(1), size(0), size(1));
      } else if (bufferRegion.getQuadrant() == BufferRegion::Quadrant::BottomRight) {
        tempData.bottomRightCorner(size(0), size(1)) = data.second.block(index(0), index(1), size(0), size(1));
      }
    }
    data.second = tempData;
  }

  startIndex_.setZero();
}

void GridMap::clear(const std::string& layer)
{
  try {
    data_.at(layer).setConstant(NAN);
  } catch (const std::out_of_range& exception) {
    throw std::out_of_range("GridMap::clear(...) : No map layer '" + layer + "' available.");
  }
}

void GridMap::clearBasic()
{
  for (auto& layer : basicLayers_) {
    clear(layer);
  }
}

void GridMap::clearAll()
{
  for (auto& data : data_) {
    data.second.setConstant(NAN);
  }
}

void GridMap::clearRows(unsigned int index, unsigned int nRows)
{
  std::vector<std::string> layersToClear;
  if (basicLayers_.size() > 0) layersToClear = basicLayers_;
  else layersToClear = layers_;
  for (auto& layer : layersToClear) {
    data_.at(layer).block(index, 0, nRows, getSize()(1)).setConstant(NAN);
  }
}

void GridMap::clearCols(unsigned int index, unsigned int nCols)
{
  std::vector<std::string> layersToClear;
  if (basicLayers_.size() > 0) layersToClear = basicLayers_;
  else layersToClear = layers_;
  for (auto& layer : layersToClear) {
    data_.at(layer).block(0, index, getSize()(0), nCols).setConstant(NAN);
  }
}

bool GridMap::atPositionLinearInterpolated(const std::string& layer, const Position& position,
                                           float& value) const
{
  Position point;
  Index indices[4];
  bool idxTempDir;
  size_t idxShift[4];

  getIndex(position, indices[0]);
  getPosition(indices[0], point);

  if (position.x() >= point.x()) {
    indices[1] = indices[0] + Index(-1, 0); // Second point is above first point.
    idxTempDir = true;
  } else {
    indices[1] = indices[0] + Index(+1, 0);
    idxTempDir = false;
  }
  if (position.y() >= point.y()) {
      indices[2] = indices[0] + Index(0, -1); // Third point is right of first point.
      if(idxTempDir){ idxShift[0]=0; idxShift[1]=1; idxShift[2]=2; idxShift[3]=3; }
      else          { idxShift[0]=1; idxShift[1]=0; idxShift[2]=3; idxShift[3]=2; }

  } else {
      indices[2] = indices[0] + Index(0, +1);
      if(idxTempDir){ idxShift[0]=2; idxShift[1]=3; idxShift[2]=0; idxShift[3]=1; }
      else          { idxShift[0]=3; idxShift[1]=2; idxShift[2]=1; idxShift[3]=0; }
  }
  indices[3].x() = indices[1].x();
  indices[3].y() = indices[2].y();

  const Size& mapSize = getSize();
  const size_t bufferSize = mapSize(0) * mapSize(1);
  const size_t startIndexLin = getLinearIndexFromIndex(startIndex_, mapSize);
  const size_t endIndexLin = startIndexLin + bufferSize;
  const auto& layerMat = operator[](layer);
  float         f[4];

  for (size_t i = 0; i < 4; ++i) {
    const size_t indexLin = getLinearIndexFromIndex(indices[idxShift[i]], mapSize);
    if ((indexLin < startIndexLin) || (indexLin > endIndexLin)) return false;
    f[i] = layerMat(indexLin);
  }

  getPosition(indices[idxShift[0]], point);
  const Position positionRed     = ( position - point ) / resolution_;
  const Position positionRedFlip = Position(1.,1.) - positionRed;

  value = f[0] * positionRedFlip.x() * positionRedFlip.y() +
          f[1] *     positionRed.x() * positionRedFlip.y() +
          f[2] * positionRedFlip.x() *     positionRed.y() +
          f[3] *     positionRed.x() *     positionRed.y();
  return true;
}

void GridMap::resize(const Index& size)
{
  size_ = size;
  for (auto& data : data_) {
    data.second.resize(size_(0), size_(1));
  }
}

} /* namespace */


text:
// @copyright 2017 - 2018 Shaun Ostoic
// Distributed under the MIT License.
// (See accompanying file LICENSE.md or copy at https://opensource.org/licenses/MIT)

#pragma once

#include <boost/winapi/basic_types.hpp>

#if !defined (BOOST_USE_WINDOWS_H)

BOOST_SYMBOL_IMPORT boost::winapi::BOOL_ WINAPI ReadProcessMemory(
	boost::winapi::HANDLE_ hProcess,
	boost::winapi::LPCVOID_ lpBaseAddress,
	boost::winapi::LPVOID_ lpBuffer,
	boost::winapi::SIZE_T_ nSize,
	boost::winapi::SIZE_T_ * lpNumberOfBytesRead);

BOOST_SYMBOL_IMPORT boost::winapi::BOOL_ WINAPI WriteProcessMemory(
	boost::winapi::HANDLE_ hProcess,
	boost::winapi::LPCVOID_ lpBaseAddress,
	boost::winapi::LPCVOID_ lpBuffer,
	boost::winapi::SIZE_T_ nSize,
	boost::winapi::SIZE_T_ * lpNumberOfBytesWritten);

#endif // !defined BOOST_USE_WINDOWS_H

namespace boost {
namespace winapi {

	using ::ReadProcessMemory;
	using ::WriteProcessMemory;

} // end namespace winapi
} // end namespace boost

ext: hpp

max_stars_repo_name: Ostoic/distant

max_issues_repo_name: Ostoic/distant

max_forks_repo_name: Ostoic/distant


text:
/*
	This file is part of solidity.

	solidity is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	solidity 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 solidity.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * Component that verifies overloads, abstract contracts, function clashes and others
 * checks at contract or function level.
 */

#include <libsolidity/analysis/ContractLevelChecker.h>

#include <libsolidity/ast/AST.h>
#include <libsolidity/ast/TypeProvider.h>
#include <libsolidity/analysis/TypeChecker.h>
#include <liblangutil/ErrorReporter.h>
#include <boost/range/adaptor/reversed.hpp>

using namespace std;
using namespace solidity;
using namespace solidity::langutil;
using namespace solidity::frontend;

namespace
{

template <class T, class B>
bool hasEqualNameAndParameters(T const& _a, B const& _b)
{
	return
		_a.name() == _b.name() &&
		FunctionType(_a).asExternallyCallableFunction(false)->hasEqualParameterTypes(
			*FunctionType(_b).asExternallyCallableFunction(false)
		);
}

}

bool ContractLevelChecker::check(ContractDefinition const& _contract)
{
	checkDuplicateFunctions(_contract);
	checkDuplicateEvents(_contract);
	m_overrideChecker.check(_contract);
	checkBaseConstructorArguments(_contract);
	checkAbstractDefinitions(_contract);
	checkExternalTypeClashes(_contract);
	checkHashCollisions(_contract);
	checkLibraryRequirements(_contract);
	checkBaseABICompatibility(_contract);
	checkPayableFallbackWithoutReceive(_contract);

	return Error::containsOnlyWarnings(m_errorReporter.errors());
}

void ContractLevelChecker::checkDuplicateFunctions(ContractDefinition const& _contract)
{
	/// Checks that two functions with the same name defined in this contract have different
	/// argument types and that there is at most one constructor.
	map<string, vector<FunctionDefinition const*>> functions;
	FunctionDefinition const* constructor = nullptr;
	FunctionDefinition const* fallback = nullptr;
	FunctionDefinition const* receive = nullptr;
	for (FunctionDefinition const* function: _contract.definedFunctions())
		if (function->isConstructor())
		{
			if (constructor)
				m_errorReporter.declarationError(
					7997_error,
					function->location(),
					SecondarySourceLocation().append("Another declaration is here:", constructor->location()),
					"More than one constructor defined."
				);
			constructor = function;
		}
		else if (function->isFallback())
		{
			if (fallback)
				m_errorReporter.declarationError(
					7301_error,
					function->location(),
					SecondarySourceLocation().append("Another declaration is here:", fallback->location()),
					"Only one fallback function is allowed."
				);
			fallback = function;
		}
		else if (function->isReceive())
		{
			if (receive)
				m_errorReporter.declarationError(
					4046_error,
					function->location(),
					SecondarySourceLocation().append("Another declaration is here:", receive->location()),
					"Only one receive function is allowed."
				);
			receive = function;
		}
		else
		{
			solAssert(!function->name().empty(), "");
			functions[function->name()].push_back(function);
		}

	findDuplicateDefinitions(functions);
}

void ContractLevelChecker::checkDuplicateEvents(ContractDefinition const& _contract)
{
	/// Checks that two events with the same name defined in this contract have different
	/// argument types
	map<string, vector<EventDefinition const*>> events;
	for (EventDefinition const* event: _contract.events())
		events[event->name()].push_back(event);

	findDuplicateDefinitions(events);
}

template <class T>
void ContractLevelChecker::findDuplicateDefinitions(map<string, vector<T>> const& _definitions)
{
	for (auto const& it: _definitions)
	{
		vector<T> const& overloads = it.second;
		set<size_t> reported;
		for (size_t i = 0; i < overloads.size() && !reported.count(i); ++i)
		{
			SecondarySourceLocation ssl;

			for (size_t j = i + 1; j < overloads.size(); ++j)
				if (hasEqualNameAndParameters(*overloads[i], *overloads[j]))
				{
					ssl.append("Other declaration is here:", overloads[j]->location());
					reported.insert(j);
				}

			if (ssl.infos.size() > 0)
			{
				ErrorId error;
				string message;
				if constexpr (is_same_v<T, FunctionDefinition const*>)
				{
					error = 1686_error;
					message = "Function with same name and arguments defined twice.";
				}
				else
				{
					static_assert(is_same_v<T, EventDefinition const*>, "Expected \"FunctionDefinition const*\" or \"EventDefinition const*\"");
					error = 5883_error;
					message = "Event with same name and arguments defined twice.";
				}

				ssl.limitSize(message);

				m_errorReporter.declarationError(
					error,
					overloads[i]->location(),
					ssl,
					message
				);
			}
		}
	}
}

void ContractLevelChecker::checkAbstractDefinitions(ContractDefinition const& _contract)
{
	// Collects functions, static variable getters and modifiers. If they
	// override (unimplemented) base class ones, they are replaced.
	set<OverrideProxy, OverrideProxy::CompareBySignature> proxies;

	auto registerProxy = [&proxies](OverrideProxy const& _overrideProxy)
	{
		// Overwrite an existing proxy, if it exists.
		if (!_overrideProxy.unimplemented())
			proxies.erase(_overrideProxy);

		proxies.insert(_overrideProxy);
	};

	// Search from base to derived, collect all functions and modifiers and
	// update proxies.
	for (ContractDefinition const* contract: boost::adaptors::reverse(_contract.annotation().linearizedBaseContracts))
	{
		for (VariableDeclaration const* v: contract->stateVariables())
			if (v->isPartOfExternalInterface())
				registerProxy(OverrideProxy(v));

		for (FunctionDefinition const* function: contract->definedFunctions())
			if (!function->isConstructor())
				registerProxy(OverrideProxy(function));

		for (ModifierDefinition const* modifier: contract->functionModifiers())
			registerProxy(OverrideProxy(modifier));
	}

	// Set to not fully implemented if at least one flag is false.
	// Note that `_contract.annotation().unimplementedDeclarations` has already been
	// pre-filled by `checkBaseConstructorArguments`.
	for (auto const& proxy: proxies)
		if (proxy.unimplemented())
			_contract.annotation().unimplementedDeclarations.push_back(proxy.declaration());

	if (_contract.abstract())
	{
		if (_contract.contractKind() == ContractKind::Interface)
			m_errorReporter.typeError(9348_error, _contract.location(), "Interfaces do not need the \"abstract\" keyword, they are abstract implicitly.");
		else if (_contract.contractKind() == ContractKind::Library)
			m_errorReporter.typeError(9571_error, _contract.location(), "Libraries cannot be abstract.");
		else
			solAssert(_contract.contractKind() == ContractKind::Contract, "");
	}

	// For libraries, we emit errors on function-level, so this is fine as long as we do
	// not have inheritance for libraries.
	if (
		_contract.contractKind() == ContractKind::Contract &&
		!_contract.abstract() &&
		!_contract.annotation().unimplementedDeclarations.empty()
	)
	{
		SecondarySourceLocation ssl;
		for (auto declaration: _contract.annotation().unimplementedDeclarations)
			ssl.append("Missing implementation: ", declaration->location());
		m_errorReporter.typeError(
			3656_error,
			_contract.location(),
			ssl,
			"Contract \"" + _contract.annotation().canonicalName + "\" should be marked as abstract."
		);
	}
}

void ContractLevelChecker::checkBaseConstructorArguments(ContractDefinition const& _contract)
{
	vector<ContractDefinition const*> const& bases = _contract.annotation().linearizedBaseContracts;

	// Determine the arguments that are used for the base constructors.
	for (ContractDefinition const* contract: bases)
	{
		if (FunctionDefinition const* constructor = contract->constructor())
			for (auto const& modifier: constructor->modifiers())
				if (auto baseContract = dynamic_cast<ContractDefinition const*>(
					modifier->name()->annotation().referencedDeclaration
				))
				{
					if (modifier->arguments())
					{
						if (baseContract->constructor())
							annotateBaseConstructorArguments(_contract, baseContract->constructor(), modifier.get());
					}
					else
						m_errorReporter.declarationError(
							1563_error,
							modifier->location(),
							"Modifier-style base constructor call without arguments."
						);
				}

		for (ASTPointer<InheritanceSpecifier> const& base: contract->baseContracts())
		{
			ContractDefinition const* baseContract = dynamic_cast<ContractDefinition const*>(
				base->name().annotation().referencedDeclaration
			);
			solAssert(baseContract, "");

			if (baseContract->constructor() && base->arguments() && !base->arguments()->empty())
				annotateBaseConstructorArguments(_contract, baseContract->constructor(), base.get());
		}
	}

	// check that we get arguments for all base constructors that need it.
	// If not mark the contract as abstract (not fully implemented)
	for (ContractDefinition const* contract: bases)
		if (FunctionDefinition const* constructor = contract->constructor())
			if (contract != &_contract && !constructor->parameters().empty())
				if (!_contract.annotation().baseConstructorArguments.count(constructor))
					_contract.annotation().unimplementedDeclarations.push_back(constructor);
}

void ContractLevelChecker::annotateBaseConstructorArguments(
	ContractDefinition const& _currentContract,
	FunctionDefinition const* _baseConstructor,
	ASTNode const* _argumentNode
)
{
	solAssert(_baseConstructor, "");
	solAssert(_argumentNode, "");

	auto insertionResult = _currentContract.annotation().baseConstructorArguments.insert(
		std::make_pair(_baseConstructor, _argumentNode)
	);
	if (!insertionResult.second)
	{
		ASTNode const* previousNode = insertionResult.first->second;

		SourceLocation const* mainLocation = nullptr;
		SecondarySourceLocation ssl;

		if (
			_currentContract.location().contains(previousNode->location()) ||
			_currentContract.location().contains(_argumentNode->location())
		)
		{
			mainLocation = &previousNode->location();
			ssl.append("Second constructor call is here:", _argumentNode->location());
		}
		else
		{
			mainLocation = &_currentContract.location();
			ssl.append("First constructor call is here:", _argumentNode->location());
			ssl.append("Second constructor call is here:", previousNode->location());
		}

		m_errorReporter.declarationError(
			3364_error,
			*mainLocation,
			ssl,
			"Base constructor arguments given twice."
		);
	}

}

void ContractLevelChecker::checkExternalTypeClashes(ContractDefinition const& _contract)
{
	map<string, vector<pair<Declaration const*, FunctionTypePointer>>> externalDeclarations;
	for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts)
	{
		for (FunctionDefinition const* f: contract->definedFunctions())
			if (f->isPartOfExternalInterface())
			{
				auto functionType = TypeProvider::function(*f);
				// under non error circumstances this should be true
				if (functionType->interfaceFunctionType())
					externalDeclarations[functionType->externalSignature()].emplace_back(
						f, functionType->asExternallyCallableFunction(false)
					);
			}
		for (VariableDeclaration const* v: contract->stateVariables())
			if (v->isPartOfExternalInterface())
			{
				auto functionType = TypeProvider::function(*v);
				// under non error circumstances this should be true
				if (functionType->interfaceFunctionType())
					externalDeclarations[functionType->externalSignature()].emplace_back(
						v, functionType->asExternallyCallableFunction(false)
					);
			}
	}
	for (auto const& it: externalDeclarations)
		for (size_t i = 0; i < it.second.size(); ++i)
			for (size_t j = i + 1; j < it.second.size(); ++j)
				if (!it.second[i].second->hasEqualParameterTypes(*it.second[j].second))
					m_errorReporter.typeError(
						9914_error,
						it.second[j].first->location(),
						"Function overload clash during conversion to external types for arguments."
					);
}

void ContractLevelChecker::checkHashCollisions(ContractDefinition const& _contract)
{
	set<util::FixedHash<4>> hashes;
	for (auto const& it: _contract.interfaceFunctionList())
	{
		util::FixedHash<4> const& hash = it.first;
		if (hashes.count(hash))
			m_errorReporter.typeError(
				1860_error,
				_contract.location(),
				string("Function signature hash collision for ") + it.second->externalSignature()
			);
		hashes.insert(hash);
	}
}

void ContractLevelChecker::checkLibraryRequirements(ContractDefinition const& _contract)
{
	if (!_contract.isLibrary())
		return;

	if (!_contract.baseContracts().empty())
		m_errorReporter.typeError(9469_error, _contract.location(), "Library is not allowed to inherit.");

	for (auto const& var: _contract.stateVariables())
		if (!var->isConstant())
			m_errorReporter.typeError(9957_error, var->location(), "Library cannot have non-constant state variables");
}

void ContractLevelChecker::checkBaseABICompatibility(ContractDefinition const& _contract)
{
	if (_contract.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2))
		return;

	if (_contract.isLibrary())
	{
		solAssert(
			_contract.baseContracts().empty() || m_errorReporter.hasErrors(),
			"Library is not allowed to inherit"
		);
		return;
	}

	SecondarySourceLocation errors;

	// interfaceFunctionList contains all inherited functions as well
	for (auto const& func: _contract.interfaceFunctionList())
	{
		solAssert(func.second->hasDeclaration(), "Function has no declaration?!");

		if (!func.second->declaration().sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2))
			continue;

		auto const& currentLoc = func.second->declaration().location();

		for (TypePointer const& paramType: func.second->parameterTypes() + func.second->parameterTypes())
			if (!TypeChecker::typeSupportedByOldABIEncoder(*paramType, false))
			{
				errors.append("Type only supported by ABIEncoderV2", currentLoc);
				break;
			}
	}

	if (!errors.infos.empty())
		m_errorReporter.fatalTypeError(
			6594_error,
			_contract.location(),
			errors,
			std::string("Contract \"") +
			_contract.name() +
			"\" does not use ABIEncoderV2 but wants to inherit from a contract " +
			"which uses types that require it. " +
			"Use \"pragma experimental ABIEncoderV2;\" for the inheriting contract as well to enable the feature."
		);

}

void ContractLevelChecker::checkPayableFallbackWithoutReceive(ContractDefinition const& _contract)
{
	if (auto const* fallback = _contract.fallbackFunction())
		if (fallback->isPayable() && !_contract.interfaceFunctionList().empty() && !_contract.receiveFunction())
			m_errorReporter.warning(
				3628_error,
				_contract.location(),
				"This contract has a payable fallback function, but no receive ether function. Consider adding a receive ether function.",
				SecondarySourceLocation{}.append("The payable fallback function is defined here.", fallback->location())
			);
}

ext: cpp


text:
#include <iostream>
#include "face_api.h"
#include <dlib/sqlite.h>

using namespace dlib;
using namespace std;

int main() {
    face_api face_app;
    string image_file("/home/pyp/face_app/face_platform/images/liuyifei_0.jpeg");
    face_app.set_input_source("");
    face_app.set_high_quality();
    face_app.set_face_model(DLIB_DNN);
    face_app.get_face_ids();

    face_app.set_database("face.db");

    //face_app.insert_face_to_database("YangMi",face_app.face_id_out[0]);
    face_app.match_face_in_database(face_app.face_id_out[0],0.4);

}


text:
/*
 * mosquitto_transport
 */

/*!
 * \file
 * \brief Helpers for spliting topic name to parts.
 * \since
 * v.0.3.0
 */

#pragma once

#include <mosquitto_transport/tools.hpp>

#include <boost/algorithm/string/split.hpp>

#include <functional>
#include <string>
#include <vector>

namespace mosquitto_transport {

namespace impl {

//
// splitted_topic_name_t
//
/*!
 * \brief A type of container with topic name splitted into parts.
 */
using splitted_topic_name_t = std::vector< std::string >;

//
// split_topic_name
//
/*!
 * \brief Helper function for deviding topic name into parts.
 *
 * \attention This implementation do not handle UTF-8!
 */
inline splitted_topic_name_t
split_topic_name( const std::string & topic_name )
	{
		ensure_with_explblock< ex_t >( topic_name.size() >= 1u,
			[]{ return "topic_name must be at least 1 symbol long"; } );

		splitted_topic_name_t result;
		boost::algorithm::split( result, topic_name,
				[]( std::string::value_type ch ) { return '/' == ch; } );

		return result;
	}

//
// fragments_extractor_t
//
/*!
 * \brief Helper class for getting parts of topic name one by one.
 *
 * Usage example:
 * \code
	const std::string & topic_name = ...;
	auto parsed_topic = impl::split_topic_name(topic_name);
	for(fragment_extractor_t fragments{ parsed_topic }; fragments.has_next();)
	{
		const std::string & f = fragments.next();
		...
	}
 * \endcode
 */
class fragments_extractor_t
	{
		//! Original parsed topic name.
		std::reference_wrapper< const splitted_topic_name_t > m_topic_name;
		//! The current position in topic name.
		splitted_topic_name_t::const_iterator m_it;

		fragments_extractor_t(
			const splitted_topic_name_t & topic_name,
			splitted_topic_name_t::const_iterator it )
			:	m_topic_name{ topic_name }
			,	m_it{ move(it) }
			{}

	public :
		fragments_extractor_t(
			//! Parsed topic name to be iterated.
			//! \attention This reference must remains valid for all
			//! lifetime of fragment_extractor_t instance.
			const splitted_topic_name_t & topic_name )
			:	m_topic_name{ topic_name }
			,	m_it{ begin(m_topic_name.get()) }
			{}

		operator bool() const { return m_it != m_topic_name.get().end(); }

		const splitted_topic_name_t::value_type &
		get() const { return *m_it; }

		const splitted_topic_name_t::value_type &
		operator*() const { return get(); }

		fragments_extractor_t
		next() const
			{
				auto next = m_it;
				return fragments_extractor_t{ m_topic_name.get(), ++next };
			}
	};

} /* namespace impl */

} /* namespace mosquitto_transport */


text:
/*
 * Copyright (c) 2020 Karim, karimdavoodi@gmail.com
 *
 * 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 <boost/log/trivial.hpp>
#include "gst.hpp"
#include <thread>
#include <mutex>
#include <gtk/gtk.h>
#include <webkit2/webkit2.h>

#define FPS 2
#define DELAY (1000/FPS)
#define WIDTH 1280
#define HEIGHT 720
#define FRAME_SIZE (WIDTH * HEIGHT * 4)
#define WAIT_MILISECOND(x) std::this_thread::sleep_for(std::chrono::milliseconds(x))

using namespace std;

GstClockTime timestamp = 0;
uint8_t* frame = nullptr;
cairo_surface_t* surface = nullptr;
std::mutex frame_mutex;

void init_display(int display_id);
void app_need_data (GstElement *appsrc, guint unused_size, gpointer user_data);
void get_snapshot(GObject *object, GAsyncResult *result, gpointer data);

/*
 *   The Gstreamer main function
 *   Streaming of Web site to udp:://out_multicast:port
 *
 *   @param web_url: URL of Web site
 *   @param out_multicast : multicast of output stream
 *   @param port: output multicast port numper
 *
 * */
void gst_convert_web_to_stream(string web_url, string out_multicast, int port)
{
    //web_url = "http://127.0.0.1/s/?mmk&u=1&p=1";
    LOG(info)
        << "Start " << web_url
        << " --> udp://" << out_multicast << ":" << port;

    Gst::Data d;
    d.loop      = g_main_loop_new(nullptr, false);
    d.pipeline  = GST_PIPELINE(gst_element_factory_make("pipeline", nullptr));
    frame = (uint8_t* ) malloc(FRAME_SIZE);

    try{
        auto appsrc       = Gst::add_element(d.pipeline, "appsrc"),
             queue_src    = Gst::add_element(d.pipeline, "queue", "queue_src"),
             videoconvert = Gst::add_element(d.pipeline, "videoconvert"),
             x264enc      = Gst::add_element(d.pipeline, "x264enc"),
             h264parse    = Gst::add_element(d.pipeline, "h264parse"),
             mpegtsmux    = Gst::add_element(d.pipeline, "mpegtsmux", "mpegtsmux"),
             rndbuffersize  = Gst::add_element(d.pipeline, "rndbuffersize","queue_sink"),
             udpsink      = Gst::add_element(d.pipeline, "udpsink");

        gst_element_link_many(
                appsrc,
                queue_src,
                videoconvert,
                x264enc,
                h264parse,
                mpegtsmux,
                rndbuffersize,
                udpsink,
                nullptr);

        g_object_set (G_OBJECT (appsrc), "caps",
                gst_caps_new_simple ("video/x-raw",
                    "format", G_TYPE_STRING, "RGBx",
                    "width", G_TYPE_INT, WIDTH,
                    "height", G_TYPE_INT, HEIGHT,
                    "framerate", GST_TYPE_FRACTION, FPS, 1,
                    NULL), NULL);
        g_object_set (G_OBJECT (appsrc),
                "stream-type", 0,
                "format", GST_FORMAT_TIME, NULL);

        g_object_set (rndbuffersize,
                "min", 1316,
                "max", 1316,
                nullptr);
        g_object_set (x264enc, "speed-preset", 1, nullptr);

        g_signal_connect (appsrc, "need-data", G_CALLBACK (app_need_data), &d);

        g_object_set(udpsink,
                "multicast_iface", "lo",
                "host", out_multicast.c_str() ,
                "port", port,
                "sync", true,
                nullptr);

        Gst::add_bus_watch(d);
        //Gst::dot_file(d.pipeline, "iptv_archive", 5);

        /////////////////////////////////////////// GTK
        GtkWidget *main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
        gtk_window_set_default_size(GTK_WINDOW(main_window), WIDTH, HEIGHT);

        WebKitWebView *webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
        gtk_container_add(GTK_CONTAINER(main_window), GTK_WIDGET(webView));

        webkit_web_view_load_uri(webView, web_url.c_str());
        bool running = true;
        std::thread snapshot_thread([&](){
                uint32_t n = 0;
                while(running){
                    WAIT_MILISECOND(DELAY);
                    if(++n % 10000 == 0){
                        LOG(debug) << "reload " << web_url;
                        webkit_web_view_reload(webView);
                    }
                    webkit_web_view_get_snapshot(webView,
                            WEBKIT_SNAPSHOT_REGION_VISIBLE,
                            WEBKIT_SNAPSHOT_OPTIONS_NONE,
                            nullptr,
                            get_snapshot,
                            webView);
                    }
                });

        gtk_widget_show_all(main_window);

        /////////////////////////////////////////// Start Pipline
        gst_element_set_state(GST_ELEMENT(d.pipeline), GST_STATE_PLAYING);
        g_main_loop_run(d.loop);
        running = false;
        free(frame);

    }catch(std::exception& e){
        LOG(error) << e.what();
    }
}
void init_display(int display_id)
{
    LOG(trace) << "Init display:" << display_id;
    string display = ":" + to_string(display_id);
    string cmd = "Xvfb " + display + " -screen scrn 1280x720x24   &";
    system(cmd.c_str());
    WAIT_MILISECOND(1000);

    const char* argv_a[] = {"prog", "--display", display.c_str(), nullptr};
    int argc = 3;
    char** argv = (char**) argv_a;
    gtk_init(&argc, &argv);

}
void app_need_data (GstElement *appsrc, guint /*unused_size*/, gpointer user_data)
{
    auto* d = (Gst::Data*) user_data;
    GstBuffer *buffer;
    GstFlowReturn ret;

    WAIT_MILISECOND(DELAY);
    buffer = gst_buffer_new_allocate (nullptr, FRAME_SIZE, nullptr);
    {
        std::unique_lock<std::mutex> lock(frame_mutex);
        gst_buffer_fill(buffer, 0, frame, FRAME_SIZE);
    }

    GST_BUFFER_PTS (buffer) = timestamp;
    GST_BUFFER_DURATION (buffer) = gst_util_uint64_scale_int (1, GST_SECOND, FPS);
    timestamp += GST_BUFFER_DURATION (buffer);
    LOG(trace) << "push buffer";
    g_signal_emit_by_name (appsrc, "push-buffer", buffer, &ret);
    gst_buffer_unref (buffer);
    if (ret != GST_FLOW_OK) {
        g_main_loop_quit (d->loop);
    }
}
void get_snapshot(GObject */*object*/, GAsyncResult *result, gpointer data)
{
    auto * webview = (WebKitWebView*)data;
    GError* error = nullptr;
	surface = webkit_web_view_get_snapshot_finish(webview, result, &error);

    LOG(trace) << "Got frame";
    std::unique_lock<std::mutex> lock(frame_mutex);
    auto* f = (uint8_t*) cairo_image_surface_get_data(surface);
    memcpy(frame, f, FRAME_SIZE);
    cairo_surface_destroy(surface);
}


text:
// Copyright (C) 2011-2012 The Trustees of Indiana University.

// Use, modification and distribution is subject to the Boost Software
// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)

//  Authors: Nicholas Edmonds
//           Thejaka Kanewala
//           Andrew Lumsdaine

#ifndef BOOST_GRAPH_PARALLEL_ITERATION_MACROS_HPP
#define BOOST_GRAPH_PARALLEL_ITERATION_MACROS_HPP

#include <utility>
#include <boost/graph/iteration_macros.hpp>

#define BGL_VSTART(linenum) BGL_CAT(bgl_vstart_,linenum)
#define BGL_VEND(linenum) BGL_CAT(bgl_vend_,linenum)
#define BGL_ESTART(linenum) BGL_CAT(bgl_estart_,linenum)
#define BGL_EEND(linenum) BGL_CAT(bgl_eend_,linenum)

#define BGL_PARFORALL_VERTICES(VNAME, GNAME, GraphType, TID, NTHREADS) \
for (boost::graph_traits<GraphType>::vertex_iterator \
     BGL_VSTART(__LINE__) \
       = (vertices(GNAME).first + (TID * (num_vertices(GNAME) + NTHREADS) / NTHREADS)), \
     BGL_VEND(__LINE__) \
       = (vertices(GNAME).first + std::min BOOST_PREVENT_MACRO_SUBSTITUTION \
           ((TID + 1) * (num_vertices(GNAME) + NTHREADS) / NTHREADS, num_vertices(GNAME))); \
  BGL_VSTART(__LINE__) != BGL_VEND(__LINE__); BGL_VSTART(__LINE__) = BGL_VEND(__LINE__)) \
  for (boost::graph_traits<GraphType>::vertex_descriptor VNAME; \
    BGL_VSTART(__LINE__) != BGL_VEND(__LINE__) ? (VNAME = *BGL_VSTART(__LINE__), true):false; \
     ++BGL_VSTART(__LINE__))

// This only works for RandomAccess Iterators
#define BGL_PARFORALL_VERTICES_T(VNAME, GNAME, GraphType, TID, NTHREADS) \
for (typename boost::graph_traits<GraphType>::vertex_iterator \
     BGL_VSTART(__LINE__) \
       = (vertices(GNAME).first + (TID * (num_vertices(GNAME) + NTHREADS) / NTHREADS)), \
     BGL_VEND(__LINE__) \
       = (std::min)(vertices(GNAME).first + ((TID + 1) * (num_vertices(GNAME) + NTHREADS) / NTHREADS), vertices(GNAME).second); \
  BGL_VSTART(__LINE__) != BGL_VEND(__LINE__); BGL_VSTART(__LINE__) = BGL_VEND(__LINE__)) \
  for (typename boost::graph_traits<GraphType>::vertex_descriptor VNAME; \
    BGL_VSTART(__LINE__) < BGL_VEND(__LINE__) ? (VNAME = *BGL_VSTART(__LINE__), true):false; \
     ++BGL_VSTART(__LINE__))

// This only works for RandomAccess Iterators
#define BGL_PARFORALL_EDGES_T(ENAME, GNAME, GraphType, TID, NTHREADS) \
for (typename boost::graph_traits<GraphType>::edge_iterator \
     BGL_ESTART(__LINE__) \
       = (edges(GNAME).first + (TID * (num_edges(GNAME) + NTHREADS) / NTHREADS)), \
     BGL_EEND(__LINE__) \
       = (std::min)(edges(GNAME).first + ((TID + 1) * (num_edges(GNAME) + NTHREADS) / NTHREADS), edges(GNAME).second); \
  BGL_ESTART(__LINE__) != BGL_EEND(__LINE__); BGL_ESTART(__LINE__) = BGL_EEND(__LINE__)) \
  for (typename boost::graph_traits<GraphType>::edge_descriptor ENAME; \
    BGL_ESTART(__LINE__) < BGL_EEND(__LINE__) ? (ENAME = *BGL_ESTART(__LINE__), true):false; \
     ++BGL_ESTART(__LINE__))

#endif // BOOST_GRAPH_PARALLEL_ITERATION_MACROS_HPP

max_stars_repo_name: thejkane/AGM

max_issues_repo_name: thejkane/AGM

max_forks_repo_name: thejkane/AGM


text:
//
// Copyright (c) 2009 by Rutger ter Borg
//
// Distributed under the Boost Software License, Version 1.0.
// (See accompanying file LICENSE_1_0.txt or copy at
// http://www.boost.org/LICENSE_1_0.txt)
//

#ifndef BOOST_NUMERIC_BINDINGS_DATA_SIDE_HPP
#define BOOST_NUMERIC_BINDINGS_DATA_SIDE_HPP

#include <boost/numeric/bindings/detail/property_map.hpp>

namespace boost {
namespace numeric {
namespace bindings {
namespace result_of {

template< typename T >
struct data_side {
    typedef typename detail::property_at< T, tag::data_side >::type type;
};

} // namespace result_of

template< typename T >
typename result_of::data_side<T>::type data_side( const T& ) {
    return result_of::data_side<T>::type();
}

} // namespace bindings
} // namespace numeric
} // namespace boost

#endif

max_stars_repo_name: ljktest/siconos

max_issues_repo_name: ljktest/siconos

max_forks_repo_name: ljktest/siconos


text:
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright Ion Gaztanaga 2006-2012. Distributed under the Boost
// Software License, Version 1.0. (See accompanying file
// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
// See http://www.boost.org/libs/interprocess for documentation.
//
//////////////////////////////////////////////////////////////////////////////

#include <boost/interprocess/detail/config_begin.hpp>
#include <boost/interprocess/offset_ptr.hpp>
#include <boost/interprocess/smart_ptr/unique_ptr.hpp>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/list.hpp>
#include <boost/interprocess/containers/set.hpp>
#include <boost/interprocess/containers/vector.hpp>
#include <boost/interprocess/smart_ptr/deleter.hpp>
#include <stdio.h>
#include <string>
#include "get_process_id_name.hpp"

using namespace boost::interprocess;

class MyClass
{
   public:
   MyClass()
   {}
};

typedef managed_unique_ptr<MyClass, managed_shared_memory>::type my_unique_ptr_class;
typedef set <my_unique_ptr_class
            ,std::less<my_unique_ptr_class>
            ,allocator  <my_unique_ptr_class
                        ,managed_shared_memory::segment_manager>
            > MySet;

typedef list<my_unique_ptr_class
            ,allocator  <my_unique_ptr_class
                        ,managed_shared_memory::segment_manager>
            > MyList;

typedef vector <my_unique_ptr_class
               ,allocator  <my_unique_ptr_class
                           ,managed_shared_memory::segment_manager>
            > MyVector;

int main()
{
   std::string process_name;
   test::get_process_id_name(process_name);

   //Create managed shared memory
   shared_memory_object::remove(process_name.c_str());
   {
      managed_shared_memory segment(create_only, process_name.c_str(), 10000);

      //Create unique_ptr using dynamic allocation
      my_unique_ptr_class my_ptr (segment.construct<MyClass>(anonymous_instance)()
                                 ,segment.get_deleter<MyClass>());
      my_unique_ptr_class my_ptr2(segment.construct<MyClass>(anonymous_instance)()
                                 ,segment.get_deleter<MyClass>());

      //Backup relative pointers to future tests
      offset_ptr<MyClass> ptr1 = my_ptr.get();
      offset_ptr<MyClass> ptr2 = my_ptr2.get();

      //Test some copy constructors
      my_unique_ptr_class my_ptr3(0, segment.get_deleter<MyClass>());
      my_unique_ptr_class my_ptr4(boost::move(my_ptr3));

      //Construct a list and fill
      MyList list(segment.get_segment_manager());

      //Insert from my_unique_ptr_class
      list.push_front(boost::move(my_ptr));
      list.push_back(boost::move(my_ptr2));

      //Check pointers
      assert(my_ptr.get() == 0);
      assert(my_ptr2.get() == 0);
      assert(list.begin()->get() == ptr1);
      assert(list.rbegin()->get() == ptr2);

      //Construct a set and fill
      typedef std::less<my_unique_ptr_class> set_less_t;
      MySet set(set_less_t(), segment.get_segment_manager());

      //Insert in set from list passing ownership
      set.insert(boost::move(*list.begin()));
      set.insert(boost::move(*list.rbegin()));

      //Check pointers
      assert(list.begin()->get() == 0);
      assert(list.rbegin()->get()== 0);

      //A set is ordered by std::less<my_unique_ptr_class> so
      //be careful when comparing pointers
      if(ptr1 < ptr2){
         assert(set.begin()->get()  == ptr1);
         assert(set.rbegin()->get() == ptr2);
      }
      else{
         assert(set.rbegin()->get() == ptr1);
         assert(set.begin()->get()  == ptr2);
      }

      //Now with vector
      MyVector vector(segment.get_segment_manager());

      //Insert from my_unique_ptr_class
      if(ptr1 < ptr2){
         vector.insert(vector.begin(), boost::move(*set.begin()));
         vector.insert(vector.end(),   boost::move(*set.rbegin()));
      }
      else{
         vector.insert(vector.begin(), boost::move(*set.rbegin()));
         vector.insert(vector.end(),   boost::move(*set.begin()));
      }

      //Check pointers
      assert(my_ptr.get() == 0);
      assert(my_ptr2.get() == 0);
      assert(vector.begin()->get() == ptr1);
      assert(vector.rbegin()->get() == ptr2);

      MyVector vector2(boost::move(vector));
      vector2.swap(vector);

      assert(vector.begin()->get() == ptr1);
      assert(vector.rbegin()->get() == ptr2);

      my_unique_ptr_class a(0, segment.get_deleter<MyClass>()), b(0, segment.get_deleter<MyClass>());
      a = boost::move(b);
   }
   shared_memory_object::remove(process_name.c_str());
   return 0;
}

#include <boost/interprocess/detail/config_end.hpp>


text:
// Copyright 2005-2008 Daniel James.
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

// Forwarding header for container_fwd.hpp's new location.
// This header is deprecated, I'll be adding a warning in a future release,
// then converting it to an error and finally removing this header completely.

#if !defined(BOOST_FUNCTIONAL_DETAIL_CONTAINER_FWD_HPP)
#define BOOST_FUNCTIONAL_DETAIL_CONTAINER_FWD_HPP

#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif

#include <boost/detail/container_fwd.hpp>

#endif

max_stars_repo_name: EricBoittier/vina-carb-docker

max_forks_repo_name: daniel-anavaino/tinkercell


text:
#include "moja/flint/operationmanagersimplecache.h"

#include "moja/flint/flintexceptions.h"
#include "moja/flint/operationproportionalsimplecache.h"
#include "moja/flint/operationresultcollection.h"
#include "moja/flint/operationresultsimplecache.h"
#include "moja/flint/operationstocksimplecache.h"
#include "moja/flint/poolsimplecache.h"

#include <moja/logging.h>

#include <boost/algorithm/string/classification.hpp>
#include <boost/algorithm/string/predicate.hpp>

namespace moja {
namespace flint {

#define OPERATION_MANAGER_CACHE_SIZE 10

OperationManagerSimpleCache::OperationManagerSimpleCache(Timing& timing, const DynamicObject& config)
    : _timing(timing) {
   _poolValues.reserve(100);
   _poolObjects.reserve(100);

   _operationResultsPending.reserve(50);
   _operationResultsLastApplied.reserve(50);
   _operationResultsCommitted.reserve(500);

   _useKahan = false;
   _allowZeroResultTransfers = false;

   if (config.find("use_kahan") != config.end()) {
      _useKahan = config["use_kahan"];
      if (_useKahan) _corrections.reserve(100);
   }
   if (config.find("allow_zero_result_transfers") != config.end()) {
      _allowZeroResultTransfers = config["allow_zero_result_transfers"];
   }

   _stockCache.reserve(OPERATION_MANAGER_CACHE_SIZE);
   for (int i = 0; i < OPERATION_MANAGER_CACHE_SIZE; i++) {
      _stockCache.push_back(
          std::make_shared<StockOperationSimpleCache>(this, _poolValues, _timing.fractionOfStep(), nullptr));
   }
   _stockCachePosition = _stockCache.begin();
   _proportionalCache.reserve(OPERATION_MANAGER_CACHE_SIZE);
   for (int i = 0; i < OPERATION_MANAGER_CACHE_SIZE; i++) {
      _proportionalCache.push_back(
          std::make_shared<ProportionalOperationSimpleCache>(this, _poolValues, _timing.fractionOfStep(), nullptr));
   }
   _proportionalCachePosition = _proportionalCache.begin();

   for (int i = 0; i < OPERATION_MANAGER_CACHE_SIZE; i++) {
      _operationResultCache.push_back(
          std::make_shared<OperationResultSimpleCache>(OperationTransferType::Proportional, nullptr));
   }
   _operationResultCachePosition = _operationResultCache.begin();
}

std::shared_ptr<IOperation> OperationManagerSimpleCache::createStockOperation(IModule& module) {
   if (_stockCachePosition == _stockCache.end()) _stockCachePosition = _stockCache.begin();

   auto obj = std::static_pointer_cast<StockOperationSimpleCache>(*_stockCachePosition);
   obj->set_metaData(&module.metaData());
   obj->_transfers.clear();
   ++_stockCachePosition;
   return obj;
}

std::shared_ptr<IOperation> OperationManagerSimpleCache::createStockOperation(IModule& module, DynamicVar& extra) {
   if (_stockCachePosition == _stockCache.end()) _stockCachePosition = _stockCache.begin();

   auto obj = std::static_pointer_cast<StockOperationSimpleCache>(*_stockCachePosition);
   // TODO: need to somehow set extraData here!
   obj->set_metaData(&module.metaData());
   obj->_transfers.clear();
   ++_stockCachePosition;
   return obj;
}

std::shared_ptr<IOperation> OperationManagerSimpleCache::createProportionalOperation(IModule& module) {
   if (_proportionalCachePosition == _proportionalCache.end()) _proportionalCachePosition = _proportionalCache.begin();

   auto obj = std::static_pointer_cast<ProportionalOperationSimpleCache>(*_proportionalCachePosition);
   obj->set_metaData(&module.metaData());
   obj->_transfers.clear();
   ++_proportionalCachePosition;
   return obj;
}

std::shared_ptr<IOperation> OperationManagerSimpleCache::createProportionalOperation(IModule& module,
                                                                                DynamicVar& dataPackage) {
   if (_proportionalCachePosition == _proportionalCache.end()) _proportionalCachePosition = _proportionalCache.begin();

   auto obj = std::static_pointer_cast<ProportionalOperationSimpleCache>(*_proportionalCachePosition);
   // TODO: need to somehow set extraData here!
   obj->set_metaData(&module.metaData());
   obj->_transfers.clear();
   ++_proportionalCachePosition;
   return obj;
}

void OperationManagerSimpleCache::applyOperations() {
   if (_useKahan) {  // used for https://en.wikipedia.org/wiki/Kahan_summation_algorithm
      double y;
      double t;

      for (auto& operationResult : _operationResultsPending) {
         // operationResult->setTimingWhenApplied(_timing);
         auto p = std::static_pointer_cast<OperationResultSimpleCache>(operationResult);
         for (auto& flux : p->_fluxes) {
            auto srcIx = flux.source();
            auto dstIx = flux.sink();
            if (srcIx == dstIx) {
               // don't process transfers to same pool
               continue;
            }
            auto val = flux.value();
            y = -val - _corrections[srcIx];  // Do source
            t = _poolValues[srcIx] + y;
            _corrections[srcIx] = (t - _poolValues[srcIx]) - y;
            _poolValues[srcIx] = t;
            y = val - _corrections[dstIx];  // Do sink
            t = _poolValues[dstIx] + y;
            _corrections[dstIx] = (t - _poolValues[dstIx]) - y;
            _poolValues[dstIx] = t;
         }
      }
   } else {
      for (auto& operationResult : _operationResultsPending) {
         auto p = std::static_pointer_cast<OperationResultSimpleCache>(operationResult);
         for (auto& flux : p->_fluxes) {
            auto srcIx = flux.source();
            auto dstIx = flux.sink();
            if (srcIx == dstIx) continue;  // don't process transfers to same pool
            auto val = flux.value();
            // MOJA_LOG_DEBUG << "SimpleCache applyOperations - pool src pre: " << std::setfill(' ') << std::setw(30) <<
            // std::setprecision(15) << _poolValues[srcIx] << ", pool dst pre: " << std::setfill(' ') << std::setw(30) <<
            // std::setprecision(15) << _poolValues[dstIx] << ", src: " << std::setfill(' ') << std::setw(3) << srcIx <<
            // ", snk: " << std::setfill(' ') << std::setw(3) << dstIx << ", value:" << val << ", ";
            _poolValues[srcIx] -= val;
            _poolValues[dstIx] += val;
            // MOJA_LOG_DEBUG << "SimpleCache applyOperations - pool src pst: " << std::setfill(' ') << std::setw(30) <<
            // std::setprecision(15) << _poolValues[srcIx] << ", pool dst pst: " << std::setfill(' ') << std::setw(30) <<
            // std::setprecision(15) << _poolValues[dstIx];
         }
      }
   }
   commitPendingOperationResults();
}

void OperationManagerSimpleCache::clearAllOperationResults() {
   _operationResultsPending.clear();
   _operationResultsLastApplied.clear();
   _operationResultsCommitted.clear();
}

void OperationManagerSimpleCache::clearLastAppliedOperationResults() { _operationResultsLastApplied.clear(); }

const OperationResultCollection& OperationManagerSimpleCache::operationResultsPending() const {
   return _operationResultsPending;
}

const OperationResultCollection& OperationManagerSimpleCache::operationResultsLastApplied() const {
   return _operationResultsLastApplied;
}

const OperationResultCollection& OperationManagerSimpleCache::operationResultsCommitted() const {
   return _operationResultsCommitted;
}

bool OperationManagerSimpleCache::hasOperationResultsLastApplied() const {
   return !_operationResultsLastApplied.empty();
}

PoolCollection OperationManagerSimpleCache::poolCollection() {
   return PoolCollection(_poolObjects);
   // return _poolObjects;
}

void OperationManagerSimpleCache::initialisePools() {
   if (_useKahan) std::fill(_corrections.begin(), _corrections.end(), 0.0);
   // std::fill(_poolValues.begin(), _poolValues.end(), 0.0);
   for (auto& pool : _poolObjects) {
      pool->init();
   }
}

const IPool* OperationManagerSimpleCache::addPool(const std::string& name, double initValue) {
   return addPool(name, "", "", 1.0, 0, initValue);
}

const IPool* OperationManagerSimpleCache::addPool(const std::string& name, const std::string& description,
                                                  const std::string& units, double scale, int order, double initValue) {
   if (name.length() == 0 || all(name, boost::algorithm::is_space())) {
      throw std::invalid_argument("name cannot be empty");
   }
   if (initValue < 0.0) {
      throw std::invalid_argument("initValue cannot be less than 0.0");  // TODO: check this is true?
   }
   _poolValues.push_back(0.0);
   auto pool = std::make_shared<PoolSimpleCache>(_poolValues, name, description, units, scale, order,
                                                 static_cast<int>(_poolValues.size() - 1), initValue);
   _poolObjects.push_back(pool);
   _poolNameObjectMap[name] = pool;

   if (_useKahan) {
      _corrections.resize(_poolValues.size());
      _corrections[_poolValues.size() - 1] = 0.0;
      std::fill(_corrections.begin(), _corrections.end(), 0.0);
   }
   return pool.get();
}

const IPool* OperationManagerSimpleCache::addPool(PoolMetaData& metadata, double initValue) {
   // TODO: finish this
   return nullptr;
}

const IPool* OperationManagerSimpleCache::getPool(const std::string& name) const {
   try {
      auto r = _poolNameObjectMap.at(name);
      return r.get();
   } catch (...) {
      throw PoolNotFoundException() << PoolName(name);
   }
}

const IPool* OperationManagerSimpleCache::getPool(int index) const {
   if (index >= _poolObjects.size() || index < 0) throw PoolNotFoundException() << PoolName("Bad index");
   auto& r = _poolObjects[index];
   return r.get();
}

std::string OperationManagerSimpleCache::config() const {
   std::stringstream ss;
   ss << "("
      << "Kahan[" << (_useKahan ? "ON" : "OFF") << "], "
      << "ZeroTransfers[" << (_allowZeroResultTransfers ? "ON" : "OFF") << "]"
      << ")";
   return ss.str();
}

void OperationManagerSimpleCache::commitPendingOperationResults() {
   std::copy(_operationResultsPending.begin(), _operationResultsPending.end(),
             std::back_inserter(_operationResultsLastApplied));
   std::move(_operationResultsPending.begin(), _operationResultsPending.end(),
             std::back_inserter(_operationResultsCommitted));
   _operationResultsPending.clear();
}

void OperationManagerSimpleCache::submitOperation(IOperation* operation) {
   auto result = operation->computeOperation(_timing);
   if (result != nullptr) _operationResultsPending.push_back(result);
}

}  // namespace flint
}  // namespace moja

max_stars_repo_name: moja-global/flint

max_issues_repo_name: moja-global/flint

max_forks_repo_name: moja-global/flint


text:
// Copyright (c) 2017 Graphcore Ltd. All rights reserved.

#ifndef popsolver_Model_hpp
#define popsolver_Model_hpp

#include <popsolver/Variable.hpp>

#include <boost/optional.hpp>

#include <cassert>
#include <cstdint>
#include <functional>
#include <iostream>
#include <memory>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>

namespace popsolver {

class Constraint;
class Scheduler;

struct ConstraintEvaluationSummary {
  using CountType = std::uint64_t;
  CountType call = 0;
  CountType product = 0;
  CountType sum = 0;
  CountType max = 0;
  CountType min = 0;
  CountType less = 0;
  CountType lessOrEqual = 0;

  CountType unknown = 0;

  CountType total() const {
    return call + product + sum + max + min + less + lessOrEqual + unknown;
  }

  void operator+=(const ConstraintEvaluationSummary &other) {
    call += other.call;
    product += other.product;
    sum += other.sum;
    max += other.max;
    min += other.min;
    less += other.less;
    lessOrEqual += other.lessOrEqual;
    unknown += other.unknown;
  }
};

// Extra breakdown information is collected when POPLIBS_LOG_LEVEL is set to
// TRACE or higher
std::ostream &operator<<(std::ostream &os,
                         const ConstraintEvaluationSummary &s);

class DataType {
public:
  using UnderlyingType = std::uint64_t;

private:
  UnderlyingType underlying = 0;

  template <typename T> constexpr bool representable(T x, T delta = 0) {
    assert(x >= 0);
    const auto partial = static_cast<UnderlyingType>(x);
    const auto xPrime = static_cast<T>(partial);
    return std::abs(x - xPrime) <= delta;
  }

public:
  DataType() = default;
  template <typename T> explicit constexpr DataType(T x) : underlying(x) {
    static_assert(std::is_unsigned<T>::value, "Must be unsigned type");
    static_assert(sizeof(T) <= sizeof(UnderlyingType),
                  "Size of type must be less or equal underlying type");
  }

  explicit constexpr DataType(double x) {
    assert(representable(x, 1.0) &&
           "can't represent double with popsolver::DataType");
    underlying = x;
  }
  explicit constexpr DataType(int64_t x) {
    assert(representable(x) &&
           "can't represent int64_t with popsolver::DataType");
    underlying = x;
  }
  explicit constexpr DataType(int x) {
    assert(representable(x) && "can't represent int with popsolver::DataType");
    underlying = x;
  }

  static constexpr DataType min() {
    return DataType{std::numeric_limits<UnderlyingType>::min()};
  }
  static constexpr DataType max() {
    return DataType{std::numeric_limits<UnderlyingType>::max()};
  }

  constexpr UnderlyingType operator*() const { return underlying; }
  explicit operator UnderlyingType() const { return underlying; }
  explicit operator UnderlyingType &() { return underlying; }

  template <typename T> T getAs() const {
    assert(static_cast<UnderlyingType>(static_cast<T>(underlying)) ==
               underlying &&
           "loss of precision for value in popsolver::DataType when converting "
           "to type");
    assert(underlying <= std::numeric_limits<T>::max() &&
           "value in popsolver::DataType is too large to fit in type");
    return static_cast<T>(underlying);
  }

  DataType &operator++() {
    underlying++;
    return *this;
  }
  DataType &operator--() {
    underlying--;
    return *this;
  }

  DataType operator++(int) {
    underlying++;
    return DataType{underlying - 1};
  }
  DataType operator--(int) {
    underlying--;
    return DataType{underlying + 1};
  }

  void operator+=(DataType r) { underlying += *r; }
  void operator*=(DataType r) { underlying *= *r; }

  friend std::istream &operator>>(std::istream &is, DataType &x);
};

inline DataType operator+(DataType l, DataType r) { return DataType{*l + *r}; }
inline DataType operator-(DataType l, DataType r) { return DataType{*l - *r}; }
inline DataType operator*(DataType l, DataType r) { return DataType{*l * *r}; }
inline DataType operator/(DataType l, DataType r) { return DataType{*l / *r}; }
inline DataType operator%(DataType l, DataType r) { return DataType{*l % *r}; }

inline bool operator<(DataType l, DataType r) { return *l < *r; }
inline bool operator>(DataType l, DataType r) { return *l > *r; }
inline bool operator<=(DataType l, DataType r) { return *l <= *r; }
inline bool operator>=(DataType l, DataType r) { return *l >= *r; }
inline bool operator!=(DataType l, DataType r) { return *l != *r; }
inline bool operator==(DataType l, DataType r) { return *l == *r; }

inline std::ostream &operator<<(std::ostream &os, DataType x) {
  os << *x;
  return os;
}
inline std::istream &operator>>(std::istream &is, DataType &x) {
  is >> x.underlying;
  return is;
}
} // namespace popsolver

namespace std {
template <> struct hash<popsolver::DataType> {
  std::size_t operator()(const popsolver::DataType &k) const {
    return std::hash<popsolver::DataType::UnderlyingType>()(*k);
  }
};
} // namespace std

namespace popsolver {

class Domain {
public:
  DataType min_;
  DataType max_;
  Domain(DataType min_, DataType max_) : min_(min_), max_(max_) {}
  DataType min() const { return min_; }
  DataType max() const { return max_; }
  DataType val() const {
    assert(min_ == max_);
    return min_;
  }
  DataType size() const { return max_ - min_ + DataType{1}; }
};

class Domains {
public:
  friend class Scheduler;
  std::vector<Domain> domains;
  using iterator = std::vector<Domain>::iterator;
  using const_iterator = std::vector<Domain>::const_iterator;
  Domain &operator[](Variable v) { return domains[v.id]; }
  const Domain &operator[](Variable v) const { return domains[v.id]; }
  iterator begin() { return domains.begin(); }
  iterator end() { return domains.end(); }
  const_iterator begin() const { return domains.begin(); }
  const_iterator end() const { return domains.end(); }
  std::size_t size() const { return domains.size(); }
  void push_back(const Domain &d) { domains.push_back(d); }
  template <typename... Args> void emplace_back(Args &&... args) {
    domains.emplace_back(std::forward<Args>(args)...);
  }
};

class Model;

class Solution {
  std::vector<DataType> values;
  ConstraintEvaluationSummary constraintEvalSummary;

public:
  Solution() = default;
  Solution(std::vector<DataType> values) : values(values) {}
  DataType &operator[](Variable v) { return values[v.id]; }
  DataType operator[](Variable v) const { return values[v.id]; }
  bool validSolution() const { return values.size() > 0; }
  ConstraintEvaluationSummary constraintsEvaluated() {
    return constraintEvalSummary;
  }

  friend class Model;
};

class Model {
  void addConstraint(std::unique_ptr<Constraint> c);
  std::pair<bool, ConstraintEvaluationSummary>
  minimize(Scheduler &scheduler, const std::vector<Variable> &objectives,
           bool &foundSolution, Solution &solution);
  Variable product(const Variable *begin, const Variable *end,
                   const std::string &debugName);
  std::string makeBinaryOpDebugName(const Variable *begin, const Variable *end,
                                    const std::string &opStr) const;
  std::string makeBinaryOpDebugName(const std::vector<Variable> &vars,
                                    const std::string &opStr) const;
  std::string makeParameterisedOpDebugName(const Variable *begin,
                                           const Variable *end,
                                           const std::string &opStr) const;
  std::string makeParameterisedOpDebugName(const std::vector<Variable> &vars,
                                           const std::string &opStr) const;
  std::string makeProductDebugName(const Variable *begin,
                                   const Variable *end) const;
  std::string makeProductDebugName(const std::vector<Variable> &v) const;
  std::string makeSumDebugName(const Variable *begin,
                               const Variable *end) const;
  std::string makeSumDebugName(const std::vector<Variable> &v) const;
  const std::string &getDebugName(Variable v) const;

public:
  Model();
  ~Model();
  std::vector<std::string> debugNames;
  std::unordered_map<DataType, Variable> constants;
  std::vector<DataType> priority;
  std::vector<std::unique_ptr<Constraint>> constraints;
  Domains initialDomains;

  /// Add a new variable.
  Variable addVariable(const std::string &debugName = "");
  /// Add a new variable with a domain of [min,max].
  Variable addVariable(DataType min, DataType max,
                       const std::string &debugName = "");
  Variable addVariable(DataType::UnderlyingType min,
                       DataType::UnderlyingType max,
                       const std::string &debugName = "");
  /// Add a constant with the specified value.
  Variable addConstant(DataType value, const std::string &debugName = "");
  Variable addConstant(DataType::UnderlyingType value,
                       const std::string &debugName = "");
  /// Add a constant with value 0 (for convenience).
  Variable zero();
  /// Add a constant with value 1 (for convenience).
  Variable one();
  /// Add a new variable that is the product of the specified variables.
  Variable product(const std::vector<Variable> &vars,
                   const std::string &debugName = "");
  /// Add a new variable that is the sum of the specified variables.
  Variable sum(std::vector<Variable> vars, const std::string &debugName = "");
  /// Add a new variable that is the max of the specified variables.
  Variable max(std::vector<Variable> vars, const std::string &debugName = "");
  /// Add a new variable that is the min of the specified variables.
  Variable min(std::vector<Variable> vars, const std::string &debugName = "");
  /// Add a new variable that is \p left divided by \p right, rounded down to
  /// the nearest integer.
  Variable floordiv(Variable left, Variable right,
                    const std::string &debugName = "");
  /// Add a new variable that is \p left divided by \p right, rounded up to the
  /// nearest integer.
  Variable ceildiv(Variable left, Variable right,
                   const std::string &debugName = "");
  // Return m.ceildiv(dividend, divisor) and constrain the divisor so it is
  // the smallest divisor that gives us that result.
  Variable ceildivConstrainDivisor(const Variable dividend,
                                   const Variable divisor,
                                   const std::string &debugName = "");
  /// Add a new variable that is \p left mod \p right.
  Variable mod(Variable left, Variable right,
               const std::string &debugName = "");
  /// Add a new variable that is \p right subtracted from \p left.
  Variable sub(Variable left, Variable right,
               const std::string &debugName = "");
  /// Constrain the left variable to be less than the right variable.
  void less(Variable left, Variable right);
  /// Constrain the left variable to be less than the right constant.
  void less(Variable left, DataType right);
  /// Constrain the left constant to be less than the right variable.
  void less(DataType left, Variable right);
  /// Constrain the left variable to be less than or equal to the right
  /// variable.
  void lessOrEqual(Variable left, Variable right);
  /// Constrain the left variable to be less than or equal to the right
  /// constant.
  void lessOrEqual(Variable left, DataType right);
  /// Constrain the left constant to be less than or equal to the right
  /// variable.
  void lessOrEqual(DataType left, Variable right);
  /// Constrain the left variable to be equal to the right variable.
  void equal(Variable left, Variable right);
  /// Constrain the left variable to be equal to the right constant.
  void equal(Variable left, DataType right);
  /// Constrain the left constant to be equal to the right variable.
  void equal(DataType left, Variable right);
  /// Constrain the right variable to be a factor of the left constant.
  void factorOf(DataType left, Variable right);
  /// Constrain the right variable to be a factor of the left variable.
  void factorOf(Variable left, Variable right);
  /// Add a new variable that is the result of applying the specified function
  /// to the specified variables. Input variable domains are restricted to be
  /// at most the range of T.
  /// Supported specialisations are DataType, unsigned.
  template <typename T>
  Variable
  call(std::vector<Variable> vars,
       std::function<boost::optional<DataType>(const std::vector<T> &values)> f,
       const std::string &debugName = "");

  /// Find a solution that minimizes the value of the specified variables.
  /// Lexicographical comparison is used to compare the values of the variables.
  /// \returns The solution
  Solution minimize(const std::vector<Variable> &v);
  /// Find a solution that minimizes the specified variable.
  /// \returns The solution
  Solution minimize(Variable v) { return minimize(std::vector<Variable>({v})); }
};

} // End namespace popsolver.

#endif // popsolver_Model_hpp