<commit_before>#include "BoundingBox.hpp"
#include "GeoCoordinate.hpp"
#include "QuadKey.hpp"
#include "entities/Element.hpp"
#include "entities/Node.hpp"
#include "entities/Way.hpp"
#include "entities/Area.hpp"
#include "entities/Relation.hpp"
#include "entities/ElementVisitor.hpp"
#include "formats/FormatTypes.hpp"
#include "index/ElementStore.hpp"
#include "mapcss/Style.hpp"
#include "mapcss/StyleProvider.hpp"
#include "utils/GeoUtils.hpp"
#include "clipper/clipper.hpp"

using namespace utymap;
using namespace utymap::entities;
using namespace utymap::formats;
using namespace utymap::mapcss;

namespace utymap { namespace index {

const static double Scale = 1E8; // max precision for Lat/Lon
const static std::string ClipKey = "clip";

// Creates bounding box of given element.
struct BoundingBoxVisitor : public ElementVisitor
{
    BoundingBox boundingBox;

    void visitNode(const Node& node)
    {
        boundingBox.expand(node.coordinate);
    }

    void visitWay(const Way& way)
    {
        boundingBox.expand(way.coordinates.cbegin(), way.coordinates.cend());
    }

    void visitArea(const Area& area)
    {
        boundingBox.expand(area.coordinates.cbegin(), area.coordinates.cend());
    }

    void visitRelation(const Relation& relation)
    {
        for (const auto& element: relation.elements) {
            element->accept(*this);
        }
    }
};

// Modifies geometry of element by bounding box clipping
class ElementGeometryVisitor : private ElementVisitor
{
public:

    // Defines polygon points location relative to current quadkey.
    enum PointLocation { AllInside, AllOutside, Mixed };

    ElementGeometryVisitor(ElementStore& elementStore) :
        elementStore_(elementStore),
        quadKeyPtr_(nullptr),
        quadKeyBboxPtr_(nullptr)
    {
    }

    void clipAndStore(const Element& element, const QuadKey& quadKey, const BoundingBox& quadKeyBbox)
    {
        quadKeyPtr_ = &quadKey;
        quadKeyBboxPtr_ = &quadKeyBbox;
        element.accept(*this);
    }

    void visitNode(const Node& node)
    {
        // here, node should be always in tile
        elementStore_.storeImpl(node, *quadKeyPtr_);
    }

    void visitWay(const Way& way)
    {
        ClipperLib::Path wayShape;
        PointLocation pointLocation = setPath(*quadKeyBboxPtr_, way, wayShape);
        // 1. all geometry inside current quadkey: no need to truncate.
        if (pointLocation == PointLocation::AllInside) {
            elementStore_.storeImpl(way, *quadKeyPtr_);
            return;
        }

        // 2. all geometry outside : way should be skipped
        if (pointLocation == PointLocation::AllOutside) {
            return;
        }

        ClipperLib::PolyTree solution;
        clipper_.AddPath(wayShape, ClipperLib::ptSubject, false);
        clipper_.AddPath(createPathFromBoundingBox(), ClipperLib::ptClip, true);
        clipper_.Execute(ClipperLib::ctIntersection, solution);
        clipper_.Clear();
        int count = solution.Total();

        // 3. way intersects border only once: store a copy with clipped geometry
        if (count == 1) {
            Way clippedWay;
            setData(clippedWay, way, solution.GetFirst()->Contour);
            elementStore_.storeImpl(clippedWay, *quadKeyPtr_);
        }
        // 4. in this case, result should be stored as relation (collection of ways)
        else {
            Relation relation;
            relation.id = way.id;
            relation.tags = way.tags;
            relation.elements.reserve(count);
            ClipperLib::PolyNode* polyNode = solution.GetFirst();
            while (polyNode)
            {
                std::shared_ptr<Way> clippedWay(new Way());
                clippedWay->id = way.id;
                setCoordinates(*clippedWay, polyNode->Contour);
                relation.elements.push_back(clippedWay);
                polyNode = polyNode->GetNext();
            }
            elementStore_.storeImpl(relation, *quadKeyPtr_);
        }
    }

    void visitArea(const Area& area)
    {
        ClipperLib::Path areaShape;
        PointLocation pointLocation = setPath(*quadKeyBboxPtr_, area, areaShape);
        // 1. all geometry inside current quadkey: no need to truncate.
        if (pointLocation == PointLocation::AllInside) {
            elementStore_.storeImpl(area, *quadKeyPtr_);
            return;
        }

        // 2. all geometry outside : pass empty
        if (pointLocation == PointLocation::AllOutside) {
            Area emptyArea;
            emptyArea.id = area.id;
            emptyArea.tags = area.tags;
            elementStore_.storeImpl(emptyArea, *quadKeyPtr_);
            return;
        }

        ClipperLib::Paths solution;
        clipper_.AddPath(areaShape, ClipperLib::ptSubject, true);
        clipper_.AddPath(createPathFromBoundingBox(), ClipperLib::ptClip, true);
        clipper_.Execute(ClipperLib::ctIntersection, solution);
        clipper_.Clear();

        // 3. way intersects border only once: store a copy with clipped geometry
        if (solution.size() == 1) {
            Area clippedArea;
            setData(clippedArea, area, solution[0]);
            elementStore_.storeImpl(clippedArea, *quadKeyPtr_);
        }
        // 4. in this case, result should be stored as relation (collection of areas)
        else {
            Relation relation;
            relation.id = area.id;
            relation.tags = area.tags;
            relation.elements.reserve(solution.size());
            for (auto it = solution.begin(); it != solution.end(); ++it) {
                std::shared_ptr<Area> clippedArea(new Area());
                clippedArea->id = area.id;
                setCoordinates(*clippedArea, *it);
                relation.elements.push_back(clippedArea);
            }
            elementStore_.storeImpl(relation, *quadKeyPtr_);
        }
    }

    void visitRelation(const Relation& relation)
    {
        struct RelationVisitor : public ElementVisitor
        {
            Relation data;

            RelationVisitor(const BoundingBox& quadKeyBbox, ClipperLib::Clipper& clipper) :
                bbox_(quadKeyBbox), clipper_(clipper) { }

            void visitNode(const Node& node)
            {
                if (bbox_.contains(node.coordinate)) {
                    data.elements.push_back(std::shared_ptr<Node>(new Node(node)));
                }
            }

            void visitWay(const Way& way)
            {
                ClipperLib::Path wayShape;
                ElementGeometryVisitor::setPath(bbox_, way, wayShape);
                clipper_.AddPath(wayShape, ClipperLib::ptSubject, false);
            }

            void visitArea(const Area& area)
            {
                ClipperLib::Path areaShape;
                ElementGeometryVisitor::setPath(bbox_, area, areaShape);
                clipper_.AddPath(areaShape, ClipperLib::ptSubject, true);
            }

            void visitRelation(const Relation& relation)
            {
                for (const auto& element : relation.elements) {
                    element->accept(*this);
                }
            }

        private:
            const BoundingBox& bbox_;
            ClipperLib::Clipper& clipper_;

        } visitor(*quadKeyBboxPtr_, clipper_);

        relation.accept(visitor);

        // Process results
        ClipperLib::PolyTree solution;
        clipper_.AddPath(createPathFromBoundingBox(), ClipperLib::ptClip, true);
        clipper_.Execute(ClipperLib::ctIntersection, solution);
        clipper_.Clear();

        int count = solution.Total();
        // Do not store one result as relation
        if (count == 1) {
            ClipperLib::PolyNode* node = solution.GetFirst();
            if (node->IsOpen()) {
                Way way;
                setData(way, relation, node->Contour);
                elementStore_.storeImpl(way, *quadKeyPtr_);
            }
            else {
                if (!node->IsHole()) {
                    Area area;
                    setData(area, relation, node->Contour);
                    elementStore_.storeImpl(area, *quadKeyPtr_);
                }
            }
        }
        else if (count > 1) {
            Relation newRelation;
            newRelation.id = relation.id;
            newRelation.tags = relation.tags;
            newRelation.elements.reserve(count);

            ClipperLib::PolyNode* polyNode = solution.GetFirst();
            while (polyNode)
            {
                if (polyNode->IsOpen()) {
                    std::shared_ptr<Way> way(new Way());
                    setCoordinates(*way, polyNode->Contour);
                    newRelation.elements.push_back(way);
                }
                else {
                    std::shared_ptr<Area> area(new Area());
                    setCoordinates(*area, polyNode->Contour);
                    newRelation.elements.push_back(area);
                }
                polyNode = polyNode->GetNext();
            }
            elementStore_.storeImpl(newRelation, *quadKeyPtr_);
        }
    }

    template<typename T>
    inline static PointLocation setPath(const BoundingBox& bbox, const T& t, ClipperLib::Path& shape) {
        shape.reserve(t.coordinates.size());
        bool allInside = false;
        bool allOutside = true;
        for (const GeoCoordinate& coord : t.coordinates) {
            bool contains = bbox.contains(coord);
            allInside &= contains;
            allOutside &= !contains;
            shape.push_back(ClipperLib::IntPoint(coord.longitude*Scale, coord.latitude*Scale));
        }

        return allInside ? PointLocation::AllInside :
              (allOutside ? PointLocation::AllOutside : PointLocation::Mixed);
    }

private:

    template<typename T>
    inline void setData(T& t, const Element& element, const ClipperLib::Path& path) {
        t.id = element.id;
        t.tags = element.tags;
        setCoordinates<T>(t, path);
    }

    template<typename T>
    inline void setCoordinates(T& t, const ClipperLib::Path& path) {
        t.coordinates.reserve(path.size());
        for (const auto& c : path) {
            t.coordinates.push_back(GeoCoordinate(c.Y / Scale, c.X / Scale));
        }
    }

    inline ClipperLib::Path createPathFromBoundingBox()
    {
        double xMin = quadKeyBboxPtr_->minPoint.longitude, yMin = quadKeyBboxPtr_->minPoint.latitude,
            xMax = quadKeyBboxPtr_->maxPoint.longitude, yMax = quadKeyBboxPtr_->maxPoint.latitude;
        ClipperLib::Path rect;
        rect.push_back(ClipperLib::IntPoint(xMin*Scale, yMin*Scale));
        rect.push_back(ClipperLib::IntPoint(xMax*Scale, yMin*Scale));
        rect.push_back(ClipperLib::IntPoint(xMax*Scale, yMax*Scale));
        rect.push_back(ClipperLib::IntPoint(xMin*Scale, yMax*Scale));
        return std::move(rect);
    }

