text:
/*
 * TrainPathMover.cpp
 *
 *  Created on: Feb 17, 2016
 *      Author: zhang huai peng
 */

#include <algorithm>
#include <limits>
#include <stdexcept>
#include "util/GeomHelpers.hpp"
#include "entities/roles/driver/TrainDriverFacets.hpp"
#include <entities/roles/driver/TrainPathMover.hpp>
#include <boost/algorithm/string/erase.hpp>
#include <boost/algorithm/string.hpp>
#include "TrainDriver.hpp"
#include "entities/TrainController.hpp"
namespace
{
    const double distanceMinimal = 0.001;
}
namespace sim_mob
{
TrainPlatformMover::TrainPlatformMover()
{

}

TrainPlatformMover::~TrainPlatformMover()
{

}

void TrainPlatformMover::setPlatforms(const std::vector<Platform*>& plats)
{
    platforms = plats;
    currPlatformIt = platforms.begin();
}
const std::vector<Platform*>& TrainPlatformMover::getPrevPlatforms() const
{
    return prevPlatforms;
}

const std::vector<Platform*>& TrainPlatformMover::getPlatforms() const
{
    return platforms;
}

Platform* TrainPlatformMover::getFirstPlatform() const
{
    if(platforms.size()>0)
    {
        return platforms.front();
    }
    else
    {
        return nullptr;
    }
}

void TrainPlatformMover::clearPrevPlatforms()
{
    prevPlatforms.clear();
}

void TrainPlatformMover::resetPlatformItr()
{
    //resets the iterator to beginning position
    currPlatformIt = platforms.begin();
}
Platform* TrainPlatformMover::getNextPlatform(bool updated)
{
    //return the next platform on the route.
    //If updated value passed is true then the iterator is moved forward
    if(updated)
    {
        prevPlatforms.push_back(*currPlatformIt);
        currPlatformIt++;
    }
    if(currPlatformIt!=platforms.end())
    {
        return (*currPlatformIt);
    }
    else
    {
        return nullptr;
    }
}
Platform* TrainPlatformMover::getPlatformByOffset(int offset) const
{
    //This function returns the platform by offset .The offset can also be negative in which case it will
    //return the platform behind it
    if(offset < 0)
    {
        std::vector<Platform*>::iterator prev = currPlatformIt;
        int offsetneg = -offset;
        while(offsetneg > 0)
        {
            prev--;
            offsetneg--;
        }
        if(prev != platforms.end())
        {
            return (*prev);
        }
        return nullptr;
    }
    std::vector<Platform*>::iterator next = std::next(currPlatformIt, offset);
    if(next != platforms.end())
    {
        return (*next);
    }
    else
    {
        return nullptr;
    }
}

void TrainPlatformMover::setPlatformIteratorToEnd()
{
    //setting the iterator to the end of the list
    while(currPlatformIt != platforms.end())
    {
        prevPlatforms.push_back(*currPlatformIt);
        currPlatformIt++;
    }
}

Platform *TrainPlatformMover::getLastPlatformOnRoute() const
{
    return *(platforms.end() - 1);
}
bool TrainPlatformMover::isLastPlatform()
{
    if((currPlatformIt+1) == platforms.end())
    {
        return true;
    }
    else
    {
        return false;
    }
}
TrainPathMover::TrainPathMover():distanceMoveToNextPoint(0),currPolyLine(nullptr),distMovedOnCurrBlock(0),distMovedOnEntirePath(0)
{

}

TrainPathMover::~TrainPathMover()
{

}

void TrainPathMover::setParentMovementFacet(MovementFacet * movementFacet)
{
    parentMovementFacet = movementFacet;
}

double TrainPathMover::calcDistanceBetweenTwoPoints() const
{
    DynamicVector vector(*currPolyPointIt, *nextPolyPointIt);
    return vector.getMagnitude();
}

double TrainPathMover::calcDistanceBetweenCurrentAndSubsequentPoint(Point a,Point b) const
{
    DynamicVector vector(a, b);
    return vector.getMagnitude();
}

PolyPoint TrainPathMover::GetStopPoint(double distance) const
{
    //this function gets the stop point at a particular distance from the current position of the train
    std::vector<Block*>::const_iterator curr = drivingPath.begin();
    double dis=0;
    while(curr != drivingPath.end())
    {
        const PolyLine *polyLine = (*curr)->getPolyLine();
        const std::vector<PolyPoint> pointvector = polyLine->getPoints();
        std::vector<PolyPoint>::const_iterator itr = pointvector.begin();

        while(itr != pointvector.end())
        {
            std::vector<PolyPoint>::const_iterator nextPolyPoint = itr + 1;
            if( nextPolyPoint == pointvector.end() )
            {
                //move on to next block
                if((curr+1) == drivingPath.end())
                {
                    break;
                }
                const PolyLine* nextPolyLine = (*(curr+1))->getPolyLine();
                nextPolyPoint = nextPolyLine->getPoints().begin();
                dis = dis + calcDistanceBetweenCurrentAndSubsequentPoint(*itr,(*nextPolyPoint));
            }

            else
            {
                // calculate the distance between current and subsequent stop point
                dis = dis + calcDistanceBetweenCurrentAndSubsequentPoint(*itr,(*nextPolyPoint));
            }
            if(dis > distance)
            {
                //if the distance ends up between two points then take the before point as the stop point
                return *itr;
            }
            else if(dis == distance)
            {
                return *nextPolyPoint;
            }
            itr++;
        }
        curr++;
    }
}
double TrainPathMover::calcDistanceBetweenTwoPoints(std::vector<PolyPoint>::const_iterator& currPointItr,std::vector<PolyPoint>::const_iterator& laterPoint,const std::vector<PolyPoint> &points) const
{
    std::vector<Block*>::const_iterator curr = drivingPath.begin();
    double dis=0;
    bool startPointfound = false;
    bool foundLaterPoint = false;
    if(currPointItr == points.end() || laterPoint == points.end())
    {
        return dis;
    }
    while(curr != drivingPath.end())
    {
        const PolyLine *polyLine = (*curr)->getPolyLine();
        const std::vector<PolyPoint> pointvector = polyLine->getPoints();
        std::vector<PolyPoint>::const_iterator itr = pointvector.begin();
        while(itr != pointvector.end())
        {
            if((*currPointItr).getX() == (*itr).getX()&&(*currPointItr).getY() == (*itr).getY()&&(*currPointItr).getZ() == (*itr).getZ())
            {
                //if all x ,y ,z coordinates of the point are compared and equal then that is the start point
                startPointfound = true;
            }

            if((*laterPoint).getX() == (*itr).getX()&&(*laterPoint).getY() == (*itr).getY()&&(*laterPoint).getZ()==(*itr).getZ())
            {
                //same for the later point
                foundLaterPoint = true;
                break;
            }
            if(startPointfound == true)
            {
                std::vector<PolyPoint>::const_iterator nextPointItr = itr + 1;
                if(nextPointItr == pointvector.end())
                {
                    //if the end of current block and move on to next block
                    if((curr+1) == drivingPath.end())
                    {
                        break;
                    }
                    const PolyLine* nextPolyLine = (*(curr+1))->getPolyLine();
                    //pick up the first point from next block
                    std::vector<PolyPoint>::const_iterator nextPolyPointItr = nextPolyLine->getPoints().begin();
                    //calculating the distance between current and subsequent point
                    dis = dis + calcDistanceBetweenCurrentAndSubsequentPoint(*itr,(*nextPolyPointItr));
                }
                else
                {
                    dis = dis+calcDistanceBetweenCurrentAndSubsequentPoint(*itr,*nextPointItr);
                }
            }
            itr++;
        }
        if(foundLaterPoint == true)
        {
            break;
        }
        curr++;
    }
    if(foundLaterPoint == false)
    {
        return 0;
    }

    return dis;
}

std::vector<PolyPoint>::const_iterator TrainPathMover::GetCurrentStopPoint() const
{
    return currPolyPointIt;
}

int TrainPathMover::getCurrentBlockId() const
{
    return (*currBlockIt)->getBlockId();
}

MovementFacet *TrainPathMover::GetParentMovementFacet() const
{
    return parentMovementFacet;
}
double TrainPathMover::advance(double distance)
{
    if(drivingPath.empty())
    {
        throw std::runtime_error("path is empty in the train");
    }
    if(isCompletePath())
    {
        throw std::runtime_error("path already completed in the train");
    }

    //Also add the previous saved distance to next point ,when its between 2 points and then calculate the distance required to move
    //so the total distance to move will be the ()distance required + the prev saved distance to next point ) from the current point
    //as if the train is between 2 points then the before point is taken as current point
    distanceMoveToNextPoint += distance;
    moverMutex.lock();
    double temp = distMovedOnEntirePath;
    distMovedOnEntirePath = (temp+distance);
    moverMutex.unlock();

    double distBetwCurrAndNxtPt = calcDistanceBetweenTwoPoints();
    //Check if we've crossed the next point, if so advance to the next point
    while(distanceMoveToNextPoint >= distBetwCurrAndNxtPt)
    {
        distanceMoveToNextPoint -= distBetwCurrAndNxtPt;
        if(!advanceToNextPoint())
        {
            break;
        }
        //calculates the distance between two points next to each other on straight line
        distBetwCurrAndNxtPt = calcDistanceBetweenTwoPoints();
    }

    return distanceMoveToNextPoint;
}
double TrainPathMover::getDistanceToNextPlatform(Platform* platform) const
{
    bool res = false;
    double distance = 0.0;
    if(platform == nullptr)
    {
        return -1;
    }
    if (currBlockIt != drivingPath.end())
    {
        if ((*currBlockIt)->getAttachedPlatform() == platform)
        {
            distance = platform->getOffset() + platform->getLength()
                    - getDistCoveredOnCurrBlock();
            res = true;
        }
        else
        {
            distance = (*currBlockIt)->getLength()
                    - getDistCoveredOnCurrBlock();
            std::vector<Block*>::const_iterator tempIt = currBlockIt + 1;

            while (tempIt != drivingPath.end())
            {
                if ((*tempIt)->getAttachedPlatform() != platform)
                {
                    distance += (*tempIt)->getLength();
                    tempIt++;
                }
                else
                {
                    distance += platform->getOffset() + platform->getLength();
                    res = true;
                    break;
                }
            }
        }
    }
    if(!res || distance < distanceMinimal)
    {
        distance = 0.0;
    }
    return distance;
}
double TrainPathMover::getDistanceToNextTrain(const TrainPathMover& other) const
{
    double distance = 0.0;
    std::vector<Block*>::const_iterator tempIt = currBlockIt;
    std::vector<Block*>::const_iterator tempOtherIt = other.currBlockIt;
    if ((*tempIt) == (*tempOtherIt))
    {
        distance = other.getDistCoveredOnCurrBlock()-getDistCoveredOnCurrBlock();
    }
    else if(tempOtherIt == other.drivingPath.end())
    {
        distance = 0.0;
    }
    else
    {
        distance = (*tempIt)->getLength() - getDistCoveredOnCurrBlock();
        tempIt++;
        while (tempIt!=drivingPath.end()&&(*tempIt) != (*tempOtherIt))
        {
            distance += (*tempIt)->getLength();
            tempIt++;
        }
        distance += other.getDistCoveredOnCurrBlock();
    }
    return distance;
}
double TrainPathMover::getDifferentDistance(const TrainPathMover& other) const
{
    double otherCoveredDis = other.getTotalCoveredDistance();
    moverMutex.lock();
    double res = otherCoveredDis-distMovedOnEntirePath;
    moverMutex.unlock();
    return res;
}
double TrainPathMover::getCurrentSpeedLimit()
{
    double speedLimit = 0.0;
    if(drivingPath.size() != 0&&currBlockIt != drivingPath.end())
    {
        speedLimit = (*currBlockIt)->getSpeedLimit();
    }
    return speedLimit;
}
double TrainPathMover::getCurrentDecelerationRate()
{
    double decelerate = 0.0;
    if(drivingPath.size() !=0 && currBlockIt != drivingPath.end()){
        decelerate = (*currBlockIt)->getDecelerateRate();
    }
    return decelerate;
}
double TrainPathMover::getCurrentAccelerationRate()
{
    double accelerate = 0.0;
    if(drivingPath.size() !=0 && currBlockIt != drivingPath.end())
    {
        accelerate = (*currBlockIt)->getAccelerateRate();
    }
    return accelerate;
}
Point TrainPathMover::getCurrentPosition() const
{
    if(isDrivingPath())
    {
        if(!isCompletePath())
        {
            DynamicVector movementVector(*currPolyPointIt, *nextPolyPointIt);
            movementVector.scaleVectTo(distanceMoveToNextPoint).translateVect();
            return Point(movementVector.getX(), movementVector.getY());
        }
        else
        {
            return *currPolyPointIt;
        }
    }
    else
    {
        throw std::runtime_error("no path is set in train");
    }
}
double TrainPathMover::getDistCoveredOnCurrBlock() const
{
    return distanceMoveToNextPoint+distMovedOnCurrBlock;
}

double TrainPathMover::getDistanceMoveToNextPoint()
{
    return distanceMoveToNextPoint;
}

std::vector<PolyPoint>::const_iterator TrainPathMover::findNearestStopPoint(const std::vector<PolyPoint>& pointVector) const
{

    std::vector<PolyPoint>::const_iterator currPointItr = currPolyPointIt;
    std::vector<PolyPoint>::const_iterator itr = pointVector.begin();
    std::vector<PolyPoint>::const_iterator nearestPoint = pointVector.end();
    double minDis=-1;
    for(;itr != pointVector.end();itr++)
    {
        double dis = calcDistanceBetweenTwoPoints(currPointItr,itr,pointVector);

        if((minDis == -1 || dis < minDis) && dis != 0 )
        {
            nearestPoint=itr;
            minDis=dis;
        }
    }
    return nearestPoint;
}

bool TrainPathMover::advanceToNextPoint()
{
    bool ret = false;
    if(nextPolyPointIt != currPolyLine->getPoints().end())
    {
        distMovedOnCurrBlock += calcDistanceBetweenTwoPoints();
        ++currPolyPointIt;
        ++nextPolyPointIt;
        ret = true;
        if(nextPolyPointIt == currPolyLine->getPoints().end())
        {
            ret = advanceToNextBlock();
        }
    }
    else
    {
        ret = advanceToNextBlock();
    }

    return ret;
}

void TrainPathMover::teleportToOppositeLine(std::string station,std::string lineId,Platform *platform)
{
    std::vector<Block*>::const_iterator tempIt = currBlockIt;
    double distance = 0;
    double distanceToBlock;
    while (tempIt != drivingPath.end())
    {
        if ((*tempIt)->getAttachedPlatform() != platform)
        {
            distance += (*tempIt)->getLength();
            tempIt++;
            currBlockIt++;
        }
        else
        {
            distanceToBlock = distance;
            distance += platform->getOffset() + platform->getLength();
            break;
        }

    }

    distMovedOnEntirePath = distance;
    distanceMoveToNextPoint = distance-distanceToBlock;
    currPolyLine = (*currBlockIt)->getPolyLine();
    currPolyPointIt = currPolyLine->getPoints().begin();
    nextPolyPointIt = currPolyPointIt + 1;
    double distBetwCurrAndNxtPt=calcDistanceBetweenTwoPoints();
    while(distanceMoveToNextPoint >= distBetwCurrAndNxtPt)
    {
        distanceMoveToNextPoint -= distBetwCurrAndNxtPt;
        if( !advanceToNextPoint() )
        {
            break;
        }
        distBetwCurrAndNxtPt = calcDistanceBetweenTwoPoints();
    }
}

double TrainPathMover::getDistanceFromStartToPlatform(std::string lineId,Platform *platform) const
{
    std::vector<Block*> route;
    TrainController<sim_mob::medium::Person_MT>::getInstance()->getTrainRoute(lineId,route);
    std::vector<Block*>::const_iterator tempIt = route.begin();
    double distance=0;
    double distanceToBlock;
    while (tempIt != route.end())
    {
        if ((*tempIt)->getAttachedPlatform() != platform)
        {
            distance += (*tempIt)->getLength();
            tempIt++;
        }
        else
        {
          if((*route.begin())->getAttachedPlatform() == (*(route.end()-1))->getAttachedPlatform() && (tempIt == route.begin()|| tempIt == route.end()-1)) //Loop route
			{
				if(getTotalCoveredDistance() <=  platform->getOffset() + platform->getLength() || tempIt == route.end()-1)
				{
					distance += platform->getOffset() + platform->getLength();
					break;
				}
				else
				{
					distance += (*tempIt)->getLength();
					tempIt++;
					continue;

				}
			}

		else
	 	{
	    	distance += platform->getOffset() + platform->getLength();
            	break;
        	}
	}
    }
 return distance;
}

bool TrainPathMover::advanceToNextBlock()
{
    bool ret = false;
    currBlockIt++;
    distMovedOnCurrBlock = 0;
    if(currBlockIt != drivingPath.end())
    {
        currPolyLine = (*currBlockIt)->getPolyLine();
        currPolyPointIt = currPolyLine->getPoints().begin();
        nextPolyPointIt = currPolyPointIt + 1;
        ret = true;
    }
    else
    {
        return false;
    }

    return ret;
}
double TrainPathMover::getTotalCoveredDistance() const
{
    moverMutex.lock();
    double res = distMovedOnEntirePath;
    moverMutex.unlock();
    return res;
}

bool TrainPathMover::isCompletePath() const
{
    return (currBlockIt == drivingPath.end());
}
bool TrainPathMover::isDrivingPath() const
{
    return !drivingPath.empty();
}

void TrainPathMover::setPath(const std::vector<Block*> &path)
{
    drivingPath.clear();
    if(!path.empty())
    {
        drivingPath = path;
        currBlockIt = drivingPath.begin();
        currPolyLine = (*currBlockIt)->getPolyLine();
        currPolyPointIt = currPolyLine->getPoints().begin();
        nextPolyPointIt = currPolyPointIt + 1;
        distanceMoveToNextPoint = 0;
        distMovedOnCurrBlock = 0;
        distMovedOnEntirePath = 0;
    }
}

void TrainPathMover::teleportToPlatform(std::string platformName)
{
    //teleports the train to a particular platform ahead of it from the start of the route
    //used in case of train U-turn
    std::vector<Block*>::const_iterator tempIt = currBlockIt;
    double distance = 0;
    double distanceToBlock;
    while (tempIt != drivingPath.end())
    {
        Platform *platform = (*tempIt)->getAttachedPlatform();
        if( !boost::iequals(platform->getPlatformNo(), platformName) )
        {
            //jump to next block and add the length of the block to distance travelled
            distance += (*tempIt)->getLength();
            tempIt++;
            currBlockIt++;
        }

        else
        {
            //if it the block of the platform then ,add the platform offset distance in the block and the length of the platform to distance travelled
            distanceToBlock = distance;
            distance += platform->getOffset() + platform->getLength();
            break;
        }

    }

    distMovedOnEntirePath = distance;
    distanceMoveToNextPoint = distance - distanceToBlock;
    currPolyLine = (*currBlockIt)->getPolyLine();
    currPolyPointIt = currPolyLine->getPoints().begin();
    nextPolyPointIt = currPolyPointIt + 1;
    double distBetwCurrAndNxtPt = calcDistanceBetweenTwoPoints();
    while(distanceMoveToNextPoint >= distBetwCurrAndNxtPt)
    {
        //keep iterating the points in current block till  the respective distance to the platform is reached
        //after crossing every point reduce the remaining distance
        //if the distance to subsequent point is less than the distance remaining keep iterating
        distanceMoveToNextPoint -= distBetwCurrAndNxtPt;
        if(!advanceToNextPoint())
        {
            //when distance to next point is more than distance remaining.That tell its between the two points
            //so the first one is taken as the relevant point.
            //and the remaining distance is saved for future use
            break;
        }
        distBetwCurrAndNxtPt = calcDistanceBetweenTwoPoints();
    }
}
} /* namespace sim_mob */


