<commit_before>#pragma once

#include <limits>
#include <algorithm>
#include <vector>
#include <map>
#include <functional>
#include <unordered_map>
#include <unordered_set>
#include <string>
#include "priority_queue.hpp"

using std::max;
using std::make_pair;
using std::min;
using std::abs;
using std::hypot;
using std::vector;
using std::map;
using std::function;
using std::unordered_map;
using std::unordered_set;
using std::string;
using std::to_string;
using std::hash;

namespace search
{
    //
    //  Lifelong planning
    //
    namespace lp
    {
        constexpr auto infinity()
        {
            return std::numeric_limits<int>::max();
        }
        constexpr auto cost()
        {
            return 1;
        }

        struct Coordinate
        {
            int x, y;

            friend auto operator== (Coordinate l, Coordinate r)
            {
                return l.x == r.x && l.y == r.y;
            }
            friend auto operator!= (Coordinate l, Coordinate r)
            {
                return !(l == r);
            }

            auto to_string() const
            {
                using std::to_string;
                return string{ "[x = " + to_string(x) + ", y = " + to_string(y) + "]" };
            }
            auto to_hash() const
            {
                return hash<string>{}(to_string());
            }

            auto neighbours() const
            {
                struct Directions : public map< char, function< Coordinate(Coordinate) >>
                {
                    Directions()
                    {
                        (*this)['1'] = [](Coordinate c) { return Coordinate{ c.x - 1, c.y - 1 }; };
                        (*this)['2'] = [](Coordinate c) { return Coordinate{ c.x - 0, c.y - 1 }; };
                        (*this)['3'] = [](Coordinate c) { return Coordinate{ c.x + 1, c.y - 1 }; };
                        (*this)['4'] = [](Coordinate c) { return Coordinate{ c.x - 1, c.y - 0 }; };
                        (*this)['5'] = [](Coordinate c) { return Coordinate{ c.x + 1, c.y + 0 }; };
                        (*this)['6'] = [](Coordinate c) { return Coordinate{ c.x - 1, c.y + 1 }; };
                        (*this)['7'] = [](Coordinate c) { return Coordinate{ c.x - 0, c.y + 1 }; };
                        (*this)['8'] = [](Coordinate c) { return Coordinate{ c.x + 1, c.y + 1 }; };
                    }
                } static const directions;

                vector<Coordinate> result;
                for (auto n = '1'; n != '9'; ++n)
                    result.push_back(directions.at(n)(*this));
                return result;
            }
        };
    }
}

namespace std
{
    using namespace search::lp;
    template<>
    struct hash<Coordinate>
    {
        auto operator()(Coordinate c) const
        {
            return c.to_hash();
        }
    };
}

namespace search
{
    namespace lp
    {
        struct LpState
        {
            Coordinate coordinate;
            int g, r;
            bool is_blocked;
            friend auto operator==(LpState const& l, LpState const& r)
            {
                return l.coordinate == r.coordinate && l.g == r.g && l.r == r.r && l.is_blocked == r.is_blocked;
            }
        };

        class Matrix
        {
        public:
            Matrix(unsigned height, unsigned width)
                : _data{ height, vector<LpState>(width) }
            {
                for (auto y = 0; y != height; ++y)
                {
                    for (auto x = 0; x != width; ++x)
                    {
                        Coordinate curr{ x, y };
                        at(curr).coordinate = curr;
                        at(curr).g = at(curr).r = infinity();
                    }
                }
            }

            auto at(Coordinate c) -> LpState&
            {
                return{ _data[c.y][c.x] };
            }
            auto at(Coordinate c) const -> LpState const&
            {
                return{ _data[c.y][c.x] };
            }

            auto rows() const
            {
                return _data.size();
            }
            auto cols() const
            {
                return _data.front().size();
            }

        private:
            vector<vector<LpState>> _data;
        };

        struct HeuristcFuncs : public unordered_map < string, function<int(Coordinate, Coordinate)> >
        {
            HeuristcFuncs()
            {
                (*this)["manhattan"] =
                    [](Coordinate curr, Coordinate goal)
                {
                    return max(abs(goal.x - curr.x), abs(goal.y - curr.y));
                };
                (*this)["euclidean"] =
                    [](Coordinate curr, Coordinate goal)
                {
                    return static_cast<int>(round(hypot(abs(goal.x - curr.x), abs(goal.y - curr.y))));
                };
            }
        };

        struct Key
        {
            const int first, second;

            Key(int fst, int snd)
                : first{ fst }, second{ snd }
            {   }
            Key(LpState s, function<int(Coordinate, Coordinate)> h, Coordinate g)
                : Key{ min(s.g, s.r + h(s.coordinate, g)), min(s.g, s.r) }
            {   }

            friend auto operator== (Key l, Key r)
            {
                return l.first == r.first && l.second == r.second;
            }
            friend auto operator < (Key l, Key r)
            {
                return (l.first < r.first) || (l.first == r.first && l.second < r.second);
            }
        };
        //
        //  Lifelong A*
        //
        class LpAstarCore
        {
            auto initialize()
            {
                q.reset();
                matrix.at(start).r = 0;
                q.push(matrix.at(start));
            }

            auto update_vertex(LpState& s)
            {
                if (s.coordinate != start)
                {
                    auto minimum = infinity();
                    for (auto n : s.coordinate.neighbours())
                    {
                        auto& vertex = matrix.at(n);
                        if (!vertex.is_blocked)
                            minimum = min(minimum, (vertex.g + cost()));
                    }
                    s.r = minimum;
                }
                q.remove(s);
                if (s.g != s.r) q.push(s);
            }

            auto compute_shortest_path()
            {
                auto top_key = [this] { return q.empty() ? Key{ infinity(), infinity() } : Key{ q.top(), h, goal };  };

                while (top_key() < Key{ matrix.at(goal), h, goal } || matrix.at(goal).r != matrix.at(goal).g)
                {
                    auto c = q.pop().coordinate;
                    if (matrix.at(c).g > matrix.at(c).r)
                    {
                        matrix.at(c).g = matrix.at(c).r;
                        for (auto n : c.neighbours())
                            if (!matrix.at(n).is_blocked)
                                update_vertex(matrix.at(n));
                    }
                    else
                    {
                        matrix.at(c).g = infinity();
                        for (auto n : c.neighbours())
                            if (!matrix.at(n).is_blocked)
                                update_vertex(matrix.at(n));
                        update_vertex(matrix.at(c));
                    }
                }
            }

        public:
            //
            //  Constructor
            //
            LpAstarCore(unsigned rows, unsigned cols, Coordinate start, Coordinate goal, string heuristic, unordered_set<Coordinate> const& blockeds):
                heuristics{},
                matrix{ rows, cols },
                start{ start },
                goal{ goal },
                h{ heuristics.at(heuristic) },
                q{ [&](LpState const& lft, LpState const& rht) { return Key{ lft, h, goal } < Key{ rht, h, goal }; } }
            {
                for (auto blocked : blockeds)
                    matrix.at(blocked).is_blocked = true;
            }

            auto operator()()
            {
                initialize();
                compute_shortest_path();
            }

            HeuristcFuncs const heuristics;
            Matrix matrix;
            Coordinate const start, goal;
            function<int(Coordinate, Coordinate)> const h;
            PriorityQueue < LpState, function<bool(LpState, LpState)>> q;
        };
    }
}//end of namespace search<commit_msg>polish<commit_after>#pragma once

#include <limits>
#include <algorithm>
#include <vector>
#include <map>
#include <functional>
#include <unordered_map>
#include <unordered_set>
#include <string>
#include "priority_queue.hpp"

using std::max;
using std::make_pair;
using std::min;
using std::abs;
using std::hypot;
using std::vector;
using std::map;
using std::function;
using std::unordered_map;
using std::unordered_set;
using std::string;
using std::to_string;
using std::hash;

namespace search
{
    //
    //  Lifelong planning
    //
    namespace lp
    {
        constexpr auto infinity()
        {
            return std::numeric_limits<int>::max();
        }
        constexpr auto cost()
        {
            return 1;
        }

        struct Coordinate
        {
            int x, y;

            friend auto operator== (Coordinate l, Coordinate r)
            {
                return l.x == r.x && l.y == r.y;
            }
            friend auto operator!= (Coordinate l, Coordinate r)
            {
                return !(l == r);
            }

            auto to_string() const
            {
                using std::to_string;
                return string{ "[x = " + to_string(x) + ", y = " + to_string(y) + "]" };
            }
            auto to_hash() const
            {
                return hash<string>{}(to_string());
            }

            auto neighbours() const
            {
                struct Directions : public map< char, function< Coordinate(Coordinate) >>
                {
                    Directions()
                    {
                        (*this)['1'] = [](Coordinate c) { return Coordinate{ c.x - 1, c.y - 1 }; };
                        (*this)['2'] = [](Coordinate c) { return Coordinate{ c.x - 0, c.y - 1 }; };
                        (*this)['3'] = [](Coordinate c) { return Coordinate{ c.x + 1, c.y - 1 }; };
                        (*this)['4'] = [](Coordinate c) { return Coordinate{ c.x - 1, c.y - 0 }; };
                        (*this)['5'] = [](Coordinate c) { return Coordinate{ c.x + 1, c.y + 0 }; };
                        (*this)['6'] = [](Coordinate c) { return Coordinate{ c.x - 1, c.y + 1 }; };
                        (*this)['7'] = [](Coordinate c) { return Coordinate{ c.x - 0, c.y + 1 }; };
                        (*this)['8'] = [](Coordinate c) { return Coordinate{ c.x + 1, c.y + 1 }; };
                    }
                } static const directions;

                vector<Coordinate> result;
                for (auto n = '1'; n != '9'; ++n)
                    result.push_back(directions.at(n)(*this));
                return result;
            }
        };
    }
}

namespace std
{
    using namespace search::lp;
    template<>
    struct hash<Coordinate>
    {
        auto operator()(Coordinate c) const
        {
            return c.to_hash();
        }
    };
}

namespace search
{
    namespace lp
    {
        struct LpState
        {
            Coordinate coordinate;
            int g, r;
            bool is_blocked;
            friend auto operator==(LpState const& l, LpState const& r)
            {
                return l.coordinate == r.coordinate && l.g == r.g && l.r == r.r && l.is_blocked == r.is_blocked;
            }
        };

        class Matrix
        {
        public:
            Matrix(unsigned height, unsigned width)
                : _data{ height, vector<LpState>(width) }
            {
                for (auto y = 0; y != height; ++y)
                {
                    for (auto x = 0; x != width; ++x)
                    {
                        Coordinate curr{ x, y };
                        at(curr).coordinate = curr;
                        at(curr).g = at(curr).r = infinity();
                    }
                }
            }

            auto at(Coordinate c) -> LpState&
            {
                return{ _data[c.y][c.x] };
            }
            auto at(Coordinate c) const -> LpState const&
            {
                return{ _data[c.y][c.x] };
            }

            auto rows() const
            {
                return _data.size();
            }
            auto cols() const
            {
                return _data.front().size();
            }

        private:
            vector<vector<LpState>> _data;
        };

        struct HeuristcFuncs : public unordered_map < string, function<int(Coordinate, Coordinate)> >
        {
            HeuristcFuncs()
            {
                (*this)["manhattan"] =
                    [](Coordinate curr, Coordinate goal)
                {
                    return max(abs(goal.x - curr.x), abs(goal.y - curr.y));
                };
                (*this)["euclidean"] =
                    [](Coordinate curr, Coordinate goal)
                {
                    return static_cast<int>(round(hypot(abs(goal.x - curr.x), abs(goal.y - curr.y))));
                };
            }
        };

        struct Key
        {
            const int first, second;

            Key(int fst, int snd)
                : first{ fst }, second{ snd }
            {   }
            Key(LpState s, function<int(Coordinate, Coordinate)> h, Coordinate g)
                : Key{ min(s.g, s.r + h(s.coordinate, g)), min(s.g, s.r) }
            {   }

            friend auto operator== (Key l, Key r)
            {
                return l.first == r.first && l.second == r.second;
            }
            friend auto operator < (Key l, Key r)
            {
                return (l.first < r.first) || (l.first == r.first && l.second < r.second);
            }
        };
        //
        //  Lifelong A*
        //
        class LpAstarCore
        {
            auto initialize()
            {
                q.reset();
                matrix.at(start).r = 0;
                q.push(matrix.at(start));
            }