    ElementStore& elementStore_;
    const QuadKey* quadKeyPtr_;
    const BoundingBox* quadKeyBboxPtr_;
    ClipperLib::Clipper clipper_;
};

ElementStore::ElementStore(StringTable& stringTable) : stringTable_(stringTable)
{
}

ElementStore::~ElementStore()
{
}

bool ElementStore::store(const Element& element, const utymap::index::LodRange& range, const StyleProvider& styleProvider)
{
    BoundingBoxVisitor bboxVisitor;
    bool wasStored = false;
    uint32_t clipKeyId = stringTable_.getId(ClipKey);
    for (int lod = range.start; lod <= range.end; ++lod) {
        // skip element for this lod
        if (!styleProvider.hasStyle(element, lod))
            continue;

        // initialize bounding box only once
        if (!bboxVisitor.boundingBox.isValid()) {
            element.accept(bboxVisitor);
        }

        Style style = styleProvider.forElement(element, lod);
        storeInTileRange(element, bboxVisitor.boundingBox, lod, style.has(clipKeyId));
        wasStored = true;
    }

    // NOTE still might be clipped and then skipped
    return wasStored;
}

void ElementStore::storeInTileRange(const Element& element, const BoundingBox& elementBbox, int levelOfDetails, bool shouldClip)
{
    ElementGeometryVisitor geometryClipper(*this);
    auto visitor = [&](const QuadKey& quadKey, const BoundingBox& quadKeyBbox) {
        if (shouldClip)
            geometryClipper.clipAndStore(element, quadKey, quadKeyBbox);
        else
            storeImpl(element, quadKey);
    };
    utymap::utils::GeoUtils::visitTileRange(elementBbox, levelOfDetails, visitor);
}

}}
<commit_msg>refactoring: adjust code style<commit_after>#include "BoundingBox.hpp"
#include "GeoCoordinate.hpp"
#include "QuadKey.hpp"
#include "entities/Element.hpp"
#include "entities/Node.hpp"
#include "entities/Way.hpp"
#include "entities/Area.hpp"
#include "entities/Relation.hpp"
#include "entities/ElementVisitor.hpp"
#include "formats/FormatTypes.hpp"
#include "index/ElementStore.hpp"
#include "mapcss/Style.hpp"
#include "mapcss/StyleProvider.hpp"
#include "utils/GeoUtils.hpp"
#include "clipper/clipper.hpp"

using namespace utymap;
using namespace utymap::entities;
using namespace utymap::formats;
using namespace utymap::mapcss;

namespace utymap { namespace index {

const static double Scale = 1E8; // max precision for Lat/Lon
const static std::string ClipKey = "clip";

// Creates bounding box of given element.
struct BoundingBoxVisitor : public ElementVisitor
{
    BoundingBox boundingBox;

    void visitNode(const Node& node)
    {
        boundingBox.expand(node.coordinate);
    }

    void visitWay(const Way& way)
    {
        boundingBox.expand(way.coordinates.cbegin(), way.coordinates.cend());
    }

    void visitArea(const Area& area)
    {
        boundingBox.expand(area.coordinates.cbegin(), area.coordinates.cend());
    }

    void visitRelation(const Relation& relation)
    {
        for (const auto& element: relation.elements) {
            element->accept(*this);
        }
    }
};

// Modifies geometry of element by bounding box clipping
class ElementGeometryVisitor : private ElementVisitor
{
public:

    // Defines polygon points location relative to current quadkey.
    enum PointLocation { AllInside, AllOutside, Mixed };

    ElementGeometryVisitor(ElementStore& elementStore) :
        elementStore_(elementStore),
        quadKeyPtr_(nullptr),
        quadKeyBboxPtr_(nullptr)
    {
    }

    void clipAndStore(const Element& element, const QuadKey& quadKey, const BoundingBox& quadKeyBbox)
    {
        quadKeyPtr_ = &quadKey;
        quadKeyBboxPtr_ = &quadKeyBbox;
        element.accept(*this);
    }

    void visitNode(const Node& node)
    {
        // here, node should be always in tile
        elementStore_.storeImpl(node, *quadKeyPtr_);
    }

    void visitWay(const Way& way)
    {
        ClipperLib::Path wayShape;
        PointLocation pointLocation = setPath(*quadKeyBboxPtr_, way, wayShape);
        // 1. all geometry inside current quadkey: no need to truncate.
        if (pointLocation == PointLocation::AllInside) {
            elementStore_.storeImpl(way, *quadKeyPtr_);
            return;
        }

        // 2. all geometry outside : way should be skipped
        if (pointLocation == PointLocation::AllOutside) {
            return;
        }

        ClipperLib::PolyTree solution;
        clipper_.AddPath(wayShape, ClipperLib::ptSubject, false);
        clipper_.AddPath(createPathFromBoundingBox(), ClipperLib::ptClip, true);
        clipper_.Execute(ClipperLib::ctIntersection, solution);
        clipper_.Clear();
        int count = solution.Total();

        // 3. way intersects border only once: store a copy with clipped geometry
        if (count == 1) {
            Way clippedWay;
            setData(clippedWay, way, solution.GetFirst()->Contour);
            elementStore_.storeImpl(clippedWay, *quadKeyPtr_);
        }
        // 4. in this case, result should be stored as relation (collection of ways)
        else {
            Relation relation;
            relation.id = way.id;
            relation.tags = way.tags;
            relation.elements.reserve(count);
            ClipperLib::PolyNode* polyNode = solution.GetFirst();
            while (polyNode) {
                std::shared_ptr<Way> clippedWay(new Way());
                clippedWay->id = way.id;
                setCoordinates(*clippedWay, polyNode->Contour);
                relation.elements.push_back(clippedWay);
                polyNode = polyNode->GetNext();
            }
            elementStore_.storeImpl(relation, *quadKeyPtr_);
        }
    }

    void visitArea(const Area& area)
    {
        ClipperLib::Path areaShape;
        PointLocation pointLocation = setPath(*quadKeyBboxPtr_, area, areaShape);
        // 1. all geometry inside current quadkey: no need to truncate.
        if (pointLocation == PointLocation::AllInside) {
            elementStore_.storeImpl(area, *quadKeyPtr_);
            return;
        }

        // 2. all geometry outside : pass empty
        if (pointLocation == PointLocation::AllOutside) {
            Area emptyArea;
            emptyArea.id = area.id;
            emptyArea.tags = area.tags;
            elementStore_.storeImpl(emptyArea, *quadKeyPtr_);
            return;
        }

        ClipperLib::Paths solution;
        clipper_.AddPath(areaShape, ClipperLib::ptSubject, true);
        clipper_.AddPath(createPathFromBoundingBox(), ClipperLib::ptClip, true);
        clipper_.Execute(ClipperLib::ctIntersection, solution);
        clipper_.Clear();

        // 3. way intersects border only once: store a copy with clipped geometry
        if (solution.size() == 1) {
            Area clippedArea;
            setData(clippedArea, area, solution[0]);
            elementStore_.storeImpl(clippedArea, *quadKeyPtr_);
        }
        // 4. in this case, result should be stored as relation (collection of areas)
        else {
            Relation relation;
            relation.id = area.id;
            relation.tags = area.tags;
            relation.elements.reserve(solution.size());
            for (auto it = solution.begin(); it != solution.end(); ++it) {
                std::shared_ptr<Area> clippedArea(new Area());
                clippedArea->id = area.id;
                setCoordinates(*clippedArea, *it);
                relation.elements.push_back(clippedArea);
            }
            elementStore_.storeImpl(relation, *quadKeyPtr_);
        }
    }

    void visitRelation(const Relation& relation)
    {
        struct RelationVisitor : public ElementVisitor
        {
            Relation data;

            RelationVisitor(const BoundingBox& quadKeyBbox, ClipperLib::Clipper& clipper) :
                bbox_(quadKeyBbox), clipper_(clipper) { }

            void visitNode(const Node& node)
            {
                if (bbox_.contains(node.coordinate)) {
                    data.elements.push_back(std::shared_ptr<Node>(new Node(node)));
                }
            }

            void visitWay(const Way& way)
            {
                ClipperLib::Path wayShape;
                ElementGeometryVisitor::setPath(bbox_, way, wayShape);
                clipper_.AddPath(wayShape, ClipperLib::ptSubject, false);
            }

            void visitArea(const Area& area)
            {
                ClipperLib::Path areaShape;
                ElementGeometryVisitor::setPath(bbox_, area, areaShape);
                clipper_.AddPath(areaShape, ClipperLib::ptSubject, true);
            }

            void visitRelation(const Relation& relation)
            {
                for (const auto& element : relation.elements) {
                    element->accept(*this);
                }
            }

        private:
            const BoundingBox& bbox_;
            ClipperLib::Clipper& clipper_;

        } visitor(*quadKeyBboxPtr_, clipper_);

        relation.accept(visitor);

        // Process results
        ClipperLib::PolyTree solution;
        clipper_.AddPath(createPathFromBoundingBox(), ClipperLib::ptClip, true);
        clipper_.Execute(ClipperLib::ctIntersection, solution);
        clipper_.Clear();

        int count = solution.Total();
        // Do not store one result as relation
        if (count == 1) {
            ClipperLib::PolyNode* node = solution.GetFirst();
            if (node->IsOpen()) {
                Way way;
                setData(way, relation, node->Contour);
                elementStore_.storeImpl(way, *quadKeyPtr_);
            }
            else {
                if (!node->IsHole()) {
                    Area area;
                    setData(area, relation, node->Contour);
                    elementStore_.storeImpl(area, *quadKeyPtr_);
                }
            }
        }
        else if (count > 1) {
            Relation newRelation;
            newRelation.id = relation.id;
            newRelation.tags = relation.tags;
            newRelation.elements.reserve(count);

            ClipperLib::PolyNode* polyNode = solution.GetFirst();
            while (polyNode) {
                if (polyNode->IsOpen()) {
                    std::shared_ptr<Way> way(new Way());
                    setCoordinates(*way, polyNode->Contour);
                    newRelation.elements.push_back(way);
                }
                else {
                    std::shared_ptr<Area> area(new Area());
                    setCoordinates(*area, polyNode->Contour);
                    newRelation.elements.push_back(area);
                }
                polyNode = polyNode->GetNext();
            }
            elementStore_.storeImpl(newRelation, *quadKeyPtr_);
        }
    }

    template<typename T>
    inline static PointLocation setPath(const BoundingBox& bbox, const T& t, ClipperLib::Path& shape) {
        shape.reserve(t.coordinates.size());
        bool allInside = false;
        bool allOutside = true;
        for (const GeoCoordinate& coord : t.coordinates) {
            bool contains = bbox.contains(coord);
            allInside &= contains;
            allOutside &= !contains;
            shape.push_back(ClipperLib::IntPoint(coord.longitude*Scale, coord.latitude*Scale));
        }

        return allInside ? PointLocation::AllInside :
              (allOutside ? PointLocation::AllOutside : PointLocation::Mixed);
    }

private:

    template<typename T>
    inline void setData(T& t, const Element& element, const ClipperLib::Path& path) {
        t.id = element.id;
        t.tags = element.tags;
        setCoordinates<T>(t, path);
    }

    template<typename T>
    inline void setCoordinates(T& t, const ClipperLib::Path& path) {
        t.coordinates.reserve(path.size());
        for (const auto& c : path) {
            t.coordinates.push_back(GeoCoordinate(c.Y / Scale, c.X / Scale));
        }
    }

    inline ClipperLib::Path createPathFromBoundingBox()
    {
        double xMin = quadKeyBboxPtr_->minPoint.longitude, yMin = quadKeyBboxPtr_->minPoint.latitude,
            xMax = quadKeyBboxPtr_->maxPoint.longitude, yMax = quadKeyBboxPtr_->maxPoint.latitude;
        ClipperLib::Path rect;
        rect.push_back(ClipperLib::IntPoint(xMin*Scale, yMin*Scale));
        rect.push_back(ClipperLib::IntPoint(xMax*Scale, yMin*Scale));
        rect.push_back(ClipperLib::IntPoint(xMax*Scale, yMax*Scale));
        rect.push_back(ClipperLib::IntPoint(xMin*Scale, yMax*Scale));
        return std::move(rect);
    }