text:
// Boost.Geometry Index
//
// n-dimensional bounds
//
// Copyright (c) 2011-2014 Adam Wulkiewicz, Lodz, Poland.
//
// This file was modified by Oracle on 2019-2021.
// Modifications copyright (c) 2019-2021 Oracle and/or its affiliates.
// Contributed and/or modified by Adam Wulkiewicz, on behalf of Oracle
//
// 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)

#ifndef BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_BOUNDS_HPP
#define BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_BOUNDS_HPP

#include <boost/geometry/algorithms/convert.hpp>
#include <boost/geometry/algorithms/detail/covered_by/interface.hpp>
#include <boost/geometry/algorithms/detail/envelope/interface.hpp>
#include <boost/geometry/algorithms/detail/expand/interface.hpp>

#include <boost/geometry/index/detail/bounded_view.hpp>

namespace boost { namespace geometry { namespace index { namespace detail
{

namespace dispatch
{

template <typename Geometry,
          typename Bounds,
          typename TagGeometry = typename geometry::tag<Geometry>::type,
          typename TagBounds = typename geometry::tag<Bounds>::type>
struct bounds
{
    template <typename Strategy>
    static inline void apply(Geometry const& g, Bounds & b, Strategy const& )
    {
        geometry::convert(g, b);
    }
};

template <typename Geometry, typename Bounds>
struct bounds<Geometry, Bounds, segment_tag, box_tag>
{
    template <typename Strategy>
    static inline void apply(Geometry const& g, Bounds & b, Strategy const& s)
    {
        index::detail::bounded_view<Geometry, Bounds, Strategy> v(g, s);
        geometry::convert(v, b);
    }
};

} // namespace dispatch

template <typename Geometry, typename Bounds, typename Strategy>
inline void bounds(Geometry const& g, Bounds & b, Strategy const& s)
{
    concepts::check_concepts_and_equal_dimensions<Geometry const, Bounds>();
    dispatch::bounds<Geometry, Bounds>::apply(g, b, s);
}

namespace dispatch
{

template <typename Bounds,
          typename Geometry,
          typename TagBounds = typename geometry::tag<Bounds>::type,
          typename TagGeometry = typename geometry::tag<Geometry>::type>
struct expand
{
    // STATIC ASSERT
};

template <typename Bounds, typename Geometry>
struct expand<Bounds, Geometry, box_tag, point_tag>
{
    static inline void apply(Bounds & b, Geometry const& g)
    {
        geometry::expand(b, g);
    }