            auto update_vertex(LpState& s)
            {
                if (s.coordinate != start)
                {
                    auto minimum = infinity();
                    for (auto n : s.coordinate.neighbours())
                    {
                        auto& vertex = matrix.at(n);
                        if (!vertex.is_blocked)
                            minimum = min(minimum, (vertex.g + cost()));
                    }
                    s.r = minimum;
                }
                q.remove(s);
                if (s.g != s.r) q.push(s);
            }

            auto compute_shortest_path()
            {
                auto top_key = [this] { return q.empty() ? Key{ infinity(), infinity() } : Key{ q.top(), h, goal };  };

                while (top_key() < Key{ matrix.at(goal), h, goal } || matrix.at(goal).r != matrix.at(goal).g)
                {
                    auto c = q.pop().coordinate;
                    if (matrix.at(c).g > matrix.at(c).r)
                    {
                        matrix.at(c).g = matrix.at(c).r;
                        for (auto n : c.neighbours())
                            if (!matrix.at(n).is_blocked)
                                update_vertex(matrix.at(n));
                    }
                    else
                    {
                        matrix.at(c).g = infinity();
                        for (auto n : c.neighbours())
                            if (!matrix.at(n).is_blocked)
                                update_vertex(matrix.at(n));
                        update_vertex(matrix.at(c));
                    }
                }
            }

        public:
            //
            //  Constructor
            //
            LpAstarCore(unsigned rows, unsigned cols, Coordinate start, Coordinate goal, string heuristic, unordered_set<Coordinate> const& blockeds) :
                heuristics{},
                matrix{ rows, cols },
                start{ start },
                goal{ goal },
                h{ heuristics.at(heuristic) },
                q{ [&](LpState const& lft, LpState const& rht) { return Key{ lft, h, goal } < Key{ rht, h, goal }; } }
            {
                for (auto blocked : blockeds)
                    matrix.at(blocked).is_blocked = true;
            }

            auto operator()()
            {
                initialize();
                compute_shortest_path();
            }

            HeuristcFuncs const heuristics;
            Matrix matrix;
            Coordinate const start, goal;
            function<int(Coordinate, Coordinate)> const h;
            PriorityQueue < LpState, function<bool(LpState, LpState)> > q;
        };
    }
}//end of namespace search<|endoftext|>


<commit_before>#include <QtGui/QOpenGLFramebufferObject>
#include <QtQuick/QQuickWindow>
#include "visualizationmanager.h"
#include "coverage.h"
#include "layersview.h"
#include "layersrenderer.h"
#include "rootdrawer.h"
#include "uicontextmodel.h"

#include <QtGui/QOpenGLFramebufferObject>

#include <QtQuick/QQuickWindow>
#include <qsgsimpletexturenode.h>

quint64 LayersView::_baseViewerId = 0;

LayersView::LayersView()
{
    _viewerId = _baseViewerId++;
    uicontext()->addViewer(this, _viewerId);
}

LayersView::~LayersView()
{
    uicontext()->removeViewer(_viewerId)    ;
}

QQuickFramebufferObject::Renderer *LayersView::createRenderer() const
{
    return new LayersRenderer(this);
}

void LayersView::addCommand(const QString &command, const QVariantMap &params)
{

}

void LayersView::setAttribute(const QString &drawercode, const QVariantMap &values)
{
    _attributeQueue.push_back(std::pair<QString, QVariantMap>(drawercode, values));

}

void LayersView::copyAttribute(const QString &drawercode, const QString &attrName)
{
    _attributerequests.push_back(std::pair<QString, QString>(drawercode, attrName));
}

QString LayersView::attributeOfDrawer(const QString &drawercode, const QString &attrName)
{
    try {
        Ilwis::Geodrawer::RootDrawer *rootdrawer = rootDrawer();
        if ( !rootdrawer)
            return "";

        QVariant var = rootdrawer->attributeOfDrawer(drawercode, attrName);
        if ( !var.isValid())
            return "";
        QString result = var.toString();
        if ( result != "")
            return result;
        QString tpName = var.typeName();
        if ( tpName == "Ilwis::Envelope"){
            Envelope env = var.value<Envelope>();
            QString result = env.toString();
            return result;
        }
        if ( tpName == "Ilwis::BoundingBox"){
            auto bb = var.value<BoundingBox>();
            return bb.toString();
        }

        return "";
    } catch ( const ErrorObject&){

    } catch ( std::exception& ex){

    }
    return "";
}

void LayersView::addCommand(const QString &expression)
{
    OperationExpression expr(expression);
    if ( expr.isValid()){
        _commands.push_front(expr);
    }
}

void LayersView::setManager(LayerManager *manager)
{
    _manager = manager;
}

QString LayersView::layerInfo(const QString& pixelpair) const
{
    try {
        if ( _manager){
            QStringList parts = pixelpair.split("|");
            if ( parts.size() == 2){
                Ilwis::Coordinate crd = rootDrawer()->pixel2Coord(Ilwis::Pixel(parts[0].toDouble(), parts[1].toDouble()));
                return _manager->layerInfo(crd);
            }
        }
        return "";
    }
    catch(const ErrorObject& ){}
    catch(const std::exception& ex){
        kernel()->issues()->log(ex.what());
    }
    return "";
}

LayerManager *LayersView::layerManager()
{
    return _manager;
}

bool LayersView::showLayerInfo() const
{
    return _showLayerInfo;
}

void LayersView::setShowLayerInfo(bool yesno)
{
    _showLayerInfo = yesno;
    emit showLayerInfoChanged();
}

QString LayersView::viewerId() const
{
    return QString::number(_viewerId);
}

Geodrawer::RootDrawer *LayersView::rootDrawer() const
{
    if ( !_manager)
        return 0;
    CoverageLayerModel *layer = _manager->layer(1); // layer 0 is the global layer, no 'real' drawer there
    if ( !layer)
        return 0;
    return layer->drawer()->rootDrawer();
}

QString LayersView::currentCoordinate() const
{
    if ( rootDrawer() && rootDrawer()->coordinateSystem().isValid()){
        if ( rootDrawer()->coordinateSystem()->isLatLon()){
            return _currentCoordinate.toString(6);
        }
    }
    return _currentCoordinate.toString();
}

void LayersView::setCurrentCoordinate(const QString &var)
{
    if ( var != ""){
        QStringList parts = var.split("|");
        if ( rootDrawer() && parts.size() == 2){
            _currentCoordinate = rootDrawer()->pixel2Coord(Ilwis::Pixel(parts[0].toDouble(), parts[1].toDouble()));
            emit currentCoordinateHasChanged();
        }
    }
}

QString LayersView::currentLatLon() const
{
    if ( rootDrawer() && rootDrawer()->coordinateSystem().isValid()){
        if ( rootDrawer()->coordinateSystem()->isLatLon()){
            LatLon ll(_currentCoordinate.y, _currentCoordinate.x);
            return ll.toString();
        }
        else if ( rootDrawer()->coordinateSystem()->canConvertToLatLon())
            return rootDrawer()->coordinateSystem()->coord2latlon(_currentCoordinate).toString();
    }
    return "";
}

<commit_msg>renamed include file<commit_after>#include <QtGui/QOpenGLFramebufferObject>
#include <QtQuick/QQuickWindow>
#include "layermanager.h"
#include "coverage.h"
#include "layersview.h"
#include "layersrenderer.h"
#include "rootdrawer.h"
#include "uicontextmodel.h"

#include <QtGui/QOpenGLFramebufferObject>

#include <QtQuick/QQuickWindow>
#include <qsgsimpletexturenode.h>

quint64 LayersView::_baseViewerId = 0;

LayersView::LayersView()
{
    _viewerId = _baseViewerId++;
    uicontext()->addViewer(this, _viewerId);
}

LayersView::~LayersView()
{
    uicontext()->removeViewer(_viewerId)    ;
}

QQuickFramebufferObject::Renderer *LayersView::createRenderer() const
{
    return new LayersRenderer(this);
}

void LayersView::addCommand(const QString &command, const QVariantMap &params)
{

}

void LayersView::setAttribute(const QString &drawercode, const QVariantMap &values)
{
    _attributeQueue.push_back(std::pair<QString, QVariantMap>(drawercode, values));

}

void LayersView::copyAttribute(const QString &drawercode, const QString &attrName)
{
    _attributerequests.push_back(std::pair<QString, QString>(drawercode, attrName));
}

QString LayersView::attributeOfDrawer(const QString &drawercode, const QString &attrName)
{
    try {
        Ilwis::Geodrawer::RootDrawer *rootdrawer = rootDrawer();
        if ( !rootdrawer)
            return "";

        QVariant var = rootdrawer->attributeOfDrawer(drawercode, attrName);
        if ( !var.isValid())
            return "";
        QString result = var.toString();
        if ( result != "")
            return result;
        QString tpName = var.typeName();
        if ( tpName == "Ilwis::Envelope"){
            Envelope env = var.value<Envelope>();
            QString result = env.toString();
            return result;
        }
        if ( tpName == "Ilwis::BoundingBox"){
            auto bb = var.value<BoundingBox>();
            return bb.toString();
        }

        return "";
    } catch ( const ErrorObject&){

    } catch ( std::exception& ex){

    }
    return "";
}

void LayersView::addCommand(const QString &expression)
{
    OperationExpression expr(expression);
    if ( expr.isValid()){
        _commands.push_back(expr);
    }
}

void LayersView::setManager(LayerManager *manager)
{
    _manager = manager;
}

QString LayersView::layerInfo(const QString& pixelpair) const
{
    try {
        if ( _manager){
            QStringList parts = pixelpair.split("|");
            if ( parts.size() == 2 && rootDrawer()){
                Ilwis::Coordinate crd = rootDrawer()->pixel2Coord(Ilwis::Pixel(parts[0].toDouble(), parts[1].toDouble()));
                return _manager->layerInfo(crd);
            }
        }
        return "";
    }
    catch(const ErrorObject& ){}
    catch(const std::exception& ex){
        kernel()->issues()->log(ex.what());
    }
    return "";
}

QVariantMap LayersView::envelope()
{
    QVariantMap vmap;
    Geodrawer::RootDrawer *root = rootDrawer();
    if ( root){
        _manager->setScreenGeoReference(root->screenGrf());
        Envelope zoomenv = root->zoomEnvelope();
        vmap["minx"] = zoomenv.min_corner().x;
        vmap["miny"] = zoomenv.min_corner().y;
        vmap["maxx"] = zoomenv.max_corner().x;
        vmap["maxy"] = zoomenv.max_corner().y;
    }

    return vmap;
}

LayerManager *LayersView::layerManager()
{
    return _manager;
}

bool LayersView::showLayerInfo() const
{
    return _showLayerInfo;
}

void LayersView::setShowLayerInfo(bool yesno)
{
    _showLayerInfo = yesno;
    emit showLayerInfoChanged();
}

QString LayersView::viewerId() const
{
    return QString::number(_viewerId);
}

Geodrawer::RootDrawer *LayersView::rootDrawer() const
{
    if ( !_manager)
        return 0;
    CoverageLayerModel *layer = _manager->layer(1); // layer 0 is the global layer, no 'real' drawer there
    if ( !layer)
        return 0;
    return layer->drawer()->rootDrawer();
}

QString LayersView::currentCoordinate() const
{
    if ( rootDrawer() && rootDrawer()->coordinateSystem().isValid()){
        if ( rootDrawer()->coordinateSystem()->isLatLon()){
            return _currentCoordinate.toString(6);
        }
    }
    return _currentCoordinate.toString();
}

void LayersView::setCurrentCoordinate(const QString &var)
{
    if ( var != ""){
        QStringList parts = var.split("|");
        if ( rootDrawer() && parts.size() == 2){
            _currentCoordinate = rootDrawer()->pixel2Coord(Ilwis::Pixel(parts[0].toDouble(), parts[1].toDouble()));
            emit currentCoordinateHasChanged();
        }
    }
}

QString LayersView::currentLatLon() const
{
    if ( rootDrawer() && rootDrawer()->coordinateSystem().isValid()){
        if ( rootDrawer()->coordinateSystem()->isLatLon()){
            LatLon ll(_currentCoordinate.y, _currentCoordinate.x);
            return ll.toString();
        }
        else if ( rootDrawer()->coordinateSystem()->canConvertToLatLon())
            return rootDrawer()->coordinateSystem()->coord2latlon(_currentCoordinate).toString();
    }
    return "";
}

<|endoftext|>