    ElementStore& elementStore_;
    const QuadKey* quadKeyPtr_;
    const BoundingBox* quadKeyBboxPtr_;
    ClipperLib::Clipper clipper_;
};

ElementStore::ElementStore(StringTable& stringTable) : stringTable_(stringTable)
{
}

ElementStore::~ElementStore()
{
}

bool ElementStore::store(const Element& element, const utymap::index::LodRange& range, const StyleProvider& styleProvider)
{
    BoundingBoxVisitor bboxVisitor;
    bool wasStored = false;
    uint32_t clipKeyId = stringTable_.getId(ClipKey);
    for (int lod = range.start; lod <= range.end; ++lod) {
        // skip element for this lod
        if (!styleProvider.hasStyle(element, lod))
            continue;

        // initialize bounding box only once
        if (!bboxVisitor.boundingBox.isValid()) {
            element.accept(bboxVisitor);
        }

        Style style = styleProvider.forElement(element, lod);
        storeInTileRange(element, bboxVisitor.boundingBox, lod, style.has(clipKeyId));
        wasStored = true;
    }

    // NOTE still might be clipped and then skipped
    return wasStored;
}

void ElementStore::storeInTileRange(const Element& element, const BoundingBox& elementBbox, int levelOfDetails, bool shouldClip)
{
    ElementGeometryVisitor geometryClipper(*this);
    auto visitor = [&](const QuadKey& quadKey, const BoundingBox& quadKeyBbox) {
        if (shouldClip)
            geometryClipper.clipAndStore(element, quadKey, quadKeyBbox);
        else
            storeImpl(element, quadKey);
    };
    utymap::utils::GeoUtils::visitTileRange(elementBbox, levelOfDetails, visitor);
}

}}
<|endoftext|>


<commit_before>/**
 * @file
 */
#pragma once

#include "libbirch/FiberState.hpp"

namespace libbirch {
/**
 * Fiber.
 *
 * @ingroup libbirch
 *
 * @tparam YieldType Yield type.
 */
template<class YieldType>
class Fiber {
public:
  /**
   * Constructor.
   */
  Fiber(const Shared<FiberState<YieldType>>& state = nullptr);

  /**
   * Clone the fiber.
   */
  Fiber<YieldType> clone() const;

  /**
   * Freeze the fiber.
   */
  void freeze() const;

  /**
   * Get the context of the fiber state.
   */
  Context* getContext() const;

  /**
   * Run to next yield point.
   *
   * @return Was a value yielded?
   */
  bool query() const;

  /**
   * Get the last yield value.
   */
  YieldType get() const;

public:
  /**
   * Fiber state.
   */
  Shared<FiberState<YieldType>> state;
};
}

template<class YieldType>
libbirch::Fiber<YieldType>::Fiber(
    const Shared<FiberState<YieldType>>& state) :
    state(state) {
  //
}

template<class YieldType>
libbirch::Fiber<YieldType> libbirch::Fiber<YieldType>::clone() const {
  return Fiber<YieldType>(state.clone());
}

template<class YieldType>
void libbirch::Fiber<YieldType>::freeze() const {
  state.freeze();
}

template<class YieldType>
libbirch::Context* libbirch::Fiber<YieldType>::getContext() const {
  return state.getContext();
}

template<class YieldType>
bool libbirch::Fiber<YieldType>::query() const {
  bool result = false;
  if (state.query()) {
    result = state->query();
    if (!result) {
      const_cast<Fiber<YieldType>*>(this)->state = nullptr;  // fiber has finished, delete the state
    }
  }
  return result;
}

template<class YieldType>
YieldType libbirch::Fiber<YieldType>::get() const {
  libbirch_assert_msg_(state.query(), "fiber handle undefined");
  return state->get();
}
<commit_msg>Added finish() to Fiber.<commit_after>/**
 * @file
 */
#pragma once

#include "libbirch/FiberState.hpp"

namespace libbirch {
/**
 * Fiber.
 *
 * @ingroup libbirch
 *
 * @tparam YieldType Yield type.
 */
template<class YieldType>
class Fiber {
public:
  /**
   * Constructor.
   */
  Fiber(const Shared<FiberState<YieldType>>& state = nullptr);

  /**
   * Clone the fiber.
   */
  Fiber<YieldType> clone() const;

  /**
   * Freeze the fiber.
   */
  void freeze() const;

  /**
   * Finish the fiber.
   */
  void finish() const;

  /**
   * Get the context of the fiber state.
   */
  Context* getContext() const;

  /**
   * Run to next yield point.
   *
   * @return Was a value yielded?
   */
  bool query() const;

  /**
   * Get the last yield value.
   */
  YieldType get() const;

public:
  /**
   * Fiber state.
   */
  Shared<FiberState<YieldType>> state;
};
}

template<class YieldType>
libbirch::Fiber<YieldType>::Fiber(
    const Shared<FiberState<YieldType>>& state) :
    state(state) {
  //
}

template<class YieldType>
libbirch::Fiber<YieldType> libbirch::Fiber<YieldType>::clone() const {
  return Fiber<YieldType>(state.clone());
}

template<class YieldType>
void libbirch::Fiber<YieldType>::freeze() const {
  state.freeze();
}

template<class YieldType>
void libbirch::Fiber<YieldType>::finish() const {
  state.finish();
}

template<class YieldType>
libbirch::Context* libbirch::Fiber<YieldType>::getContext() const {
  return state.getContext();
}

template<class YieldType>
bool libbirch::Fiber<YieldType>::query() const {
  bool result = false;
  if (state.query()) {
    result = state->query();
    if (!result) {
      const_cast<Fiber<YieldType>*>(this)->state = nullptr;  // fiber has finished, delete the state
    }
  }
  return result;
}

template<class YieldType>
YieldType libbirch::Fiber<YieldType>::get() const {
  libbirch_assert_msg_(state.query(), "fiber handle undefined");
  return state->get();
}
<|endoftext|>


<commit_before>/*****************************************************************************
 * Copyright (C) 2011-2013 Michael Krufky
 *
 * Author: Michael Krufky <mkrufky@linuxtv.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#define DBG 0

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "functions.h"
#include "log.h"
#define CLASS_MODULE "desc"

#include "dvbpsi/dr_48.h" /* service descriptor */
#include "dvbpsi/dr_4d.h" /* short event descriptor */
#include "dvbpsi/dr_62.h" /* frequency list descriptor */
#include "dvbpsi/dr_83.h" /* LCN descriptor */

#include "desc.h"

#define dprintf(fmt, arg...) __dprintf(DBG_DESC, fmt, ##arg)

#define DT_Service                    0x48
#define DT_ShortEvent                 0x4d
#define DT_Teletext                   0x56
#define DT_FrequencyList              0x62
#define DT_LogicalChannelNumber       0x83

desc::desc()
//  : f_kill_thread(false)
{
	dprintf("()");
}

desc::~desc()
{
	dprintf("()");
}

bool desc::service(dvbpsi_descriptor_t* p_descriptor)
{
	if (p_descriptor->i_tag != DT_Service)
		return false;

	dvbpsi_service_dr_t* dr = dvbpsi_DecodeServiceDr(p_descriptor);

	get_descriptor_text(dr->i_service_provider_name, dr->i_service_provider_name_length, provider_name);
	get_descriptor_text(dr->i_service_name,          dr->i_service_name_length,          service_name);

	dprintf("%s, %s", provider_name, service_name);

	return true;
}

bool desc::short_event(dvbpsi_descriptor_t* p_descriptor)
{
	if (p_descriptor->i_tag != DT_ShortEvent)
		return false;

	dvbpsi_short_event_dr_t* dr = dvbpsi_DecodeShortEventDr(p_descriptor);

	memcpy(_4d.lang, dr->i_iso_639_code, 3);
	get_descriptor_text(dr->i_event_name, dr->i_event_name_length, _4d.name);
	get_descriptor_text(dr->i_text, dr->i_text_length, _4d.text);

	dprintf("%s, %s, %s", _4d.lang, _4d.name, _4d.text);

	return true;
}

bool desc::freq_list(dvbpsi_descriptor_t* p_descriptor)
{
	if (p_descriptor->i_tag != DT_FrequencyList)
		return false;

	dvbpsi_frequency_list_dr_t* dr = dvbpsi_DecodeFrequencyListDr(p_descriptor);
	for (int i = 0; i < dr->i_number_of_frequencies; ++i) {
#if 0
		= dr->p_center_frequencies[i]
#else
		dprintf("%d", dr->p_center_frequencies[i]);
#endif
	}
	return true;
}

bool desc::_lcn(dvbpsi_descriptor_t* p_descriptor)
{
	if (p_descriptor->i_tag != DT_LogicalChannelNumber)
		return false;

	dvbpsi_lcn_dr_t* dr = dvbpsi_DecodeLCNDr(p_descriptor);
	for (int i = 0; i < dr->i_number_of_entries; i ++) {
#if 0
		= lcn->p_entries[i].i_service_id;
		= lcn->p_entries[i].i_logical_channel_number;
#else
		lcn[dr->p_entries[i].i_service_id] = dr->p_entries[i].i_logical_channel_number;
		dprintf("%d, %d", dr->p_entries[i].i_service_id, lcn[dr->p_entries[i].i_service_id]);
#endif
	}

	return true;
}

void desc::decode(dvbpsi_descriptor_t* p_descriptor)
{
	while (p_descriptor) {
		switch (p_descriptor->i_tag) {
		case DT_Service:
			service(p_descriptor);
			break;
		case DT_ShortEvent:
			short_event(p_descriptor);
			break;
		case DT_FrequencyList:
			freq_list(p_descriptor);
			break;
		case DT_LogicalChannelNumber:
			_lcn(p_descriptor);
			break;
		default:
			dprintf("unknown descriptor tag: %02x", p_descriptor->i_tag);
			break;
		}
		p_descriptor = p_descriptor->p_next;
	}
}
<commit_msg>desc: don't process descriptor data if decoder failed<commit_after>/*****************************************************************************
 * Copyright (C) 2011-2013 Michael Krufky
 *
 * Author: Michael Krufky <mkrufky@linuxtv.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

#define DBG 0

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "functions.h"
#include "log.h"
#define CLASS_MODULE "desc"

#include "dvbpsi/dr_48.h" /* service descriptor */
#include "dvbpsi/dr_4d.h" /* short event descriptor */
#include "dvbpsi/dr_62.h" /* frequency list descriptor */
#include "dvbpsi/dr_83.h" /* LCN descriptor */

#include "desc.h"

#define dprintf(fmt, arg...) __dprintf(DBG_DESC, fmt, ##arg)

#define DT_Service                    0x48
#define DT_ShortEvent                 0x4d
#define DT_Teletext                   0x56
#define DT_FrequencyList              0x62
#define DT_LogicalChannelNumber       0x83

desc::desc()
//  : f_kill_thread(false)
{
	dprintf("()");
}

desc::~desc()
{
	dprintf("()");
}

bool desc::service(dvbpsi_descriptor_t* p_descriptor)
{
	if (p_descriptor->i_tag != DT_Service)
		return false;

	dvbpsi_service_dr_t* dr = dvbpsi_DecodeServiceDr(p_descriptor);
	if (!dr) return false;

	get_descriptor_text(dr->i_service_provider_name, dr->i_service_provider_name_length, provider_name);
	get_descriptor_text(dr->i_service_name,          dr->i_service_name_length,          service_name);

	dprintf("%s, %s", provider_name, service_name);

	return true;
}

bool desc::short_event(dvbpsi_descriptor_t* p_descriptor)
{
	if (p_descriptor->i_tag != DT_ShortEvent)
		return false;

	dvbpsi_short_event_dr_t* dr = dvbpsi_DecodeShortEventDr(p_descriptor);
	if (!dr) return false;

	memcpy(_4d.lang, dr->i_iso_639_code, 3);
	get_descriptor_text(dr->i_event_name, dr->i_event_name_length, _4d.name);
	get_descriptor_text(dr->i_text, dr->i_text_length, _4d.text);

	dprintf("%s, %s, %s", _4d.lang, _4d.name, _4d.text);

	return true;
}