    template <typename Strategy>
    static inline void apply(Bounds & b, Geometry const& g, Strategy const& s)
    {
        geometry::expand(b, g, s);
    }
};

template <typename Bounds, typename Geometry>
struct expand<Bounds, Geometry, box_tag, box_tag>
{
    static inline void apply(Bounds & b, Geometry const& g)
    {
        geometry::expand(b, g);
    }

    template <typename Strategy>
    static inline void apply(Bounds & b, Geometry const& g, Strategy const& s)
    {
        geometry::expand(b, g, s);
    }
};

template <typename Bounds, typename Geometry>
struct expand<Bounds, Geometry, box_tag, segment_tag>
{
    static inline void apply(Bounds & b, Geometry const& g)
    {
        geometry::expand(b, g);
    }

    template <typename Strategy>
    static inline void apply(Bounds & b, Geometry const& g, Strategy const& s)
    {
        geometry::expand(b, geometry::return_envelope<Bounds>(g, s), s);
        // requires additional strategy
        //geometry::expand(b, g, s);
    }
};

} // namespace dispatch

template <typename Bounds, typename Geometry, typename Strategy>
inline void expand(Bounds & b, Geometry const& g, Strategy const& s)
{
    dispatch::expand<Bounds, Geometry>::apply(b, g, s);
}

template <typename Bounds, typename Geometry>
inline void expand(Bounds & b, Geometry const& g, default_strategy const& )
{
    dispatch::expand<Bounds, Geometry>::apply(b, g);
}

namespace dispatch
{

template <typename Geometry,
          typename Bounds,
          typename TagGeometry = typename geometry::tag<Geometry>::type,
          typename TagBounds = typename geometry::tag<Bounds>::type>
struct covered_by_bounds
{};

template <typename Geometry, typename Bounds>
struct covered_by_bounds<Geometry, Bounds, point_tag, box_tag>
{
    static inline bool apply(Geometry const& g, Bounds & b)
    {
        return geometry::covered_by(g, b);
    }

    template <typename Strategy>
    static inline bool apply(Geometry const& g, Bounds & b, Strategy const& s)
    {
        return geometry::covered_by(g, b, s);
    }
};

template <typename Geometry, typename Bounds>
struct covered_by_bounds<Geometry, Bounds, box_tag, box_tag>
{
    static inline bool apply(Geometry const& g, Bounds & b)
    {
        return geometry::covered_by(g, b);
    }

    template <typename Strategy>
    static inline bool apply(Geometry const& g, Bounds & b, Strategy const& s)
    {
        return geometry::covered_by(g, b, s);
    }
};

template <typename Geometry, typename Bounds>
struct covered_by_bounds<Geometry, Bounds, segment_tag, box_tag>
{
    static inline bool apply(Geometry const& g, Bounds & b)
    {
        typedef typename point_type<Geometry>::type point_type;
        typedef geometry::model::box<point_type> bounds_type;
        typedef index::detail::bounded_view<Geometry, bounds_type, default_strategy> view_type;

        return geometry::covered_by(view_type(g, default_strategy()), b);
    }

    template <typename Strategy>
    static inline bool apply(Geometry const& g, Bounds & b, Strategy const& strategy)
    {
        typedef typename point_type<Geometry>::type point_type;
        typedef geometry::model::box<point_type> bounds_type;
        typedef index::detail::bounded_view<Geometry, bounds_type, Strategy> view_type;

        return geometry::covered_by(view_type(g, strategy), b, strategy);
    }
};

} // namespace dispatch

template <typename Geometry, typename Bounds, typename Strategy>
inline bool covered_by_bounds(Geometry const& g, Bounds & b, Strategy const& s)
{
    return dispatch::covered_by_bounds<Geometry, Bounds>::apply(g, b, s);
}

template <typename Geometry, typename Bounds>
inline bool covered_by_bounds(Geometry const& g, Bounds & b, default_strategy const& )
{
    return dispatch::covered_by_bounds<Geometry, Bounds>::apply(g, b);
}

}}}} // namespace boost::geometry::index::detail

#endif // BOOST_GEOMETRY_INDEX_DETAIL_ALGORITHMS_BOUNDS_HPP

ext: hpp


text:
#include <boost/format.hpp>

#include <autom8/net/server.hpp>
#include <autom8/message/response.hpp>
#include <autom8/device/device_system.hpp>
#include <autom8/message/requests/get_security_alert_count.hpp>

using namespace autom8;

bool get_security_alert_count::can_handle(session_ptr session, message_ptr request) {
    return (request->name() == "get_security_alert_count");
}

void get_security_alert_count::operator()(session_ptr session, message_ptr request) {
    device_list devices;
    if (device_system::instance()->model().all_devices(devices)) {
        int count = 0;

        // TODO: add device_model::find_by_type() or something.
        device_list::iterator it = devices.begin();
        for ( ; it != devices.end(); it++) {
            device_ptr device = *it;
            if (device->type() == device_type_security_sensor) {
                security_sensor* sensor;
                if (device->get_interface(sensor)) {
                    if (sensor->is_tripped() && sensor->is_armed()) {
                        ++count;
                    }
                }
            }
        }

        // build JSON body
        json_value_ref document(new json_value());
        (*document)["security_alert_count"] = count;

        // send response
        response_ptr response = response::create(
            "autom8://response/get_security_alert_count",
            document,
            response::requester_only);

        server::send(session, response);
    }
}

request_handler_ptr get_security_alert_count::create() {
    return request_handler_ptr(new get_security_alert_count());
}

ext: cpp


text:
#define BOOST_TEST_MODULE
#include <boost/test/unit_test.hpp>
#include <core/util/test_macros.hpp>
#include <string>
#include <random>
#include <set>
#include <sstream>
#include <vector>
#include <array>
#include <algorithm>
#include <core/util/cityhash_tc.hpp>

// Eigen
#include <Eigen/Core>
#include <Eigen/SparseCore>

// SFrame and Flex type
#include <model_server/lib/flex_dict_view.hpp>
#include <core/random/random.hpp>

// ML-Data Utils
#include <toolkits/ml_data_2/ml_data.hpp>
#include <toolkits/ml_data_2/ml_data_entry.hpp>
#include <toolkits/ml_data_2/metadata.hpp>
#include <toolkits/ml_data_2/ml_data_iterators.hpp>
#include <toolkits/ml_data_2/sframe_index_mapping.hpp>

// Testing utils common to all of ml_data_iterator
#include <core/storage/sframe_data/testing_utils.hpp>
#include <core/util/testing_utils.hpp>
#include <toolkits/ml_data_2/testing_utils.hpp>

#include <core/globals/globals.hpp>

BOOST_TEST_DONT_PRINT_LOG_VALUE(turi::v2::ml_column_mode)
using namespace turi;

struct test_metadata  {
 public:

  void test_basic_1() {

    std::vector<std::vector<flexible_type> > raw_data =
        {{"0",
          "ut0",
          10,
          10.0,
          flex_vec{1.0, 10.1},
          flex_list{"1", "2"},
          flex_dict{ {"8", 1}, {"3", 2}}},

         {"1",
          "ut1",
          11,
          11.0,
          flex_vec{2.0, 11.1},
          flex_list{"2", "3"},
          flex_dict{ {"8", 1}, {"4", 2}}}

        };

    std::vector<std::string> names = {
      "string",
      "untranslated_string",
      "int",
      "float",
      "vec",
      "list",
      "dict"};

    std::vector<std::vector<flexible_type> > raw_data_side =
        {{"0", "new_string_0", 11.0},
         {"1", "new_string_1", 12.0} };

    std::vector<std::string> side_names = {
      "string",
      "side_string",
      "side_float"};

    sframe data_sf = make_testing_sframe(names, raw_data);
    sframe side_sf = make_testing_sframe(side_names, raw_data_side);

    v2::ml_data X;
    X.set_data(data_sf, "", {}, { {"untranslated_string", v2::ml_column_mode::UNTRANSLATED} });
    X.add_side_data(side_sf);
    X.fill();

    std::shared_ptr<v2::ml_metadata> m1 = X.metadata();

    // Also try a saved and loaded one.
    std::shared_ptr<v2::ml_metadata> m2;
    save_and_load_object(m2, m1);

    // Now try one that has been through select_columns a couple of
    // times; the first to shuffle, the second to put things back in
    // the correct order for testing

    std::shared_ptr<v2::ml_metadata> m3 = (
        m1
        ->select_columns( {"float", "list", "dict", "untranslated_string", "string", "int", "vec"})
        ->select_columns(names));

    for(auto m : {m1, m2, m3}) {

      // Check to make sure that everything is correct

      TS_ASSERT(!m->has_target());

      TS_ASSERT_EQUALS(m->num_columns(), 9);
      TS_ASSERT_EQUALS(m->num_untranslated_columns(), 1);
      TS_ASSERT(m->has_untranslated_columns());
      TS_ASSERT(m->has_side_features());

      TS_ASSERT_EQUALS(m->column_names().size(), 9);

      // Without the side columns
      TS_ASSERT_EQUALS(m->column_names(false).size(), 7);

      {
        bool include_side_columns_if_present = false;
        bool include_untranslated_columns = true;
        TS_ASSERT_EQUALS(m->num_columns(include_side_columns_if_present, include_untranslated_columns), 7);
      }

      {
        bool include_side_columns_if_present = true;
        bool include_untranslated_columns = false;
        TS_ASSERT_EQUALS(m->num_columns(include_side_columns_if_present, include_untranslated_columns), 8);
      }

      {
        bool include_side_columns_if_present = false;
        bool include_untranslated_columns = false;
        TS_ASSERT_EQUALS(m->num_columns(include_side_columns_if_present, include_untranslated_columns), 6);
      }

      size_t global_index_offset = 0;

      {
        // The string column
        TS_ASSERT(m->column_name(0) == "string");
        TS_ASSERT(m->column_names()[0] == "string");
        TS_ASSERT(m->column_index("string") == 0);

        TS_ASSERT(m->is_indexed(0));
        TS_ASSERT(m->is_indexed("string"));

        TS_ASSERT(m->indexer("string").get() == m->indexer(0).get());

        TS_ASSERT(m->statistics("string").get() == m->statistics(0).get());

        // 2 unique entries
        TS_ASSERT_EQUALS(m->index_size(0), 2);
        TS_ASSERT_EQUALS(m->index_size("string"), 2);
        global_index_offset += 2;

        // 2 unique entries
        TS_ASSERT_EQUALS(m->global_index_offset(0), 0);
        TS_ASSERT_EQUALS(m->global_index_offset("string"), 0);

        TS_ASSERT(m->is_categorical(0));
        TS_ASSERT(m->is_categorical("string"));

        TS_ASSERT(!m->is_untranslated_column(0));
        TS_ASSERT(!m->is_untranslated_column("string"));

        TS_ASSERT(!m->is_side_column(0));
        TS_ASSERT(!m->is_side_column("string"));

        TS_ASSERT_EQUALS(m->column_mode(0), v2::ml_column_mode::CATEGORICAL);
        TS_ASSERT_EQUALS(m->column_mode("string"), v2::ml_column_mode::CATEGORICAL);

        TS_ASSERT_EQUALS(m->column_type(0), flex_type_enum::STRING);
        TS_ASSERT_EQUALS(m->column_type("string"), flex_type_enum::STRING);
      }

      {
        // The untranslated string column
        TS_ASSERT(m->column_name(1) == "untranslated_string");
        TS_ASSERT(m->column_names()[1] == "untranslated_string");
        TS_ASSERT(m->column_index("untranslated_string") == 1);

        TS_ASSERT(!m->is_indexed(1));
        TS_ASSERT(!m->is_indexed("untranslated_string"));

        // nothing here; it's untranslated
        TS_ASSERT_EQUALS(m->index_size(1), 0);
        TS_ASSERT_EQUALS(m->index_size("untranslated_string"), 0);
        global_index_offset += 0;

        TS_ASSERT(!m->is_categorical(1));
        TS_ASSERT(!m->is_categorical("untranslated_string"));

        TS_ASSERT(m->is_untranslated_column(1));
        TS_ASSERT(m->is_untranslated_column("untranslated_string"));

        TS_ASSERT(!m->is_side_column(1));
        TS_ASSERT(!m->is_side_column("untranslated_string"));

        TS_ASSERT_EQUALS(m->column_mode(1), v2::ml_column_mode::UNTRANSLATED);
        TS_ASSERT_EQUALS(m->column_mode("untranslated_string"), v2::ml_column_mode::UNTRANSLATED);

        TS_ASSERT_EQUALS(m->column_type(1), flex_type_enum::STRING);
        TS_ASSERT_EQUALS(m->column_type("untranslated_string"), flex_type_enum::STRING);
      }

      {
        // The int column
        TS_ASSERT(m->column_name(2) == "int");
        TS_ASSERT(m->column_names()[2] == "int");
        TS_ASSERT(m->column_index("int") == 2);

        TS_ASSERT(!m->is_indexed(2));
        TS_ASSERT(!m->is_indexed("int"));

        TS_ASSERT(m->indexer("int").get() == m->indexer(2).get());

        TS_ASSERT(m->statistics("int").get() == m->statistics(2).get());

        // 1 category
        TS_ASSERT_EQUALS(m->index_size(2), 1);
        TS_ASSERT_EQUALS(m->index_size("int"), 1);

        TS_ASSERT_EQUALS(m->global_index_offset(2), global_index_offset);
        TS_ASSERT_EQUALS(m->global_index_offset("int"), global_index_offset);

        global_index_offset += 1;

        TS_ASSERT(!m->is_categorical(2));
        TS_ASSERT(!m->is_categorical("int"));

        TS_ASSERT(!m->is_untranslated_column(2));
        TS_ASSERT(!m->is_untranslated_column("int"));

        TS_ASSERT(!m->is_side_column(2));
        TS_ASSERT(!m->is_side_column("int"));

        TS_ASSERT_EQUALS(m->column_mode(2), v2::ml_column_mode::NUMERIC);
        TS_ASSERT_EQUALS(m->column_mode("int"), v2::ml_column_mode::NUMERIC);

        TS_ASSERT_EQUALS(m->column_type(2), flex_type_enum::INTEGER);
        TS_ASSERT_EQUALS(m->column_type("int"), flex_type_enum::INTEGER);
      }

      {
        // The float column
        TS_ASSERT(m->column_name(3) == "float");
        TS_ASSERT(m->column_names()[3] == "float");
        TS_ASSERT(m->column_index("float") == 3);

        TS_ASSERT(!m->is_indexed(3));
        TS_ASSERT(!m->is_indexed("float"));

        TS_ASSERT(m->indexer("float").get() == m->indexer(3).get());

        TS_ASSERT(m->statistics("float").get() == m->statistics(3).get());

        // 1 category
        TS_ASSERT_EQUALS(m->index_size(3), 1);
        TS_ASSERT_EQUALS(m->index_size("float"), 1);

        TS_ASSERT_EQUALS(m->global_index_offset(3), global_index_offset);
        TS_ASSERT_EQUALS(m->global_index_offset("float"), global_index_offset);

        global_index_offset += 1;

        TS_ASSERT(!m->is_categorical(3));
        TS_ASSERT(!m->is_categorical("float"));

        TS_ASSERT(!m->is_untranslated_column(3));
        TS_ASSERT(!m->is_untranslated_column("float"));

        TS_ASSERT(!m->is_side_column(3));
        TS_ASSERT(!m->is_side_column("float"));

        TS_ASSERT_EQUALS(m->column_mode(3), v2::ml_column_mode::NUMERIC);
        TS_ASSERT_EQUALS(m->column_mode("float"), v2::ml_column_mode::NUMERIC);

        TS_ASSERT_EQUALS(m->column_type(3), flex_type_enum::FLOAT);
        TS_ASSERT_EQUALS(m->column_type("float"), flex_type_enum::FLOAT);
      }

      {
        // The vec column
        TS_ASSERT(m->column_name(4) == "vec");
        TS_ASSERT(m->column_names()[4] == "vec");
        TS_ASSERT(m->column_index("vec") == 4);

        TS_ASSERT(!m->is_indexed(4));
        TS_ASSERT(!m->is_indexed("vec"));

        TS_ASSERT(m->indexer("vec").get() == m->indexer(4).get());

        TS_ASSERT(m->statistics("vec").get() == m->statistics(4).get());

        // 2 dimensional array
        TS_ASSERT_EQUALS(m->index_size(4), 2);
        TS_ASSERT_EQUALS(m->index_size("vec"), 2);

        // 4 unique entries
        TS_ASSERT_EQUALS(m->global_index_offset(4), global_index_offset);
        TS_ASSERT_EQUALS(m->global_index_offset("vec"), global_index_offset);

        global_index_offset += 2;

        TS_ASSERT(!m->is_categorical(4));
        TS_ASSERT(!m->is_categorical("vec"));

        TS_ASSERT(!m->is_untranslated_column(4));
        TS_ASSERT(!m->is_untranslated_column("vec"));

        TS_ASSERT(!m->is_side_column(4));
        TS_ASSERT(!m->is_side_column("vec"));

        TS_ASSERT_EQUALS(m->column_mode(4), v2::ml_column_mode::NUMERIC_VECTOR);
        TS_ASSERT_EQUALS(m->column_mode("vec"), v2::ml_column_mode::NUMERIC_VECTOR);

        TS_ASSERT_EQUALS(m->column_type(4), flex_type_enum::VECTOR);
        TS_ASSERT_EQUALS(m->column_type("vec"), flex_type_enum::VECTOR);
      }

      {
        // The list column
        TS_ASSERT(m->column_name(5) == "list");
        TS_ASSERT(m->column_names()[5] == "list");
        TS_ASSERT(m->column_index("list") == 5);

        TS_ASSERT(m->is_indexed(5));
        TS_ASSERT(m->is_indexed("list"));

        TS_ASSERT(m->indexer("list").get() == m->indexer(5).get());

        TS_ASSERT(m->statistics("list").get() == m->statistics(5).get());

        // 3 unique categorical keys
        TS_ASSERT_EQUALS(m->index_size(5), 3);
        TS_ASSERT_EQUALS(m->index_size("list"), 3);

        // 5 unique entries
        TS_ASSERT_EQUALS(m->global_index_offset(5), global_index_offset);
        TS_ASSERT_EQUALS(m->global_index_offset("list"), global_index_offset);

        global_index_offset += 3;

        TS_ASSERT(m->is_categorical(5));
        TS_ASSERT(m->is_categorical("list"));

        TS_ASSERT(!m->is_untranslated_column(5));
        TS_ASSERT(!m->is_untranslated_column("list"));

        TS_ASSERT(!m->is_side_column(5));
        TS_ASSERT(!m->is_side_column("list"));

        TS_ASSERT_EQUALS(m->column_mode(5), v2::ml_column_mode::CATEGORICAL_VECTOR);
        TS_ASSERT_EQUALS(m->column_mode("list"), v2::ml_column_mode::CATEGORICAL_VECTOR);

        TS_ASSERT_EQUALS(m->column_type(5), flex_type_enum::LIST);
        TS_ASSERT_EQUALS(m->column_type("list"), flex_type_enum::LIST);
      }

      {
        // The dict column
        TS_ASSERT(m->column_name(6) == "dict");
        TS_ASSERT(m->column_names()[6] == "dict");
        TS_ASSERT(m->column_index("dict") == 6);

        TS_ASSERT(m->is_indexed(6));
        TS_ASSERT(m->is_indexed("dict"));

        TS_ASSERT(m->indexer("dict").get() == m->indexer(6).get());

        TS_ASSERT(m->statistics("dict").get() == m->statistics(6).get());

        // 3 unique categorical keys
        TS_ASSERT_EQUALS(m->index_size(6), 3);
        TS_ASSERT_EQUALS(m->index_size("dict"), 3);

        // 6 unique entries
        TS_ASSERT_EQUALS(m->global_index_offset(6), global_index_offset);
        TS_ASSERT_EQUALS(m->global_index_offset("dict"), global_index_offset);

        global_index_offset += 3;

        // Dicts are not categoricals
        TS_ASSERT(!m->is_categorical(6));
        TS_ASSERT(!m->is_categorical("dict"));

        TS_ASSERT(!m->is_untranslated_column(6));
        TS_ASSERT(!m->is_untranslated_column("dict"));

        TS_ASSERT(!m->is_side_column(6));
        TS_ASSERT(!m->is_side_column("dict"));

        TS_ASSERT_EQUALS(m->column_mode(6), v2::ml_column_mode::DICTIONARY);
        TS_ASSERT_EQUALS(m->column_mode("dict"), v2::ml_column_mode::DICTIONARY);

        TS_ASSERT_EQUALS(m->column_type(6), flex_type_enum::DICT);
        TS_ASSERT_EQUALS(m->column_type("dict"), flex_type_enum::DICT);
      }

      {
        // The side_string column
        TS_ASSERT(m->column_name(7) == "side_string");
        TS_ASSERT(m->column_names()[7] == "side_string");
        TS_ASSERT(m->column_index("side_string") == 7);

        TS_ASSERT(m->is_indexed(7));
        TS_ASSERT(m->is_indexed("side_string"));

        TS_ASSERT(m->indexer("side_string").get() == m->indexer(7).get());

        TS_ASSERT(m->statistics("side_string").get() == m->statistics(7).get());

        // 2 unique entries
        TS_ASSERT_EQUALS(m->index_size(7), 2);
        TS_ASSERT_EQUALS(m->index_size("side_string"), 2);

        // 2 unique entries
        TS_ASSERT_EQUALS(m->global_index_offset(7), global_index_offset);
        TS_ASSERT_EQUALS(m->global_index_offset("side_string"), global_index_offset);
        global_index_offset += 2;

        TS_ASSERT(m->is_categorical(7));
        TS_ASSERT(m->is_categorical("side_string"));

        TS_ASSERT(!m->is_untranslated_column(7));
        TS_ASSERT(!m->is_untranslated_column("side_string"));

        TS_ASSERT(m->is_side_column(7));
        TS_ASSERT(m->is_side_column("side_string"));

        TS_ASSERT_EQUALS(m->column_mode(7), v2::ml_column_mode::CATEGORICAL);
        TS_ASSERT_EQUALS(m->column_mode("side_string"), v2::ml_column_mode::CATEGORICAL);

        TS_ASSERT_EQUALS(m->column_type(7), flex_type_enum::STRING);
        TS_ASSERT_EQUALS(m->column_type("side_string"), flex_type_enum::STRING);
      }

      {
        // The side_float column
        TS_ASSERT(m->column_name(8) == "side_float");
        TS_ASSERT(m->column_names()[8] == "side_float");
        TS_ASSERT(m->column_index("side_float") == 8);

        TS_ASSERT(!m->is_indexed(8));
        TS_ASSERT(!m->is_indexed("side_float"));

        TS_ASSERT(m->indexer("side_float").get() == m->indexer(8).get());

        TS_ASSERT(m->statistics("side_float").get() == m->statistics(8).get());

        // 1 category
        TS_ASSERT_EQUALS(m->index_size(8), 1);
        TS_ASSERT_EQUALS(m->index_size("side_float"), 1);

        TS_ASSERT_EQUALS(m->global_index_offset(8), global_index_offset);
        TS_ASSERT_EQUALS(m->global_index_offset("side_float"), global_index_offset);

        global_index_offset += 1;

        TS_ASSERT(!m->is_categorical(8));
        TS_ASSERT(!m->is_categorical("side_float"));

        TS_ASSERT(!m->is_untranslated_column(8));
        TS_ASSERT(!m->is_untranslated_column("side_float"));

        TS_ASSERT(m->is_side_column(8));
        TS_ASSERT(m->is_side_column("side_float"));

        TS_ASSERT_EQUALS(m->column_mode(8), v2::ml_column_mode::NUMERIC);
        TS_ASSERT_EQUALS(m->column_mode("side_float"), v2::ml_column_mode::NUMERIC);

        TS_ASSERT_EQUALS(m->column_type(8), flex_type_enum::FLOAT);
        TS_ASSERT_EQUALS(m->column_type("side_float"), flex_type_enum::FLOAT);
      }

      TS_ASSERT_EQUALS(global_index_offset, m->num_dimensions());
    }
  }
};