<commit_before>/*
    Copyright (C) 2001 by Christopher Nelson

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"

#include "awstest_config.h"

#ifdef TEST_AWS2

#include "csutil/sysfunc.h"
#include "csutil/cscolor.h"
#include "csutil/csevent.h"
#include "csutil/event.h"

#include "cstool/csfxscr.h"
#include "cstool/csview.h"
#include "cstool/initapp.h"
#include "csutil/cmdhelp.h"
#include "ivideo/graph3d.h"
#include "ivideo/fontserv.h"
#include "ivideo/graph2d.h"
#include "ivideo/natwin.h"
#include "ivaria/conout.h"
#include "iengine/engine.h"
#include "iengine/sector.h"
#include "iengine/light.h"
#include "iengine/camera.h"
#include "iengine/mesh.h"
#include "iengine/movable.h"
#include "iengine/halo.h"
#include "imesh/thing.h"
#include "imesh/particle.h"
#include "imesh/sprite2d.h"
#include "imesh/sprite3d.h"
#include "imesh/object.h"
#include "imap/reader.h"
#include "igraphic/imageio.h"
#include "imap/loader.h"
#include "iengine/material.h"
#include "ivaria/reporter.h"
#include "iutil/eventq.h"
#include "iutil/virtclk.h"
#include "iutil/plugin.h"
#include "iutil/vfs.h"
#include "csqsqrt.h"

#include "csgeom/csrect.h"
#include "csgeom/csrectrg.h"

#include "awstest2.h"
#include <stdio.h>

#define  QUERY_REG(myPlug, iFace, errMsg) \
  myPlug = CS_QUERY_REGISTRY (object_reg, iFace); \
  if (!myPlug) \
  { \
    Report (CS_REPORTER_SEVERITY_ERROR, errMsg); \
    return false; \
  }

extern awsTest *System;

awsTest::awsTest()
{
}

awsTest::~awsTest()
{
}

static bool AwsEventHandler (iEvent& ev)
{
  if (!System)
    return false;
  if (ev.Name == System->Process)
  {
    System->SetupFrame ();
    return true;
  }
  else if (ev.Name == System->FinalProcess)
  {
    System->FinishFrame ();
    return true;
  }
  else
  {
    return System->HandleEvent (ev);
  }
}

bool
awsTest::Initialize(int argc, const char* const argv[], const char *iConfigName)
{
  object_reg = csInitializer::CreateEnvironment (argc, argv);
  if (!object_reg) return false;

  if (!csInitializer::SetupConfigManager (object_reg, iConfigName))
  {
    Report (CS_REPORTER_SEVERITY_ERROR, "Could not init app!");
    return false;
  }

  if (!csInitializer::RequestPlugins (object_reg, CS_REQUEST_END))
  {
    Report (CS_REPORTER_SEVERITY_ERROR, "Could not init app!");
    return false;
  }

  Process = csevProcess (object_reg);
  FinalProcess = csevFinalProcess (object_reg);
  KeyboardDown = csevKeyboardDown (object_reg);

  if (!csInitializer::SetupEventHandler (object_reg, AwsEventHandler))
  {
    Report (CS_REPORTER_SEVERITY_ERROR, "Could not setup event handler!");
    return false;
  }

   // Check for commandline help.
  if (csCommandLineHelper::CheckHelp (object_reg))
  {
    csCommandLineHelper::Help (object_reg);
    exit (0);
  }

  // The virtual clock.
  vc = CS_QUERY_REGISTRY (object_reg, iVirtualClock);
  csRef<iPluginManager> plugin_mgr (
  	CS_QUERY_REGISTRY (object_reg, iPluginManager));

  // Load the engine plugin.
  Report (CS_REPORTER_SEVERITY_NOTIFY, "Loading engine...");
  engine = CS_LOAD_PLUGIN(plugin_mgr, "crystalspace.engine.3d", iEngine);
  if (!engine)
  {
    Report (CS_REPORTER_SEVERITY_ERROR, "Could not load the engine plugin!");
    return false;
  }
  if (!object_reg->Register (engine, "iEngine"))
  {
    Report (CS_REPORTER_SEVERITY_ERROR, "Could not register engine!");
    return false;
  }

  QUERY_REG (myG3D, iGraphics3D, "Couldn't load iGraphics3D plugin!");
  QUERY_REG (myG2D, iGraphics2D, "Couldn't load  iGraphics2D plugin!");
  QUERY_REG (myVFS, iVFS, "Couldn't load  iVFS plugin!");
  QUERY_REG (myConsole, iConsoleOutput, "Couldn't load iConsoleOutput plugin!");

  // Load AWS
  Report(CS_REPORTER_SEVERITY_NOTIFY, "Loading AWS 2.0 ...");
  aws = CS_LOAD_PLUGIN(plugin_mgr,
  	"crystalspace.window.alternatemanager2", iAws);

  if (!aws)
  {
    Report(CS_REPORTER_SEVERITY_ERROR, "Could not load the AWS plugin!");
    return false;
  }

  loader = CS_LOAD_PLUGIN(plugin_mgr, "crystalspace.level.loader", iLoader);
  if (!loader)
  {
    Report (CS_REPORTER_SEVERITY_ERROR, "No iLoader plugin!");
    return false;
  }
  if (!object_reg->Register (loader, "iLoader"))
  {
    Report (CS_REPORTER_SEVERITY_ERROR, "Could not register loader!");
    return false;
  }

  // Open the main system. This will open all the previously loaded plug-ins.
  iNativeWindow* nw = myG2D->GetNativeWindow ();
  if (nw) nw->SetTitle ("AWS 2.0 Test Harness");

  if (!csInitializer::OpenApplication (object_reg))
  {
    Report(CS_REPORTER_SEVERITY_ERROR, "Error opening system!");
    return false;
  }

  font = myG2D->GetFontServer()->LoadFont (CSFONT_LARGE);

  // Initialize the console
  if (myConsole != 0)
    // Don't let messages before this one appear
    myConsole->Clear ();

  // Some commercials...
  Report (CS_REPORTER_SEVERITY_NOTIFY,
    "The Alternate Window System 2.0 Test Harness.");

  // First disable the lighting cache. Our app is simple enough
  // not to need this.
  engine->SetLightingCacheMode (0);

  // Create our world.
  Report (CS_REPORTER_SEVERITY_NOTIFY, "Creating world!...");

  if (!loader->LoadTexture ("stone", "/lib/stdtex/parket.jpg"))
  {
    Report (CS_REPORTER_SEVERITY_ERROR, "Error loading 'parket' texture!");
    exit (1);
  }
  iMaterialWrapper* tm = engine->GetMaterialList ()->FindByName ("stone");

  room = engine->CreateSector ("room");
  csRef<iMeshWrapper> walls (engine->CreateSectorWallsMesh (room, "walls"));
  csRef<iThingFactoryState> walls_state =
    scfQueryInterface<iThingFactoryState> (walls->GetMeshObject ()->GetFactory());
  walls_state->AddInsideBox (csVector3 (-5, 0, -5), csVector3 (5, 20, 5));
  walls_state->SetPolygonMaterial (CS_POLYRANGE_LAST, tm);
  walls_state->SetPolygonTextureMapping (CS_POLYRANGE_LAST, 3);

  csRef<iLight> light;
  iLightList* ll = room->GetLights ();
  light = engine->CreateLight (0, csVector3 (-10, 10.5, -10), 15,
  	csColor (1, 0, 0));
  ll->Add (light);

  light = engine->CreateLight (0, csVector3 (10, 10.5,  10), 15,
  	csColor (0, 0, 1));
  ll->Add (light);

  light = engine->CreateLight (0, csVector3 (-10, 10.5, 10), 15,
  	csColor (0, 1, 0));
  ll->Add (light);

  light = engine->CreateLight (0, csVector3 (10, 10.5, -10), 15,
  	csColor (1, 1, 1));
  ll->Add (light);

  engine->Prepare ();

  Report(CS_REPORTER_SEVERITY_NOTIFY, "--------------------------------------");

  view = csPtr<iView> (new csView (engine, myG3D));
  view->GetCamera ()->SetSector (room);
  view->GetCamera ()->GetTransform ().SetOrigin (csVector3 (0, 5, -3));
  view->SetRectangle (0, 0, myG2D->GetWidth (), myG2D->GetHeight ());

  wview = csPtr<iView> (new csView (engine, myG3D));
  wview->GetCamera ()->SetSector (room);
  wview->GetCamera ()->GetTransform ().SetOrigin (csVector3 (0, 5, -3));

  col_red = myG2D->FindRGB (255, 0, 0);
  col_blue = myG2D->FindRGB (0, 0, 255);
  col_white = myG2D->FindRGB (255, 255, 255);
  col_gray = myG2D->FindRGB (50, 50, 50);
  col_black = myG2D->FindRGB (0, 0, 0);
  col_yellow = myG2D->FindRGB (255, 255, 0);
  col_cyan = myG2D->FindRGB (0, 255, 255);
  col_green = myG2D->FindRGB (0, 255, 0);

 // Setup AWS specific stuff here.
 //aws->Initialize(object_reg);
 aws->SetDrawTarget(myG2D, myG3D);

 // Load a definition file
 if (aws->Load("/aws/awstest.js.def")==false)
    Report(CS_REPORTER_SEVERITY_ERROR, "Unable to load the definition file '/aws/awstest.js.def'");

  Report(CS_REPORTER_SEVERITY_NOTIFY, "Init done.");

  return true;
}

void
awsTest::SetupFrame()
{
  static int counter=0;

  iCamera* c = view->GetCamera();
  iCamera* c2 = wview->GetCamera();

  counter++;

  // First get elapsed time from the system driver.
  csTicks elapsed_time, current_time;
  elapsed_time = vc->GetElapsedTicks ();
  current_time = vc->GetCurrentTicks ();

  // Now rotate the camera according to keyboard state
  float speed = (elapsed_time / 1000.0f) * (0.03f * 2);

  c->GetTransform ().RotateThis (CS_VEC_ROT_RIGHT, speed);
  c2->GetTransform ().RotateThis (CS_VEC_ROT_LEFT, speed);

  // Tell 3D driver we're going to display 3D things.
  if (!myG3D->BeginDraw (
      engine->GetBeginDrawFlags () | CSDRAW_3DGRAPHICS))
      return;

  // Tell the camera to render into the frame buffer.
  view->Draw ();
  wview->Draw();

  // Start drawing 2D graphics.
  if (!myG3D->BeginDraw (CSDRAW_2DGRAPHICS)) return;

  message.Format ("awsTest2(%d)", counter);
  myG2D->Write(font, 5, 5, col_green, -1, message);

  aws->Redraw();
}

void
awsTest::FinishFrame ()
{
  myG3D->FinishDraw ();
  myG3D->Print (0);
}

bool
awsTest::HandleEvent (iEvent &Event)
{
   if ((Event.Name == KeyboardDown) &&
      (csKeyEventHelper::GetCookedCode (&Event) == CSKEY_ESC))
  {
    csRef<iEventQueue> q (CS_QUERY_REGISTRY (object_reg, iEventQueue));
    if (q)
      q->GetEventOutlet()->Broadcast (csevQuit (object_reg));
    return true;
  }

  if (aws) return aws->HandleEvent(Event);
  return false;
}

void
awsTest::Report (int severity, const char* msg, ...)
{
  va_list arg;
  va_start (arg, msg);
  csRef<iReporter> rep (CS_QUERY_REGISTRY (object_reg, iReporter));
  if (rep)
    rep->ReportV (severity, "crystalspace.application.awstest", msg, arg);
  else
  {
    csPrintfV (msg, arg);
    csPrintf ("\n");
  }
  va_end (arg);
}

#endif // end only compile if testing aws2.
<commit_msg>Added auto-load back so the test file loads automatically.<commit_after>/*
    Copyright (C) 2001 by Christopher Nelson

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 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
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/

#include "cssysdef.h"

#include "awstest_config.h"

#ifdef TEST_AWS2

#include "csutil/sysfunc.h"
#include "csutil/cscolor.h"
#include "csutil/csevent.h"
#include "csutil/event.h"

#include "cstool/csfxscr.h"
#include "cstool/csview.h"
#include "cstool/initapp.h"
#include "csutil/cmdhelp.h"
#include "ivideo/graph3d.h"
#include "ivideo/fontserv.h"
#include "ivideo/graph2d.h"
#include "ivideo/natwin.h"
#include "ivaria/conout.h"
#include "iengine/engine.h"
#include "iengine/sector.h"
#include "iengine/light.h"
#include "iengine/camera.h"
#include "iengine/mesh.h"
#include "iengine/movable.h"
#include "iengine/halo.h"
#include "imesh/thing.h"
#include "imesh/particle.h"
#include "imesh/sprite2d.h"
#include "imesh/sprite3d.h"
#include "imesh/object.h"
#include "imap/reader.h"
#include "igraphic/imageio.h"
#include "imap/loader.h"
#include "iengine/material.h"
#include "ivaria/reporter.h"
#include "iutil/eventq.h"
#include "iutil/virtclk.h"
#include "iutil/plugin.h"
#include "iutil/vfs.h"
#include "csqsqrt.h"

#include "csgeom/csrect.h"
#include "csgeom/csrectrg.h"

#include "awstest2.h"
#include <stdio.h>

#define  QUERY_REG(myPlug, iFace, errMsg) \
  myPlug = CS_QUERY_REGISTRY (object_reg, iFace); \
  if (!myPlug) \
  { \
    Report (CS_REPORTER_SEVERITY_ERROR, errMsg); \
    return false; \
  }

extern awsTest *System;

awsTest::awsTest()
{
}

awsTest::~awsTest()
{
}

static bool AwsEventHandler (iEvent& ev)
{
  if (!System)
    return false;
  if (ev.Name == System->Process)
  {
    System->SetupFrame ();
    return true;
  }
  else if (ev.Name == System->FinalProcess)
  {
    System->FinishFrame ();
    return true;
  }
  else
  {
    return System->HandleEvent (ev);
  }
}

bool
awsTest::Initialize(int argc, const char* const argv[], const char *iConfigName)
{
  object_reg = csInitializer::CreateEnvironment (argc, argv);
  if (!object_reg) return false;

  if (!csInitializer::SetupConfigManager (object_reg, iConfigName))
  {
    Report (CS_REPORTER_SEVERITY_ERROR, "Could not init app!");
    return false;
  }

  if (!csInitializer::RequestPlugins (object_reg, CS_REQUEST_END))
  {
    Report (CS_REPORTER_SEVERITY_ERROR, "Could not init app!");
    return false;
  }

  Process = csevProcess (object_reg);
  FinalProcess = csevFinalProcess (object_reg);
  KeyboardDown = csevKeyboardDown (object_reg);

  if (!csInitializer::SetupEventHandler (object_reg, AwsEventHandler))
  {
    Report (CS_REPORTER_SEVERITY_ERROR, "Could not setup event handler!");
    return false;
  }

   // Check for commandline help.
  if (csCommandLineHelper::CheckHelp (object_reg))
  {
    csCommandLineHelper::Help (object_reg);
    exit (0);
  }

  // The virtual clock.
  vc = CS_QUERY_REGISTRY (object_reg, iVirtualClock);
  csRef<iPluginManager> plugin_mgr (
  	CS_QUERY_REGISTRY (object_reg, iPluginManager));

  // Load the engine plugin.
  Report (CS_REPORTER_SEVERITY_NOTIFY, "Loading engine...");
  engine = CS_LOAD_PLUGIN(plugin_mgr, "crystalspace.engine.3d", iEngine);
  if (!engine)
  {
    Report (CS_REPORTER_SEVERITY_ERROR, "Could not load the engine plugin!");
    return false;
  }
  if (!object_reg->Register (engine, "iEngine"))
  {
    Report (CS_REPORTER_SEVERITY_ERROR, "Could not register engine!");
    return false;
  }

  QUERY_REG (myG3D, iGraphics3D, "Couldn't load iGraphics3D plugin!");
  QUERY_REG (myG2D, iGraphics2D, "Couldn't load  iGraphics2D plugin!");
  QUERY_REG (myVFS, iVFS, "Couldn't load  iVFS plugin!");
  QUERY_REG (myConsole, iConsoleOutput, "Couldn't load iConsoleOutput plugin!");

  // Load AWS
  Report(CS_REPORTER_SEVERITY_NOTIFY, "Loading AWS 2.0 ...");
  aws = CS_LOAD_PLUGIN(plugin_mgr,
  	"crystalspace.window.alternatemanager2", iAws);

  if (!aws)
  {
    Report(CS_REPORTER_SEVERITY_ERROR, "Could not load the AWS plugin!");
    return false;
  }

  loader = CS_LOAD_PLUGIN(plugin_mgr, "crystalspace.level.loader", iLoader);
  if (!loader)
  {
    Report (CS_REPORTER_SEVERITY_ERROR, "No iLoader plugin!");
    return false;
  }
  if (!object_reg->Register (loader, "iLoader"))
  {
    Report (CS_REPORTER_SEVERITY_ERROR, "Could not register loader!");
    return false;
  }

  // Open the main system. This will open all the previously loaded plug-ins.
  iNativeWindow* nw = myG2D->GetNativeWindow ();
  if (nw) nw->SetTitle ("AWS 2.0 Test Harness");

  if (!csInitializer::OpenApplication (object_reg))
  {
    Report(CS_REPORTER_SEVERITY_ERROR, "Error opening system!");
    return false;
  }

  font = myG2D->GetFontServer()->LoadFont (CSFONT_LARGE);

  // Initialize the console
  if (myConsole != 0)
    // Don't let messages before this one appear
    myConsole->Clear ();

  // Some commercials...
  Report (CS_REPORTER_SEVERITY_NOTIFY,
    "The Alternate Window System 2.0 Test Harness.");

  // First disable the lighting cache. Our app is simple enough
  // not to need this.
  engine->SetLightingCacheMode (0);

  // Create our world.
  Report (CS_REPORTER_SEVERITY_NOTIFY, "Creating world!...");

  if (!loader->LoadTexture ("stone", "/lib/stdtex/parket.jpg"))
  {
    Report (CS_REPORTER_SEVERITY_ERROR, "Error loading 'parket' texture!");
    exit (1);
  }
  iMaterialWrapper* tm = engine->GetMaterialList ()->FindByName ("stone");

  room = engine->CreateSector ("room");
  csRef<iMeshWrapper> walls (engine->CreateSectorWallsMesh (room, "walls"));
  csRef<iThingFactoryState> walls_state =
    scfQueryInterface<iThingFactoryState> (walls->GetMeshObject ()->GetFactory());
  walls_state->AddInsideBox (csVector3 (-5, 0, -5), csVector3 (5, 20, 5));
  walls_state->SetPolygonMaterial (CS_POLYRANGE_LAST, tm);
  walls_state->SetPolygonTextureMapping (CS_POLYRANGE_LAST, 3);

  csRef<iLight> light;
  iLightList* ll = room->GetLights ();
  light = engine->CreateLight (0, csVector3 (-10, 10.5, -10), 15,
  	csColor (1, 0, 0));
  ll->Add (light);

  light = engine->CreateLight (0, csVector3 (10, 10.5,  10), 15,
  	csColor (0, 0, 1));
  ll->Add (light);

  light = engine->CreateLight (0, csVector3 (-10, 10.5, 10), 15,
  	csColor (0, 1, 0));
  ll->Add (light);

  light = engine->CreateLight (0, csVector3 (10, 10.5, -10), 15,
  	csColor (1, 1, 1));
  ll->Add (light);

  engine->Prepare ();

  Report(CS_REPORTER_SEVERITY_NOTIFY, "--------------------------------------");

  view = csPtr<iView> (new csView (engine, myG3D));
  view->GetCamera ()->SetSector (room);
  view->GetCamera ()->GetTransform ().SetOrigin (csVector3 (0, 5, -3));
  view->SetRectangle (0, 0, myG2D->GetWidth (), myG2D->GetHeight ());

  wview = csPtr<iView> (new csView (engine, myG3D));
  wview->GetCamera ()->SetSector (room);
  wview->GetCamera ()->GetTransform ().SetOrigin (csVector3 (0, 5, -3));

  col_red = myG2D->FindRGB (255, 0, 0);
  col_blue = myG2D->FindRGB (0, 0, 255);
  col_white = myG2D->FindRGB (255, 255, 255);
  col_gray = myG2D->FindRGB (50, 50, 50);
  col_black = myG2D->FindRGB (0, 0, 0);
  col_yellow = myG2D->FindRGB (255, 255, 0);
  col_cyan = myG2D->FindRGB (0, 255, 255);
  col_green = myG2D->FindRGB (0, 255, 0);

 // Setup AWS specific stuff here.
 //aws->Initialize(object_reg);
 aws->SetDrawTarget(myG2D, myG3D);

 // Load a definition file
 if (aws->Load("/aws/awstest.js.def")==false)
   Report(CS_REPORTER_SEVERITY_ERROR, "Unable to load the definition file '/aws/awstest.js.def'");

  Report(CS_REPORTER_SEVERITY_NOTIFY, "Init done.");

  return true;
}

void
awsTest::SetupFrame()
{
  static int counter=0;

  iCamera* c = view->GetCamera();
  iCamera* c2 = wview->GetCamera();

  counter++;

  // First get elapsed time from the system driver.
  csTicks elapsed_time, current_time;
  elapsed_time = vc->GetElapsedTicks ();
  current_time = vc->GetCurrentTicks ();

  // Now rotate the camera according to keyboard state
  float speed = (elapsed_time / 1000.0f) * (0.03f * 2);

  c->GetTransform ().RotateThis (CS_VEC_ROT_RIGHT, speed);
  c2->GetTransform ().RotateThis (CS_VEC_ROT_LEFT, speed);

  // Tell 3D driver we're going to display 3D things.
  if (!myG3D->BeginDraw (
      engine->GetBeginDrawFlags () | CSDRAW_3DGRAPHICS))
      return;

  // Tell the camera to render into the frame buffer.
  view->Draw ();
  wview->Draw();

  // Start drawing 2D graphics.
  if (!myG3D->BeginDraw (CSDRAW_2DGRAPHICS)) return;

  message.Format ("awsTest2(%d)", counter);
  myG2D->Write(font, 5, 5, col_green, -1, message);

  aws->Redraw();
}

void
awsTest::FinishFrame ()
{
  myG3D->FinishDraw ();
  myG3D->Print (0);
}

bool
awsTest::HandleEvent (iEvent &Event)
{
   if ((Event.Name == KeyboardDown) &&
      (csKeyEventHelper::GetCookedCode (&Event) == CSKEY_ESC))
  {
    csRef<iEventQueue> q (CS_QUERY_REGISTRY (object_reg, iEventQueue));
    if (q)
      q->GetEventOutlet()->Broadcast (csevQuit (object_reg));
    return true;
  }

  if (aws) return aws->HandleEvent(Event);
  return false;
}

void
awsTest::Report (int severity, const char* msg, ...)
{
  va_list arg;
  va_start (arg, msg);
  csRef<iReporter> rep (CS_QUERY_REGISTRY (object_reg, iReporter));
  if (rep)
    rep->ReportV (severity, "crystalspace.application.awstest", msg, arg);
  else
  {
    csPrintfV (msg, arg);
    csPrintf ("\n");
  }
  va_end (arg);
}

#endif // end only compile if testing aws2.
<|endoftext|>


<commit_before>#include <sirius.h>

using namespace sirius;

void test_complex_exp()
{
    int N = 100000000;
    mdarray<double_complex, 1> phase(N);
    phase.zero();

    for (int i = 0; i < N; i++)
    {
        phase(i) = type_wrapper<double_complex>::random();
    }

    Timer t("random_plus_exp");
    #pragma omp parallel for
    for (int i = 0; i < N; i++)
    {
        phase(i) = std::exp(phase(i));
    }
    double tval = t.stop();

    printf("number of evaluations: %i\n", N);

    printf("%8.2f M double complex exponents / sec.\n", N / tval / 1000000);

}

int main(int argn, char** argv)
{
    Platform::initialize(1);
    test_complex_exp();
    Platform::finalize();
}
<commit_msg>rerun complexe exponnents test<commit_after>#include <sirius.h>

using namespace sirius;

void test_complex_exp()
{
    int N = 100000000;
    mdarray<double_complex, 1> phase(N);
    phase.zero();

    for (int i = 0; i < N; i++)
    {
        phase(i) = type_wrapper<double_complex>::random();
    }

    runtime::Timer t("random_plus_exp");
    #pragma omp parallel for
    for (int i = 0; i < N; i++)
    {
        phase(i) = std::exp(phase(i));
    }
    double tval = t.stop();

    printf("number of evaluations: %i\n", N);

    printf("%8.2f M double complex exponents / sec.\n", N / tval / 1000000);

}

int main(int argn, char** argv)
{
    sirius::initialize(1);
    test_complex_exp();
    sirius::finalize();
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2006, 2007 Apple Computer, Inc.
 * Copyright (c) 2006, 2007, 2008, 2009, 2012 Google Inc. 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 Google Inc. 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.
 */