bool desc::freq_list(dvbpsi_descriptor_t* p_descriptor)
{
	if (p_descriptor->i_tag != DT_FrequencyList)
		return false;

	dvbpsi_frequency_list_dr_t* dr = dvbpsi_DecodeFrequencyListDr(p_descriptor);
	if (!dr) return false;

	for (int i = 0; i < dr->i_number_of_frequencies; ++i) {
#if 0
		= dr->p_center_frequencies[i]
#else
		dprintf("%d", dr->p_center_frequencies[i]);
#endif
	}
	return true;
}

bool desc::_lcn(dvbpsi_descriptor_t* p_descriptor)
{
	if (p_descriptor->i_tag != DT_LogicalChannelNumber)
		return false;

	dvbpsi_lcn_dr_t* dr = dvbpsi_DecodeLCNDr(p_descriptor);
	if (!dr) return false;

	for (int i = 0; i < dr->i_number_of_entries; i ++) {
#if 0
		= lcn->p_entries[i].i_service_id;
		= lcn->p_entries[i].i_logical_channel_number;
#else
		lcn[dr->p_entries[i].i_service_id] = dr->p_entries[i].i_logical_channel_number;
		dprintf("%d, %d", dr->p_entries[i].i_service_id, lcn[dr->p_entries[i].i_service_id]);
#endif
	}

	return true;
}

void desc::decode(dvbpsi_descriptor_t* p_descriptor)
{
	while (p_descriptor) {
		switch (p_descriptor->i_tag) {
		case DT_Service:
			service(p_descriptor);
			break;
		case DT_ShortEvent:
			short_event(p_descriptor);
			break;
		case DT_FrequencyList:
			freq_list(p_descriptor);
			break;
		case DT_LogicalChannelNumber:
			_lcn(p_descriptor);
			break;
		default:
			dprintf("unknown descriptor tag: %02x", p_descriptor->i_tag);
			break;
		}
		p_descriptor = p_descriptor->p_next;
	}
}
<|endoftext|>


<commit_before>//
// Created by Nick on 27.03.16.
//

<commit_msg>Add some simple tests<commit_after>#include "gtest/gtest.h"
#include "jsrs.h"

TEST(jsrs_test, jsrs_test_dump_Test1) {
  jstp::JSRS t;
  EXPECT_EQ(t.dump(), "undefined");
}

TEST(jsrs_test, jsrs_test_dump_Test2) {
  jstp::JSRS t(nullptr);
  EXPECT_EQ(t.dump(), "null");
}

TEST(jsrs_test, jsrs_test_dump_Test3) {
  jstp::JSRS t(25.5);
  EXPECT_EQ(t.dump(), "25.5");
}

TEST(jsrs_test, jsrs_test_dump_Test4) {
  jstp::JSRS t(true);
  jstp::JSRS f(false);
  EXPECT_EQ(t.dump(), "true");
  EXPECT_EQ(f.dump(), "false");
}

TEST(jsrs_test, jsrs_test_dump_Test5) {
  jstp::JSRS t("test");
  EXPECT_EQ(t.dump(), "\"test\"");
}

TEST(jsrs_test, jsrs_test_dump_Test6) {
  char* str;
  str = "test";
  jstp::JSRS t(str);
  EXPECT_EQ(t.dump(), "\"test\"");
}

TEST(jsrs_test, jsrs_test_dump_Test7) {
  jstp::JSRS t1(25.5);
  jstp::JSRS t2(true);
  std::vector<jstp::JSRS> v;
  v.push_back(t1);
  v.push_back(t2);
  jstp::JSRS t(v);
  EXPECT_EQ(t.dump(), "[25.5,true]");
}

TEST(jsrs_test, jsrs_test_dump_Test8) {
  std::map<std::string, jstp::JSRS> m;
  jstp::JSRS t1(25.5);
  jstp::JSRS t2(true);
  jstp::JSRS t3("test");
  std::vector<jstp::JSRS> v;
  v.push_back(t1);
  v.push_back(t2);
  jstp::JSRS arr(v);
  m["test1"] = t1;
  m["test2"] = t2;
  m["test3"] = t3;
  m["arr"] = arr;
  jstp::JSRS t(m);
  EXPECT_EQ(t.dump(), "{arr:[25.5,true],test1:25.5,test2:true,test3:\"test\"}");
}

<|endoftext|>


<commit_before>#include "node_usb.h"