BOOST_FIXTURE_TEST_SUITE(_test_metadata, test_metadata)
BOOST_AUTO_TEST_CASE(test_basic_1) {
  test_metadata::test_basic_1();
}
BOOST_AUTO_TEST_SUITE_END()

ext: cxx


text:
/*
 * Copyright (c) 2015, Gregory Rogers All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *   * Redistributions of source code must retain the above copyright notice,
 *     this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above copyright notice,
 *     this list of conditions and the following disclaimer in the documentation
 *     and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

// It demonstrates how to add support for boost::tuple by
// writing a custom generator (using std::tuple).
//
// Note this file uses C++14 features.

#include "cppqc.h"

#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_io.hpp>
#include <utility>
#include "boost/tuple/tuple_comparison.hpp"

using namespace cppqc;

namespace {

template <typename StdTuple, std::size_t... Is>
auto asBoostTuple(StdTuple&& stdTuple, std::index_sequence<Is...>) {
  return boost::tuple<std::tuple_element_t<Is, std::decay_t<StdTuple>>...>(
      std::get<Is>(std::forward<StdTuple>(stdTuple))...);
}

template <typename BoostTuple, std::size_t... Is>
auto asStdTuple(BoostTuple&& boostTuple, std::index_sequence<Is...>) {
  return std::tuple<
      typename boost::tuples::element<Is, std::decay_t<BoostTuple>>::type...>(
      boost::get<Is>(std::forward<BoostTuple>(boostTuple))...);
}

template <typename StdTuple>
auto asBoostTuple(StdTuple&& stdTuple) {
  return asBoostTuple(std::forward<StdTuple>(stdTuple),
                      std::make_index_sequence<
                          std::tuple_size<std::decay_t<StdTuple>>::value>());
}

template <typename BoostTuple>
auto asStdTuple(BoostTuple&& boostTuple) {
  return asStdTuple(
      std::forward<BoostTuple>(boostTuple),
      std::make_index_sequence<
          boost::tuples::length<std::decay_t<BoostTuple>>::value>());
}

template <typename... T>
struct BoostTupleGenerator {
  BoostTupleGenerator(const Generator<T>&... g)
      : m_tupleGenerator(tupleOf(g...)) {}

  boost::tuple<T...> unGen(RngEngine& rng, std::size_t size) const {
    return asBoostTuple(m_tupleGenerator.unGen(rng, size));
  }

  std::vector<boost::tuple<T...>> shrink(boost::tuple<T...> shrinkInput) const {
    std::vector<boost::tuple<T...>> result;
    for (const auto& shrink :
         m_tupleGenerator.shrink(asStdTuple(shrinkInput))) {
      result.push_back(asBoostTuple(shrink));
    }
    return result;
  }

 private:
  Generator<std::tuple<T...>> m_tupleGenerator;
};

}  // namespace

template <typename... T>
Generator<boost::tuple<T...>> boostTupleOf(const Generator<T>&... g) {
  return BoostTupleGenerator<T...>(g...);
}

template <typename... T>
Generator<boost::tuple<T...>> boostTupleOf() {
  return BoostTupleGenerator<T...>(Arbitrary<T>()...);
}

struct AntisymmetricRelationProp
    : Property<boost::tuple<int, std::string, int>,
               boost::tuple<int, std::string, int>> {
  AntisymmetricRelationProp()
      : Property(boostTupleOf<int, std::string, int>(),
                 boostTupleOf<int, std::string, int>()) {}

  bool check(const boost::tuple<int, std::string, int>& v1,
             const boost::tuple<int, std::string, int>& v2) const override {
    return (v1 <= v2 && v1 >= v2) == (v1 == v2);
  }

  std::string name() const override {
    return "Comparison must be antisymmetric";
  }
};

int main() {
  cppqc::quickCheckOutput(AntisymmetricRelationProp());
}

max_stars_repo_name: Thorius/CppQuickCheck

max_issues_repo_name: Thorius/CppQuickCheck

max_forks_repo_name: Thorius/CppQuickCheck


text:
/*
 * Copyright 2019 Xilinx Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <iostream>
#include <chrono>
#include <boost/filesystem.hpp>

using namespace std;

#include "ext/AksSysManagerExt.h"
#include "ext/AksNodeParams.h"

using namespace AKS;

void usage (const char* exename) {
  std::cout << "[INFO] Usage: " << std::endl;
  std::cout << "[INFO] ---------------------- " << std::endl;
  std::cout << "[INFO] " << exename << " <Image Directory Path>" << std::endl;
  std::cout << std::endl;
}

/// Routine to process a set of images on a particular graph
int executeGraph(
    std::string graphName,
    std::vector<std::string>& images)
{
  /// Access the global system manager
  auto sysMan = AKS::SysManagerExt::getGlobal();

  /// Get graph instance
  AKS::AIGraph *graph = sysMan->getGraph(graphName);

  if(!graph){
    cout<<"[ERROR] Couldn't find requested graph"<<endl;
    AKS::SysManagerExt::deleteGlobal();
    return -1;
  }

  int nImages = images.size();

  sysMan->resetTimer();
  auto t1 = std::chrono::steady_clock::now();

  /// Enqueue the images to graph for execution
  std::cout << "[INFO] Starting enqueue ... " << std::endl;
  for(auto& imagePath: images) {
    std::vector<AKS::DataDescriptor> v; v.reserve(3);
    sysMan->enqueueJob (graph, imagePath , std::move(v), nullptr);
  }

  /// Wait for results
  sysMan->waitForAllResults();

  /// Report - applicable for accuracy kernel
  sysMan->report(graph);

  auto t2 = std::chrono::steady_clock::now();

  auto time_taken = std::chrono::duration<double>(t2-t1).count();
  auto throughput = static_cast<double>(nImages)/time_taken;

  /// Print Stats
  std::cout << "[INFO] Total Images : " << nImages << std::endl;
  std::cout << "[INFO] Total Time (s): " << time_taken << std::endl;
  std::cout << "[INFO] Overall FPS : " << throughput << std::endl;

  sysMan->printPerfStats();
  return 0;
}

int main(int argc, char **argv)
{
  int ret = 0;
  if (argc != 2) {
    std::cout << "[ERROR] Usage invalid!" << std::endl;
    usage(argv[0]);
    return -1;
  }

  std::string graphJson = "graph_zoo/graph_googlenet_pp_accel.json";
  std::string graphName = "googlenet_pp_accel";

  /// Get image directory path
  std::string imgDirPath (argv[1]);

  /// Get AKS System Manager instance
  AKS::SysManagerExt * sysMan = AKS::SysManagerExt::getGlobal();

  /// Load all kernels
  sysMan->loadKernels("kernel_zoo");

  /// Load graph
  sysMan->loadGraphs(graphJson);

  /// Get all the images in the given input directory.
  std::vector<std::string> images;
  int i = 0;
  for (boost::filesystem::directory_iterator it {imgDirPath};
      it != boost::filesystem::directory_iterator{}; it++) {
    std::string fileExtension = it->path().extension().string();
    if(fileExtension == ".jpg" || fileExtension == ".JPEG" || fileExtension == ".png")
      images.push_back((*it).path().string());
  }

  int nImages = images.size();
  std::cout << "[INFO] Running " << nImages << " Images" << std::endl;

  /// Start the graph execution on a separate thread
  /// so that main thread is free to do its own work.
  std::thread t(executeGraph, graphName, std::ref(images));

  std::cout << "[INFO] Waiting for Results ... " << std::endl;
  t.join();

  AKS::SysManagerExt::deleteGlobal();
	return ret;
}

max_stars_repo_name: dendisuhubdy/Vitis-AI

max_issues_repo_name: dendisuhubdy/Vitis-AI

max_forks_repo_name: dendisuhubdy/Vitis-AI


text:
/*
 * Copyright (c) 2015 Cryptonomex, Inc., and contributors.
 *
 * The MIT License
 *
 * 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/test/unit_test.hpp>

#include <graphene/chain/database.hpp>

#include <graphene/chain/account_object.hpp>
#include <graphene/chain/asset_object.hpp>
#include <graphene/chain/exceptions.hpp>

#include <graphene/db/simple_index.hpp>

#include <fc/crypto/digest.hpp>
#include <fc/crypto/hex.hpp>
#include "../common/database_fixture.hpp"

#include <algorithm>
#include <random>

using namespace graphene::chain;
using namespace graphene::db;

BOOST_FIXTURE_TEST_SUITE( basic_tests, database_fixture )

/**
 * Verify that names are RFC-1035 compliant https://tools.ietf.org/html/rfc1035
 * https://github.com/cryptonomex/graphene/issues/15
 */