#include "config.h"
#include "core/platform/graphics/FontPlatformData.h"

#include "RuntimeEnabledFeatures.h"
#include "SkPaint.h"
#include "SkTypeface.h"
#include "SkTypeface_win.h"
#include "core/platform/graphics/FontCache.h"
#include "core/platform/graphics/GraphicsContext.h"
#include "core/platform/graphics/skia/SkiaFontWin.h"
#include "platform/LayoutTestSupport.h"
#include "platform/SharedBuffer.h"
#include "platform/win/HWndDC.h"
#include "public/platform/Platform.h"
#include "public/platform/win/WebSandboxSupport.h"
#include "wtf/PassOwnPtr.h"
#include "wtf/StdLibExtras.h"
#include <mlang.h>
#include <objidl.h>
#include <windows.h>

namespace WebCore {

void FontPlatformData::setupPaint(SkPaint* paint, GraphicsContext* context) const
{
    const float ts = m_textSize >= 0 ? m_textSize : 12;
    paint->setTextSize(SkFloatToScalar(m_textSize));
    paint->setTypeface(typeface());
    paint->setFakeBoldText(m_fakeBold);
    paint->setTextSkewX(m_fakeItalic ? -SK_Scalar1 / 4 : 0);
    if (RuntimeEnabledFeatures::subpixelFontScalingEnabled())
        paint->setSubpixelText(true);

    // Only set painting flags when we're actually painting.
    if (context) {
        int textFlags = paintTextFlags();
        if (!context->couldUseLCDRenderedText()) {
            textFlags &= ~SkPaint::kLCDRenderText_Flag;
            // If we *just* clear our request for LCD, then GDI seems to
            // sometimes give us AA text, and sometimes give us BW text. Since the
            // original intent was LCD, we want to force AA (rather than BW), so we
            // add a special bit to tell Skia to do its best to avoid the BW: by
            // drawing LCD offscreen and downsampling that to AA.
            textFlags |= SkPaint::kGenA8FromLCD_Flag;
        }

        static const uint32_t textFlagsMask = SkPaint::kAntiAlias_Flag |
            SkPaint::kLCDRenderText_Flag |
            SkPaint::kGenA8FromLCD_Flag;

        SkASSERT(!(textFlags & ~textFlagsMask));
        uint32_t flags = paint->getFlags();
        flags &= ~textFlagsMask;
        flags |= textFlags;
        paint->setFlags(flags);
    }
}

// Lookup the current system settings for font smoothing.
// We cache these values for performance, but if the browser has a way to be
// notified when these change, we could re-query them at that time.
static uint32_t getDefaultGDITextFlags()
{
    static bool gInited;
    static uint32_t gFlags;
    if (!gInited) {
        BOOL enabled;
        gFlags = 0;
        if (SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &enabled, 0) && enabled) {
            gFlags |= SkPaint::kAntiAlias_Flag;

            UINT smoothType;
            if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &smoothType, 0)) {
                if (FE_FONTSMOOTHINGCLEARTYPE == smoothType)
                    gFlags |= SkPaint::kLCDRenderText_Flag;
            }
        }
        gInited = true;
    }
    return gFlags;
}