#define STRUCT_TO_V8(TARGET, STR, NAME) \
		TARGET->Set(V8STR(#NAME), Uint32::New((STR).NAME), CONST_PROP);

#define CHECK_OPEN() \
		if (!self->handle){THROW_ERROR("Device is not opened");}

Device::Device(libusb_device* d): device(d), handle(0) {
	libusb_ref_device(device);
	DEBUG_LOG("Created device %p", this);
}

Device::~Device(){
	DEBUG_LOG("Freed device %p", this);
	libusb_close(handle);
	libusb_unref_device(device);
}

// Map pinning each libusb_device to a particular V8 instance
std::map<libusb_device*, Persistent<Value> > Device::byPtr;

// Get a V8 instance for a libusb_device: either the existing one from the map,
// or create a new one and add it to the map.
Handle<Value> Device::get(libusb_device* dev){
	auto it = byPtr.find(dev);
	if (it != byPtr.end()){
		return it->second;
	}else{
		auto v = Persistent<Value>::New(pDevice.create(new Device(dev)));
		v.MakeWeak(dev, weakCallback);
		byPtr.insert(std::make_pair(dev, v));
		return v;
	}
}

// Callback to remove an instance from the cache map when V8 wants to GC it
void Device::weakCallback(Persistent<Value> object, void *parameter){
	byPtr.erase(static_cast<libusb_device*>(parameter));
	object.Dispose();
	object.Clear();
	DEBUG_LOG("Removed cached device %p", parameter);
}

static Handle<Value> deviceConstructor(const Arguments& args){
	ENTER_CONSTRUCTOR_POINTER(pDevice, 1);

	args.This()->Set(V8SYM("busNumber"),
		Uint32::New(libusb_get_bus_number(self->device)), CONST_PROP);
	args.This()->Set(V8SYM("deviceAddress"),
		Uint32::New(libusb_get_device_address(self->device)), CONST_PROP);

	Local<Object> v8dd = Object::New();
	args.This()->Set(V8SYM("deviceDescriptor"), v8dd, CONST_PROP);

	struct libusb_device_descriptor dd;
	CHECK_USB(libusb_get_device_descriptor(self->device, &dd));

	STRUCT_TO_V8(v8dd, dd, bLength)
	STRUCT_TO_V8(v8dd, dd, bDescriptorType)
	STRUCT_TO_V8(v8dd, dd, bcdUSB)
	STRUCT_TO_V8(v8dd, dd, bDeviceClass)
	STRUCT_TO_V8(v8dd, dd, bDeviceSubClass)
	STRUCT_TO_V8(v8dd, dd, bDeviceProtocol)
	STRUCT_TO_V8(v8dd, dd, bMaxPacketSize0)
	STRUCT_TO_V8(v8dd, dd, idVendor)
	STRUCT_TO_V8(v8dd, dd, idProduct)
	STRUCT_TO_V8(v8dd, dd, bcdDevice)
	STRUCT_TO_V8(v8dd, dd, iManufacturer)
	STRUCT_TO_V8(v8dd, dd, iProduct)
	STRUCT_TO_V8(v8dd, dd, iSerialNumber)
	STRUCT_TO_V8(v8dd, dd, bNumConfigurations)

	return scope.Close(args.This());
}

Handle<Value> Device_GetConfigDescriptor(const Arguments& args){
	ENTER_METHOD(pDevice, 0);

	libusb_config_descriptor* cdesc;
	CHECK_USB(libusb_get_active_config_descriptor(self->device, &cdesc));

	Local<Object> v8cdesc = Object::New();

	STRUCT_TO_V8(v8cdesc, *cdesc, bLength)
	STRUCT_TO_V8(v8cdesc, *cdesc, bDescriptorType)
	STRUCT_TO_V8(v8cdesc, *cdesc, wTotalLength)
	STRUCT_TO_V8(v8cdesc, *cdesc, bNumInterfaces)
	STRUCT_TO_V8(v8cdesc, *cdesc, bConfigurationValue)
	STRUCT_TO_V8(v8cdesc, *cdesc, iConfiguration)
	STRUCT_TO_V8(v8cdesc, *cdesc, bmAttributes)
	STRUCT_TO_V8(v8cdesc, *cdesc, MaxPower)
	//r->Set(V8STR("extra"), makeBuffer(cd.extra, cd.extra_length), CONST_PROP);

	Local<Array> v8interfaces = Array::New(cdesc->bNumInterfaces);
	v8cdesc->Set(V8SYM("interfaces"), v8interfaces);

	for (int idxInterface = 0; idxInterface < cdesc->bNumInterfaces; idxInterface++) {
		int numAltSettings = cdesc->interface[idxInterface].num_altsetting;

		Local<Array> v8altsettings = Array::New(numAltSettings);
		v8interfaces->Set(idxInterface, v8altsettings);

		for (int idxAltSetting = 0; idxAltSetting < numAltSettings; idxAltSetting++) {
			const libusb_interface_descriptor& idesc =
				cdesc->interface[idxInterface].altsetting[idxAltSetting];

			Local<Object> v8idesc = Object::New();
			v8altsettings->Set(idxAltSetting, v8idesc);

			STRUCT_TO_V8(v8idesc, idesc, bLength)
			STRUCT_TO_V8(v8idesc, idesc, bDescriptorType)
			STRUCT_TO_V8(v8idesc, idesc, bInterfaceNumber)
			STRUCT_TO_V8(v8idesc, idesc, bAlternateSetting)
			STRUCT_TO_V8(v8idesc, idesc, bNumEndpoints)
			STRUCT_TO_V8(v8idesc, idesc, bInterfaceClass)
			STRUCT_TO_V8(v8idesc, idesc, bInterfaceSubClass)
			STRUCT_TO_V8(v8idesc, idesc, bInterfaceProtocol)
			STRUCT_TO_V8(v8idesc, idesc, iInterface)
			// TODO: extra data

			Local<Array> v8endpoints = Array::New(idesc.bNumEndpoints);
			v8idesc->Set(V8SYM("endpoints"), v8endpoints, CONST_PROP);
			for (int idxEndpoint = 0; idxEndpoint < idesc.bNumEndpoints; idxEndpoint++){
				const libusb_endpoint_descriptor& edesc = idesc.endpoint[idxEndpoint];

				Local<Object> v8edesc = Object::New();
				v8endpoints->Set(idxEndpoint, v8edesc);

				STRUCT_TO_V8(v8edesc, edesc, bLength)
				STRUCT_TO_V8(v8edesc, edesc, bDescriptorType)
				STRUCT_TO_V8(v8edesc, edesc, bEndpointAddress)
				STRUCT_TO_V8(v8edesc, edesc, bmAttributes)
				STRUCT_TO_V8(v8edesc, edesc, bInterval)
				STRUCT_TO_V8(v8edesc, edesc, bRefresh)
				STRUCT_TO_V8(v8edesc, edesc, bSynchAddress)
			}
		}
	}

	libusb_free_config_descriptor(cdesc);
	return scope.Close(v8cdesc);
}

Handle<Value> Device_Open(const Arguments& args){
	ENTER_METHOD(pDevice, 0);
	if (!self->handle){
		CHECK_USB(libusb_open(self->device, &self->handle));
	}
	return scope.Close(Undefined());
}

Handle<Value> Device_Close(const Arguments& args){
	ENTER_METHOD(pDevice, 0);
	if (self->canClose()){
		libusb_close(self->handle);
		self->handle = NULL;
	}else{
		THROW_ERROR("Can't close device with a pending request");
	}
	return scope.Close(Undefined());
}

struct Req{
	uv_work_t req;
	Device* device;
	Persistent<Function> callback;
	int errcode;

	void submit(Device* d, Handle<Function> cb, uv_work_cb backend, uv_work_cb after){
		callback = Persistent<Function>::New(cb);
		device = d;
		device->ref();
		req.data = this;
		uv_queue_work(uv_default_loop(), &req, backend, (uv_after_work_cb) after);
	}

	static void default_after(uv_work_t *req){
		HandleScope scope;
		auto baton = (Req*) req->data;

		auto device = Local<Object>::New(baton->device->handle_);
		baton->device->unref();

		if (!baton->callback.IsEmpty()) {
			Handle<Value> error = Undefined();
			if (baton->errcode < 0){
				error = libusbException(baton->errcode);
			}
			Handle<Value> argv[1] = {error};
			TryCatch try_catch;
			baton->callback->Call(device, 1, argv);
			if (try_catch.HasCaught()) {
				FatalException(try_catch);
			}
			baton->callback.Dispose();
		}
		delete baton;
	}
};

struct Device_Reset: Req{
	static Handle<Value> begin(const Arguments& args){
		ENTER_METHOD(pDevice, 0);
		CHECK_OPEN();
		CALLBACK_ARG(0);
		auto baton = new Device_Reset;
		baton->submit(self, callback, &backend, &default_after);
		return scope.Close(Undefined());
	}

	static void backend(uv_work_t *req){
		auto baton = (Device_Reset*) req->data;
		baton->errcode = libusb_reset_device(baton->device->handle);
	}
};

Handle<Value> IsKernelDriverActive(const Arguments& args) {
	ENTER_METHOD(pDevice, 1);
	CHECK_OPEN();
	int interface;
	INT_ARG(interface, 0);
	int r = libusb_kernel_driver_active(self->handle, interface);
	CHECK_USB(r);
	return scope.Close(Boolean::New(r));
}

Handle<Value> DetachKernelDriver(const Arguments& args) {
	ENTER_METHOD(pDevice, 1);
	CHECK_OPEN();
	int interface;
	INT_ARG(interface, 0);
	CHECK_USB(libusb_detach_kernel_driver(self->handle, interface));
	return Undefined();
}

Handle<Value> AttachKernelDriver(const Arguments& args) {
	ENTER_METHOD(pDevice, 1);
	CHECK_OPEN();
	int interface;
	INT_ARG(interface, 0);
	CHECK_USB(libusb_attach_kernel_driver(self->handle, interface));
	return Undefined();
}

Handle<Value> Device_ClaimInterface(const Arguments& args) {
	ENTER_METHOD(pDevice, 1);
	CHECK_OPEN();
	int interface;
	INT_ARG(interface, 0);
	CHECK_USB(libusb_claim_interface(self->handle, interface));
	return Undefined();
}

struct Device_ReleaseInterface: Req{
	int interface;

	static Handle<Value> begin(const Arguments& args){
		ENTER_METHOD(pDevice, 1);
		CHECK_OPEN();
		int interface;
		INT_ARG(interface, 0);
		CALLBACK_ARG(1);
		auto baton = new Device_ReleaseInterface;
		baton->interface = interface;
		baton->submit(self, callback, &backend, &default_after);

		return scope.Close(Undefined());
	}

	static void backend(uv_work_t *req){
		auto baton = (Device_ReleaseInterface*) req->data;
		baton->errcode = libusb_release_interface(baton->device->handle, baton->interface);
	}
};

struct Device_SetInterface: Req{
	int interface;
	int altsetting;

	static Handle<Value> begin(const Arguments& args){
		ENTER_METHOD(pDevice, 2);
		CHECK_OPEN();
		int interface, altsetting;
		INT_ARG(interface, 0);
		INT_ARG(altsetting, 1);
		CALLBACK_ARG(2);
		auto baton = new Device_SetInterface;
		baton->interface = interface;
		baton->altsetting = altsetting;
		baton->submit(self, callback, &backend, &default_after);
		return scope.Close(Undefined());
	}

	static void backend(uv_work_t *req){
		auto baton = (Device_SetInterface*) req->data;
		baton->errcode = libusb_set_interface_alt_setting(
			baton->device->handle, baton->interface, baton->altsetting);
	}
};

static void init(Handle<Object> target){
	pDevice.init(&deviceConstructor);
	pDevice.addMethod("__getConfigDescriptor", Device_GetConfigDescriptor);
	pDevice.addMethod("__open", Device_Open);
	pDevice.addMethod("__close", Device_Close);
	pDevice.addMethod("reset", Device_Reset::begin);

	pDevice.addMethod("__claimInterface", Device_ClaimInterface);
	pDevice.addMethod("__releaseInterface", Device_ReleaseInterface::begin);
	pDevice.addMethod("__setInterface", Device_SetInterface::begin);

	pDevice.addMethod("__isKernelDriverActive", IsKernelDriverActive);
	pDevice.addMethod("__detachKernelDriver", DetachKernelDriver);
	pDevice.addMethod("__attachKernelDriver", AttachKernelDriver);
}

Proto<Device> pDevice("Device", &init);
<commit_msg>Expose endpoint descriptor's wMaxPacketSize.<commit_after>#include "node_usb.h"

#define STRUCT_TO_V8(TARGET, STR, NAME) \
		TARGET->Set(V8STR(#NAME), Uint32::New((STR).NAME), CONST_PROP);

#define CHECK_OPEN() \
		if (!self->handle){THROW_ERROR("Device is not opened");}

Device::Device(libusb_device* d): device(d), handle(0) {
	libusb_ref_device(device);
	DEBUG_LOG("Created device %p", this);
}

Device::~Device(){
	DEBUG_LOG("Freed device %p", this);
	libusb_close(handle);
	libusb_unref_device(device);
}

// Map pinning each libusb_device to a particular V8 instance
std::map<libusb_device*, Persistent<Value> > Device::byPtr;

// Get a V8 instance for a libusb_device: either the existing one from the map,
// or create a new one and add it to the map.
Handle<Value> Device::get(libusb_device* dev){
	auto it = byPtr.find(dev);
	if (it != byPtr.end()){
		return it->second;
	}else{
		auto v = Persistent<Value>::New(pDevice.create(new Device(dev)));
		v.MakeWeak(dev, weakCallback);
		byPtr.insert(std::make_pair(dev, v));
		return v;
	}
}

// Callback to remove an instance from the cache map when V8 wants to GC it
void Device::weakCallback(Persistent<Value> object, void *parameter){
	byPtr.erase(static_cast<libusb_device*>(parameter));
	object.Dispose();
	object.Clear();
	DEBUG_LOG("Removed cached device %p", parameter);
}

static Handle<Value> deviceConstructor(const Arguments& args){
	ENTER_CONSTRUCTOR_POINTER(pDevice, 1);

	args.This()->Set(V8SYM("busNumber"),
		Uint32::New(libusb_get_bus_number(self->device)), CONST_PROP);
	args.This()->Set(V8SYM("deviceAddress"),
		Uint32::New(libusb_get_device_address(self->device)), CONST_PROP);

	Local<Object> v8dd = Object::New();
	args.This()->Set(V8SYM("deviceDescriptor"), v8dd, CONST_PROP);

	struct libusb_device_descriptor dd;
	CHECK_USB(libusb_get_device_descriptor(self->device, &dd));

	STRUCT_TO_V8(v8dd, dd, bLength)
	STRUCT_TO_V8(v8dd, dd, bDescriptorType)
	STRUCT_TO_V8(v8dd, dd, bcdUSB)
	STRUCT_TO_V8(v8dd, dd, bDeviceClass)
	STRUCT_TO_V8(v8dd, dd, bDeviceSubClass)
	STRUCT_TO_V8(v8dd, dd, bDeviceProtocol)
	STRUCT_TO_V8(v8dd, dd, bMaxPacketSize0)
	STRUCT_TO_V8(v8dd, dd, idVendor)
	STRUCT_TO_V8(v8dd, dd, idProduct)
	STRUCT_TO_V8(v8dd, dd, bcdDevice)
	STRUCT_TO_V8(v8dd, dd, iManufacturer)
	STRUCT_TO_V8(v8dd, dd, iProduct)
	STRUCT_TO_V8(v8dd, dd, iSerialNumber)
	STRUCT_TO_V8(v8dd, dd, bNumConfigurations)

	return scope.Close(args.This());
}

Handle<Value> Device_GetConfigDescriptor(const Arguments& args){
	ENTER_METHOD(pDevice, 0);

	libusb_config_descriptor* cdesc;
	CHECK_USB(libusb_get_active_config_descriptor(self->device, &cdesc));

	Local<Object> v8cdesc = Object::New();

	STRUCT_TO_V8(v8cdesc, *cdesc, bLength)
	STRUCT_TO_V8(v8cdesc, *cdesc, bDescriptorType)
	STRUCT_TO_V8(v8cdesc, *cdesc, wTotalLength)
	STRUCT_TO_V8(v8cdesc, *cdesc, bNumInterfaces)
	STRUCT_TO_V8(v8cdesc, *cdesc, bConfigurationValue)
	STRUCT_TO_V8(v8cdesc, *cdesc, iConfiguration)
	STRUCT_TO_V8(v8cdesc, *cdesc, bmAttributes)
	STRUCT_TO_V8(v8cdesc, *cdesc, MaxPower)
	//r->Set(V8STR("extra"), makeBuffer(cd.extra, cd.extra_length), CONST_PROP);

	Local<Array> v8interfaces = Array::New(cdesc->bNumInterfaces);
	v8cdesc->Set(V8SYM("interfaces"), v8interfaces);

	for (int idxInterface = 0; idxInterface < cdesc->bNumInterfaces; idxInterface++) {
		int numAltSettings = cdesc->interface[idxInterface].num_altsetting;

		Local<Array> v8altsettings = Array::New(numAltSettings);
		v8interfaces->Set(idxInterface, v8altsettings);

		for (int idxAltSetting = 0; idxAltSetting < numAltSettings; idxAltSetting++) {
			const libusb_interface_descriptor& idesc =
				cdesc->interface[idxInterface].altsetting[idxAltSetting];

			Local<Object> v8idesc = Object::New();
			v8altsettings->Set(idxAltSetting, v8idesc);

			STRUCT_TO_V8(v8idesc, idesc, bLength)
			STRUCT_TO_V8(v8idesc, idesc, bDescriptorType)
			STRUCT_TO_V8(v8idesc, idesc, bInterfaceNumber)
			STRUCT_TO_V8(v8idesc, idesc, bAlternateSetting)
			STRUCT_TO_V8(v8idesc, idesc, bNumEndpoints)
			STRUCT_TO_V8(v8idesc, idesc, bInterfaceClass)
			STRUCT_TO_V8(v8idesc, idesc, bInterfaceSubClass)
			STRUCT_TO_V8(v8idesc, idesc, bInterfaceProtocol)
			STRUCT_TO_V8(v8idesc, idesc, iInterface)
			// TODO: extra data

			Local<Array> v8endpoints = Array::New(idesc.bNumEndpoints);
			v8idesc->Set(V8SYM("endpoints"), v8endpoints, CONST_PROP);
			for (int idxEndpoint = 0; idxEndpoint < idesc.bNumEndpoints; idxEndpoint++){
				const libusb_endpoint_descriptor& edesc = idesc.endpoint[idxEndpoint];

				Local<Object> v8edesc = Object::New();
				v8endpoints->Set(idxEndpoint, v8edesc);

				STRUCT_TO_V8(v8edesc, edesc, bLength)
				STRUCT_TO_V8(v8edesc, edesc, bDescriptorType)
				STRUCT_TO_V8(v8edesc, edesc, bEndpointAddress)
				STRUCT_TO_V8(v8edesc, edesc, bmAttributes)
				STRUCT_TO_V8(v8edesc, edesc, wMaxPacketSize)
				STRUCT_TO_V8(v8edesc, edesc, bInterval)
				STRUCT_TO_V8(v8edesc, edesc, bRefresh)
				STRUCT_TO_V8(v8edesc, edesc, bSynchAddress)
			}
		}
	}

	libusb_free_config_descriptor(cdesc);
	return scope.Close(v8cdesc);
}

Handle<Value> Device_Open(const Arguments& args){
	ENTER_METHOD(pDevice, 0);
	if (!self->handle){
		CHECK_USB(libusb_open(self->device, &self->handle));
	}
	return scope.Close(Undefined());
}

Handle<Value> Device_Close(const Arguments& args){
	ENTER_METHOD(pDevice, 0);
	if (self->canClose()){
		libusb_close(self->handle);
		self->handle = NULL;
	}else{
		THROW_ERROR("Can't close device with a pending request");
	}
	return scope.Close(Undefined());
}

struct Req{
	uv_work_t req;
	Device* device;
	Persistent<Function> callback;
	int errcode;

	void submit(Device* d, Handle<Function> cb, uv_work_cb backend, uv_work_cb after){
		callback = Persistent<Function>::New(cb);
		device = d;
		device->ref();
		req.data = this;
		uv_queue_work(uv_default_loop(), &req, backend, (uv_after_work_cb) after);
	}

	static void default_after(uv_work_t *req){
		HandleScope scope;
		auto baton = (Req*) req->data;

		auto device = Local<Object>::New(baton->device->handle_);
		baton->device->unref();

		if (!baton->callback.IsEmpty()) {
			Handle<Value> error = Undefined();
			if (baton->errcode < 0){
				error = libusbException(baton->errcode);
			}
			Handle<Value> argv[1] = {error};
			TryCatch try_catch;
			baton->callback->Call(device, 1, argv);
			if (try_catch.HasCaught()) {
				FatalException(try_catch);
			}
			baton->callback.Dispose();
		}
		delete baton;
	}
};

struct Device_Reset: Req{
	static Handle<Value> begin(const Arguments& args){
		ENTER_METHOD(pDevice, 0);
		CHECK_OPEN();
		CALLBACK_ARG(0);
		auto baton = new Device_Reset;
		baton->submit(self, callback, &backend, &default_after);
		return scope.Close(Undefined());
	}

	static void backend(uv_work_t *req){
		auto baton = (Device_Reset*) req->data;
		baton->errcode = libusb_reset_device(baton->device->handle);
	}
};

Handle<Value> IsKernelDriverActive(const Arguments& args) {
	ENTER_METHOD(pDevice, 1);
	CHECK_OPEN();
	int interface;
	INT_ARG(interface, 0);
	int r = libusb_kernel_driver_active(self->handle, interface);
	CHECK_USB(r);
	return scope.Close(Boolean::New(r));
}

Handle<Value> DetachKernelDriver(const Arguments& args) {
	ENTER_METHOD(pDevice, 1);
	CHECK_OPEN();
	int interface;
	INT_ARG(interface, 0);
	CHECK_USB(libusb_detach_kernel_driver(self->handle, interface));
	return Undefined();
}

Handle<Value> AttachKernelDriver(const Arguments& args) {
	ENTER_METHOD(pDevice, 1);
	CHECK_OPEN();
	int interface;
	INT_ARG(interface, 0);
	CHECK_USB(libusb_attach_kernel_driver(self->handle, interface));
	return Undefined();
}

Handle<Value> Device_ClaimInterface(const Arguments& args) {
	ENTER_METHOD(pDevice, 1);
	CHECK_OPEN();
	int interface;
	INT_ARG(interface, 0);
	CHECK_USB(libusb_claim_interface(self->handle, interface));
	return Undefined();
}

struct Device_ReleaseInterface: Req{
	int interface;

	static Handle<Value> begin(const Arguments& args){
		ENTER_METHOD(pDevice, 1);
		CHECK_OPEN();
		int interface;
		INT_ARG(interface, 0);
		CALLBACK_ARG(1);
		auto baton = new Device_ReleaseInterface;
		baton->interface = interface;
		baton->submit(self, callback, &backend, &default_after);

		return scope.Close(Undefined());
	}

	static void backend(uv_work_t *req){
		auto baton = (Device_ReleaseInterface*) req->data;
		baton->errcode = libusb_release_interface(baton->device->handle, baton->interface);
	}
};

struct Device_SetInterface: Req{
	int interface;
	int altsetting;

	static Handle<Value> begin(const Arguments& args){
		ENTER_METHOD(pDevice, 2);
		CHECK_OPEN();
		int interface, altsetting;
		INT_ARG(interface, 0);
		INT_ARG(altsetting, 1);
		CALLBACK_ARG(2);
		auto baton = new Device_SetInterface;
		baton->interface = interface;
		baton->altsetting = altsetting;
		baton->submit(self, callback, &backend, &default_after);
		return scope.Close(Undefined());
	}

	static void backend(uv_work_t *req){
		auto baton = (Device_SetInterface*) req->data;
		baton->errcode = libusb_set_interface_alt_setting(
			baton->device->handle, baton->interface, baton->altsetting);
	}
};

static void init(Handle<Object> target){
	pDevice.init(&deviceConstructor);
	pDevice.addMethod("__getConfigDescriptor", Device_GetConfigDescriptor);
	pDevice.addMethod("__open", Device_Open);
	pDevice.addMethod("__close", Device_Close);
	pDevice.addMethod("reset", Device_Reset::begin);

	pDevice.addMethod("__claimInterface", Device_ClaimInterface);
	pDevice.addMethod("__releaseInterface", Device_ReleaseInterface::begin);
	pDevice.addMethod("__setInterface", Device_SetInterface::begin);

	pDevice.addMethod("__isKernelDriverActive", IsKernelDriverActive);
	pDevice.addMethod("__detachKernelDriver", DetachKernelDriver);
	pDevice.addMethod("__attachKernelDriver", AttachKernelDriver);
}

Proto<Device> pDevice("Device", &init);
<|endoftext|>


<commit_before>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * 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.
 *****************************************************************************/

/**
 * @file dp_st_cost.cc
 **/

#include "modules/planning/tasks/dp_st_speed/dp_st_cost.h"

#include <limits>

#include "modules/planning/common/speed/st_point.h"

namespace apollo {
namespace planning {
namespace {
constexpr double kInf = std::numeric_limits<double>::infinity();
}

DpStCost::DpStCost(const DpStSpeedConfig& config,
                   const std::vector<const PathObstacle*>& obstacles,
                   const common::TrajectoryPoint& init_point)
    : config_(config),
      obstacles_(obstacles),
      init_point_(init_point),
      unit_s_(config_.total_path_length() / config_.matrix_dimension_s()),
      unit_t_(config_.total_time() / config_.matrix_dimension_t()),
      unit_v_(unit_s_ / unit_t_) {}

double DpStCost::GetObstacleCost(const StGraphPoint& st_graph_point) const {
  const double s = st_graph_point.point().s();
  const double t = st_graph_point.point().t();

  double cost = 0.0;
  for (const auto* obstacle : obstacles_) {
    auto boundary = obstacle->st_boundary();
    const double kIgnoreDistance = 200.0;
    if (boundary.min_s() > kIgnoreDistance) {
      continue;
    }
    if (t < boundary.min_t() || t > boundary.max_t()) {
      continue;
    }
    if (obstacle->IsBlockingObstacle() &&
        boundary.IsPointInBoundary(STPoint(s, t))) {
      return kInf;
    }
    double s_upper = 0.0;
    double s_lower = 0.0;
    boundary.GetBoundarySRange(t, &s_upper, &s_lower);
    if (s < s_lower) {
      constexpr double kSafeTimeBuffer = 3.0;
      const double len = obstacle->obstacle()->Speed() * kSafeTimeBuffer;
      if (s + len < s_lower) {
        continue;
      } else {
        cost += config_.obstacle_weight() * config_.default_obstacle_cost() *
                std::pow((len - s_lower + s), 2);
      }
    } else if (s > s_upper) {
      const double kSafeDistance = 20.0;  // or calculated from velocity
      if (s > s_upper + kSafeDistance) {
        continue;
      } else {
        cost += config_.obstacle_weight() *
                std::pow((kSafeDistance + s_upper - s), 2);
      }
    }
  }
  return cost * unit_t_;
}

double DpStCost::GetReferenceCost(const STPoint& point,
                                  const STPoint& reference_point) const {
  return config_.reference_weight() * (point.s() - reference_point.s()) *
         (point.s() - reference_point.s()) * unit_t_;
}

double DpStCost::GetSpeedCost(const STPoint& first, const STPoint& second,
                              const double speed_limit) const {
  double cost = 0.0;
  const double speed = (second.s() - first.s()) / unit_t_;
  if (speed < 0) {
    return kInf;
  }
  double det_speed = (speed - speed_limit) / speed_limit;
  if (det_speed > 0) {
    cost = config_.exceed_speed_penalty() * config_.default_speed_cost() *
           fabs(speed * speed) * unit_t_;
  } else if (det_speed < 0) {
    cost = config_.low_speed_penalty() * config_.default_speed_cost() *
           -det_speed * unit_t_;
  } else {
    cost = 0.0;
  }
  return cost;
}

double DpStCost::GetAccelCost(const double accel) const {
  const double accel_sq = accel * accel;
  double max_acc = config_.max_acceleration();
  double max_dec = config_.max_deceleration();
  double accel_penalty = config_.accel_penalty();
  double decel_penalty = config_.decel_penalty();
  double cost = 0.0;
  if (accel > 0.0) {
    cost = accel_penalty * accel_sq;
  } else {
    cost = decel_penalty * accel_sq;
  }
  cost += accel_sq * decel_penalty * decel_penalty /
              (1 + std::exp(1.0 * (accel - max_dec))) +
          accel_sq * accel_penalty * accel_penalty /
              (1 + std::exp(-1.0 * (accel - max_acc)));
  return cost * unit_t_;
}

double DpStCost::GetAccelCostByThreePoints(const STPoint& first,
                                           const STPoint& second,
                                           const STPoint& third) const {
  double accel = (first.s() + third.s() - 2 * second.s()) / (unit_t_ * unit_t_);
  return GetAccelCost(accel);
}

double DpStCost::GetAccelCostByTwoPoints(const double pre_speed,
                                         const STPoint& pre_point,
                                         const STPoint& curr_point) const {
  double current_speed = (curr_point.s() - pre_point.s()) / unit_t_;
  double accel = (current_speed - pre_speed) / unit_t_;
  return GetAccelCost(accel);
}

double DpStCost::JerkCost(const double jerk) const {
  double jerk_sq = jerk * jerk;
  double cost = 0.0;
  if (jerk > 0) {
    cost = config_.positive_jerk_coeff() * jerk_sq * unit_t_;
  } else {
    cost = config_.negative_jerk_coeff() * jerk_sq * unit_t_;
  }
  return cost;
}

double DpStCost::GetJerkCostByFourPoints(const STPoint& first,
                                         const STPoint& second,
                                         const STPoint& third,
                                         const STPoint& fourth) const {
  double jerk = (fourth.s() - 3 * third.s() + 3 * second.s() - first.s()) /
                (unit_t_ * unit_t_ * unit_t_);
  return JerkCost(jerk);
}

double DpStCost::GetJerkCostByTwoPoints(const double pre_speed,
                                        const double pre_acc,
                                        const STPoint& pre_point,
                                        const STPoint& curr_point) const {
  const double curr_speed = (curr_point.s() - pre_point.s()) / unit_t_;
  const double curr_accel = (curr_speed - pre_speed) / unit_t_;
  const double jerk = (curr_accel - pre_acc) / unit_t_;
  return JerkCost(jerk);
}

double DpStCost::GetJerkCostByThreePoints(const double first_speed,
                                          const STPoint& first,
                                          const STPoint& second,
                                          const STPoint& third) const {
  const double pre_speed = (second.s() - first.s()) / unit_t_;
  const double pre_acc = (pre_speed - first_speed) / unit_t_;
  const double curr_speed = (third.s() - second.s()) / unit_t_;
  const double curr_acc = (curr_speed - pre_speed) / unit_t_;
  const double jerk = (curr_acc - pre_acc) / unit_t_;
  return JerkCost(jerk);
}

}  // namespace planning
}  // namespace apollo
<commit_msg>Planning: added default obstacle cost for overtake. (#2207)<commit_after>/******************************************************************************
 * Copyright 2017 The Apollo Authors. All Rights Reserved.
 *
 * 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.
 *****************************************************************************/

/**
 * @file dp_st_cost.cc
 **/

#include "modules/planning/tasks/dp_st_speed/dp_st_cost.h"

#include <limits>

#include "modules/planning/common/speed/st_point.h"

namespace apollo {
namespace planning {
namespace {
constexpr double kInf = std::numeric_limits<double>::infinity();
}

DpStCost::DpStCost(const DpStSpeedConfig& config,
                   const std::vector<const PathObstacle*>& obstacles,
                   const common::TrajectoryPoint& init_point)
    : config_(config),
      obstacles_(obstacles),
      init_point_(init_point),
      unit_s_(config_.total_path_length() / config_.matrix_dimension_s()),
      unit_t_(config_.total_time() / config_.matrix_dimension_t()),
      unit_v_(unit_s_ / unit_t_) {}

double DpStCost::GetObstacleCost(const StGraphPoint& st_graph_point) const {
  const double s = st_graph_point.point().s();
  const double t = st_graph_point.point().t();

  double cost = 0.0;
  for (const auto* obstacle : obstacles_) {
    auto boundary = obstacle->st_boundary();
    const double kIgnoreDistance = 200.0;
    if (boundary.min_s() > kIgnoreDistance) {
      continue;
    }
    if (t < boundary.min_t() || t > boundary.max_t()) {
      continue;
    }
    if (obstacle->IsBlockingObstacle() &&
        boundary.IsPointInBoundary(STPoint(s, t))) {
      return kInf;
    }
    double s_upper = 0.0;
    double s_lower = 0.0;
    boundary.GetBoundarySRange(t, &s_upper, &s_lower);
    if (s < s_lower) {
      constexpr double kSafeTimeBuffer = 3.0;
      const double len = obstacle->obstacle()->Speed() * kSafeTimeBuffer;
      if (s + len < s_lower) {
        continue;
      } else {
        cost += config_.obstacle_weight() * config_.default_obstacle_cost() *
                std::pow((len - s_lower + s), 2);
      }
    } else if (s > s_upper) {
      const double kSafeDistance = 20.0;  // or calculated from velocity
      if (s > s_upper + kSafeDistance) {
        continue;
      } else {
        cost += config_.obstacle_weight() * config_.default_obstacle_cost() *
                std::pow((kSafeDistance + s_upper - s), 2);
      }
    }
  }
  return cost * unit_t_;
}

double DpStCost::GetReferenceCost(const STPoint& point,
                                  const STPoint& reference_point) const {
  return config_.reference_weight() * (point.s() - reference_point.s()) *
         (point.s() - reference_point.s()) * unit_t_;
}

double DpStCost::GetSpeedCost(const STPoint& first, const STPoint& second,
                              const double speed_limit) const {
  double cost = 0.0;
  const double speed = (second.s() - first.s()) / unit_t_;
  if (speed < 0) {
    return kInf;
  }
  double det_speed = (speed - speed_limit) / speed_limit;
  if (det_speed > 0) {
    cost = config_.exceed_speed_penalty() * config_.default_speed_cost() *
           fabs(speed * speed) * unit_t_;
  } else if (det_speed < 0) {
    cost = config_.low_speed_penalty() * config_.default_speed_cost() *
           -det_speed * unit_t_;
  } else {
    cost = 0.0;
  }
  return cost;
}

double DpStCost::GetAccelCost(const double accel) const {
  const double accel_sq = accel * accel;
  double max_acc = config_.max_acceleration();
  double max_dec = config_.max_deceleration();
  double accel_penalty = config_.accel_penalty();
  double decel_penalty = config_.decel_penalty();
  double cost = 0.0;
  if (accel > 0.0) {
    cost = accel_penalty * accel_sq;
  } else {
    cost = decel_penalty * accel_sq;
  }
  cost += accel_sq * decel_penalty * decel_penalty /
              (1 + std::exp(1.0 * (accel - max_dec))) +
          accel_sq * accel_penalty * accel_penalty /
              (1 + std::exp(-1.0 * (accel - max_acc)));
  return cost * unit_t_;
}

double DpStCost::GetAccelCostByThreePoints(const STPoint& first,
                                           const STPoint& second,
                                           const STPoint& third) const {
  double accel = (first.s() + third.s() - 2 * second.s()) / (unit_t_ * unit_t_);
  return GetAccelCost(accel);
}

double DpStCost::GetAccelCostByTwoPoints(const double pre_speed,
                                         const STPoint& pre_point,
                                         const STPoint& curr_point) const {
  double current_speed = (curr_point.s() - pre_point.s()) / unit_t_;
  double accel = (current_speed - pre_speed) / unit_t_;
  return GetAccelCost(accel);
}

double DpStCost::JerkCost(const double jerk) const {
  double jerk_sq = jerk * jerk;
  double cost = 0.0;
  if (jerk > 0) {
    cost = config_.positive_jerk_coeff() * jerk_sq * unit_t_;
  } else {
    cost = config_.negative_jerk_coeff() * jerk_sq * unit_t_;
  }
  return cost;
}

double DpStCost::GetJerkCostByFourPoints(const STPoint& first,
                                         const STPoint& second,
                                         const STPoint& third,
                                         const STPoint& fourth) const {
  double jerk = (fourth.s() - 3 * third.s() + 3 * second.s() - first.s()) /
                (unit_t_ * unit_t_ * unit_t_);
  return JerkCost(jerk);
}

double DpStCost::GetJerkCostByTwoPoints(const double pre_speed,
                                        const double pre_acc,
                                        const STPoint& pre_point,
                                        const STPoint& curr_point) const {
  const double curr_speed = (curr_point.s() - pre_point.s()) / unit_t_;
  const double curr_accel = (curr_speed - pre_speed) / unit_t_;
  const double jerk = (curr_accel - pre_acc) / unit_t_;
  return JerkCost(jerk);
}

double DpStCost::GetJerkCostByThreePoints(const double first_speed,
                                          const STPoint& first,
                                          const STPoint& second,
                                          const STPoint& third) const {
  const double pre_speed = (second.s() - first.s()) / unit_t_;
  const double pre_acc = (pre_speed - first_speed) / unit_t_;
  const double curr_speed = (third.s() - second.s()) / unit_t_;
  const double curr_acc = (curr_speed - pre_speed) / unit_t_;
  const double jerk = (curr_acc - pre_acc) / unit_t_;
  return JerkCost(jerk);
}

}  // namespace planning
}  // namespace apollo
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2006 The Regents of The University of Michigan
 * 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;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * 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
 * OWNER 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.
 *
 * Authors: Ali Saidi
 */

#ifndef __BASE_COMPILER_HH__
#define __BASE_COMPILER_HH__

// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html

#if defined(__GNUC__) // clang or gcc
#  define M5_ATTR_NORETURN  __attribute__((noreturn))
#  define M5_DUMMY_RETURN
#  define M5_VAR_USED __attribute__((unused))
#  define M5_ATTR_PACKED __attribute__ ((__packed__))
#  define M5_NO_INLINE __attribute__ ((__noinline__))
#  define M5_DEPRECATED __attribute__((deprecated))
#  define M5_DEPRECATED_MSG(MSG) __attribute__((deprecated(MSG)))
#endif

#if defined(__clang__)
#  define M5_CLASS_VAR_USED M5_VAR_USED
#else
#  define M5_CLASS_VAR_USED
#endif

#endif // __BASE_COMPILER_HH__
<commit_msg>base: Defining make_unique for C++11<commit_after>/*
 * Copyright (c) 2012,2017 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2006 The Regents of The University of Michigan
 * 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;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * 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
 * OWNER 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.
 *
 * Authors: Ali Saidi
 */

#ifndef __BASE_COMPILER_HH__
#define __BASE_COMPILER_HH__

#include <memory>

// http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html

#if defined(__GNUC__) // clang or gcc
#  define M5_ATTR_NORETURN  __attribute__((noreturn))
#  define M5_DUMMY_RETURN
#  define M5_VAR_USED __attribute__((unused))
#  define M5_ATTR_PACKED __attribute__ ((__packed__))
#  define M5_NO_INLINE __attribute__ ((__noinline__))
#  define M5_DEPRECATED __attribute__((deprecated))
#  define M5_DEPRECATED_MSG(MSG) __attribute__((deprecated(MSG)))
#endif

#if defined(__clang__)
#  define M5_CLASS_VAR_USED M5_VAR_USED
#else
#  define M5_CLASS_VAR_USED
#endif

// std::make_unique redefined for C++11 compilers
namespace m5
{

#if __cplusplus == 201402L // C++14

using std::make_unique;

#else // C++11

/** Defining custom version of make_unique: m5::make_unique<>() */
template<typename T, typename... Args>
std::unique_ptr<T>
make_unique( Args&&... constructor_args )
{
    return std::unique_ptr<T>(
               new T( std::forward<Args>(constructor_args)... )
           );
}

#endif // __cplusplus == 201402L

} //namespace m5

#endif // __BASE_COMPILER_HH__
<|endoftext|>


<commit_before>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#if defined(HAVE_CONFIG_H)
#include <config/gridcoin-config.h>
#endif

#include <util/time.h>

#include <atomic>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread.hpp>
#include <ctime>
#include <tinyformat.h>
#include <inttypes.h>

#include "logging.h"

static int64_t nMockTime = 0;  // For unit testing

int64_t GetTime()
{
    if (nMockTime) return nMockTime;

    return time(nullptr);
}

int64_t GetMockTime()
{
    return nMockTime;
}

void SetMockTime(int64_t nMockTimeIn)
{
    nMockTime = nMockTimeIn;
}

template <typename T>
T GetTime()
{
    const std::chrono::seconds mocktime(nMockTime);

    return std::chrono::duration_cast<T>(
        mocktime.count() ?
            mocktime :
            std::chrono::microseconds{GetTimeMicros()});
}
template std::chrono::seconds GetTime();
template std::chrono::milliseconds GetTime();
template std::chrono::microseconds GetTime();

int64_t GetTimeMillis()
{
    int64_t now = (boost::posix_time::microsec_clock::universal_time() -
                   boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_milliseconds();
    assert(now > 0);
    return now;
}

int64_t GetTimeMicros()
{
    int64_t now = (boost::posix_time::microsec_clock::universal_time() -
                   boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_microseconds();
    assert(now > 0);
    return now;
}

int64_t GetSystemTimeInSeconds()
{
    return GetTimeMicros()/1000000;
}

void MilliTimer::InitTimer(const std::string& label, bool log)
{
    internal_timer timer;

    timer.start_time = GetTimeMillis();
    timer.checkpoint_time = timer.start_time;
    timer.log = log;

    LOCK(cs_timer_map_lock);

    // the [] either creates a new timer with the label or replaces an existing one.
    timer_map[label] = timer;
}

bool MilliTimer::DeleteTimer(const std::string& label)
{
    bool delete_status = false;

    LOCK(cs_timer_map_lock);

    if (timer_map.find(label) != timer_map.end())
    {
        timer_map.erase(label);

        delete_status = true;
    }

    return delete_status;
}

bool MilliTimer::LogTimer(const std::string& label, bool log)
{
    LOCK(cs_timer_map_lock);

    auto it = timer_map.find(label);

    if (it != timer_map.end())
    {
        it->second.log = log;
        return true;
    }

    return false;
}

int64_t MilliTimer::GetStartTime(const std::string& label)
{
    internal_timer internal_timer;

    try
    {

        LOCK(cs_timer_map_lock);

        // This will throw an internal exception if the entry specified by label doesn't exist.
        internal_timer = timer_map.at(label);
    }
    catch (std::out_of_range) {}

    return internal_timer.start_time;
}

const MilliTimer::timer MilliTimer::GetTimes(const std::string& log_string, const std::string& label)
{
    internal_timer internal_timer;
    timer timer;

    try
    {
        LOCK(cs_timer_map_lock);

        // This will throw an internal exception if the entry specified by label doesn't exist.
        internal_timer = timer_map.at(label);

        int64_t current_time = GetTimeMillis();

        timer.elapsed_time = current_time - internal_timer.start_time;
        timer.time_since_last_check = current_time - internal_timer.checkpoint_time;

        internal_timer.checkpoint_time = current_time;

        //Because of the exception guard above the map entry can be updated with [].
        timer_map[label] = internal_timer;
    }
    catch (std::out_of_range)
    {
        //Re-initialize timer if internal exception is thrown.
        timer = {};
        return timer;
    }

    // Only log if no exception above, and also done after the release of the lock on the map to
    // minimize lock time.
    if (internal_timer.log)
    {
        LogPrintf("timer %s: %s: elapsed time: %" PRId64 " ms, time since last check: %" PRId64 " ms.",
                  label, log_string, timer.elapsed_time, timer.time_since_last_check);
    }

    return timer;
}

int64_t MilliTimer::GetElapsedTime(const std::string& log_string, const std::string& label)
{
    return GetTimes(log_string, label).elapsed_time;
}

// Create global timer instance.
MilliTimer g_timer;

void MilliSleep(int64_t n)
{

/**
 * Boost's sleep_for was uninterruptible when backed by nanosleep from 1.50
 * until fixed in 1.52. Use the deprecated sleep method for the broken case.
 * See: https://svn.boost.org/trac/boost/ticket/7238
 */
#if defined(HAVE_WORKING_BOOST_SLEEP_FOR)
    boost::this_thread::sleep_for(boost::chrono::milliseconds(n));
#elif defined(HAVE_WORKING_BOOST_SLEEP)
    boost::this_thread::sleep(boost::posix_time::milliseconds(n));
#else
//should never get here
#error missing boost sleep implementation
#endif
}

std::string FormatISO8601DateTime(int64_t nTime) {
    struct tm ts;
    time_t time_val = nTime;
#ifdef HAVE_GMTIME_R
    if (gmtime_r(&time_val, &ts) == nullptr) {
#else
    if (gmtime_s(&ts, &time_val) != 0) {
#endif
        return {};
    }
    return strprintf("%04i-%02i-%02iT%02i:%02i:%02iZ", ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday, ts.tm_hour, ts.tm_min, ts.tm_sec);
}

std::string FormatISO8601Date(int64_t nTime) {
    struct tm ts;
    time_t time_val = nTime;
#ifdef HAVE_GMTIME_R
    if (gmtime_r(&time_val, &ts) == nullptr) {
#else
    if (gmtime_s(&ts, &time_val) != 0) {
#endif
        return {};
    }
    return strprintf("%04i-%02i-%02i", ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday);
}

int64_t ParseISO8601DateTime(const std::string& str)
{
    static const boost::posix_time::ptime epoch = boost::posix_time::from_time_t(0);
    static const std::locale loc(std::locale::classic(),
        new boost::posix_time::time_input_facet("%Y-%m-%dT%H:%M:%SZ"));
    std::istringstream iss(str);
    iss.imbue(loc);
    boost::posix_time::ptime ptime(boost::date_time::not_a_date_time);
    iss >> ptime;
    if (ptime.is_not_a_date_time() || epoch > ptime)
        return 0;
    return (ptime - epoch).total_seconds();
}
<commit_msg>Tweak exception handling in MilliTimer class to eliminate compiler warnings<commit_after>// Copyright (c) 2009-2010 Satoshi Nakamoto
// Copyright (c) 2009-2019 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#if defined(HAVE_CONFIG_H)
#include <config/gridcoin-config.h>
#endif

#include <util/time.h>

#include <atomic>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread.hpp>
#include <ctime>
#include <tinyformat.h>
#include <inttypes.h>

#include "logging.h"

static int64_t nMockTime = 0;  // For unit testing

int64_t GetTime()
{
    if (nMockTime) return nMockTime;

    return time(nullptr);
}

int64_t GetMockTime()
{
    return nMockTime;
}

void SetMockTime(int64_t nMockTimeIn)
{
    nMockTime = nMockTimeIn;
}

template <typename T>
T GetTime()
{
    const std::chrono::seconds mocktime(nMockTime);

    return std::chrono::duration_cast<T>(
        mocktime.count() ?
            mocktime :
            std::chrono::microseconds{GetTimeMicros()});
}
template std::chrono::seconds GetTime();
template std::chrono::milliseconds GetTime();
template std::chrono::microseconds GetTime();

int64_t GetTimeMillis()
{
    int64_t now = (boost::posix_time::microsec_clock::universal_time() -
                   boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_milliseconds();
    assert(now > 0);
    return now;
}

int64_t GetTimeMicros()
{
    int64_t now = (boost::posix_time::microsec_clock::universal_time() -
                   boost::posix_time::ptime(boost::gregorian::date(1970,1,1))).total_microseconds();
    assert(now > 0);
    return now;
}

int64_t GetSystemTimeInSeconds()
{
    return GetTimeMicros()/1000000;
}

void MilliTimer::InitTimer(const std::string& label, bool log)
{
    internal_timer timer;

    timer.start_time = GetTimeMillis();
    timer.checkpoint_time = timer.start_time;
    timer.log = log;

    LOCK(cs_timer_map_lock);

    // the [] either creates a new timer with the label or replaces an existing one.
    timer_map[label] = timer;
}

bool MilliTimer::DeleteTimer(const std::string& label)
{
    bool delete_status = false;

    LOCK(cs_timer_map_lock);

    if (timer_map.find(label) != timer_map.end())
    {
        timer_map.erase(label);

        delete_status = true;
    }

    return delete_status;
}

bool MilliTimer::LogTimer(const std::string& label, bool log)
{
    LOCK(cs_timer_map_lock);

    auto it = timer_map.find(label);

    if (it != timer_map.end())
    {
        it->second.log = log;
        return true;
    }

    return false;
}

int64_t MilliTimer::GetStartTime(const std::string& label)
{
    internal_timer internal_timer;

    try
    {
        LOCK(cs_timer_map_lock);

        // This will throw an internal exception if the entry specified by label doesn't exist.
        internal_timer = timer_map.at(label);
    }
    catch (std::out_of_range&) {
        LogPrintf("WARNING: %s: Timer with specified label does not exist. Returning zero start time.");
    }

    return internal_timer.start_time;
}

const MilliTimer::timer MilliTimer::GetTimes(const std::string& log_string, const std::string& label)
{
    internal_timer internal_timer;
    timer timer;

    try
    {
        LOCK(cs_timer_map_lock);

        // This will throw an internal exception if the entry specified by label doesn't exist.
        internal_timer = timer_map.at(label);

        int64_t current_time = GetTimeMillis();

        timer.elapsed_time = current_time - internal_timer.start_time;
        timer.time_since_last_check = current_time - internal_timer.checkpoint_time;

        internal_timer.checkpoint_time = current_time;

        //Because of the exception guard above the map entry can be updated with [].
        timer_map[label] = internal_timer;
    }
    catch (std::out_of_range&)
    {
        LogPrintf("WARNING: %s: Timer with specified label does not exist. Returning zeroed timer.");
        timer = {};
        return timer;
    }

    // Only log if no exception above, and also done after the release of the lock on the map to
    // minimize lock time.
    if (internal_timer.log)
    {
        LogPrintf("timer %s: %s: elapsed time: %" PRId64 " ms, time since last check: %" PRId64 " ms.",
                  label, log_string, timer.elapsed_time, timer.time_since_last_check);
    }

    return timer;
}

int64_t MilliTimer::GetElapsedTime(const std::string& log_string, const std::string& label)
{
    return GetTimes(log_string, label).elapsed_time;
}

// Create global timer instance.
MilliTimer g_timer;

void MilliSleep(int64_t n)
{

/**
 * Boost's sleep_for was uninterruptible when backed by nanosleep from 1.50
 * until fixed in 1.52. Use the deprecated sleep method for the broken case.
 * See: https://svn.boost.org/trac/boost/ticket/7238
 */
#if defined(HAVE_WORKING_BOOST_SLEEP_FOR)
    boost::this_thread::sleep_for(boost::chrono::milliseconds(n));
#elif defined(HAVE_WORKING_BOOST_SLEEP)
    boost::this_thread::sleep(boost::posix_time::milliseconds(n));
#else
//should never get here
#error missing boost sleep implementation
#endif
}

std::string FormatISO8601DateTime(int64_t nTime) {
    struct tm ts;
    time_t time_val = nTime;
#ifdef HAVE_GMTIME_R
    if (gmtime_r(&time_val, &ts) == nullptr) {
#else
    if (gmtime_s(&ts, &time_val) != 0) {
#endif
        return {};
    }
    return strprintf("%04i-%02i-%02iT%02i:%02i:%02iZ", ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday, ts.tm_hour, ts.tm_min, ts.tm_sec);
}

std::string FormatISO8601Date(int64_t nTime) {
    struct tm ts;
    time_t time_val = nTime;
#ifdef HAVE_GMTIME_R
    if (gmtime_r(&time_val, &ts) == nullptr) {
#else
    if (gmtime_s(&ts, &time_val) != 0) {
#endif
        return {};
    }
    return strprintf("%04i-%02i-%02i", ts.tm_year + 1900, ts.tm_mon + 1, ts.tm_mday);
}

int64_t ParseISO8601DateTime(const std::string& str)
{
    static const boost::posix_time::ptime epoch = boost::posix_time::from_time_t(0);
    static const std::locale loc(std::locale::classic(),
        new boost::posix_time::time_input_facet("%Y-%m-%dT%H:%M:%SZ"));
    std::istringstream iss(str);
    iss.imbue(loc);
    boost::posix_time::ptime ptime(boost::date_time::not_a_date_time);
    iss >> ptime;
    if (ptime.is_not_a_date_time() || epoch > ptime)
        return 0;
    return (ptime - epoch).total_seconds();
}
<|endoftext|>