BOOST_AUTO_TEST_CASE( valid_name_test )
{
   BOOST_CHECK( is_valid_name( "a" ) );
   BOOST_CHECK( !is_valid_name( "A" ) );
   BOOST_CHECK( !is_valid_name( "0" ) );
   BOOST_CHECK( !is_valid_name( "." ) );
   BOOST_CHECK( !is_valid_name( "-" ) );

   BOOST_CHECK( is_valid_name( "aa" ) );
   BOOST_CHECK( !is_valid_name( "aA" ) );
   BOOST_CHECK( is_valid_name( "a0" ) );
   BOOST_CHECK( !is_valid_name( "a." ) );
   BOOST_CHECK( !is_valid_name( "a-" ) );

   BOOST_CHECK( is_valid_name( "aaa" ) );
   BOOST_CHECK( !is_valid_name( "aAa" ) );
   BOOST_CHECK( is_valid_name( "a0a" ) );
   BOOST_CHECK( is_valid_name( "a.a" ) );
   BOOST_CHECK( is_valid_name( "a-a" ) );

   BOOST_CHECK( is_valid_name( "aa0" ) );
   BOOST_CHECK( !is_valid_name( "aA0" ) );
   BOOST_CHECK( is_valid_name( "a00" ) );
   BOOST_CHECK( !is_valid_name( "a.0" ) );
   BOOST_CHECK( is_valid_name( "a-0" ) );

   BOOST_CHECK(  is_valid_name( "aaa-bbb-ccc" ) );
   BOOST_CHECK(  is_valid_name( "aaa-bbb.ccc" ) );

   BOOST_CHECK( !is_valid_name( "aaa,bbb-ccc" ) );
   BOOST_CHECK( !is_valid_name( "aaa_bbb-ccc" ) );
   BOOST_CHECK( !is_valid_name( "aaa-BBB-ccc" ) );

   BOOST_CHECK( !is_valid_name( "1aaa-bbb" ) );
   BOOST_CHECK( !is_valid_name( "-aaa-bbb-ccc" ) );
   BOOST_CHECK( !is_valid_name( ".aaa-bbb-ccc" ) );
   BOOST_CHECK( !is_valid_name( "/aaa-bbb-ccc" ) );

   BOOST_CHECK( !is_valid_name( "aaa-bbb-ccc-" ) );
   BOOST_CHECK( !is_valid_name( "aaa-bbb-ccc." ) );
   BOOST_CHECK( !is_valid_name( "aaa-bbb-ccc.." ) );
   BOOST_CHECK( !is_valid_name( "aaa-bbb-ccc/" ) );

   BOOST_CHECK( !is_valid_name( "aaa..bbb-ccc" ) );
   BOOST_CHECK( is_valid_name( "aaa.bbb-ccc" ) );
   BOOST_CHECK( is_valid_name( "aaa.bbb.ccc" ) );

   BOOST_CHECK(  is_valid_name( "aaa--bbb--ccc" ) );
   BOOST_CHECK(  is_valid_name( "xn--sandmnnchen-p8a.de" ) );
   BOOST_CHECK(  is_valid_name( "xn--sandmnnchen-p8a.dex" ) );
   BOOST_CHECK(  is_valid_name( "xn-sandmnnchen-p8a.de" ) );
   BOOST_CHECK(  is_valid_name( "xn-sandmnnchen-p8a.dex" ) );

   BOOST_CHECK(  is_valid_name( "this-label-has-less-than-64-char.acters-63-to-be-really-precise" ) );
   BOOST_CHECK( !is_valid_name( "this-label-has-more-than-63-char.act.ers-64-to-be-really-precise" ) );
   BOOST_CHECK( !is_valid_name( "none.of.these.labels.has.more.than-63.chars--but.still.not.valid" ) );
}

BOOST_AUTO_TEST_CASE( valid_symbol_test )
{
   BOOST_CHECK( !is_valid_symbol( "A" ) );
   BOOST_CHECK( !is_valid_symbol( "a" ) );
   BOOST_CHECK( !is_valid_symbol( "0" ) );
   BOOST_CHECK( !is_valid_symbol( "." ) );

   BOOST_CHECK( !is_valid_symbol( "AA" ) );
   BOOST_CHECK( !is_valid_symbol( "Aa" ) );
   BOOST_CHECK( !is_valid_symbol( "A0" ) );
   BOOST_CHECK( !is_valid_symbol( "A." ) );

   BOOST_CHECK( is_valid_symbol( "AAA" ) );
   BOOST_CHECK( !is_valid_symbol( "AaA" ) );
   BOOST_CHECK( is_valid_symbol( "A0A" ) );
   BOOST_CHECK( is_valid_symbol( "A.A" ) );

   BOOST_CHECK( !is_valid_symbol( "A..A" ) );
   BOOST_CHECK( !is_valid_symbol( "A.A." ) );
   BOOST_CHECK( !is_valid_symbol( "A.A.A" ) );

   BOOST_CHECK( is_valid_symbol( "AAAAAAAAAAAAAAAA" ) );
   BOOST_CHECK( !is_valid_symbol( "AAAAAAAAAAAAAAAAA" ) );
   BOOST_CHECK( is_valid_symbol( "A.AAAAAAAAAAAAAA" ) );
   BOOST_CHECK( !is_valid_symbol( "A.AAAAAAAAAAAA.A" ) );

   BOOST_CHECK( is_valid_symbol( "AAA000AAA" ) );
}