static bool isWebFont(const LOGFONT& lf)
{
    // web-fonts have artifical names constructed to always be
    // 1. 24 characters, followed by a '\0'
    // 2. the last two characters are '=='
    return '=' == lf.lfFaceName[22] && '=' == lf.lfFaceName[23] && '\0' == lf.lfFaceName[24];
}

static int computePaintTextFlags(const LOGFONT& lf)
{
    int textFlags = 0;
    switch (lf.lfQuality) {
    case NONANTIALIASED_QUALITY:
        textFlags = 0;
        break;
    case ANTIALIASED_QUALITY:
        textFlags = SkPaint::kAntiAlias_Flag;
        break;
    case CLEARTYPE_QUALITY:
        textFlags = (SkPaint::kAntiAlias_Flag | SkPaint::kLCDRenderText_Flag);
        break;
    default:
        textFlags = getDefaultGDITextFlags();
        break;
    }

    // only allow features that SystemParametersInfo allows
    textFlags &= getDefaultGDITextFlags();

    /*
     *  FontPlatformData(...) will read our logfont, and try to honor the the lfQuality
     *  setting (computing the corresponding SkPaint flags for AA and LCD). However, it
     *  will limit the quality based on its query of SPI_GETFONTSMOOTHING. This could mean
     *  we end up drawing the text in BW, even though our lfQuality requested antialiasing.
     *
     *  Many web-fonts are so poorly hinted that they are terrible to read when drawn in BW.
     *  In these cases, we have decided to FORCE these fonts to be drawn with at least grayscale AA,
     *  even when the System (getDefaultGDITextFlags) tells us to draw only in BW.
     */
    if (isWebFont(lf) && !isRunningLayoutTest())
        textFlags |= SkPaint::kAntiAlias_Flag;
    return textFlags;
}

PassRefPtr<SkTypeface> CreateTypefaceFromHFont(HFONT hfont, int* size, int* paintTextFlags)
{
    LOGFONT info;
    GetObject(hfont, sizeof(info), &info);
    if (size) {
        int height = info.lfHeight;
        if (height < 0)
            height = -height;
        *size = height;
    }
    if (paintTextFlags)
        *paintTextFlags = computePaintTextFlags(info);
    return adoptRef(SkCreateTypefaceFromLOGFONT(info));
}

FontPlatformData::FontPlatformData(WTF::HashTableDeletedValueType)
    : m_font(0)
    , m_textSize(-1)
    , m_fakeBold(false)
    , m_fakeItalic(false)
    , m_orientation(Horizontal)
    , m_scriptCache(0)
    , m_typeface(SkTypeface::RefDefault())
    , m_paintTextFlags(0)
    , m_isHashTableDeletedValue(true)
{
}

FontPlatformData::FontPlatformData()
    : m_font(0)
    , m_textSize(0)
    , m_fakeBold(false)
    , m_fakeItalic(false)
    , m_orientation(Horizontal)
    , m_scriptCache(0)
    , m_typeface(SkTypeface::RefDefault())
    , m_paintTextFlags(0)
    , m_isHashTableDeletedValue(false)
{
}

#if ENABLE(GDI_FONTS_ON_WINDOWS)
FontPlatformData::FontPlatformData(HFONT font, float size, FontOrientation orientation)
    : m_font(RefCountedHFONT::create(font))
    , m_textSize(size)
    , m_fakeBold(false)
    , m_fakeItalic(false)
    , m_orientation(orientation)
    , m_scriptCache(0)
    , m_typeface(CreateTypefaceFromHFont(font, 0, &m_paintTextFlags))
    , m_isHashTableDeletedValue(false)
{
}
#endif

// FIXME: this constructor is needed for SVG fonts but doesn't seem to do much
FontPlatformData::FontPlatformData(float size, bool bold, bool oblique)
    : m_font(0)
    , m_textSize(size)
    , m_fakeBold(false)
    , m_fakeItalic(false)
    , m_orientation(Horizontal)
    , m_scriptCache(0)
    , m_typeface(SkTypeface::RefDefault())
    , m_paintTextFlags(0)
    , m_isHashTableDeletedValue(false)
{
}

FontPlatformData::FontPlatformData(const FontPlatformData& data)
    : m_font(data.m_font)
    , m_textSize(data.m_textSize)
    , m_fakeBold(data.m_fakeBold)
    , m_fakeItalic(data.m_fakeItalic)
    , m_orientation(data.m_orientation)
    , m_scriptCache(0)
    , m_typeface(data.m_typeface)
    , m_paintTextFlags(data.m_paintTextFlags)
    , m_isHashTableDeletedValue(false)
{
}

FontPlatformData::FontPlatformData(const FontPlatformData& data, float textSize)
    : m_font(data.m_font)
    , m_textSize(textSize)
    , m_fakeBold(data.m_fakeBold)
    , m_fakeItalic(data.m_fakeItalic)
    , m_orientation(data.m_orientation)
    , m_scriptCache(0)
    , m_typeface(data.m_typeface)
    , m_paintTextFlags(data.m_paintTextFlags)
    , m_isHashTableDeletedValue(false)
{
}

FontPlatformData::FontPlatformData(PassRefPtr<SkTypeface> tf, const char* family, float textSize, bool fakeBold, bool fakeItalic, FontOrientation orientation)
    : m_font(0)
    , m_textSize(textSize)
    , m_fakeBold(fakeBold)
    , m_fakeItalic(fakeItalic)
    , m_orientation(orientation)
    , m_scriptCache(0)
    , m_typeface(tf)
    , m_isHashTableDeletedValue(false)
{
    // FIXME: This can be removed together with m_font once the last few
    // uses of hfont() has been eliminated.
    LOGFONT logFont;
    SkLOGFONTFromTypeface(m_typeface.get(), &logFont);
    logFont.lfHeight = -textSize;
    HFONT hFont = CreateFontIndirect(&logFont);
    if (hFont)
        m_font = RefCountedHFONT::create(hFont);
    m_paintTextFlags = computePaintTextFlags(logFont);
}

FontPlatformData& FontPlatformData::operator=(const FontPlatformData& data)
{
    if (this != &data) {
        m_font = data.m_font;
        m_textSize = data.m_textSize;
        m_fakeBold = data.m_fakeBold;
        m_fakeItalic = data.m_fakeItalic;
        m_orientation = data.m_orientation;
        m_typeface = data.m_typeface;
        m_paintTextFlags = data.m_paintTextFlags;

        // The following fields will get re-computed if necessary.
        ScriptFreeCache(&m_scriptCache);
        m_scriptCache = 0;
        m_scriptFontProperties.clear();
    }
    return *this;
}

FontPlatformData::~FontPlatformData()
{
    ScriptFreeCache(&m_scriptCache);
    m_scriptCache = 0;
}

String FontPlatformData::fontFamilyName() const
{
    HWndDC dc(0);
    HGDIOBJ oldFont = static_cast<HFONT>(SelectObject(dc, hfont()));
    WCHAR name[LF_FACESIZE];
    unsigned resultLength = GetTextFace(dc, LF_FACESIZE, name);
    if (resultLength > 0)
        resultLength--; // ignore the null terminator
    SelectObject(dc, oldFont);
    return String(name, resultLength);
}

bool FontPlatformData::isFixedPitch() const
{
#if ENABLE(GDI_FONTS_ON_WINDOWS)
    // TEXTMETRICS have this. Set m_treatAsFixedPitch based off that.
    HWndDC dc(0);
    HGDIOBJ oldFont = SelectObject(dc, hfont());

    // Yes, this looks backwards, but the fixed pitch bit is actually set if the font
    // is *not* fixed pitch. Unbelievable but true.
    TEXTMETRIC textMetric = { 0 };
    if (!GetTextMetrics(dc, &textMetric)) {
        if (ensureFontLoaded(hfont())) {
            // Retry GetTextMetrics.
            // FIXME: Handle gracefully the error if this call also fails.
            // See http://crbug.com/6401.
            if (!GetTextMetrics(dc, &textMetric))
                LOG_ERROR("Unable to get the text metrics after second attempt");
        }
    }

    bool treatAsFixedPitch = !(textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH);

    SelectObject(dc, oldFont);

    return treatAsFixedPitch;
#else
    return typeface() && typeface()->isFixedPitch();
#endif
}

FontPlatformData::RefCountedHFONT::~RefCountedHFONT()
{
    DeleteObject(m_hfont);
}

SCRIPT_FONTPROPERTIES* FontPlatformData::scriptFontProperties() const
{
    if (!m_scriptFontProperties) {
        m_scriptFontProperties = adoptPtr(new SCRIPT_FONTPROPERTIES);
        memset(m_scriptFontProperties.get(), 0, sizeof(SCRIPT_FONTPROPERTIES));
        m_scriptFontProperties->cBytes = sizeof(SCRIPT_FONTPROPERTIES);
        HRESULT result = ScriptGetFontProperties(0, scriptCache(), m_scriptFontProperties.get());
        if (result == E_PENDING) {
            HWndDC dc(0);
            HGDIOBJ oldFont = SelectObject(dc, hfont());
            HRESULT hr = ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties.get());
            if (S_OK != hr) {
                if (FontPlatformData::ensureFontLoaded(hfont())) {
                    // FIXME: Handle gracefully the error if this call also fails.
                    hr = ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties.get());
                    if (S_OK != hr) {
                        LOG_ERROR("Unable to get the font properties after second attempt");
                    }
                }
            }

            SelectObject(dc, oldFont);
        }
    }
    return m_scriptFontProperties.get();
}

#ifndef NDEBUG
String FontPlatformData::description() const
{
    return String();
}
#endif

bool FontPlatformData::ensureFontLoaded(HFONT font)
{
    WebKit::WebSandboxSupport* sandboxSupport = WebKit::Platform::current()->sandboxSupport();
    // if there is no sandbox, then we can assume the font
    // was able to be loaded successfully already
    return sandboxSupport ? sandboxSupport->ensureFontLoaded(font) : true;
}

}
<commit_msg>Fixing leaked references in FontPlatformData<commit_after>/*
 * Copyright (C) 2006, 2007 Apple Computer, Inc.
 * Copyright (c) 2006, 2007, 2008, 2009, 2012 Google Inc. 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 Google Inc. 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.
 */

#include "config.h"
#include "core/platform/graphics/FontPlatformData.h"

#include "RuntimeEnabledFeatures.h"
#include "SkPaint.h"
#include "SkTypeface.h"
#include "SkTypeface_win.h"
#include "core/platform/graphics/FontCache.h"
#include "core/platform/graphics/GraphicsContext.h"
#include "core/platform/graphics/skia/SkiaFontWin.h"
#include "platform/LayoutTestSupport.h"
#include "platform/SharedBuffer.h"
#include "platform/win/HWndDC.h"
#include "public/platform/Platform.h"
#include "public/platform/win/WebSandboxSupport.h"
#include "wtf/PassOwnPtr.h"
#include "wtf/StdLibExtras.h"
#include <mlang.h>
#include <objidl.h>
#include <windows.h>

namespace WebCore {

void FontPlatformData::setupPaint(SkPaint* paint, GraphicsContext* context) const
{
    const float ts = m_textSize >= 0 ? m_textSize : 12;
    paint->setTextSize(SkFloatToScalar(m_textSize));
    paint->setTypeface(typeface());
    paint->setFakeBoldText(m_fakeBold);
    paint->setTextSkewX(m_fakeItalic ? -SK_Scalar1 / 4 : 0);
    if (RuntimeEnabledFeatures::subpixelFontScalingEnabled())
        paint->setSubpixelText(true);

    // Only set painting flags when we're actually painting.
    if (context) {
        int textFlags = paintTextFlags();
        if (!context->couldUseLCDRenderedText()) {
            textFlags &= ~SkPaint::kLCDRenderText_Flag;
            // If we *just* clear our request for LCD, then GDI seems to
            // sometimes give us AA text, and sometimes give us BW text. Since the
            // original intent was LCD, we want to force AA (rather than BW), so we
            // add a special bit to tell Skia to do its best to avoid the BW: by
            // drawing LCD offscreen and downsampling that to AA.
            textFlags |= SkPaint::kGenA8FromLCD_Flag;
        }

        static const uint32_t textFlagsMask = SkPaint::kAntiAlias_Flag |
            SkPaint::kLCDRenderText_Flag |
            SkPaint::kGenA8FromLCD_Flag;

        SkASSERT(!(textFlags & ~textFlagsMask));
        uint32_t flags = paint->getFlags();
        flags &= ~textFlagsMask;
        flags |= textFlags;
        paint->setFlags(flags);
    }
}

// Lookup the current system settings for font smoothing.
// We cache these values for performance, but if the browser has a way to be
// notified when these change, we could re-query them at that time.
static uint32_t getDefaultGDITextFlags()
{
    static bool gInited;
    static uint32_t gFlags;
    if (!gInited) {
        BOOL enabled;
        gFlags = 0;
        if (SystemParametersInfo(SPI_GETFONTSMOOTHING, 0, &enabled, 0) && enabled) {
            gFlags |= SkPaint::kAntiAlias_Flag;

            UINT smoothType;
            if (SystemParametersInfo(SPI_GETFONTSMOOTHINGTYPE, 0, &smoothType, 0)) {
                if (FE_FONTSMOOTHINGCLEARTYPE == smoothType)
                    gFlags |= SkPaint::kLCDRenderText_Flag;
            }
        }
        gInited = true;
    }
    return gFlags;
}

static bool isWebFont(const LOGFONT& lf)
{
    // web-fonts have artifical names constructed to always be
    // 1. 24 characters, followed by a '\0'
    // 2. the last two characters are '=='
    return '=' == lf.lfFaceName[22] && '=' == lf.lfFaceName[23] && '\0' == lf.lfFaceName[24];
}

static int computePaintTextFlags(const LOGFONT& lf)
{
    int textFlags = 0;
    switch (lf.lfQuality) {
    case NONANTIALIASED_QUALITY:
        textFlags = 0;
        break;
    case ANTIALIASED_QUALITY:
        textFlags = SkPaint::kAntiAlias_Flag;
        break;
    case CLEARTYPE_QUALITY:
        textFlags = (SkPaint::kAntiAlias_Flag | SkPaint::kLCDRenderText_Flag);
        break;
    default:
        textFlags = getDefaultGDITextFlags();
        break;
    }

    // only allow features that SystemParametersInfo allows
    textFlags &= getDefaultGDITextFlags();

    /*
     *  FontPlatformData(...) will read our logfont, and try to honor the the lfQuality
     *  setting (computing the corresponding SkPaint flags for AA and LCD). However, it
     *  will limit the quality based on its query of SPI_GETFONTSMOOTHING. This could mean
     *  we end up drawing the text in BW, even though our lfQuality requested antialiasing.
     *
     *  Many web-fonts are so poorly hinted that they are terrible to read when drawn in BW.
     *  In these cases, we have decided to FORCE these fonts to be drawn with at least grayscale AA,
     *  even when the System (getDefaultGDITextFlags) tells us to draw only in BW.
     */
    if (isWebFont(lf) && !isRunningLayoutTest())
        textFlags |= SkPaint::kAntiAlias_Flag;
    return textFlags;
}

PassRefPtr<SkTypeface> CreateTypefaceFromHFont(HFONT hfont, int* size, int* paintTextFlags)
{
    LOGFONT info;
    GetObject(hfont, sizeof(info), &info);
    if (size) {
        int height = info.lfHeight;
        if (height < 0)
            height = -height;
        *size = height;
    }
    if (paintTextFlags)
        *paintTextFlags = computePaintTextFlags(info);
    return adoptRef(SkCreateTypefaceFromLOGFONT(info));
}

FontPlatformData::FontPlatformData(WTF::HashTableDeletedValueType)
    : m_font(0)
    , m_textSize(-1)
    , m_fakeBold(false)
    , m_fakeItalic(false)
    , m_orientation(Horizontal)
    , m_scriptCache(0)
    , m_typeface(adoptRef(SkTypeface::RefDefault()))
    , m_paintTextFlags(0)
    , m_isHashTableDeletedValue(true)
{
}

FontPlatformData::FontPlatformData()
    : m_font(0)
    , m_textSize(0)
    , m_fakeBold(false)
    , m_fakeItalic(false)
    , m_orientation(Horizontal)
    , m_scriptCache(0)
    , m_typeface(adoptRef(SkTypeface::RefDefault()))
    , m_paintTextFlags(0)
    , m_isHashTableDeletedValue(false)
{
}

#if ENABLE(GDI_FONTS_ON_WINDOWS)
FontPlatformData::FontPlatformData(HFONT font, float size, FontOrientation orientation)
    : m_font(RefCountedHFONT::create(font))
    , m_textSize(size)
    , m_fakeBold(false)
    , m_fakeItalic(false)
    , m_orientation(orientation)
    , m_scriptCache(0)
    , m_typeface(CreateTypefaceFromHFont(font, 0, &m_paintTextFlags))
    , m_isHashTableDeletedValue(false)
{
}
#endif

// FIXME: this constructor is needed for SVG fonts but doesn't seem to do much
FontPlatformData::FontPlatformData(float size, bool bold, bool oblique)
    : m_font(0)
    , m_textSize(size)
    , m_fakeBold(false)
    , m_fakeItalic(false)
    , m_orientation(Horizontal)
    , m_scriptCache(0)
    , m_typeface(adoptRef(SkTypeface::RefDefault()))
    , m_paintTextFlags(0)
    , m_isHashTableDeletedValue(false)
{
}

FontPlatformData::FontPlatformData(const FontPlatformData& data)
    : m_font(data.m_font)
    , m_textSize(data.m_textSize)
    , m_fakeBold(data.m_fakeBold)
    , m_fakeItalic(data.m_fakeItalic)
    , m_orientation(data.m_orientation)
    , m_scriptCache(0)
    , m_typeface(data.m_typeface)
    , m_paintTextFlags(data.m_paintTextFlags)
    , m_isHashTableDeletedValue(false)
{
}

FontPlatformData::FontPlatformData(const FontPlatformData& data, float textSize)
    : m_font(data.m_font)
    , m_textSize(textSize)
    , m_fakeBold(data.m_fakeBold)
    , m_fakeItalic(data.m_fakeItalic)
    , m_orientation(data.m_orientation)
    , m_scriptCache(0)
    , m_typeface(data.m_typeface)
    , m_paintTextFlags(data.m_paintTextFlags)
    , m_isHashTableDeletedValue(false)
{
}

FontPlatformData::FontPlatformData(PassRefPtr<SkTypeface> tf, const char* family, float textSize, bool fakeBold, bool fakeItalic, FontOrientation orientation)
    : m_font(0)
    , m_textSize(textSize)
    , m_fakeBold(fakeBold)
    , m_fakeItalic(fakeItalic)
    , m_orientation(orientation)
    , m_scriptCache(0)
    , m_typeface(tf)
    , m_isHashTableDeletedValue(false)
{
    // FIXME: This can be removed together with m_font once the last few
    // uses of hfont() has been eliminated.
    LOGFONT logFont;
    SkLOGFONTFromTypeface(m_typeface.get(), &logFont);
    logFont.lfHeight = -textSize;
    HFONT hFont = CreateFontIndirect(&logFont);
    if (hFont)
        m_font = RefCountedHFONT::create(hFont);
    m_paintTextFlags = computePaintTextFlags(logFont);
}

FontPlatformData& FontPlatformData::operator=(const FontPlatformData& data)
{
    if (this != &data) {
        m_font = data.m_font;
        m_textSize = data.m_textSize;
        m_fakeBold = data.m_fakeBold;
        m_fakeItalic = data.m_fakeItalic;
        m_orientation = data.m_orientation;
        m_typeface = data.m_typeface;
        m_paintTextFlags = data.m_paintTextFlags;

        // The following fields will get re-computed if necessary.
        ScriptFreeCache(&m_scriptCache);
        m_scriptCache = 0;
        m_scriptFontProperties.clear();
    }
    return *this;
}

FontPlatformData::~FontPlatformData()
{
    ScriptFreeCache(&m_scriptCache);
    m_scriptCache = 0;
}

String FontPlatformData::fontFamilyName() const
{
    HWndDC dc(0);
    HGDIOBJ oldFont = static_cast<HFONT>(SelectObject(dc, hfont()));
    WCHAR name[LF_FACESIZE];
    unsigned resultLength = GetTextFace(dc, LF_FACESIZE, name);
    if (resultLength > 0)
        resultLength--; // ignore the null terminator
    SelectObject(dc, oldFont);
    return String(name, resultLength);
}

bool FontPlatformData::isFixedPitch() const
{
#if ENABLE(GDI_FONTS_ON_WINDOWS)
    // TEXTMETRICS have this. Set m_treatAsFixedPitch based off that.
    HWndDC dc(0);
    HGDIOBJ oldFont = SelectObject(dc, hfont());

    // Yes, this looks backwards, but the fixed pitch bit is actually set if the font
    // is *not* fixed pitch. Unbelievable but true.
    TEXTMETRIC textMetric = { 0 };
    if (!GetTextMetrics(dc, &textMetric)) {
        if (ensureFontLoaded(hfont())) {
            // Retry GetTextMetrics.
            // FIXME: Handle gracefully the error if this call also fails.
            // See http://crbug.com/6401.
            if (!GetTextMetrics(dc, &textMetric))
                LOG_ERROR("Unable to get the text metrics after second attempt");
        }
    }

    bool treatAsFixedPitch = !(textMetric.tmPitchAndFamily & TMPF_FIXED_PITCH);

    SelectObject(dc, oldFont);

    return treatAsFixedPitch;
#else
    return typeface() && typeface()->isFixedPitch();
#endif
}

FontPlatformData::RefCountedHFONT::~RefCountedHFONT()
{
    DeleteObject(m_hfont);
}

SCRIPT_FONTPROPERTIES* FontPlatformData::scriptFontProperties() const
{
    if (!m_scriptFontProperties) {
        m_scriptFontProperties = adoptPtr(new SCRIPT_FONTPROPERTIES);
        memset(m_scriptFontProperties.get(), 0, sizeof(SCRIPT_FONTPROPERTIES));
        m_scriptFontProperties->cBytes = sizeof(SCRIPT_FONTPROPERTIES);
        HRESULT result = ScriptGetFontProperties(0, scriptCache(), m_scriptFontProperties.get());
        if (result == E_PENDING) {
            HWndDC dc(0);
            HGDIOBJ oldFont = SelectObject(dc, hfont());
            HRESULT hr = ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties.get());
            if (S_OK != hr) {
                if (FontPlatformData::ensureFontLoaded(hfont())) {
                    // FIXME: Handle gracefully the error if this call also fails.
                    hr = ScriptGetFontProperties(dc, scriptCache(), m_scriptFontProperties.get());
                    if (S_OK != hr) {
                        LOG_ERROR("Unable to get the font properties after second attempt");
                    }
                }
            }

            SelectObject(dc, oldFont);
        }
    }
    return m_scriptFontProperties.get();
}