BOOST_AUTO_TEST_CASE( price_test )
{
    auto price_max = []( uint32_t a, uint32_t b )
    {   return price::max( asset_id_type(a), asset_id_type(b) );   };
    auto price_min = []( uint32_t a, uint32_t b )
    {   return price::min( asset_id_type(a), asset_id_type(b) );   };

    BOOST_CHECK( price_max(0,1) > price_min(0,1) );
    BOOST_CHECK( price_max(1,0) > price_min(1,0) );
    BOOST_CHECK( price_max(0,1) >= price_min(0,1) );
    BOOST_CHECK( price_max(1,0) >= price_min(1,0) );
    BOOST_CHECK( price_max(0,1) >= price_max(0,1) );
    BOOST_CHECK( price_max(1,0) >= price_max(1,0) );
    BOOST_CHECK( price_min(0,1) < price_max(0,1) );
    BOOST_CHECK( price_min(1,0) < price_max(1,0) );
    BOOST_CHECK( price_min(0,1) <= price_max(0,1) );
    BOOST_CHECK( price_min(1,0) <= price_max(1,0) );
    BOOST_CHECK( price_min(0,1) <= price_min(0,1) );
    BOOST_CHECK( price_min(1,0) <= price_min(1,0) );
    BOOST_CHECK( price_min(1,0) != price_max(1,0) );
    BOOST_CHECK( ~price_max(0,1) != price_min(0,1) );
    BOOST_CHECK( ~price_min(0,1) != price_max(0,1) );
    BOOST_CHECK( ~price_max(0,1) == price_min(1,0) );
    BOOST_CHECK( ~price_min(0,1) == price_max(1,0) );
    BOOST_CHECK( ~price_max(0,1) < ~price_min(0,1) );
    BOOST_CHECK( ~price_max(0,1) <= ~price_min(0,1) );
    price a(asset(1), asset(2,asset_id_type(1)));
    price b(asset(2), asset(2,asset_id_type(1)));
    price c(asset(1), asset(2,asset_id_type(1)));
    BOOST_CHECK(a < b);
    BOOST_CHECK(b > a);
    BOOST_CHECK(a == c);
    BOOST_CHECK(!(b == c));

    GRAPHENE_REQUIRE_THROW( price(asset(1),  asset(1)) * ratio_type(1,1), fc::exception );
    GRAPHENE_REQUIRE_THROW( price(asset(0),  asset(1, asset_id_type(1))) * ratio_type(1,1), fc::exception );
    GRAPHENE_REQUIRE_THROW( price(asset(-1), asset(1, asset_id_type(1))) * ratio_type(1,1), fc::exception );
    GRAPHENE_REQUIRE_THROW( price(asset(1),  asset(0, asset_id_type(1))) * ratio_type(1,1), fc::exception );
    GRAPHENE_REQUIRE_THROW( price(asset(1),  asset(-1, asset_id_type(1))) * ratio_type(1,1), fc::exception );
    GRAPHENE_REQUIRE_THROW( price(asset(1),  asset(1, asset_id_type(1))) * ratio_type(0,1), fc::exception );
    GRAPHENE_REQUIRE_THROW( price(asset(1),  asset(1, asset_id_type(1))) * ratio_type(-1,1), fc::exception );
    GRAPHENE_REQUIRE_THROW( price(asset(1),  asset(1, asset_id_type(1))) * ratio_type(1,0), std::domain_error ); // zero denominator
    GRAPHENE_REQUIRE_THROW( price(asset(1),  asset(1, asset_id_type(1))) * ratio_type(1,-1), fc::exception );

    GRAPHENE_REQUIRE_THROW( price(asset(0),  asset(1, asset_id_type(1))) / ratio_type(1,1), fc::exception );
    GRAPHENE_REQUIRE_THROW( price(asset(-1), asset(1, asset_id_type(1))) / ratio_type(1,1), fc::exception );
    GRAPHENE_REQUIRE_THROW( price(asset(1),  asset(0, asset_id_type(1))) / ratio_type(1,1), fc::exception );
    GRAPHENE_REQUIRE_THROW( price(asset(1),  asset(-1, asset_id_type(1))) / ratio_type(1,1), fc::exception );
    GRAPHENE_REQUIRE_THROW( price(asset(1),  asset(1, asset_id_type(1))) / ratio_type(0,1), fc::exception );
    GRAPHENE_REQUIRE_THROW( price(asset(1),  asset(1, asset_id_type(1))) / ratio_type(-1,1), fc::exception );
    GRAPHENE_REQUIRE_THROW( price(asset(1),  asset(1, asset_id_type(1))) / ratio_type(1,0), std::domain_error ); // zero denominator
    GRAPHENE_REQUIRE_THROW( price(asset(1),  asset(1, asset_id_type(1))) / ratio_type(1,-1), fc::exception );

    BOOST_CHECK( price(asset(1), asset(1, asset_id_type(1))) * ratio_type(1,1) == price(asset(1), asset(1, asset_id_type(1))) );
    BOOST_CHECK( price(asset(3), asset(2, asset_id_type(1))) * ratio_type(80,100) == price(asset(12), asset(10, asset_id_type(1))) );
    BOOST_CHECK( price(asset(3), asset(2, asset_id_type(1))) * ratio_type(120,100) == price(asset(9), asset(5, asset_id_type(1))) );

    BOOST_CHECK( price(asset(1), asset(1, asset_id_type(1))) / ratio_type(1,1) == price(asset(1), asset(1, asset_id_type(1))) );
    BOOST_CHECK( price(asset(3), asset(2, asset_id_type(1))) / ratio_type(80,100) == price(asset(15), asset(8, asset_id_type(1))) );
    BOOST_CHECK( price(asset(3), asset(2, asset_id_type(1))) / ratio_type(120,100) == price(asset(30), asset(24, asset_id_type(1))) );

    BOOST_CHECK( price_max(0,1) * ratio_type(2,1) == price_max(0,1) );
    BOOST_CHECK( price_max(0,1) * ratio_type(125317293,125317292) == price_max(0,1) );
    BOOST_CHECK( price_max(0,1) * ratio_type(125317293,105317292) == price_max(0,1) );
    BOOST_CHECK( price_max(0,1) * ratio_type(125317293,25317292) == price_max(0,1) );
    BOOST_CHECK( price_min(0,1) * ratio_type(1,2) == price_min(0,1) );
    BOOST_CHECK( price_min(0,1) * ratio_type(98752395,98752396) == price_min(0,1) );
    BOOST_CHECK( price_min(0,1) * ratio_type(70000000,99999999) == price_min(0,1) );
    BOOST_CHECK( price_min(0,1) * ratio_type(30000000,99999999) == price_min(0,1) );

    price more_than_max = price_max(0,1);
    more_than_max.base.amount *= 5;
    more_than_max.quote.amount *= 3;
    BOOST_CHECK( more_than_max * ratio_type(125317293,125317292) == more_than_max );
    BOOST_CHECK( more_than_max * ratio_type(125317293,125317293) == more_than_max );
    BOOST_CHECK( more_than_max * ratio_type(125317293,125317294) == price_max(0,1) );

    price less_than_min = price_min(0,1);
    less_than_min.base.amount *= 19;
    less_than_min.quote.amount *= 47;
    BOOST_CHECK( less_than_min * ratio_type(125317293,125317292) == price_min(0,1) );
    BOOST_CHECK( less_than_min * ratio_type(125317293,125317293) == less_than_min );
    BOOST_CHECK( less_than_min * ratio_type(125317293,125317294) == less_than_min );

    price less_than_max = price_max(0,1);
    less_than_max.quote.amount = 11;
    BOOST_CHECK( less_than_max * ratio_type(7,1) == price(asset(less_than_max.base.amount*7/11),asset(1,asset_id_type(1))) );
    less_than_max.quote.amount = 92131419;
    BOOST_CHECK( less_than_max * ratio_type(7,1) == price(asset(less_than_max.base.amount*7/92131419),asset(1,asset_id_type(1))) );
    less_than_max.quote.amount = 192131419;
    BOOST_CHECK( less_than_max * ratio_type(7,1) == price(asset(less_than_max.base.amount.value*7>>3),asset(192131419>>3,asset_id_type(1))) );

    price more_than_min = price_min(0,1);
    more_than_min.base.amount = 11;
    BOOST_CHECK( more_than_min * ratio_type(1,7) == price(asset(1),asset(more_than_min.quote.amount*7/11,asset_id_type(1))) );
    more_than_min.base.amount = 64823;
    BOOST_CHECK( more_than_min * ratio_type(31672,102472047) == price(asset(1),asset((fc::uint128(more_than_min.quote.amount.value)*102472047/(64823*31672)).to_uint64(),asset_id_type(1))) );
    more_than_min.base.amount = 13;
    BOOST_CHECK( more_than_min * ratio_type(202472059,3) == price(asset((int64_t(13)*202472059)>>1),asset((more_than_min.quote.amount.value*3)>>1,asset_id_type(1))) ); // after >>1, quote = max*1.5, but gcd = 3, so quote/=3 = max/2, less than max

    price less_than_max2 = price_max(0,1);
    less_than_max2.base.amount *= 2;
    less_than_max2.quote.amount *= 7;
    BOOST_CHECK( less_than_max2 * ratio_type(1,1) == less_than_max2 );
    BOOST_CHECK( less_than_max2 * ratio_type(5,2) == price(asset(less_than_max2.base.amount*5/2/7),asset(1,asset_id_type(1))) );

    BOOST_CHECK( ( asset(1) * price( asset(1), asset(1, asset_id_type(1)) ) ) == asset(1, asset_id_type(1)) );
    BOOST_CHECK( ( asset(1) * price( asset(1, asset_id_type(1)), asset(1) ) ) == asset(1, asset_id_type(1)) );
    BOOST_CHECK( ( asset(1, asset_id_type(1)) * price( asset(1), asset(1, asset_id_type(1)) ) ) == asset(1) );
    BOOST_CHECK( ( asset(1, asset_id_type(1)) * price( asset(1, asset_id_type(1)), asset(1) ) ) == asset(1) );

    BOOST_CHECK( ( asset(3) * price( asset(3), asset(5, asset_id_type(1)) ) ) == asset(5, asset_id_type(1)) ); // round_down(3*5/3)
    BOOST_CHECK( ( asset(5) * price( asset(2, asset_id_type(1)), asset(7) ) ) == asset(1, asset_id_type(1)) ); // round_down(5*2/7)
    BOOST_CHECK( ( asset(7, asset_id_type(1)) * price( asset(2), asset(3, asset_id_type(1)) ) ) == asset(4) ); // round_down(7*2/3)
    BOOST_CHECK( ( asset(9, asset_id_type(1)) * price( asset(8, asset_id_type(1)), asset(7) ) ) == asset(7) ); // round_down(9*7/8)

    // asset and price doesn't match
    BOOST_CHECK_THROW( asset(1) * price( asset(1, asset_id_type(2)), asset(1, asset_id_type(1)) ), fc::assert_exception );
    // divide by zero
    BOOST_CHECK_THROW( asset(1) * price( asset(0), asset(1, asset_id_type(1)) ), fc::assert_exception );
    BOOST_CHECK_THROW( asset(1) * price( asset(1, asset_id_type(1)), asset(0) ), fc::assert_exception );
    // overflow
    BOOST_CHECK_THROW( asset(GRAPHENE_MAX_SHARE_SUPPLY/2+1) * price( asset(1), asset(2, asset_id_type(1)) ), fc::assert_exception );
    BOOST_CHECK_THROW( asset(2) * price( asset(GRAPHENE_MAX_SHARE_SUPPLY/2+1, asset_id_type(1)), asset(1) ), fc::assert_exception );

    BOOST_CHECK( asset(1).multiply_and_round_up( price( asset(1), asset(1, asset_id_type(1)) ) ) == asset(1, asset_id_type(1)) );
    BOOST_CHECK( asset(1).multiply_and_round_up( price( asset(1, asset_id_type(1)), asset(1) ) ) == asset(1, asset_id_type(1)) );
    BOOST_CHECK( asset(1, asset_id_type(1)).multiply_and_round_up( price( asset(1), asset(1, asset_id_type(1)) ) ) == asset(1) );
    BOOST_CHECK( asset(1, asset_id_type(1)).multiply_and_round_up( price( asset(1, asset_id_type(1)), asset(1) ) ) == asset(1) );

    // round_up(3*5/3)
    BOOST_CHECK( asset(3).multiply_and_round_up( price( asset(3), asset(5, asset_id_type(1)) ) ) == asset(5, asset_id_type(1)) );
    // round_up(5*2/7)
    BOOST_CHECK( asset(5).multiply_and_round_up( price( asset(2, asset_id_type(1)), asset(7) ) ) == asset(2, asset_id_type(1)) );
    // round_up(7*2/3)
    BOOST_CHECK( asset(7, asset_id_type(1)).multiply_and_round_up( price( asset(2), asset(3, asset_id_type(1)) ) ) == asset(5) );
    // round_up(9*7/8)
    BOOST_CHECK( asset(9, asset_id_type(1)).multiply_and_round_up( price( asset(8, asset_id_type(1)), asset(7) ) ) == asset(8) );

    // asset and price doesn't match
    BOOST_CHECK_THROW( asset(1, asset_id_type(3)).multiply_and_round_up( price( asset(1, asset_id_type(2)), asset(1) ) ),
                       fc::assert_exception );
    // divide by zero
    BOOST_CHECK_THROW( asset(1).multiply_and_round_up( price( asset(0), asset(1, asset_id_type(1)) ) ), fc::assert_exception );
    BOOST_CHECK_THROW( asset(1).multiply_and_round_up( price( asset(1, asset_id_type(1)), asset(0) ) ), fc::assert_exception );
    // overflow
    BOOST_CHECK_THROW( asset(GRAPHENE_MAX_SHARE_SUPPLY/2+1).multiply_and_round_up( price( asset(1), asset(2, asset_id_type(1)) ) ),
                       fc::assert_exception );
    BOOST_CHECK_THROW( asset(2).multiply_and_round_up( price( asset(GRAPHENE_MAX_SHARE_SUPPLY/2+1, asset_id_type(1)), asset(1) ) ),
                       fc::assert_exception );

    price_feed dummy;
    dummy.maintenance_collateral_ratio = 1002;
    dummy.maximum_short_squeeze_ratio = 1234;
    dummy.settlement_price = price(asset(1000), asset(2000, asset_id_type(1)));
    price_feed dummy2 = dummy;
    BOOST_CHECK(dummy == dummy2);
}