#ifndef NDEBUG
String FontPlatformData::description() const
{
    return String();
}
#endif

bool FontPlatformData::ensureFontLoaded(HFONT font)
{
    WebKit::WebSandboxSupport* sandboxSupport = WebKit::Platform::current()->sandboxSupport();
    // if there is no sandbox, then we can assume the font
    // was able to be loaded successfully already
    return sandboxSupport ? sandboxSupport->ensureFontLoaded(font) : true;
}

}
<|endoftext|>


<commit_before>// Title       : Implementation of Coroutine in Cpp
// Author      : hanzh.xu@gmail.com
// Date        : 11-21-2020
// License     : MIT License

/*
Implementation of Coroutine in Cpp

Compiler:
// clang -std=c++17 -lstdc++

Usage:
// class MyGen        : public Gen<Output type of the generator>
class OneMoreHanoiGen : public Gen<string> {
public:
    // Local variables of the generator.
    int n;
    string a, b, c;
    shared_ptr<Gen<string> > iter;

    // Constructor of the generator.
    OneMoreHanoiGen(int _n, string _a, string _b, string _c):
        n(_n), a(_a), b(_b), c(_c) {}

    // Write your code in the step method.
    // It is very straight forward.
    // You just need to replace all control statements with the MACRO in your generator.
    // bool step(string& output);
    // Args:
    //   output: the output of your generator, set the output before doing yield.
    // Return:
    //    The return value is used by the framework.
    ///   You don't need to return true or false by yourself, and the MACRO will take care of it.
    bool step(string& output) {
        // Declare all the control statements at first.
        // IMPORTANT: You can NOT use a control MACRO without declaring its name.
        // DEC_BEG : begin the declaration.
        // DEF_IF(if_name) : declare a if statement named if_name.
        // DEF_LOOP(loop_name) : declare a loop statement named loop_name.
        // DEC_YIELD(yield_name) : declare a loop statement named yield_name.
        // DEC_END : end the declaration.
        DEC_BEG
            DEC_IF(if1), DEC_LOOP(loop1), DEC_LOOP(loop2), DEC_LOOP(loop3),
            DEC_YIELD(y1), DEC_YIELD(y2), DEC_YIELD(y3), DEC_YIELD(y4)
        DEC_END

        // Using the control MACRO to write the code.
        // PRG_BEG : begin the program.
        //   IF(name, condition, true_block, false_block);
        //   WHILE(name, condition loop_block);
        //   BREAK(loop_name);
        //   CONTINUE(loop_name);
        //   YIELD(name);
        //   RETURN();
        // PRG_END : end the program.
        PRG_BEG
        IF(if1, n == 1, {
            output = a + " --> " + c;
            YIELD(y1);
        }, {
            iter = make_shared<OneMoreHanoiGen>(n - 1, a, c, b);
            WHILE(loop1, iter->next(output), YIELD(y2));
            iter = make_shared<OneMoreHanoiGen>(1, a, b, c);
            WHILE(loop2, iter->next(output), YIELD(y3));
            iter = make_shared<OneMoreHanoiGen>(n - 1, b, a, c);
            WHILE(loop3, iter->next(output), YIELD(y4));
        });
        PRG_END
    }
};

int main() {
    string output;

    // Build a HanoiGen with Args (3, "A", "B", "C").
    OneMoreHanoiGen hanoiGen(3, "A", "B", "C");

    // Get the next output, until the generator returns false.
    // bool isAlive = hanoiGen(output);
    // if(isAlive) cout << output << endl;
    while(hanoiGen(output)) cout << output << endl;

    return 0;
}
*/

#include <cstdlib>
#include <ctime>
#include <iostream>
#include <functional>
#include <memory>
#include <string>
#include <tuple>
#include <typeinfo>
#include <utility>
#include <vector>

using namespace std;

template<typename T>
void print(vector<T>& vec) {
    for(int i = 0; i < vec.size(); ++i) {
        cout << vec[i] << " ";
    }
    cout << endl;
}

template<typename S>
class Source : public std::enable_shared_from_this<Source<S>> {
public:
	virtual ~Source() {}
    virtual bool operator()(S& output) = 0;
    bool next(S& output) {
        return (*this)(output);
    }
    shared_ptr<Source<S>> getPtr() { return this->shared_from_this(); }
};

template<typename S>
class Gen : public Source<S> {
public:
    int state;
    bool isAlive;
    Gen() : state(0), isAlive(true) {}
    virtual bool step(S& output) = 0;
    bool operator()(S& output) {
        while(!step(output));
        return isAlive;
    }
};

template<typename S, typename T>
class Coroutine : public std::enable_shared_from_this<Coroutine<S,T>> {
public:
    int state;
    bool isAlive;
    Coroutine() : state(0), isAlive(true) {}

    virtual ~Coroutine() {}
    virtual bool step(S& input, T& output) = 0;

    bool next(S& input, T& output) {
        while(!step(input, output));
        return isAlive;
    }
    bool operator()(S& input, T& output) {
        return next(input, output);
    }
    shared_ptr<Coroutine<S,T>> getPtr() { return this->shared_from_this(); }
};

#define PRG_BEG \
switch(state) { \
case PBEG: {}

#define PRG_END \
case PEND: {} \
default: { isAlive = false; return true; } }

#define BEG(name) BEG_##name
#define ELSE(name) ELSE_##name
#define END(name) END_##name

#define IF(name,c,a,b) \
case BEG(name): { if(c) { {a;} state = END(name); return false; } else { state = ELSE(name); } } \
case ELSE(name): { b; } \
case END(name): {}

#define LOOP(name,s) \
case BEG(name): { {s;} state = BEG(name); return false; } \
case END(name): {}

#define WHILE(name,c,s) \
case BEG(name): { if(!(c)) { state = END(name); return false; } {s;} state = BEG(name); return false; } \
case END(name): {}

#define YIELD(name) \
case BEG(name): { state = END(name); isAlive = true; return true; } \
case END(name): {}

#define CONTINUE(loop) { state = BEG(loop); return false; }
#define BREAK(loop) { state = END(loop); return false; }

#define GOTO(label) { state = label; return false; }

#define RETURN() { state = PEND; return false; }

#define DEC_BEG enum { PBEG = 0, PEND,
#define DEC_IF(name) BEG(name), ELSE(name), END(name)
#define DEC_LOOP(name) BEG(name), END(name)
#define DEC_YIELD(name) BEG(name), END(name)
#define DEC_END };

/*
L: def prod_iter(s):
0:   if len(s) == 0:
1:     yield []
2:   else:
3:     x = 0
4:     while true:
5:       xs = []
6:       iter = generator.create(prod_iter(s[1:]))
7:       while true:
8:         xs, isAlive = iter.resume()
9:         if !isAlive:
10           break
11         yield [x] + xs
12       x += 1
13       if x >= s[0]:
14         break
-1   return
*/
class OneMoreProdGen : public Gen<vector<int> > {
public:
    vector<unsigned int> s;
    int x;
    shared_ptr<Source<vector<int> > > iter;
    vector<int> xs;
    OneMoreProdGen(const vector<unsigned int>& _s) : s(_s) {}
    bool step(vector<int>& output) {
        DEC_BEG
            DEC_IF(if1), DEC_IF(if2), DEC_IF(if3),
            DEC_LOOP(loop1), DEC_LOOP(loop2),
            DEC_YIELD(y1), DEC_YIELD(y2)
        DEC_END
        PRG_BEG
        IF(if1, s.size()==0, {
            output.clear();
            YIELD(y1);
        }, {
            x = 0;
            WHILE(loop1, true, {
                IF(if3, x >= s[0], BREAK(loop1), {});
                {
                vector<unsigned int> ss(s.begin() + 1, s.end());
                iter = make_shared<OneMoreProdGen>(ss);
                }
                WHILE(loop2, iter->next(xs), {
                    output.clear();
                    output.push_back(x);
                    output.insert(output.end(), xs.begin(), xs.end());
                    YIELD(y2);
                });
                x += 1;
            })
        });
        PRG_END
    }
};

/*
def hanoi(n, a, b, c):
    if n == 1:
        s = str(a) +  ' --> ' + str(c)
        yield s
    else:
        for s in hanoi(n - 1, a, c, b):
            yield s
        for s in hanoi(1    , a, b, c):
            yield s
        for s in hanoi(n - 1, b, a, c):
            yield s
*/
class OneMoreHanoiGen : public Gen<string> {
public:
    int n;
    string a, b, c;
    shared_ptr<Gen<string> > iter;
    OneMoreHanoiGen(int _n, string _a, string _b, string _c):
        n(_n), a(_a), b(_b), c(_c) {}
    bool step(string& output) {
        DEC_BEG
            DEC_IF(if1), DEC_LOOP(loop1), DEC_LOOP(loop2), DEC_LOOP(loop3),
            DEC_YIELD(y1), DEC_YIELD(y2), DEC_YIELD(y3), DEC_YIELD(y4)
        DEC_END
        PRG_BEG
        IF(if1, n == 1, {
            output = a + " --> " + c;
            YIELD(y1);
        }, {
            iter = make_shared<OneMoreHanoiGen>(n - 1, a, c, b);
            WHILE(loop1, iter->next(output), YIELD(y2));
            iter = make_shared<OneMoreHanoiGen>(1, a, b, c);
            WHILE(loop2, iter->next(output), YIELD(y3));
            iter = make_shared<OneMoreHanoiGen>(n - 1, b, a, c);
            WHILE(loop3, iter->next(output), YIELD(y4));
        });
        PRG_END
    }
};

class PrimeGen : public Gen<int> {
public:
    vector<int> primes;
    int i, j;
    PrimeGen() {}
    bool step(int& output) {
        DEC_BEG
            DEC_IF(if1), DEC_IF(if2),
            DEC_LOOP(loop1), DEC_LOOP(loop2),
            DEC_YIELD(y1)
        DEC_END
        PRG_BEG
        i = 2;
        WHILE(loop1, true, {
            j = 0;
            WHILE(loop2, j < primes.size(), {
               IF(if1, i % primes[j] == 0, {i++; CONTINUE(loop1);}, j++);
            });
            primes.push_back(i);
            output = i;
            YIELD(y1);
        });
        PRG_END
    }
};

class GuessNumber : public Coroutine<int, int> {
public:
    int t, num;
    GuessNumber() {}
    bool step(int& input, int& output) {
        DEC_BEG
            DEC_IF(if1), DEC_IF(if2),
            DEC_LOOP(loop1), DEC_LOOP(loop2),
            DEC_YIELD(y1), DEC_YIELD(y2)
        DEC_END
        PRG_BEG
        t = 0;
        srand(time(0));
        cout << "Guess a number between 0 and 100!" << endl;
        WHILE(loop1, true, {
            cout << "Match " << t << endl;
            num = rand() % 100;
            cout << "input a number:";
            YIELD(y1);
            WHILE(loop2, input != num, {
                IF(if2, input == -1, BREAK(loop1), {});
                IF(if1, input < num, {
                    cout << "Too small!" << endl;
                    output = -1;
                }, {
                    cout << "Too large!" << endl;
                    output = 1;
                });
                cout << "input a number agian:";
                YIELD(y2);
            });
            cout << "Bingo! It's " << num << "!" << endl;
            cout << "Let's play it again!" << endl;
            t++;
            output = 0;
        });
        cout << "ByeBye!" << endl;
        PRG_END
    }
};

void testGuessNumber() {
    GuessNumber guess;
    int num, output;
    guess(num, output);
    do {
        cin >> num;
    } while(guess(num, output));
}

int main() {
    cout << "HanoiGen" << endl;
    string s;
    OneMoreHanoiGen hanoiGen(3, "A", "B", "C");
    while(hanoiGen(s)) cout << s << endl;

    cout << "CartesianProduct" << endl;
    vector<unsigned int> dimSize({2,3,4});
    vector<int> output(dimSize.size());
    OneMoreProdGen prodGen(dimSize);
    while(prodGen(output)) print(output);

    cout << "Prime numbers" << endl;
    PrimeGen primeGen;
    int p;
    for(int i = 0; i < 30; ++i) {
        primeGen(p);
        cout << p << " ";
    }
    cout << endl;

    testGuessNumber();
    return 0;
}
<commit_msg>Update macro_yield.cpp<commit_after>// Title       : Implementation of Coroutine in Cpp
// Author      : hanzh.xu@gmail.com
// Date        : 11-21-2020
// License     : MIT License

/*
Implementation of Coroutine in Cpp

Compiler:
// clang -std=c++17 -lstdc++

Usage:
// class MyGen        : public Gen<Output type of the generator>
class OneMoreHanoiGen : public Gen<string> {
public:
    // Local variables of the generator.
    int n;
    string a, b, c;
    shared_ptr<Gen<string> > iter;

    // Constructor of the generator.
    OneMoreHanoiGen(int _n, string _a, string _b, string _c):
        n(_n), a(_a), b(_b), c(_c) {}

    // Write your code in the step method.
    // It is very straight forward.
    // You just need to replace all control statements with the MACRO in your generator.
    // bool step(string& output);
    // Args:
    //   output: the output of your generator, set the output before doing yield.
    // Return:
    //    The return value is used by the framework.
    //    You don't need to return true or false by yourself, and the MACRO will take care of it.
    bool step(string& output) {
        // Declare all the control statements at first.
        // IMPORTANT: You can NOT use a control MACRO without declaring its name.
        // DEC_BEG : begin the declaration.
        // DEF_IF(if_name) : declare a if statement named if_name.
        // DEF_LOOP(loop_name) : declare a loop statement named loop_name.
        // DEC_YIELD(yield_name) : declare a loop statement named yield_name.
        // DEC_END : end the declaration.
        DEC_BEG
            DEC_IF(if1), DEC_LOOP(loop1), DEC_LOOP(loop2), DEC_LOOP(loop3),
            DEC_YIELD(y1), DEC_YIELD(y2), DEC_YIELD(y3), DEC_YIELD(y4)
        DEC_END

        // Using the control MACRO to write the code.
        // PRG_BEG                                       -> Begin the program.
        //   IF(name, condition, true_block, false_block); -> A if statment with name.
        //   WHILE(name, condition loop_block);            -> A while loop with name.
        //   BREAK(loop_name);                             -> Jump to the end of the loop named loop_name
        //   CONTINUE(loop_name);                          -> Jump to the begin of the loop named loop_name
        //   YIELD(name);                                  -> A yield statement with name.
        //   RETURN();                                     -> Finish the generator.
        // PRG_END                                       -> End the program.
        PRG_BEG
        IF(if1, n == 1, {
            output = a + " --> " + c;
            YIELD(y1);
        }, {
            iter = make_shared<OneMoreHanoiGen>(n - 1, a, c, b);
            WHILE(loop1, iter->next(output), YIELD(y2));
            iter = make_shared<OneMoreHanoiGen>(1, a, b, c);
            WHILE(loop2, iter->next(output), YIELD(y3));
            iter = make_shared<OneMoreHanoiGen>(n - 1, b, a, c);
            WHILE(loop3, iter->next(output), YIELD(y4));
        });
        PRG_END
    }
};

int main() {
    string output;

    // Build a HanoiGen with Args (3, "A", "B", "C").
    OneMoreHanoiGen hanoiGen(3, "A", "B", "C");

    // Get the next output, until the generator returns false.
    // bool isAlive = hanoiGen(output);
    // if(isAlive) cout << output << endl;
    while(hanoiGen(output)) cout << output << endl;

    return 0;
}
*/

#include <cstdlib>
#include <ctime>
#include <iostream>
#include <functional>
#include <memory>
#include <string>
#include <tuple>
#include <typeinfo>
#include <utility>
#include <vector>

using namespace std;

template<typename S>
class Source : public std::enable_shared_from_this<Source<S>> {
public:
	virtual ~Source() {}
    virtual bool operator()(S& output) = 0;
    bool next(S& output) {
        return (*this)(output);
    }
    shared_ptr<Source<S>> getPtr() { return this->shared_from_this(); }
};

template<typename S>
class Gen : public Source<S> {
public:
    int state;
    bool isAlive;
    Gen() : state(0), isAlive(true) {}
    virtual bool step(S& output) = 0;
    bool operator()(S& output) {
        while(!step(output));
        return isAlive;
    }
};

template<typename S, typename T>
class Coroutine : public std::enable_shared_from_this<Coroutine<S,T>> {
public:
    int state;
    bool isAlive;
    Coroutine() : state(0), isAlive(true) {}

    virtual ~Coroutine() {}
    virtual bool step(S& input, T& output) = 0;

    bool next(S& input, T& output) {
        while(!step(input, output));
        return isAlive;
    }
    bool operator()(S& input, T& output) {
        return next(input, output);
    }
    shared_ptr<Coroutine<S,T>> getPtr() { return this->shared_from_this(); }
};

#define PRG_BEG \
switch(state) { \
case PBEG: {}

#define PRG_END \
case PEND: {} \
default: { isAlive = false; return true; } }

#define BEG(name) BEG_##name
#define ELSE(name) ELSE_##name
#define END(name) END_##name

#define IF(name,c,a,b) \
case BEG(name): { if(c) { {a;} state = END(name); return false; } else { state = ELSE(name); } } \
case ELSE(name): { b; } \
case END(name): {}

#define LOOP(name,s) \
case BEG(name): { {s;} state = BEG(name); return false; } \
case END(name): {}

#define WHILE(name,c,s) \
case BEG(name): { if(!(c)) { state = END(name); return false; } {s;} state = BEG(name); return false; } \
case END(name): {}

#define YIELD(name) \
case BEG(name): { state = END(name); isAlive = true; return true; } \
case END(name): {}

#define CONTINUE(loop) { state = BEG(loop); return false; }
#define BREAK(loop) { state = END(loop); return false; }

#define GOTO(label) { state = label; return false; }

#define RETURN() { state = PEND; return false; }

#define DEC_BEG enum { PBEG = 0, PEND,
#define DEC_IF(name) BEG(name), ELSE(name), END(name)
#define DEC_LOOP(name) BEG(name), END(name)
#define DEC_YIELD(name) BEG(name), END(name)
#define DEC_END };

/*
L: def prod_iter(s):
0:   if len(s) == 0:
1:     yield []
2:   else:
3:     x = 0
4:     while true:
5:       xs = []
6:       iter = generator.create(prod_iter(s[1:]))
7:       while true:
8:         xs, isAlive = iter.resume()
9:         if !isAlive:
10           break
11         yield [x] + xs
12       x += 1
13       if x >= s[0]:
14         break
-1   return
*/
class OneMoreProdGen : public Gen<vector<int> > {
public:
    vector<unsigned int> s;
    int x;
    shared_ptr<Source<vector<int> > > iter;
    vector<int> xs;
    OneMoreProdGen(const vector<unsigned int>& _s) : s(_s) {}
    bool step(vector<int>& output) {
        DEC_BEG
            DEC_IF(if1), DEC_IF(if2), DEC_IF(if3),
            DEC_LOOP(loop1), DEC_LOOP(loop2),
            DEC_YIELD(y1), DEC_YIELD(y2)
        DEC_END
        PRG_BEG
        IF(if1, s.size()==0, {
            output.clear();
            YIELD(y1);
        }, {
            x = 0;
            WHILE(loop1, true, {
                IF(if3, x >= s[0], BREAK(loop1), {});
                {
                vector<unsigned int> ss(s.begin() + 1, s.end());
                iter = make_shared<OneMoreProdGen>(ss);
                }
                WHILE(loop2, iter->next(xs), {
                    output.clear();
                    output.push_back(x);
                    output.insert(output.end(), xs.begin(), xs.end());
                    YIELD(y2);
                });
                x += 1;
            })
        });
        PRG_END
    }
};

/*
def hanoi(n, a, b, c):
    if n == 1:
        s = str(a) +  ' --> ' + str(c)
        yield s
    else:
        for s in hanoi(n - 1, a, c, b):
            yield s
        for s in hanoi(1    , a, b, c):
            yield s
        for s in hanoi(n - 1, b, a, c):
            yield s
*/
class OneMoreHanoiGen : public Gen<string> {
public:
    int n;
    string a, b, c;
    shared_ptr<Gen<string> > iter;
    OneMoreHanoiGen(int _n, string _a, string _b, string _c):
        n(_n), a(_a), b(_b), c(_c) {}
    bool step(string& output) {
        DEC_BEG
            DEC_IF(if1), DEC_LOOP(loop1), DEC_LOOP(loop2), DEC_LOOP(loop3),
            DEC_YIELD(y1), DEC_YIELD(y2), DEC_YIELD(y3), DEC_YIELD(y4)
        DEC_END
        PRG_BEG
        IF(if1, n == 1, {
            output = a + " --> " + c;
            YIELD(y1);
        }, {
            iter = make_shared<OneMoreHanoiGen>(n - 1, a, c, b);
            WHILE(loop1, iter->next(output), YIELD(y2));
            iter = make_shared<OneMoreHanoiGen>(1, a, b, c);
            WHILE(loop2, iter->next(output), YIELD(y3));
            iter = make_shared<OneMoreHanoiGen>(n - 1, b, a, c);
            WHILE(loop3, iter->next(output), YIELD(y4));
        });
        PRG_END
    }
};

class PrimeGen : public Gen<int> {
public:
    vector<int> primes;
    int i, j;
    PrimeGen() {}
    bool step(int& output) {
        DEC_BEG
            DEC_IF(if1), DEC_IF(if2),
            DEC_LOOP(loop1), DEC_LOOP(loop2),
            DEC_YIELD(y1)
        DEC_END
        PRG_BEG
        i = 2;
        WHILE(loop1, true, {
            j = 0;
            WHILE(loop2, j < primes.size(), {
               IF(if1, i % primes[j] == 0, {i++; CONTINUE(loop1);}, j++);
            });
            primes.push_back(i);
            output = i;
            YIELD(y1);
        });
        PRG_END
    }
};

class GuessNumber : public Coroutine<int, int> {
public:
    int t, num;
    GuessNumber() {}
    bool step(int& input, int& output) {
        DEC_BEG
            DEC_IF(if1), DEC_IF(if2),
            DEC_LOOP(loop1), DEC_LOOP(loop2),
            DEC_YIELD(y1), DEC_YIELD(y2)
        DEC_END
        PRG_BEG
        t = 0;
        srand(time(0));
        cout << "Guess a number between 0 and 100!" << endl;
        WHILE(loop1, true, {
            cout << "Match " << t << endl;
            num = rand() % 100;
            cout << "input a number:";
            YIELD(y1);
            WHILE(loop2, input != num, {
                IF(if2, input == -1, BREAK(loop1), {});
                IF(if1, input < num, {
                    cout << "Too small!" << endl;
                    output = -1;
                }, {
                    cout << "Too large!" << endl;
                    output = 1;
                });
                cout << "input a number agian:";
                YIELD(y2);
            });
            cout << "Bingo! It's " << num << "!" << endl;
            cout << "Let's play it again!" << endl;
            t++;
            output = 0;
        });
        cout << "ByeBye!" << endl;
        PRG_END
    }
};

template<typename T>
void print(vector<T>& vec) {
    for(int i = 0; i < vec.size(); ++i) {
        cout << vec[i] << " ";
    }
    cout << endl;
}

void testGuessNumber() {
    GuessNumber guess;
    int num, output;
    guess(num, output);
    do {
        cin >> num;
    } while(guess(num, output));
}

int main() {
    cout << "HanoiGen" << endl;
    string s;
    OneMoreHanoiGen hanoiGen(3, "A", "B", "C");
    while(hanoiGen(s)) cout << s << endl;

    cout << "CartesianProduct" << endl;
    vector<unsigned int> dimSize({2,3,4});
    vector<int> output(dimSize.size());
    OneMoreProdGen prodGen(dimSize);
    while(prodGen(output)) print(output);

    cout << "Prime numbers" << endl;
    PrimeGen primeGen;
    int p;
    for(int i = 0; i < 30; ++i) {
        primeGen(p);
        cout << p << " ";
    }
    cout << endl;

    testGuessNumber();
    return 0;
}
<|endoftext|>