BOOST_AUTO_TEST_CASE( price_multiplication_test )
{ try {
   // random test
   std::mt19937_64 gen( time(NULL) );
   std::uniform_int_distribution<int64_t> amt_uid(1, GRAPHENE_MAX_SHARE_SUPPLY);
   std::uniform_int_distribution<int64_t> amt_uid2(1, 1000*1000*1000);
   std::uniform_int_distribution<int64_t> amt_uid3(1, 1000*1000);
   std::uniform_int_distribution<int64_t> amt_uid4(1, 1000);
   asset a;
   price p;
   for( int i = 1*1000*1000; i > 0; --i )
   {
      if( i <= 30 )
         a = asset( 0 );
      else if( i % 4 == 0 )
         a = asset( amt_uid(gen) );
      else if( i % 4 == 1 )
         a = asset( amt_uid2(gen) );
      else if( i % 4 == 2 )
         a = asset( amt_uid3(gen) );
      else // if( i % 4 == 3 )
         a = asset( amt_uid4(gen) );

      if( i % 7 == 0 )
         p = price( asset(amt_uid(gen)), asset(amt_uid(gen), asset_id_type(1)) );
      else if( i % 7 == 1 )
         p = price( asset(amt_uid2(gen)), asset(amt_uid2(gen), asset_id_type(1)) );
      else if( i % 7 == 2 )
         p = price( asset(amt_uid3(gen)), asset(amt_uid3(gen), asset_id_type(1)) );
      else if( i % 7 == 3 )
         p = price( asset(amt_uid4(gen)), asset(amt_uid4(gen), asset_id_type(1)) );
      else if( i % 7 == 4 )
         p = price( asset(amt_uid(gen)), asset(amt_uid(gen), asset_id_type(1)) );
      else if( i % 7 == 5 )
         p = price( asset(amt_uid4(gen)), asset(amt_uid2(gen), asset_id_type(1)) );
      else // if( i % 7 == 6 )
         p = price( asset(amt_uid2(gen)), asset(amt_uid4(gen), asset_id_type(1)) );

      try
      {
         asset b = a * p;
         asset a1 = b.multiply_and_round_up( p );
         BOOST_CHECK( a1 <= a );
         BOOST_CHECK( (a1 * p) == b );

         b = a.multiply_and_round_up( p );
         a1 = b * p;
         BOOST_CHECK( a1 >= a );
         BOOST_CHECK( a1.multiply_and_round_up( p ) == b );
      }
      catch( fc::assert_exception& e )
      {
         BOOST_CHECK( e.to_detail_string().find( "result <= GRAPHENE_MAX_SHARE_SUPPLY" ) != string::npos );
      }
   }
} FC_LOG_AND_RETHROW() }

BOOST_AUTO_TEST_CASE( memo_test )
{ try {
   memo_data m;
   auto sender = generate_private_key("1");
   auto receiver = generate_private_key("2");
   m.from = sender.get_public_key();
   m.to = receiver.get_public_key();
   m.set_message(sender, receiver.get_public_key(), "Hello, world!", 12345);

   decltype(fc::digest(m)) hash("8de72a07d093a589f574460deb19023b4aff354b561eb34590d9f4629f51dbf3");
   if( fc::digest(m) != hash )
   {
      // If this happens, notify the web guys that the memo serialization format changed.
      edump((m)(fc::digest(m)));
      BOOST_FAIL("Memo format has changed. Notify the web guys and update this test.");
   }
   BOOST_CHECK_EQUAL(m.get_message(receiver, sender.get_public_key()), "Hello, world!");
} FC_LOG_AND_RETHROW() }

BOOST_AUTO_TEST_CASE( exceptions )
{
   GRAPHENE_CHECK_THROW(FC_THROW_EXCEPTION(balance_claim_invalid_claim_amount, "Etc"), balance_claim_invalid_claim_amount);
}

BOOST_AUTO_TEST_CASE( scaled_precision )
{
   const int64_t _k = 1000;
   const int64_t _m = _k*_k;
   const int64_t _g = _m*_k;
   const int64_t _t = _g*_k;
   const int64_t _p = _t*_k;
   const int64_t _e = _p*_k;

   BOOST_CHECK( asset::scaled_precision( 0) == share_type(   1   ) );
   BOOST_CHECK( asset::scaled_precision( 1) == share_type(  10   ) );
   BOOST_CHECK( asset::scaled_precision( 2) == share_type( 100   ) );
   BOOST_CHECK( asset::scaled_precision( 3) == share_type(   1*_k) );
   BOOST_CHECK( asset::scaled_precision( 4) == share_type(  10*_k) );
   BOOST_CHECK( asset::scaled_precision( 5) == share_type( 100*_k) );
   BOOST_CHECK( asset::scaled_precision( 6) == share_type(   1*_m) );
   BOOST_CHECK( asset::scaled_precision( 7) == share_type(  10*_m) );
   BOOST_CHECK( asset::scaled_precision( 8) == share_type( 100*_m) );
   BOOST_CHECK( asset::scaled_precision( 9) == share_type(   1*_g) );
   BOOST_CHECK( asset::scaled_precision(10) == share_type(  10*_g) );
   BOOST_CHECK( asset::scaled_precision(11) == share_type( 100*_g) );
   BOOST_CHECK( asset::scaled_precision(12) == share_type(   1*_t) );
   BOOST_CHECK( asset::scaled_precision(13) == share_type(  10*_t) );
   BOOST_CHECK( asset::scaled_precision(14) == share_type( 100*_t) );
   BOOST_CHECK( asset::scaled_precision(15) == share_type(   1*_p) );
   BOOST_CHECK( asset::scaled_precision(16) == share_type(  10*_p) );
   BOOST_CHECK( asset::scaled_precision(17) == share_type( 100*_p) );
   BOOST_CHECK( asset::scaled_precision(18) == share_type(   1*_e) );
   GRAPHENE_CHECK_THROW( asset::scaled_precision(19), fc::exception );
}

BOOST_AUTO_TEST_CASE( merkle_root )
{
   clearable_block block;
   vector<processed_transaction> tx;
   vector<digest_type> t;
   const uint32_t num_tx = 10;

   for( uint32_t i=0; i<num_tx; i++ )
   {
      tx.emplace_back();
      tx.back().ref_block_prefix = i;
      t.push_back( tx.back().merkle_digest() );
   }

   auto c = []( const digest_type& digest ) -> checksum_type
   {   return checksum_type::hash( digest );   };

   auto d = []( const digest_type& left, const digest_type& right ) -> digest_type
   {   return digest_type::hash( std::make_pair( left, right ) );   };

   BOOST_CHECK( block.calculate_merkle_root() == checksum_type() );

   block.transactions.push_back( tx[0] );
   BOOST_CHECK( block.calculate_merkle_root() ==
      c(t[0])
      );

   digest_type dA, dB, dC, dD, dE, dI, dJ, dK, dM, dN, dO;

   /*
      A=d(0,1)
         / \
        0   1
   */

   dA = d(t[0], t[1]);

   block.transactions.push_back( tx[1] );
   block.clear();
   BOOST_CHECK( block.calculate_merkle_root() == c(dA) );

   /*
            I=d(A,B)
           /        \
      A=d(0,1)      B=2
         / \        /
        0   1      2
   */

   dB = t[2];
   dI = d(dA, dB);

   block.transactions.push_back( tx[2] );
   block.clear();
   BOOST_CHECK( block.calculate_merkle_root() == c(dI) );

   /*
          I=d(A,B)
           /    \
      A=d(0,1)   B=d(2,3)
         / \    /   \
        0   1  2     3
   */

   dB = d(t[2], t[3]);
   dI = d(dA, dB);

   block.transactions.push_back( tx[3] );
   block.clear();
   BOOST_CHECK( block.calculate_merkle_root() == c(dI) );

   /*
                     __M=d(I,J)__
                    /            \
            I=d(A,B)              J=C
           /        \            /
      A=d(0,1)   B=d(2,3)      C=4
         / \        / \        /
        0   1      2   3      4
   */

   dC = t[4];
   dJ = dC;
   dM = d(dI, dJ);

   block.transactions.push_back( tx[4] );
   block.clear();
   BOOST_CHECK( block.calculate_merkle_root() == c(dM) );

   /*
                     __M=d(I,J)__
                    /            \
            I=d(A,B)              J=C
           /        \            /
      A=d(0,1)   B=d(2,3)   C=d(4,5)
         / \        / \        / \
        0   1      2   3      4   5
   */

   dC = d(t[4], t[5]);
   dJ = dC;
   dM = d(dI, dJ);

   block.transactions.push_back( tx[5] );
   block.clear();
   BOOST_CHECK( block.calculate_merkle_root() == c(dM) );

   /*
                     __M=d(I,J)__
                    /            \
            I=d(A,B)              J=d(C,D)
           /        \            /        \
      A=d(0,1)   B=d(2,3)   C=d(4,5)      D=6
         / \        / \        / \        /
        0   1      2   3      4   5      6
   */

   dD = t[6];
   dJ = d(dC, dD);
   dM = d(dI, dJ);

   block.transactions.push_back( tx[6] );
   block.clear();
   BOOST_CHECK( block.calculate_merkle_root() == c(dM) );

   /*
                     __M=d(I,J)__
                    /            \
            I=d(A,B)              J=d(C,D)
           /        \            /        \
      A=d(0,1)   B=d(2,3)   C=d(4,5)   D=d(6,7)
         / \        / \        / \        / \
        0   1      2   3      4   5      6   7
   */

   dD = d(t[6], t[7]);
   dJ = d(dC, dD);
   dM = d(dI, dJ);

   block.transactions.push_back( tx[7] );
   block.clear();
   BOOST_CHECK( block.calculate_merkle_root() == c(dM) );

   /*
                                _____________O=d(M,N)______________
                               /                                   \
                     __M=d(I,J)__                                  N=K
                    /            \                              /
            I=d(A,B)              J=d(C,D)                 K=E
           /        \            /        \            /
      A=d(0,1)   B=d(2,3)   C=d(4,5)   D=d(6,7)      E=8
         / \        / \        / \        / \        /
        0   1      2   3      4   5      6   7      8
   */

   dE = t[8];
   dK = dE;
   dN = dK;
   dO = d(dM, dN);

   block.transactions.push_back( tx[8] );
   block.clear();
   BOOST_CHECK( block.calculate_merkle_root() == c(dO) );

   /*
                                _____________O=d(M,N)______________
                               /                                   \
                     __M=d(I,J)__                                  N=K
                    /            \                              /
            I=d(A,B)              J=d(C,D)                 K=E
           /        \            /        \            /
      A=d(0,1)   B=d(2,3)   C=d(4,5)   D=d(6,7)   E=d(8,9)
         / \        / \        / \        / \        / \
        0   1      2   3      4   5      6   7      8   9
   */

   dE = d(t[8], t[9]);
   dK = dE;
   dN = dK;
   dO = d(dM, dN);

   block.transactions.push_back( tx[9] );
   block.clear();
   BOOST_CHECK( block.calculate_merkle_root() == c(dO) );
}

/**
 * Reproduces https://github.com/x4trade-org/x4trade-core/issues/888 and tests fix for it.
 */
BOOST_AUTO_TEST_CASE( bitasset_feed_expiration_test )
{
   time_point_sec now = fc::time_point::now();

   asset_bitasset_data_object o;

   o.current_feed_publication_time = now - fc::hours(1);
   o.options.feed_lifetime_sec = std::numeric_limits<uint32_t>::max() - 1;

   BOOST_CHECK( !o.feed_is_expired( now ) );
}

BOOST_AUTO_TEST_SUITE_END()