<commit_before>// Ouzel by Elviss Strazdins

#include <algorithm>
#include <cassert>
#include "Actor.hpp"
#include "SceneManager.hpp"
#include "Layer.hpp"
#include "Camera.hpp"
#include "Component.hpp"
#include "../math/Scalar.hpp"

namespace ouzel::scene
{
    ActorContainer::~ActorContainer()
    {
        for (const auto actor : children)
        {
            if (entered) actor->leave();
            actor->parent = nullptr;
            actor->setLayer(nullptr);
        }
    }

    void ActorContainer::addChild(std::unique_ptr<Actor> actor)
    {
        assert(actor.get());

        addChild(*actor);
        ownedChildren.push_back(std::move(actor));
    }

    void ActorContainer::addChild(Actor& actor)
    {
        if (actor.parent)
            actor.parent->removeChild(actor);

        actor.parent = this;
        actor.setLayer(layer);
        if (entered) actor.enter();
        children.push_back(&actor);
    }

    bool ActorContainer::removeChild(const Actor& actor)
    {
        bool result = false;

        if (const auto childIterator = std::find(children.begin(), children.end(), &actor); childIterator != children.end())
        {
            Actor* child = *childIterator;

            if (entered) child->leave();
            child->parent = nullptr;
            child->setLayer(nullptr);
            children.erase(childIterator);

            result = true;
        }

        const auto ownedChildIterator = std::find_if(ownedChildren.begin(), ownedChildren.end(), [&actor](const auto& ownedChild) noexcept {
            return ownedChild.get() == &actor;
        });
        if (ownedChildIterator != ownedChildren.end())
            ownedChildren.erase(ownedChildIterator);

        return result;
    }

    std::unique_ptr<Actor> ActorContainer::releaseChild(const Actor& actor)
    {
        std::unique_ptr<Actor> result;

        const auto ownedChildIterator = std::find_if(ownedChildren.begin(), ownedChildren.end(), [&actor](const auto& ownedChild) noexcept {
            return ownedChild.get() == &actor;
        });

        if (ownedChildIterator != ownedChildren.end())
        {
            result = std::move(*ownedChildIterator);
            ownedChildren.erase(ownedChildIterator);
        }

        removeChild(actor);

        return result;
    }

    bool ActorContainer::moveChildToBack(Actor& actor)
    {
        if (const auto i = std::find(children.begin(), children.end(), &actor); i != children.end())
        {
            std::rotate(children.begin(), i, i + 1);
            return true;
        }

        return false;
    }

    bool ActorContainer::moveChildToFront(Actor& actor)
    {
        if (const auto i = std::find(children.begin(), children.end(), &actor); i != children.end())
        {
            std::rotate(i, i + 1, children.end());
            return true;
        }

        return false;
    }

    void ActorContainer::removeAllChildren()
    {
        for (const auto actor : children)
        {
            if (entered) actor->leave();
            actor->parent = nullptr;
        }

        children.clear();
        ownedChildren.clear();
    }

    bool ActorContainer::hasChild(const Actor& actor, bool recursive) const
    {
        for (auto i = children.cbegin(); i != children.cend(); ++i)
        {
            const Actor* child = *i;

            if (child == &actor || (recursive && child->hasChild(actor, true)))
                return true;
        }

        return false;
    }

    void ActorContainer::enter()
    {
        entered = true;

        for (const auto actor : children)
            actor->enter();
    }

    void ActorContainer::leave()
    {
        entered = false;

        for (const auto actor : children)
            actor->leave();
    }

    void ActorContainer::setLayer(Layer* newLayer)
    {
        layer = newLayer;

        for (const auto actor : children)
            actor->setLayer(layer);
    }

    std::vector<std::pair<Actor*, math::Vector<float, 3>>> ActorContainer::findActors(const math::Vector<float, 2>& position) const
    {
        std::vector<std::pair<Actor*, math::Vector<float, 3>>> actors;

        std::queue<const ActorContainer*> actorContainers;
        actorContainers.push(this);

        while (!actorContainers.empty())
        {
            const auto actorContainer = actorContainers.front();
            actorContainers.pop();

            for (auto i = actorContainer->children.rbegin(); i != actorContainer->children.rend(); ++i)
            {
                Actor* actor = *i;

                if (!actor->isHidden())
                {
                    actorContainers.push(actor);

                    if (actor->isPickable() && actor->pointOn(position))
                    {
                        auto result = std::pair(actor, actor->convertWorldToLocal(math::Vector<float, 3>{position}));

                        const auto upperBound = std::upper_bound(actors.begin(), actors.end(), result,
                                                                 [](const auto& a, const auto& b) noexcept {
                                                                     return a.first->worldOrder < b.first->worldOrder;
                                                                 });

                        actors.insert(upperBound, result);
                    }
                }
            }
        }

        return actors;
    }

    std::vector<Actor*> ActorContainer::findActors(const std::vector<math::Vector<float, 2>>& edges) const
    {
        std::vector<Actor*> actors;

        std::queue<const ActorContainer*> actorContainers;
        actorContainers.push(this);

        while (!actorContainers.empty())
        {
            const auto actorContainer = actorContainers.front();
            actorContainers.pop();

            for (auto i = actorContainer->children.rbegin(); i != actorContainer->children.rend(); ++i)
            {
                Actor* actor = *i;

                if (!actor->isHidden())
                {
                    actorContainers.push(actor);

                    if (actor->isPickable() && actor->shapeOverlaps(edges))
                    {
                        const auto upperBound = std::upper_bound(actors.begin(), actors.end(), actor,
                                                                 [](const auto a, const auto b) noexcept {
                                                                     return a->worldOrder < b->worldOrder;
                                                                 });

                        actors.insert(upperBound, actor);
                    }
                }
            }
        }

        return actors;
    }

    Actor::~Actor()
    {
        if (parent) parent->removeChild(*this);

        for (const auto component : components)
            component->setActor(nullptr);
    }

    void Actor::visit(std::vector<Actor*>& drawQueue,
                      const math::Matrix<float, 4>& newParentTransform,
                      bool parentTransformDirty,
                      Camera* camera,
                      Order parentOrder,
                      bool parentHidden)
    {
        worldOrder = parentOrder + order;
        worldHidden = parentHidden || hidden;

        if (parentTransformDirty) updateTransform(newParentTransform);
        if (transformDirty) calculateTransform();

        if (!worldHidden)
        {
            const auto boundingBox = getBoundingBox();

            if (cullDisabled || (!boundingBox.isEmpty() && camera->checkVisibility(getTransform(), boundingBox)))
            {
                const auto upperBound = std::upper_bound(drawQueue.begin(), drawQueue.end(), this,
                                                         [](const auto a, const auto b) noexcept {
                                                             return a->worldOrder > b->worldOrder;
                                                         });

                drawQueue.insert(upperBound, this);
            }
        }

        for (const auto actor : children)
            actor->visit(drawQueue, transform, updateChildrenTransform, camera, worldOrder, worldHidden);

        updateChildrenTransform = false;
    }

    void Actor::draw(Camera* camera, bool wireframe)
    {
        if (transformDirty)
            calculateTransform();

        for (const auto component : components)
            if (!component->isHidden())
                component->draw(transform,
                                opacity,
                                camera->getRenderViewProjection(),
                                wireframe);
    }

    void Actor::addChild(Actor& actor)
    {
        ActorContainer::addChild(actor);

        actor.updateTransform(getTransform());
    }

    void Actor::setPosition(const math::Vector<float, 2>& newPosition)
    {
        position.v[0] = newPosition.v[0];
        position.v[1] = newPosition.v[1];

        updateLocalTransform();
    }

    void Actor::setPosition(const math::Vector<float, 3>& newPosition)
    {
        position = newPosition;

        updateLocalTransform();
    }

    void Actor::setRotation(const math::Quaternion<float>& newRotation)
    {
        rotation = newRotation;

        updateLocalTransform();
    }

    void Actor::setRotation(const math::Vector<float, 3>& newRotation)
    {
        math::Quaternion<float> roationQuaternion;
        setEulerAngles(roationQuaternion, newRotation);

        rotation = roationQuaternion;

        updateLocalTransform();
    }

    void Actor::setRotation(float newRotation)
    {
        math::Quaternion<float> roationQuaternion;
        rotate(roationQuaternion,
               newRotation,
               math::Vector<float, 3>{0.0F, 0.0F, 1.0F});

        rotation = roationQuaternion;

        updateLocalTransform();
    }

    void Actor::setScale(const math::Vector<float, 2>& newScale)
    {
        scale.v[0] = newScale.v[0];
        scale.v[1] = newScale.v[1];

        updateLocalTransform();
    }

    void Actor::setScale(const math::Vector<float, 3>& newScale)
    {
        scale = newScale;

        updateLocalTransform();
    }

    void Actor::setOpacity(float newOpacity)
    {
        opacity = std::clamp(newOpacity, 0.0F, 1.0F);
    }

    void Actor::setFlipX(bool newFlipX)
    {
        flipX = newFlipX;

        updateLocalTransform();
    }

    void Actor::setFlipY(bool newFlipY)
    {
        flipY = newFlipY;

        updateLocalTransform();
    }

    void Actor::setHidden(bool newHidden)
    {
        hidden = newHidden;
    }

    bool Actor::pointOn(const math::Vector<float, 2>& worldPosition) const
    {
        const auto localPosition = math::Vector<float, 2>{convertWorldToLocal(math::Vector<float, 3>{worldPosition})};

        for (const auto component : components)
            if (component->pointOn(localPosition))
                return true;

        return false;
    }

    bool Actor::shapeOverlaps(const std::vector<math::Vector<float, 2>>& edges) const
    {
        const auto& inverse = getInverseTransform();

        std::vector<math::Vector<float, 2>> transformedEdges;

        for (const auto& edge : edges)
        {
            auto transformedEdge = math::Vector<float, 3>{edge};

            inverse.transformPoint(transformedEdge);

            transformedEdges.emplace_back(transformedEdge.v[0], transformedEdge.v[1]);
        }

        for (const auto component : components)
            if (component->shapeOverlaps(transformedEdges))
                return true;

        return false;
    }

    void Actor::updateLocalTransform()
    {
        localTransformDirty = transformDirty = inverseTransformDirty = true;
        for (const auto component : components)
            component->updateTransform();
    }

    void Actor::updateTransform(const math::Matrix<float, 4>& newParentTransform)
    {
        parentTransform = newParentTransform;
        transformDirty = inverseTransformDirty = true;
        for (const auto component : components)
            component->updateTransform();
    }

    math::Vector<float, 3> Actor::getWorldPosition() const
    {
        auto result = position;
        const auto& currentTransform = getTransform();
        currentTransform.transformPoint(result);

        return position;
    }

    math::Vector<float, 3> Actor::convertWorldToLocal(const math::Vector<float, 3>& worldPosition) const
    {
        auto localPosition = worldPosition;

        const auto& currentInverseTransform = getInverseTransform();
        currentInverseTransform.transformPoint(localPosition);

        return localPosition;
    }

    math::Vector<float, 3> Actor::convertLocalToWorld(const math::Vector<float, 3>& localPosition) const
    {
        auto worldPosition = localPosition;

        const auto& currentTransform = getTransform();
        currentTransform.transformPoint(worldPosition);

        return worldPosition;
    }

    void Actor::calculateLocalTransform() const
    {
        setTranslation(localTransform, position);

        math::Matrix<float, 4> rotationMatrix;
        math::setRotation(rotationMatrix, rotation);

        localTransform *= rotationMatrix;

        const auto finalScale = math::Vector<float, 3>{
            scale.v[0] * (flipX ? -1.0F : 1.0F),
            scale.v[1] * (flipY ? -1.0F : 1.0F),
            scale.v[2]
        };

        math::Matrix<float, 4> scaleMatrix;
        math::setScale(scaleMatrix, finalScale);

        localTransform *= scaleMatrix;

        localTransformDirty = false;
    }

    void Actor::calculateTransform() const
    {
        transform = parentTransform * getLocalTransform();
        transformDirty = false;

        updateChildrenTransform = true;
    }

    void Actor::calculateInverseTransform() const
    {
        inverseTransform = getTransform();
        invert(inverseTransform);
        inverseTransformDirty = false;
    }

    void Actor::removeFromParent()
    {
        if (parent) parent->removeChild(*this);
    }

    void Actor::addComponent(std::unique_ptr<Component> component)
    {
        addComponent(*component);
        ownedComponents.push_back(std::move(component));
    }

    void Actor::addComponent(Component& component)
    {
        if (component.actor)
            component.actor->removeComponent(component);

        component.setActor(this);
        components.push_back(&component);
    }

    bool Actor::removeComponent(Component& component)
    {
        bool result = false;

        const auto componentIterator = std::find(components.begin(), components.end(), &component);

        if (componentIterator != components.end())
        {
            component.setActor(nullptr);
            components.erase(componentIterator);
            result = true;
        }

        const auto ownedComponentIterator = std::find_if(ownedComponents.begin(), ownedComponents.end(), [&component](const auto& ownedComponent) noexcept {
            return ownedComponent.get() == &component;
        });
        if (ownedComponentIterator != ownedComponents.end())
            ownedComponents.erase(ownedComponentIterator);

        return result;
    }

    void Actor::removeAllComponents()
    {
        for (const auto component : components)
            component->actor = nullptr;

        components.clear();
        ownedComponents.clear();
    }

    void Actor::setLayer(Layer* newLayer)
    {
        ActorContainer::setLayer(newLayer);

        for (const auto component : components)
            component->setLayer(newLayer);
    }

    math::Box<float, 3> Actor::getBoundingBox() const
    {
        math::Box<float, 3> boundingBox;

        for (const auto component : components)
            if (!component->isHidden())
                boundingBox.merge(component->getBoundingBox());

        return boundingBox;
    }
}
<commit_msg>Fix the isEmpty call<commit_after>// Ouzel by Elviss Strazdins

#include <algorithm>
#include <cassert>
#include "Actor.hpp"
#include "SceneManager.hpp"
#include "Layer.hpp"
#include "Camera.hpp"
#include "Component.hpp"
#include "../math/Scalar.hpp"

namespace ouzel::scene
{
    ActorContainer::~ActorContainer()
    {
        for (const auto actor : children)
        {
            if (entered) actor->leave();
            actor->parent = nullptr;
            actor->setLayer(nullptr);
        }
    }

    void ActorContainer::addChild(std::unique_ptr<Actor> actor)
    {
        assert(actor.get());

        addChild(*actor);
        ownedChildren.push_back(std::move(actor));
    }

    void ActorContainer::addChild(Actor& actor)
    {
        if (actor.parent)
            actor.parent->removeChild(actor);

        actor.parent = this;
        actor.setLayer(layer);
        if (entered) actor.enter();
        children.push_back(&actor);
    }

    bool ActorContainer::removeChild(const Actor& actor)
    {
        bool result = false;

        if (const auto childIterator = std::find(children.begin(), children.end(), &actor); childIterator != children.end())
        {
            Actor* child = *childIterator;

            if (entered) child->leave();
            child->parent = nullptr;
            child->setLayer(nullptr);
            children.erase(childIterator);

            result = true;
        }

        const auto ownedChildIterator = std::find_if(ownedChildren.begin(), ownedChildren.end(), [&actor](const auto& ownedChild) noexcept {
            return ownedChild.get() == &actor;
        });
        if (ownedChildIterator != ownedChildren.end())
            ownedChildren.erase(ownedChildIterator);

        return result;
    }

    std::unique_ptr<Actor> ActorContainer::releaseChild(const Actor& actor)
    {
        std::unique_ptr<Actor> result;

        const auto ownedChildIterator = std::find_if(ownedChildren.begin(), ownedChildren.end(), [&actor](const auto& ownedChild) noexcept {
            return ownedChild.get() == &actor;
        });

        if (ownedChildIterator != ownedChildren.end())
        {
            result = std::move(*ownedChildIterator);
            ownedChildren.erase(ownedChildIterator);
        }

        removeChild(actor);

        return result;
    }

    bool ActorContainer::moveChildToBack(Actor& actor)
    {
        if (const auto i = std::find(children.begin(), children.end(), &actor); i != children.end())
        {
            std::rotate(children.begin(), i, i + 1);
            return true;
        }

        return false;
    }

    bool ActorContainer::moveChildToFront(Actor& actor)
    {
        if (const auto i = std::find(children.begin(), children.end(), &actor); i != children.end())
        {
            std::rotate(i, i + 1, children.end());
            return true;
        }

        return false;
    }

    void ActorContainer::removeAllChildren()
    {
        for (const auto actor : children)
        {
            if (entered) actor->leave();
            actor->parent = nullptr;
        }

        children.clear();
        ownedChildren.clear();
    }

    bool ActorContainer::hasChild(const Actor& actor, bool recursive) const
    {
        for (auto i = children.cbegin(); i != children.cend(); ++i)
        {
            const Actor* child = *i;

            if (child == &actor || (recursive && child->hasChild(actor, true)))
                return true;
        }

        return false;
    }

    void ActorContainer::enter()
    {
        entered = true;

        for (const auto actor : children)
            actor->enter();
    }

    void ActorContainer::leave()
    {
        entered = false;

        for (const auto actor : children)
            actor->leave();
    }

    void ActorContainer::setLayer(Layer* newLayer)
    {
        layer = newLayer;

        for (const auto actor : children)
            actor->setLayer(layer);
    }

    std::vector<std::pair<Actor*, math::Vector<float, 3>>> ActorContainer::findActors(const math::Vector<float, 2>& position) const
    {
        std::vector<std::pair<Actor*, math::Vector<float, 3>>> actors;

        std::queue<const ActorContainer*> actorContainers;
        actorContainers.push(this);

        while (!actorContainers.empty())
        {
            const auto actorContainer = actorContainers.front();
            actorContainers.pop();

            for (auto i = actorContainer->children.rbegin(); i != actorContainer->children.rend(); ++i)
            {
                Actor* actor = *i;

                if (!actor->isHidden())
                {
                    actorContainers.push(actor);

                    if (actor->isPickable() && actor->pointOn(position))
                    {
                        auto result = std::pair(actor, actor->convertWorldToLocal(math::Vector<float, 3>{position}));

                        const auto upperBound = std::upper_bound(actors.begin(), actors.end(), result,
                                                                 [](const auto& a, const auto& b) noexcept {
                                                                     return a.first->worldOrder < b.first->worldOrder;
                                                                 });

                        actors.insert(upperBound, result);
                    }
                }
            }
        }

        return actors;
    }

    std::vector<Actor*> ActorContainer::findActors(const std::vector<math::Vector<float, 2>>& edges) const
    {
        std::vector<Actor*> actors;

        std::queue<const ActorContainer*> actorContainers;
        actorContainers.push(this);

        while (!actorContainers.empty())
        {
            const auto actorContainer = actorContainers.front();
            actorContainers.pop();

            for (auto i = actorContainer->children.rbegin(); i != actorContainer->children.rend(); ++i)
            {
                Actor* actor = *i;

                if (!actor->isHidden())
                {
                    actorContainers.push(actor);

                    if (actor->isPickable() && actor->shapeOverlaps(edges))
                    {
                        const auto upperBound = std::upper_bound(actors.begin(), actors.end(), actor,
                                                                 [](const auto a, const auto b) noexcept {
                                                                     return a->worldOrder < b->worldOrder;
                                                                 });

                        actors.insert(upperBound, actor);
                    }
                }
            }
        }

        return actors;
    }

    Actor::~Actor()
    {
        if (parent) parent->removeChild(*this);

        for (const auto component : components)
            component->setActor(nullptr);
    }

    void Actor::visit(std::vector<Actor*>& drawQueue,
                      const math::Matrix<float, 4>& newParentTransform,
                      bool parentTransformDirty,
                      Camera* camera,
                      Order parentOrder,
                      bool parentHidden)
    {
        worldOrder = parentOrder + order;
        worldHidden = parentHidden || hidden;

        if (parentTransformDirty) updateTransform(newParentTransform);
        if (transformDirty) calculateTransform();

        if (!worldHidden)
        {
            const auto boundingBox = getBoundingBox();

            if (cullDisabled || (!isEmpty(boundingBox) && camera->checkVisibility(getTransform(), boundingBox)))
            {
                const auto upperBound = std::upper_bound(drawQueue.begin(), drawQueue.end(), this,
                                                         [](const auto a, const auto b) noexcept {
                                                             return a->worldOrder > b->worldOrder;
                                                         });

                drawQueue.insert(upperBound, this);
            }
        }

        for (const auto actor : children)
            actor->visit(drawQueue, transform, updateChildrenTransform, camera, worldOrder, worldHidden);

        updateChildrenTransform = false;
    }

    void Actor::draw(Camera* camera, bool wireframe)
    {
        if (transformDirty)
            calculateTransform();

        for (const auto component : components)
            if (!component->isHidden())
                component->draw(transform,
                                opacity,
                                camera->getRenderViewProjection(),
                                wireframe);
    }

    void Actor::addChild(Actor& actor)
    {
        ActorContainer::addChild(actor);

        actor.updateTransform(getTransform());
    }

    void Actor::setPosition(const math::Vector<float, 2>& newPosition)
    {
        position.v[0] = newPosition.v[0];
        position.v[1] = newPosition.v[1];

        updateLocalTransform();
    }

    void Actor::setPosition(const math::Vector<float, 3>& newPosition)
    {
        position = newPosition;

        updateLocalTransform();
    }

    void Actor::setRotation(const math::Quaternion<float>& newRotation)
    {
        rotation = newRotation;

        updateLocalTransform();
    }

    void Actor::setRotation(const math::Vector<float, 3>& newRotation)
    {
        math::Quaternion<float> roationQuaternion;
        setEulerAngles(roationQuaternion, newRotation);

        rotation = roationQuaternion;

        updateLocalTransform();
    }

    void Actor::setRotation(float newRotation)
    {
        math::Quaternion<float> roationQuaternion;
        rotate(roationQuaternion,
               newRotation,
               math::Vector<float, 3>{0.0F, 0.0F, 1.0F});

        rotation = roationQuaternion;

        updateLocalTransform();
    }

    void Actor::setScale(const math::Vector<float, 2>& newScale)
    {
        scale.v[0] = newScale.v[0];
        scale.v[1] = newScale.v[1];

        updateLocalTransform();
    }

    void Actor::setScale(const math::Vector<float, 3>& newScale)
    {
        scale = newScale;

        updateLocalTransform();
    }

    void Actor::setOpacity(float newOpacity)
    {
        opacity = std::clamp(newOpacity, 0.0F, 1.0F);
    }

    void Actor::setFlipX(bool newFlipX)
    {
        flipX = newFlipX;

        updateLocalTransform();
    }

    void Actor::setFlipY(bool newFlipY)
    {
        flipY = newFlipY;

        updateLocalTransform();
    }

    void Actor::setHidden(bool newHidden)
    {
        hidden = newHidden;
    }

    bool Actor::pointOn(const math::Vector<float, 2>& worldPosition) const
    {
        const auto localPosition = math::Vector<float, 2>{convertWorldToLocal(math::Vector<float, 3>{worldPosition})};

        for (const auto component : components)
            if (component->pointOn(localPosition))
                return true;

        return false;
    }

    bool Actor::shapeOverlaps(const std::vector<math::Vector<float, 2>>& edges) const
    {
        const auto& inverse = getInverseTransform();

        std::vector<math::Vector<float, 2>> transformedEdges;

        for (const auto& edge : edges)
        {
            auto transformedEdge = math::Vector<float, 3>{edge};

            inverse.transformPoint(transformedEdge);

            transformedEdges.emplace_back(transformedEdge.v[0], transformedEdge.v[1]);
        }

        for (const auto component : components)
            if (component->shapeOverlaps(transformedEdges))
                return true;

        return false;
    }

    void Actor::updateLocalTransform()
    {
        localTransformDirty = transformDirty = inverseTransformDirty = true;
        for (const auto component : components)
            component->updateTransform();
    }

    void Actor::updateTransform(const math::Matrix<float, 4>& newParentTransform)
    {
        parentTransform = newParentTransform;
        transformDirty = inverseTransformDirty = true;
        for (const auto component : components)
            component->updateTransform();
    }

    math::Vector<float, 3> Actor::getWorldPosition() const
    {
        auto result = position;
        const auto& currentTransform = getTransform();
        currentTransform.transformPoint(result);

        return position;
    }

    math::Vector<float, 3> Actor::convertWorldToLocal(const math::Vector<float, 3>& worldPosition) const
    {
        auto localPosition = worldPosition;

        const auto& currentInverseTransform = getInverseTransform();
        currentInverseTransform.transformPoint(localPosition);

        return localPosition;
    }

    math::Vector<float, 3> Actor::convertLocalToWorld(const math::Vector<float, 3>& localPosition) const
    {
        auto worldPosition = localPosition;

        const auto& currentTransform = getTransform();
        currentTransform.transformPoint(worldPosition);

        return worldPosition;
    }

    void Actor::calculateLocalTransform() const
    {
        setTranslation(localTransform, position);

        math::Matrix<float, 4> rotationMatrix;
        math::setRotation(rotationMatrix, rotation);

        localTransform *= rotationMatrix;

        const auto finalScale = math::Vector<float, 3>{
            scale.v[0] * (flipX ? -1.0F : 1.0F),
            scale.v[1] * (flipY ? -1.0F : 1.0F),
            scale.v[2]
        };

        math::Matrix<float, 4> scaleMatrix;
        math::setScale(scaleMatrix, finalScale);

        localTransform *= scaleMatrix;

        localTransformDirty = false;
    }

    void Actor::calculateTransform() const
    {
        transform = parentTransform * getLocalTransform();
        transformDirty = false;

        updateChildrenTransform = true;
    }

    void Actor::calculateInverseTransform() const
    {
        inverseTransform = getTransform();
        invert(inverseTransform);
        inverseTransformDirty = false;
    }

    void Actor::removeFromParent()
    {
        if (parent) parent->removeChild(*this);
    }

    void Actor::addComponent(std::unique_ptr<Component> component)
    {
        addComponent(*component);
        ownedComponents.push_back(std::move(component));
    }

    void Actor::addComponent(Component& component)
    {
        if (component.actor)
            component.actor->removeComponent(component);

        component.setActor(this);
        components.push_back(&component);
    }

    bool Actor::removeComponent(Component& component)
    {
        bool result = false;

        const auto componentIterator = std::find(components.begin(), components.end(), &component);

        if (componentIterator != components.end())
        {
            component.setActor(nullptr);
            components.erase(componentIterator);
            result = true;
        }

        const auto ownedComponentIterator = std::find_if(ownedComponents.begin(), ownedComponents.end(), [&component](const auto& ownedComponent) noexcept {
            return ownedComponent.get() == &component;
        });
        if (ownedComponentIterator != ownedComponents.end())
            ownedComponents.erase(ownedComponentIterator);

        return result;
    }

    void Actor::removeAllComponents()
    {
        for (const auto component : components)
            component->actor = nullptr;

        components.clear();
        ownedComponents.clear();
    }

    void Actor::setLayer(Layer* newLayer)
    {
        ActorContainer::setLayer(newLayer);

        for (const auto component : components)
            component->setLayer(newLayer);
    }

    math::Box<float, 3> Actor::getBoundingBox() const
    {
        math::Box<float, 3> boundingBox;

        for (const auto component : components)
            if (!component->isHidden())
                boundingBox.merge(component->getBoundingBox());

        return boundingBox;
    }
}
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// TypeSymbols.cpp
// Contains type-related symbol definitions.
//
// File is under the MIT license; see LICENSE for details.
//------------------------------------------------------------------------------
#include "TypeSymbols.h"

#include "binding/ConstantValue.h"
#include "compilation/Compilation.h"

namespace {

using namespace slang;

string_view getName(BuiltInIntegerType::Kind kind) {
    switch (kind) {
        case BuiltInIntegerType::Bit: return "bit";
        case BuiltInIntegerType::Logic: return "logic";
        case BuiltInIntegerType::Reg: return "reg";
        case BuiltInIntegerType::ShortInt: return "shortint";
        case BuiltInIntegerType::Int: return "int";
        case BuiltInIntegerType::LongInt: return "longint";
        case BuiltInIntegerType::Byte: return "byte";
        case BuiltInIntegerType::Integer: return "integer";
        case BuiltInIntegerType::Time: return "time";
        default: THROW_UNREACHABLE;
    }
}

uint32_t getWidth(BuiltInIntegerType::Kind kind) {
    switch (kind) {
        case BuiltInIntegerType::Bit: return 1;
        case BuiltInIntegerType::Logic: return 1;
        case BuiltInIntegerType::Reg: return 1;
        case BuiltInIntegerType::ShortInt: return 16;
        case BuiltInIntegerType::Int: return 32;
        case BuiltInIntegerType::LongInt: return 64;
        case BuiltInIntegerType::Byte: return 8;
        case BuiltInIntegerType::Integer: return 32;
        case BuiltInIntegerType::Time: return 64;
        default: THROW_UNREACHABLE;
    }
}

bool getSigned(BuiltInIntegerType::Kind kind) {
    switch (kind) {
        case BuiltInIntegerType::Bit: return false;
        case BuiltInIntegerType::Logic: return false;
        case BuiltInIntegerType::Reg: return false;
        case BuiltInIntegerType::ShortInt: return true;
        case BuiltInIntegerType::Int: return true;
        case BuiltInIntegerType::LongInt: return true;
        case BuiltInIntegerType::Byte: return true;
        case BuiltInIntegerType::Integer: return true;
        case BuiltInIntegerType::Time: return false;
        default: THROW_UNREACHABLE;
    }
}

bool getFourState(BuiltInIntegerType::Kind kind) {
    switch (kind) {
        case BuiltInIntegerType::Bit: return false;
        case BuiltInIntegerType::Logic: return true;
        case BuiltInIntegerType::Reg: return true;
        case BuiltInIntegerType::ShortInt: return false;
        case BuiltInIntegerType::Int: return false;
        case BuiltInIntegerType::LongInt: return false;
        case BuiltInIntegerType::Byte: return false;
        case BuiltInIntegerType::Integer: return true;
        case BuiltInIntegerType::Time: return true;
        default: THROW_UNREACHABLE;
    }
}

uint32_t getWidth(span<ConstantRange const> dims) {
    uint32_t width = 0;
    for (const auto& dim : dims)
        width += dim.width();
    return width;
}

string_view getName(FloatingType::Kind kind) {
    switch (kind) {
        case FloatingType::Real: return "real";
        case FloatingType::RealTime: return "realtime";
        case FloatingType::ShortReal: return "shortreal";
        default: THROW_UNREACHABLE;
    }
}

}

namespace slang {

const ErrorType ErrorType::Instance;

const Type& Type::getCanonicalType() const {
    return *this;
}

uint32_t Type::getBitWidth() const {
    if (isIntegral())
        return as<IntegralType>().bitWidth;
    if (isFloating()) {
        switch (as<FloatingType>().floatKind) {
            case FloatingType::Real: return 64;
            case FloatingType::RealTime: return 64;
            case FloatingType::ShortReal: return 32;
            default: THROW_UNREACHABLE;
        }
    }
    return 0;
}

bool Type::isIntegral() const {
    switch (kind) {
        case SymbolKind::BuiltInIntegerType:
        case SymbolKind::VectorType:
            return true;
        default:
            return false;
    }
}

bool Type::isMatching(const Type& rhs) const {
    const Type* l = &getCanonicalType();
    const Type* r = &rhs.getCanonicalType();

    // If the two types have the same address, they are literally the same type.
    // This handles all built-in types, which are allocated once and then shared,
    // and also handles simple bit vector types that share the same range, signedness,
    // and four-stateness because we uniquify them in the compilation cache.
    if (l == r)
        return true;

    // TODO: check array types here

    return false;
}

bool Type::isEquivalent(const Type& rhs) const {
    if (isMatching(rhs))
        return true;

    return true;
}

bool Type::isAssignmentCompatible(const Type& rhs) const {
    if (isEquivalent(rhs))
        return true;

    return true;
}

bool Type::isCastCompatible(const Type& rhs) const {
    if (isAssignmentCompatible(rhs))
        return true;

    return true;
}

std::string Type::toString() const {
    return "";
}

IntegralType::IntegralType(SymbolKind kind, string_view name, uint32_t bitWidth_,
                           bool isSigned_, bool isFourState_) :
    Type(kind, name),
    bitWidth(bitWidth_), isSigned(isSigned_), isFourState(isFourState_)
{
}

bool IntegralType::isSimpleBitVector() const {
    return isBuiltIn() || (kind == SymbolKind::VectorType && as<VectorType>().dimensions.size() == 1);
}

ConstantRange IntegralType::getBitVectorRange() const {
    if (isBuiltIn())
        return { (int)bitWidth - 1, 0 };

    ASSERT(kind == SymbolKind::VectorType);

    const auto& vt = as<VectorType>();
    ASSERT(vt.dimensions.size() == 1);
    return vt.dimensions[0];
}

const Type& IntegralType::fromSyntax(Compilation& compilation, const IntegerTypeSyntax& syntax,
                                     const Scope& scope) {
    // This is a simple integral vector (possibly of just one element).
    bool isReg = syntax.keyword.kind == TokenKind::RegKeyword;
    bool isSigned = syntax.signing.kind == TokenKind::SignedKeyword;
    bool isFourState = syntax.kind != SyntaxKind::BitType;

    SmallVectorSized<ConstantRange, 4> dims;
    if (!evaluateConstantDims(compilation, syntax.dimensions, dims, scope))
        return compilation.getErrorType();

    // TODO: review this whole mess

    if (dims.empty()) {
        // TODO: signing
        return compilation.getType(syntax.kind);
    }
    else if (dims.size() == 1 && dims[0].right == 0) {
        // if we have the common case of only one dimension and lsb == 0
        // then we can use the shared representation
        int width = dims[0].left + 1;
        return compilation.getType((uint16_t)width, isSigned, isFourState, isReg);
    }
    else {
        return compilation.getType(isSigned, isFourState, isReg, dims.copy(compilation));
    }
}

bool IntegralType::evaluateConstantDims(Compilation&,
                                        const SyntaxList<VariableDimensionSyntax>& dimensions,
                                        SmallVector<ConstantRange>& results, const Scope& scope) {
    for (const VariableDimensionSyntax* dim : dimensions) {
        const SelectorSyntax* selector;
        if (!dim->specifier || dim->specifier->kind != SyntaxKind::RangeDimensionSpecifier ||
            (selector = &dim->specifier->as<RangeDimensionSpecifierSyntax>().selector)->kind != SyntaxKind::SimpleRangeSelect) {

            // TODO: errors
            //auto& diag = addError(DiagCode::PackedDimRequiresConstantRange, dim->specifier->getFirstToken().location());
            //diag << dim->specifier->sourceRange();
            return false;
        }

        const RangeSelectSyntax& range = selector->as<RangeSelectSyntax>();

        // 6.9.1 - Implementations may set a limit on the maximum length of a vector,
        // but the limit shall be at least 65536 (2^16) bits.
        const int MaxRangeBits = 16;

        // TODO: errors
        auto left = scope.evaluateConstant(range.left).coerceInteger(MaxRangeBits);
        auto right = scope.evaluateConstant(range.right).coerceInteger(MaxRangeBits);

        if (!left || !right)
            return false;

        results.emplace(ConstantRange { *left, *right });
    }
    return true;
}

BuiltInIntegerType::BuiltInIntegerType(Kind builtInKind) :
    BuiltInIntegerType(builtInKind, getSigned(builtInKind))
{
}

BuiltInIntegerType::BuiltInIntegerType(Kind builtInKind, bool isSigned) :
    IntegralType(SymbolKind::BuiltInIntegerType,
                 getName(builtInKind),
                 getWidth(builtInKind),
                 isSigned,
                 getFourState(builtInKind)),
    integerKind(builtInKind)
{
}

VectorType::VectorType(ScalarType scalarType_, span<ConstantRange const> dimensions_, bool isSigned) :
    IntegralType(SymbolKind::VectorType, getName((BuiltInIntegerType::Kind)scalarType_),
                 getWidth(dimensions_),
                 isSigned,
                 getFourState((BuiltInIntegerType::Kind)scalarType_)),
    scalarType(scalarType_),
    dimensions(dimensions_)
{
}

FloatingType::FloatingType(Kind floatKind_) :
    Type(SymbolKind::FloatingType, getName(floatKind_)),
    floatKind(floatKind_)
{
}

}
<commit_msg>Fix the Linux build<commit_after>//------------------------------------------------------------------------------
// TypeSymbols.cpp
// Contains type-related symbol definitions.
//
// File is under the MIT license; see LICENSE for details.
//------------------------------------------------------------------------------
#include "TypeSymbols.h"

#include "binding/ConstantValue.h"
#include "compilation/Compilation.h"

namespace {

using namespace slang;

string_view getName(BuiltInIntegerType::Kind kind) {
    switch (kind) {
        case BuiltInIntegerType::Bit: return "bit";
        case BuiltInIntegerType::Logic: return "logic";
        case BuiltInIntegerType::Reg: return "reg";
        case BuiltInIntegerType::ShortInt: return "shortint";
        case BuiltInIntegerType::Int: return "int";
        case BuiltInIntegerType::LongInt: return "longint";
        case BuiltInIntegerType::Byte: return "byte";
        case BuiltInIntegerType::Integer: return "integer";
        case BuiltInIntegerType::Time: return "time";
        default: THROW_UNREACHABLE;
    }
}

uint32_t getWidth(BuiltInIntegerType::Kind kind) {
    switch (kind) {
        case BuiltInIntegerType::Bit: return 1;
        case BuiltInIntegerType::Logic: return 1;
        case BuiltInIntegerType::Reg: return 1;
        case BuiltInIntegerType::ShortInt: return 16;
        case BuiltInIntegerType::Int: return 32;
        case BuiltInIntegerType::LongInt: return 64;
        case BuiltInIntegerType::Byte: return 8;
        case BuiltInIntegerType::Integer: return 32;
        case BuiltInIntegerType::Time: return 64;
        default: THROW_UNREACHABLE;
    }
}

bool getSigned(BuiltInIntegerType::Kind kind) {
    switch (kind) {
        case BuiltInIntegerType::Bit: return false;
        case BuiltInIntegerType::Logic: return false;
        case BuiltInIntegerType::Reg: return false;
        case BuiltInIntegerType::ShortInt: return true;
        case BuiltInIntegerType::Int: return true;
        case BuiltInIntegerType::LongInt: return true;
        case BuiltInIntegerType::Byte: return true;
        case BuiltInIntegerType::Integer: return true;
        case BuiltInIntegerType::Time: return false;
        default: THROW_UNREACHABLE;
    }
}

bool getFourState(BuiltInIntegerType::Kind kind) {
    switch (kind) {
        case BuiltInIntegerType::Bit: return false;
        case BuiltInIntegerType::Logic: return true;
        case BuiltInIntegerType::Reg: return true;
        case BuiltInIntegerType::ShortInt: return false;
        case BuiltInIntegerType::Int: return false;
        case BuiltInIntegerType::LongInt: return false;
        case BuiltInIntegerType::Byte: return false;
        case BuiltInIntegerType::Integer: return true;
        case BuiltInIntegerType::Time: return true;
        default: THROW_UNREACHABLE;
    }
}

uint32_t getWidth(span<ConstantRange const> dims) {
    uint32_t width = 0;
    for (const auto& dim : dims)
        width += dim.width();
    return width;
}

string_view getName(FloatingType::Kind kind) {
    switch (kind) {
        case FloatingType::Real: return "real";
        case FloatingType::RealTime: return "realtime";
        case FloatingType::ShortReal: return "shortreal";
        default: THROW_UNREACHABLE;
    }
}

}

namespace slang {

const ErrorType ErrorType::Instance;

const Type& Type::getCanonicalType() const {
    return *this;
}

uint32_t Type::getBitWidth() const {
    if (isIntegral())
        return as<IntegralType>().bitWidth;
    if (isFloating()) {
        switch (as<FloatingType>().floatKind) {
            case FloatingType::Real: return 64;
            case FloatingType::RealTime: return 64;
            case FloatingType::ShortReal: return 32;
            default: THROW_UNREACHABLE;
        }
    }
    return 0;
}

bool Type::isIntegral() const {
    switch (kind) {
        case SymbolKind::BuiltInIntegerType:
        case SymbolKind::VectorType:
            return true;
        default:
            return false;
    }
}

bool Type::isMatching(const Type& rhs) const {
    const Type* l = &getCanonicalType();
    const Type* r = &rhs.getCanonicalType();

    // If the two types have the same address, they are literally the same type.
    // This handles all built-in types, which are allocated once and then shared,
    // and also handles simple bit vector types that share the same range, signedness,
    // and four-stateness because we uniquify them in the compilation cache.
    if (l == r)
        return true;

    // TODO: check array types here

    return false;
}

bool Type::isEquivalent(const Type& rhs) const {
    if (isMatching(rhs))
        return true;

    return true;
}

bool Type::isAssignmentCompatible(const Type& rhs) const {
    if (isEquivalent(rhs))
        return true;

    return true;
}

bool Type::isCastCompatible(const Type& rhs) const {
    if (isAssignmentCompatible(rhs))
        return true;

    return true;
}

std::string Type::toString() const {
    return "";
}

IntegralType::IntegralType(SymbolKind kind, string_view name, uint32_t bitWidth_,
                           bool isSigned_, bool isFourState_) :
    Type(kind, name),
    bitWidth(bitWidth_), isSigned(isSigned_), isFourState(isFourState_)
{
}

bool IntegralType::isSimpleBitVector() const {
    return isBuiltIn() || (kind == SymbolKind::VectorType && as<VectorType>().dimensions.size() == 1);
}

ConstantRange IntegralType::getBitVectorRange() const {
    if (isBuiltIn())
        return { (int)bitWidth - 1, 0 };

    ASSERT(kind == SymbolKind::VectorType);

    const auto& vt = as<VectorType>();
    ASSERT(vt.dimensions.size() == 1);
    return vt.dimensions[0];
}

const Type& IntegralType::fromSyntax(Compilation& compilation, const IntegerTypeSyntax& syntax,
                                     const Scope& scope) {
    // This is a simple integral vector (possibly of just one element).
    bool isReg = syntax.keyword.kind == TokenKind::RegKeyword;
    bool isSigned = syntax.signing.kind == TokenKind::SignedKeyword;
    bool isFourState = syntax.kind != SyntaxKind::BitType;

    SmallVectorSized<ConstantRange, 4> dims;
    if (!evaluateConstantDims(compilation, syntax.dimensions, dims, scope))
        return compilation.getErrorType();

    // TODO: review this whole mess

    if (dims.empty()) {
        // TODO: signing
        return compilation.getType(syntax.kind);
    }
    else if (dims.size() == 1 && dims[0].right == 0) {
        // if we have the common case of only one dimension and lsb == 0
        // then we can use the shared representation
        int width = dims[0].left + 1;
        return compilation.getType((uint16_t)width, isSigned, isFourState, isReg);
    }
    else {
        return compilation.getType(isSigned, isFourState, isReg, dims.copy(compilation));
    }
}

bool IntegralType::evaluateConstantDims(Compilation&,
                                        const SyntaxList<VariableDimensionSyntax>& dimensions,
                                        SmallVector<ConstantRange>& results, const Scope& scope) {
    for (const VariableDimensionSyntax* dim : dimensions) {
        const SelectorSyntax* selector;
        if (!dim->specifier || dim->specifier->kind != SyntaxKind::RangeDimensionSpecifier ||
            (selector = &dim->specifier->as<RangeDimensionSpecifierSyntax>().selector)->kind != SyntaxKind::SimpleRangeSelect) {

            // TODO: errors
            //auto& diag = addError(DiagCode::PackedDimRequiresConstantRange, dim->specifier->getFirstToken().location());
            //diag << dim->specifier->sourceRange();
            return false;
        }

        const RangeSelectSyntax& range = selector->as<RangeSelectSyntax>();

        // 6.9.1 - Implementations may set a limit on the maximum length of a vector,
        // but the limit shall be at least 65536 (2^16) bits.
        const int MaxRangeBits = 16;

        // TODO: errors
        auto left = scope.evaluateConstant(range.left).coerceInteger(MaxRangeBits);
        auto right = scope.evaluateConstant(range.right).coerceInteger(MaxRangeBits);

        if (!left || !right)
            return false;

        results.emplace(ConstantRange { *left, *right });
    }
    return true;
}

BuiltInIntegerType::BuiltInIntegerType(Kind builtInKind) :
    BuiltInIntegerType(builtInKind, getSigned(builtInKind))
{
}

BuiltInIntegerType::BuiltInIntegerType(Kind builtInKind, bool isSigned) :
    IntegralType(SymbolKind::BuiltInIntegerType,
                 getName(builtInKind),
                 getWidth(builtInKind),
                 isSigned,
                 getFourState(builtInKind)),
    integerKind(builtInKind)
{
}

VectorType::VectorType(ScalarType scalarType_, span<ConstantRange const> dimensions_, bool isSigned) :
    IntegralType(SymbolKind::VectorType, getName((BuiltInIntegerType::Kind)scalarType_),
                 getWidth(dimensions_),
                 isSigned,
                 getFourState((BuiltInIntegerType::Kind)scalarType_)),
    dimensions(dimensions_),
    scalarType(scalarType_)
{
}

FloatingType::FloatingType(Kind floatKind_) :
    Type(SymbolKind::FloatingType, getName(floatKind_)),
    floatKind(floatKind_)
{
}

}
<|endoftext|>


<commit_before>#include "tests-base.hpp"

#include "utf8rewind.h"

#include "helpers-strings.hpp"

TEST(ToLower, BasicLatin)
{
	const char* c = "Hello World!";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(12, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("hello world!", b);
	EXPECT_EQ(0, errors);
}

TEST(ToLower, BasicLatinUppercase)
{
	const char* c = "G";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(1, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("g", b);
	EXPECT_EQ(0, errors);
}

TEST(ToLower, BasicLatinLowercase)
{
	const char* c = "y";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(1, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("y", b);
	EXPECT_EQ(0, errors);
}

TEST(ToLower, BasicLatinUnaffected)
{
	const char* c = "@";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(1, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("@", b);
	EXPECT_EQ(0, errors);
}

TEST(ToLower, BasicLatinAmountOfBytes)
{
	const char* c = "Playable";
	int32_t errors = 0;

	EXPECT_EQ(8, utf8tolower(c, strlen(c), nullptr, 0, &errors));
	EXPECT_EQ(0, errors);
}

TEST(ToLower, BasicLatinNotEnoughSpace)
{
	const char* c = "VERY important";
	const size_t s = 9;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(8, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("very imp", b);
	EXPECT_EQ(UTF8_ERR_NOT_ENOUGH_SPACE, errors);
}

TEST(ToLower, TwoBytes)
{
	const char* c = "Rac\xC3\x88r";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(6, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("rac\xC3\xA8r", b);
	EXPECT_EQ(0, errors);
}

TEST(ToLower, TwoBytesUppercase)
{
	const char* c = "\xC3\x82";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(2, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("\xC3\xA2", b);
	EXPECT_EQ(0, errors);
}

TEST(ToLower, TwoBytesLowercase)
{
	const char* c = "\xC3\xA7";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(2, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("\xC3\xA7", b);
	EXPECT_EQ(0, errors);
}

TEST(ToLower, TwoBytesUnaffected)
{
	const char* c = "\xC3\xB7";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(2, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("\xC3\xB7", b);
	EXPECT_EQ(0, errors);
}

TEST(ToLower, TwoBytesAmountOfBytes)
{
	const char* c = "\xC3\x8Dnteresting";
	int32_t errors = 0;

	EXPECT_EQ(12, utf8tolower(c, strlen(c), nullptr, 0, &errors));
	EXPECT_EQ(0, errors);
}

TEST(ToLower, TwoBytesNotEnoughSpace)
{
	const char* c = "Atl\xC3\x84ntis";
	const size_t s = 4;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(3, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("atl", b);
	EXPECT_EQ(UTF8_ERR_NOT_ENOUGH_SPACE, errors);
}

TEST(ToLower, ThreeBytes)
{
	const char* c = "You're number \xE2\x85\xA0";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(17, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("you're number \xE2\x85\xB0", b);
	EXPECT_EQ(0, errors);
}

TEST(ToLower, ThreeBytesUppercase)
{
	const char* c = "\xE2\x85\xAF";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(3, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("\xE2\x85\xBF", b);
	EXPECT_EQ(0, errors);
}

TEST(ToLower, ThreeBytesLowercase)
{
	const char* c = "\xE2\x85\xB6";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(3, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("\xE2\x85\xB6", b);
	EXPECT_EQ(0, errors);
}

TEST(ToLower, ThreeBytesUnaffected)
{
	const char* c = "\xE2\x86\x89";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(3, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("\xE2\x86\x89", b);
	EXPECT_EQ(0, errors);
}

TEST(ToLower, ThreeBytesAmountOfBytes)
{
	const char* c = "That's \xE2\x93\xA9" "any";
	int32_t errors = 0;

	EXPECT_EQ(13, utf8tolower(c, strlen(c), nullptr, 0, &errors));
	EXPECT_EQ(0, errors);
}

TEST(ToLower, ThreeBytesNotEnoughSpace)
{
	const char* c = "Whole Lotta \xE2\x93\xA1osie";
	const size_t s = 14;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(12, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("whole lotta ", b);
	EXPECT_EQ(UTF8_ERR_NOT_ENOUGH_SPACE, errors);
}

TEST(ToLower, InvalidData)
{
	int32_t errors = 0;

	EXPECT_EQ(0, utf8tolower(nullptr, 1, nullptr, 0, &errors));
	EXPECT_EQ(UTF8_ERR_INVALID_DATA, errors);
}<commit_msg>suite-tolower: Added tests for four-byte codepoints.<commit_after>#include "tests-base.hpp"

#include "utf8rewind.h"

#include "helpers-strings.hpp"

TEST(ToLower, BasicLatin)
{
	const char* c = "Hello World!";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(12, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("hello world!", b);
	EXPECT_EQ(0, errors);
}

TEST(ToLower, BasicLatinUppercase)
{
	const char* c = "G";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(1, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("g", b);
	EXPECT_EQ(0, errors);
}

TEST(ToLower, BasicLatinLowercase)
{
	const char* c = "y";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(1, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("y", b);
	EXPECT_EQ(0, errors);
}

TEST(ToLower, BasicLatinUnaffected)
{
	const char* c = "@";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(1, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("@", b);
	EXPECT_EQ(0, errors);
}

TEST(ToLower, BasicLatinAmountOfBytes)
{
	const char* c = "Playable";
	int32_t errors = 0;

	EXPECT_EQ(8, utf8tolower(c, strlen(c), nullptr, 0, &errors));
	EXPECT_EQ(0, errors);
}

TEST(ToLower, BasicLatinNotEnoughSpace)
{
	const char* c = "VERY important";
	const size_t s = 9;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(8, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("very imp", b);
	EXPECT_EQ(UTF8_ERR_NOT_ENOUGH_SPACE, errors);
}

TEST(ToLower, TwoBytes)
{
	const char* c = "Rac\xC3\x88r";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(6, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("rac\xC3\xA8r", b);
	EXPECT_EQ(0, errors);
}

TEST(ToLower, TwoBytesUppercase)
{
	const char* c = "\xC3\x82";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(2, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("\xC3\xA2", b);
	EXPECT_EQ(0, errors);
}

TEST(ToLower, TwoBytesLowercase)
{
	const char* c = "\xC3\xA7";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(2, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("\xC3\xA7", b);
	EXPECT_EQ(0, errors);
}

TEST(ToLower, TwoBytesUnaffected)
{
	const char* c = "\xC3\xB7";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(2, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("\xC3\xB7", b);
	EXPECT_EQ(0, errors);
}

TEST(ToLower, TwoBytesAmountOfBytes)
{
	const char* c = "\xC3\x8Dnteresting";
	int32_t errors = 0;

	EXPECT_EQ(12, utf8tolower(c, strlen(c), nullptr, 0, &errors));
	EXPECT_EQ(0, errors);
}

TEST(ToLower, TwoBytesNotEnoughSpace)
{
	const char* c = "Atl\xC3\x84ntis";
	const size_t s = 4;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(3, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("atl", b);
	EXPECT_EQ(UTF8_ERR_NOT_ENOUGH_SPACE, errors);
}

TEST(ToLower, ThreeBytes)
{
	const char* c = "You're number \xE2\x85\xA0";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(17, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("you're number \xE2\x85\xB0", b);
	EXPECT_EQ(0, errors);
}

TEST(ToLower, ThreeBytesUppercase)
{
	const char* c = "\xE2\x85\xAF";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(3, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("\xE2\x85\xBF", b);
	EXPECT_EQ(0, errors);
}

TEST(ToLower, ThreeBytesLowercase)
{
	const char* c = "\xE2\x85\xB6";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(3, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("\xE2\x85\xB6", b);
	EXPECT_EQ(0, errors);
}

TEST(ToLower, ThreeBytesUnaffected)
{
	const char* c = "\xE2\x86\x89";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(3, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("\xE2\x86\x89", b);
	EXPECT_EQ(0, errors);
}

TEST(ToLower, ThreeBytesAmountOfBytes)
{
	const char* c = "That's \xE2\x93\xA9" "any";
	int32_t errors = 0;

	EXPECT_EQ(13, utf8tolower(c, strlen(c), nullptr, 0, &errors));
	EXPECT_EQ(0, errors);
}

TEST(ToLower, ThreeBytesNotEnoughSpace)
{
	const char* c = "Whole Lotta \xE2\x93\xA1osie";
	const size_t s = 14;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(12, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("whole lotta ", b);
	EXPECT_EQ(UTF8_ERR_NOT_ENOUGH_SPACE, errors);
}

TEST(ToLower, FourBytes)
{
	const char* c = "Bring a t\xF0\x91\xA2\xA9wel";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(16, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("bring a t\xF0\x91\xA3\x89wel", b);
	EXPECT_EQ(0, errors);
}

TEST(ToLower, FourBytesUppercase)
{
	const char* c = "\xF0\x91\xA2\xB2";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(4, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("\xF0\x91\xA3\x92", b);
	EXPECT_EQ(0, errors);
}

TEST(ToLower, FourBytesLowercase)
{
	const char* c = "\xF0\x90\x90\xB6";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(4, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("\xF0\x90\x90\xB6", b);
	EXPECT_EQ(0, errors);
}

TEST(ToLower, FourBytesUnaffected)
{
	const char* c = "\xF0\x91\xA3\xA4";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(4, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("\xF0\x91\xA3\xA4", b);
	EXPECT_EQ(0, errors);
}

TEST(ToLower, FourBytesAmountOfBytes)
{
	const char* c = "Say \xF0\x91\xA2\xB9";
	int32_t errors = 0;

	EXPECT_EQ(8, utf8tolower(c, strlen(c), nullptr, 0, &errors));
	EXPECT_EQ(0, errors);
}

TEST(ToLower, FourBytesNotEnoughSpace)
{
	const char* c = "My \xF0\x91\xA3\x8Eurt";
	const size_t s = 5;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(3, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("my ", b);
	EXPECT_EQ(UTF8_ERR_NOT_ENOUGH_SPACE, errors);
}

TEST(ToLower, InvalidCodepoint)
{
	const char* c = "\xF0\x92";
	const size_t s = 256;
	char b[s] = { 0 };
	int32_t errors = 0;

	EXPECT_EQ(3, utf8tolower(c, strlen(c), b, s - 1, &errors));
	EXPECT_UTF8EQ("\xEF\xBF\xBD", b);
	EXPECT_EQ(0, errors);
}

TEST(ToLower, InvalidData)
{
	int32_t errors = 0;

	EXPECT_EQ(0, utf8tolower(nullptr, 1, nullptr, 0, &errors));
	EXPECT_EQ(UTF8_ERR_INVALID_DATA, errors);
}<|endoftext|>


<commit_before>/* -*- mode:C++; -*- */
/* MyThOS: The Many-Threads Operating System
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Copyright 2016 Randolf Rotta, Robert Kuban, and contributors, BTU Cottbus-Senftenberg
 */
#pragma once

#include <atomic>
#include "async/Place.hh"
#include "async/Tasklet.hh"
#include "async/mlog.hh"

namespace mythos {
namespace async {

class DeletionMonitor
{
public:
  DeletionMonitor() : refcount(0), deleteTask(nullptr) {}

  void acquireRef() { refcount++; }

  void releaseRef() {
    auto result = refcount.fetch_sub(1);
    if (result == 0 && deleteTask != nullptr) {
      MLOG_DETAIL(mlog::async, this, "schedule delete task");
      getLocalPlace().pushShared(deleteTask);
    }
  }

  template<class FUNCTOR>
  void doDelete(Tasklet* msg, FUNCTOR fun) {
    refcount++;
    deleteTask = msg->set(fun);
    if (--refcount == 0) {
      MLOG_DETAIL(mlog::async, this, "schedule delete task immediately");
      getLocalPlace().pushShared(deleteTask);
    }
  }

protected:
  std::atomic<size_t> refcount;
  std::atomic<Tasklet*> deleteTask;
};

} // async
} //mythos

<commit_msg>Fixed off-by-one error in reference counter.<commit_after>/* -*- mode:C++; -*- */
/* MyThOS: The Many-Threads Operating System
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 * Copyright 2016 Randolf Rotta, Robert Kuban, and contributors, BTU Cottbus-Senftenberg
 */
#pragma once

#include <atomic>
#include "async/Place.hh"
#include "async/Tasklet.hh"
#include "async/mlog.hh"

namespace mythos {
namespace async {

class DeletionMonitor
{
public:
  DeletionMonitor() : refcount(0), deleteTask(nullptr) {}

  void acquireRef() { refcount++; }

  void releaseRef() {
    auto result = --refcount;
    if (result == 0 && deleteTask != nullptr) {
      MLOG_DETAIL(mlog::async, this, "schedule delete task");
      getLocalPlace().pushShared(deleteTask);
    }
  }

  template<class FUNCTOR>
  void doDelete(Tasklet* msg, FUNCTOR fun) {
    refcount++;
    deleteTask = msg->set(fun);
    if (--refcount == 0) {
      MLOG_DETAIL(mlog::async, this, "schedule delete task immediately");
      getLocalPlace().pushShared(deleteTask);
    }
  }

protected:
  std::atomic<size_t> refcount;
  std::atomic<Tasklet*> deleteTask;
};

} // async
} //mythos

<|endoftext|>


<commit_before>//
// Created by salmon on 17-1-6.
//

#include <gtest/gtest.h>
#include <complex>
#include <iostream>
#include "simpla/SIMPLA_config.h"
#include "simpla/data/Data.h"
#include "simpla/utilities/FancyStream.h"
#include "simpla/utilities/SingletonHolder.h"

using namespace simpla;
using namespace simpla::data;
TEST(DataTable, memory) {
    auto db = DataNode::New();

    *(*db)["CartesianGeometry"] = {"hello world!"};
    *(*db)["d"] = {1, 2, 3, 4, 5, 56, 6, 6};
    (*db)["g"]->SetValue<nTuple<int, 2, 2, 2>>({{{1, 2}, {3, 4}}, {{5, 5}, {6, 6}}});
    //    *(*db)["strlist"] = {{"abc", "def"}, {"abc", "def"}, {"abc", "def"}, {"abc", "def"}};
    *(*db)["b/a"] = (5);

    *(*db)["/b/sub/1/2/3/4/d/123456"] = {1, 2, 3};

    *(*db)["/b/sub/c"] += {5, 6, 7, 8};
    *(*db)["/b/sub/c"] += {1, 5, 3, 4};
    *(*db)["/b/sub/c"] += {2, 5, 3, 4};
    *(*db)["/b/sub/c"] += {3, 5, 3, 4};
    *(*db)["/b/sub/c"] += {4, 5, 3, 4};

    //    db->AddValue("/b/sub/d", 1);
    //    db->AddValue("/b/sub/d", 5);
    //    db->AddValue("/b/sub/d", 5);
    //    db->AddValue("/b/sub/d", 5);
    //    //
    *(*db)["/b/sub/d"] += "wa wa";
    *(*db)["/b/sub/d"] += "la la";

    *(*db)["/b/sub/a"] += {3, 5, 3, 4};
    *(*db)["/b/sub/a"] += {3, 5, 3, 4};

    *(*db)["/b/sub/e"] = {1, 2, 3, 4};
    *(*db)["/b/sub/e"] += 9;

    *(*db)["a"] += {"a"_, "not_debug"_ = false, "g"_ = {1, 2, 3, 4, 5, 5, 6, 6},
                    "c"_ = {" world!", "hello!", "hello !", "hello!", "hello !", "hello !", "hello !", "hello!"}};
    //    *(*db)["h"] = {{"abc"_ = "def"}, {"abc"_ = "def"}, {"abc"_ = "def"}, {"abc"_ = "def"}};
    *(*db)["i"] = {"default"_, "abc"_ = 1, "abc"_ = "def", "abc"_ = 2, "abc"_ = "sadfsdf"};
    *(*db)["i"] += {"abc"_ = {"abc1"_ = {"def"_ = {"abc"_ = {"abc"_ = "sadfsdf"}}}}};
    LOGGER << db->GetNumberOfChildren() << std::endl;
    LOGGER << "db: " << (*db) << std::endl;
    EXPECT_EQ(db->GetNode("b/a")->as<int>(), 5);

    EXPECT_EQ((*db)["/CartesianGeometry"]->as<std::string>(), "hello world!");
}

TEST(DataTable, lua) {
    auto db = DataNode::New("lua://");
    db->Parse(
        "PI = 3.141592653589793\n"
        "Context = {\n"
        "    c = 299792458.0, -- m/s\n"
        "    qe = 1.60217656e-19, -- C\n"
        "    me = 9.10938291e-31, --kg\n"
        "    mp = 1.672621777e-27, --kg\n"
        "    mp_me = 1836.15267245, --\n"
        "    KeV = 1.1604e7, -- K\n"
        "    Tesla = 1.0, -- Tesla\n"
        "    TWOPI = PI * 2,\n"
        "    k_B = 1.3806488e-23, --Boltzmann_constant\n"
        "    epsilon0 = 8.8542e-12,\n"
        "    AAA = { c =  3 , d = { c = \"3\", e = { 1, 3, 4, 5 } } },\n"
        "    CCC = { 1, 3, 4, 5 }\n"
        "}");
    LOGGER << "lua:// " << *(*db)["/Context"] << std::endl;
    EXPECT_EQ((*db)["/Context/AAA/c"]->as<int>(), 3);
    //    EXPECT_EQ(((*db)["/Context/CCC"]->as<nTuple<int, 4>>()), (nTuple<int, 4>{1, 3, 4, 5}));

    EXPECT_DOUBLE_EQ((*db)["/Context/c"]->as<double>(), 299792458);

    //   db->Set("box", {{1, 2, 3}, {4, 5, 6}});
    //    LOGGER << "box  = " <<db->Get<std::tuple<nTuple<int, 3>, nTuple<int, 3>>>("box") << std::endl;
}
//
// TEST(DataTable, samrai) {
//    logger::set_stdout_level(1000);
//
//    LOGGER << "Registered DataBase: " << GLOBAL_DATA_BACKEND_FACTORY.GetBackendList() << std::endl;
//    DataTable db("samrai://");
//    //   db->Set("f", {1, 2, 3, 4, 5, 56, 6, 6});
//    //   db->Set("/d/e/f", "Just atest");
//    //   db->Set("/d/e/g", {"a"_ = "la la land", "b"_ = 1235.5});
//    //   db->Set("/d/e/e", 1.23456);
//   db->Set("box", {{1, 2, 3}, {4, 5, 6}});
//    LOGGER << *db.database() << std::endl;
//    LOGGER << "box  = " <<db->Get<std::tuple<nTuple<int, 3>, nTuple<int, 3>>>("box") << std::endl;
//
//}
//
// TEST(DataTable, hdf5) {
//    logger::set_stdout_level(1000);
//
//    //    LOGGER << "Registered DataBase: " << GLOBAL_DATA_BACKEND_FACTORY.GetBackendList() << std::endl;
//    auto db = DataBase::New("test.h5");
//    db->Set("pi", 3.1415926);
//    db->Set("a", "just a test");
//    //   db->Set("c", {1.2346, 4.0, 5.0, 6.0, 6.1});
//    //   db->Set({"a"_, "not_debug"_ = false, "g"_ = {1, 2, 3, 4, 5, 5, 6, 6},
//    //                 "c"_ = {" world!", "hello!", "hello !", "hello!", "hello !", "hello !", "hello !",
//    "hello!"}});
//    //   db->Set("h", {{"abc"_ = "def"}, {"abc"_ = "def"}, {"abc"_ = "def"}, {"abc"_ = "def"}});
//    db->Set("i", {"abc"_ = 1, "abc"_ = "def", "abc"_ = 2, "abc"_ = "sadfsdf"});
//    db->Set("j", {"abc"_ = {"abc"_ = {"def"_ = {"abc"_ = {"abc"_ = "sadfsdf"}}}}});
//    //   db->AddValue("/b/sub/d", {1, 2});
//    //   db->AddValue("/b/sub/d", 5);
//    //   db->AddValue("/b/sub/d", 5);
//    //   db->AddValue("/b/sub/d", 5);
//
//    //   db->Set("/b/sub/a", {3, 5, 3, 4});
//    db->Set("/b/sub/b", 9);
//    LOGGER << "h5:// " << db << std::endl;
//    db->Set("box", {{1, 2, 3}, {4, 5, 6}});
//    LOGGER << "box  = " << db->Get<std::tuple<nTuple<int, 3>, nTuple<int, 3>>>("box") << std::endl;
//}<commit_msg> snapshot<commit_after>//
// Created by salmon on 17-1-6.
//

#include <gtest/gtest.h>
#include <complex>
#include <iostream>
#include "simpla/SIMPLA_config.h"
#include "simpla/data/Data.h"
#include "simpla/utilities/FancyStream.h"
#include "simpla/utilities/SingletonHolder.h"

using namespace simpla;
using namespace simpla::data;
TEST(DataTable, memory) {
    auto db = DataNode::New();

    *(*db)["CartesianGeometry"] = {"hello world!"};
    *(*db)["d"] = {1, 2, 3, 4, 5, 56, 6, 6};
    (*db)["g"]->SetValue<nTuple<int, 2, 2, 2>>({{{1, 2}, {3, 4}}, {{5, 5}, {6, 6}}});
    //    *(*db)["strlist"] = {{"abc", "def"}, {"abc", "def"}, {"abc", "def"}, {"abc", "def"}};
    *(*db)["b/a"] = (5);

    *(*db)["/b/sub/1/2/3/4/d/123456"] = {1, 2, 3};

    *(*db)["/b/sub/c"] += {5, 6, 7, 8};
    *(*db)["/b/sub/c"] += {1, 5, 3, 4};
    *(*db)["/b/sub/c"] += {2, 5, 3, 4};
    *(*db)["/b/sub/c"] += {3, 5, 3, 4};
    *(*db)["/b/sub/c"] += {4, 5, 3, 4};

    //    db->AddValue("/b/sub/d", 1);
    //    db->AddValue("/b/sub/d", 5);
    //    db->AddValue("/b/sub/d", 5);
    //    db->AddValue("/b/sub/d", 5);
    //    //
    *(*db)["/b/sub/d"] += "wa wa";
    *(*db)["/b/sub/d"] += "la la";

    *(*db)["/b/sub/a"] += {0, 1, 2, 3};
    *(*db)["/b/sub/a"] += {3, 5, 3, 4};

    *(*db)["/b/sub/e"] = {1, 2, 3, 4};
    *(*db)["/b/sub/e"] += 9;

    *(*db)["a"] += {"a"_, "not_debug"_ = false, "g"_ = {1, 2, 3, 4, 5, 5, 6, 6},
                    "c"_ = {" world!", "hello!", "hello !", "hello!", "hello !", "hello !", "hello !", "hello!"}};
    //    *(*db)["h"] = {{"abc"_ = "def"}, {"abc"_ = "def"}, {"abc"_ = "def"}, {"abc"_ = "def"}};
    *(*db)["i"] = {"default"_, "abc"_ = 1, "abc"_ = "def", "abc"_ = 2, "abc"_ = "sadfsdf"};
    *(*db)["i"] += {"abc"_ = {"abc1"_ = {"def"_ = {"abc"_ = {"abc"_ = "sadfsdf"}}}}};
    MESSAGE << "db: " << (*db) << std::endl;
    EXPECT_EQ(db->GetNode("/b/sub/d")->GetNumberOfChildren(), 2);
    EXPECT_EQ(db->GetNode("b/a")->as<int>(), 5);
    EXPECT_TRUE(db->Check("a/a"));
    EXPECT_FALSE(db->Check("a/not_debug"));

    EXPECT_EQ((db->GetNode("/b/sub/a/1")->as<nTuple<int, 4>>()), (nTuple<int, 4>{3, 5, 3, 4}));

    EXPECT_EQ((*db)["/CartesianGeometry"]->as<std::string>(), "hello world!");
}

TEST(DataTable, lua) {
    auto db = DataNode::New("lua://");
    db->Parse(
        "PI = 3.141592653589793\n"
        "Context = {\n"
        "    c = 299792458.0, -- m/s\n"
        "    qe = 1.60217656e-19, -- C\n"
        "    me = 9.10938291e-31, --kg\n"
        "    mp = 1.672621777e-27, --kg\n"
        "    mp_me = 1836.15267245, --\n"
        "    KeV = 1.1604e7, -- K\n"
        "    Tesla = 1.0, -- Tesla\n"
        "    TWOPI = PI * 2,\n"
        "    k_B = 1.3806488e-23, --Boltzmann_constant\n"
        "    epsilon0 = 8.8542e-12,\n"
        "    AAA = { c =  3 , d = { c = \"3\", e = { 1, 3, 4, 5 } } },\n"
        "    CCC = { 1, 3, 4, 5 }\n"
        "}");
    MESSAGE << "lua:// " << *(*db)["/Context"] << std::endl;
    EXPECT_EQ((*db)["/Context/AAA/c"]->as<int>(), 3);
    //    EXPECT_EQ(((*db)["/Context/CCC"]->as<nTuple<int, 4>>()), (nTuple<int, 4>{1, 3, 4, 5}));

    EXPECT_DOUBLE_EQ((*db)["/Context/c"]->as<double>(), 299792458);

    //   db->Set("box", {{1, 2, 3}, {4, 5, 6}});
    //    LOGGER << "box  = " <<db->Get<std::tuple<nTuple<int, 3>, nTuple<int, 3>>>("box") << std::endl;
}
//
// TEST(DataTable, samrai) {
//    logger::set_stdout_level(1000);
//
//    LOGGER << "Registered DataBase: " << GLOBAL_DATA_BACKEND_FACTORY.GetBackendList() << std::endl;
//    DataTable db("samrai://");
//    //   db->Set("f", {1, 2, 3, 4, 5, 56, 6, 6});
//    //   db->Set("/d/e/f", "Just atest");
//    //   db->Set("/d/e/g", {"a"_ = "la la land", "b"_ = 1235.5});
//    //   db->Set("/d/e/e", 1.23456);
//   db->Set("box", {{1, 2, 3}, {4, 5, 6}});
//    LOGGER << *db.database() << std::endl;
//    LOGGER << "box  = " <<db->Get<std::tuple<nTuple<int, 3>, nTuple<int, 3>>>("box") << std::endl;
//
//}
//
// TEST(DataTable, hdf5) {
//    logger::set_stdout_level(1000);
//
//    //    LOGGER << "Registered DataBase: " << GLOBAL_DATA_BACKEND_FACTORY.GetBackendList() << std::endl;
//    auto db = DataBase::New("test.h5");
//    db->Set("pi", 3.1415926);
//    db->Set("a", "just a test");
//    //   db->Set("c", {1.2346, 4.0, 5.0, 6.0, 6.1});
//    //   db->Set({"a"_, "not_debug"_ = false, "g"_ = {1, 2, 3, 4, 5, 5, 6, 6},
//    //                 "c"_ = {" world!", "hello!", "hello !", "hello!", "hello !", "hello !", "hello !",
//    "hello!"}});
//    //   db->Set("h", {{"abc"_ = "def"}, {"abc"_ = "def"}, {"abc"_ = "def"}, {"abc"_ = "def"}});
//    db->Set("i", {"abc"_ = 1, "abc"_ = "def", "abc"_ = 2, "abc"_ = "sadfsdf"});
//    db->Set("j", {"abc"_ = {"abc"_ = {"def"_ = {"abc"_ = {"abc"_ = "sadfsdf"}}}}});
//    //   db->AddValue("/b/sub/d", {1, 2});
//    //   db->AddValue("/b/sub/d", 5);
//    //   db->AddValue("/b/sub/d", 5);
//    //   db->AddValue("/b/sub/d", 5);
//
//    //   db->Set("/b/sub/a", {3, 5, 3, 4});
//    db->Set("/b/sub/b", 9);
//    LOGGER << "h5:// " << db << std::endl;
//    db->Set("box", {{1, 2, 3}, {4, 5, 6}});
//    LOGGER << "box  = " << db->Get<std::tuple<nTuple<int, 3>, nTuple<int, 3>>>("box") << std::endl;
//}<|endoftext|>


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

// Class include:
#include "window-platform.h"

// Internal includes:
#include "application.h"

// External includes:
#include "krust/public-api/scoped-free.h"
#include "krust/public-api/logging.h"
#include <string.h>

namespace Krust {

namespace IO {

/**
 * @brief A helper struct to init a values array to be passed to XCB.
 */
struct XcbValueList
{
  XcbValueList()
  {
    // Zero the values array in the absence of documentation for how
    // the list must be terminated:
    memset(values, 0, sizeof(values[0]) * 32);
  }

  // Have a nice long list of values in the absence of documentation for how
  // long the list must be:
  uint32_t values[32];
};

WindowPlatform::WindowPlatform(
  Krust::IO::Application& application,
  Krust::IO::Window& container,
  const char* title) :
    mApplication(application),
    mDeleteWindowEventAtom(0)
{
  KRUST_LOG_INFO << "WindowPlatform created.\n";
  suppress_unused(&container, &title); ///@ToDo: Set the window title through XCB

  // Create the X11 window:
  KRUST_ASSERT1(Connection(), "Null connection.");
  if(Connection())
  {
    mXcbWindow = xcb_generate_id(Connection());
    KRUST_ASSERT1(mXcbWindow, "No window id.");
    if(!mXcbWindow)
    {
      KRUST_LOG_ERROR << "Failed to generate window ID." << endlog;
    }
    else
    {
      const uint32_t  mask =
          // Not sure having this background is a good idea for Vulkan:
          XCB_CW_BACK_PIXEL |
          XCB_CW_EVENT_MASK;
      XcbValueList values;
      values.values[0] = Screen()->black_pixel;
      values.values[1] =
        XCB_EVENT_MASK_EXPOSURE         |
        XCB_EVENT_MASK_STRUCTURE_NOTIFY |
        XCB_EVENT_MASK_FOCUS_CHANGE     |
        // The app should control which of these are subscribed to:
        XCB_EVENT_MASK_BUTTON_PRESS     | XCB_EVENT_MASK_BUTTON_RELEASE |
        XCB_EVENT_MASK_POINTER_MOTION   |
        XCB_EVENT_MASK_ENTER_WINDOW     | XCB_EVENT_MASK_LEAVE_WINDOW   |
        XCB_EVENT_MASK_KEY_PRESS        | XCB_EVENT_MASK_KEY_RELEASE
      ;

      // Calculate a reasonable width and height:
      // Note in multimonitor setups this screen is likely the whole virtual
      // screen encompassing both monitors. We should really figure out the
      // primary monitor and size ourself to fit onto that:
      // https://stackoverflow.com/questions/36966900/xcb-get-all-monitors-ands-their-x-y-coordinates
      const unsigned windowClientWidth  = std::min(1800u, Screen()->width_in_pixels  / 4u * 3u);
      const unsigned windowClientHeight = std::min(windowClientWidth * 100000 / 177778,  Screen()->height_in_pixels / 4u * 3u);
      KRUST_LOG_INFO << "windowClientWidth: "  << windowClientWidth  << '.' << endlog;
      KRUST_LOG_INFO << "windowClientHeight: " << windowClientHeight << '.' << endlog;
      mWidth = windowClientWidth;
      mHeight = windowClientHeight;

      xcb_create_window(Connection(),
          XCB_COPY_FROM_PARENT, ///< Depth
          mXcbWindow,
          Screen()->root, ///< Parent to root of screen
          0, ///< X
          0, ///< Y
          windowClientWidth, ///< Width
          windowClientHeight, ///< Height
          0, ///< Border
          XCB_WINDOW_CLASS_INPUT_OUTPUT, ///< Class
          Screen()->root_visual, ///> Visual
          mask, values.values );

      // Setup the window to receive window close events:
      // (see: http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.2.7 )

      // We need to specify window properties using X11 Atoms which are interned
      // strings, so lets get the atoms we need (WM_PROTOCOLS, WM_DELETE_WINDOW):
      const xcb_intern_atom_cookie_t wm_protocols_cookie =
          xcb_intern_atom(Connection(), 1, sizeof("WM_PROTOCOLS")-1, "WM_PROTOCOLS");
      const xcb_intern_atom_cookie_t wm_delete_window_cookie =
          xcb_intern_atom(Connection(), 0, sizeof("WM_DELETE_WINDOW")-1, "WM_DELETE_WINDOW");
      xcb_generic_error_t* wm_protocols_error = 0;
      xcb_intern_atom_reply_t* wm_protocols_reply = xcb_intern_atom_reply(Connection(), wm_protocols_cookie, &wm_protocols_error);
      ScopedFree free_wm_protocols_reply(wm_protocols_reply);
      xcb_generic_error_t* wm_delete_window_error = 0;
      xcb_intern_atom_reply_t* wm_delete_window_reply = xcb_intern_atom_reply(Connection(), wm_delete_window_cookie, &wm_delete_window_error);
      ScopedFree free_wm_delete_window_reply(wm_delete_window_reply);
      mDeleteWindowEventAtom = wm_delete_window_reply->atom;

      // Finally append the WM_DELETE_WINDOW atom to the WM_PROTOCOLS property of the
      // window so client message events will be sent:
      xcb_change_property(
        Connection(),
        XCB_PROP_MODE_APPEND, /// XCB_PROP_MODE_REPLACE
        mXcbWindow,
        wm_protocols_reply->atom,
        XCB_ATOM_ATOM/*4*/, sizeof(mDeleteWindowEventAtom) * 8, 1,
        &mDeleteWindowEventAtom
      );

      // Set the title of the window:
      if(title && *title)
      {
      //xcb_void_cookie_t title_cookie =
      xcb_change_property(
        Connection(),
        XCB_PROP_MODE_REPLACE,
        mXcbWindow,
        XCB_ATOM_WM_NAME,
        XCB_ATOM_STRING,
        8,
        strlen(title),
        title);
      }

      // Show the window:
      xcb_map_window(Connection(), mXcbWindow);

      // Position the window centred in screen:
      const uint32_t winXY[] = { (windowClientWidth / 3) / 2, (windowClientHeight / 3) / 2 };
      xcb_configure_window(Connection(), mXcbWindow, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, winXY);

      // Sync:
      xcb_flush(Connection());
    }
  }
}

WindowPlatform::~WindowPlatform() {
  KRUST_LOG_INFO << "WindowPlatform destroyed.\n";
}

xcb_connection_t* WindowPlatform::Connection() const {
  return mApplication.mPlatformApplication.mXcbConnection;
}

xcb_screen_t* WindowPlatform::Screen() const {
  return mApplication.mPlatformApplication.mXcbScreen;
}

} /* namespace Krust::IO */

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

// Class include:
#include "window-platform.h"

// Internal includes:
#include "application.h"

// External includes:
#include "krust/public-api/scoped-free.h"
#include "krust/public-api/logging.h"
#include <string.h>

namespace Krust {

namespace IO {

/**
 * @brief A helper struct to init a values array to be passed to XCB.
 */
struct XcbValueList
{
  XcbValueList()
  {
    // Zero the values array in the absence of documentation for how
    // the list must be terminated:
    memset(values, 0, sizeof(values[0]) * 32);
  }

  // Have a nice long list of values in the absence of documentation for how
  // long the list must be:
  uint32_t values[32];
};

WindowPlatform::WindowPlatform(
  Krust::IO::Application& application,
  Krust::IO::Window& container,
  const char* title) :
    mApplication(application),
    mDeleteWindowEventAtom(0)
{
  KRUST_LOG_INFO << "WindowPlatform created.\n";
  suppress_unused(&container, &title); ///@ToDo: Set the window title through XCB

  // Create the X11 window:
  KRUST_ASSERT1(Connection(), "Null connection.");
  if(Connection())
  {
    mXcbWindow = xcb_generate_id(Connection());
    KRUST_ASSERT1(mXcbWindow, "No window id.");
    if(!mXcbWindow)
    {
      KRUST_LOG_ERROR << "Failed to generate window ID." << endlog;
    }
    else
    {
      const uint32_t  mask =
          // Not sure having this background is a good idea for Vulkan:
          XCB_CW_BACK_PIXEL |
          XCB_CW_EVENT_MASK;
      XcbValueList values;
      values.values[0] = Screen()->black_pixel;
      values.values[1] =
        XCB_EVENT_MASK_EXPOSURE         |
        XCB_EVENT_MASK_STRUCTURE_NOTIFY |
        XCB_EVENT_MASK_FOCUS_CHANGE     |
        // The app should control which of these are subscribed to:
        XCB_EVENT_MASK_BUTTON_PRESS     | XCB_EVENT_MASK_BUTTON_RELEASE |
        XCB_EVENT_MASK_POINTER_MOTION   |
        XCB_EVENT_MASK_ENTER_WINDOW     | XCB_EVENT_MASK_LEAVE_WINDOW   |
        XCB_EVENT_MASK_KEY_PRESS        | XCB_EVENT_MASK_KEY_RELEASE
      ;

      // Calculate a reasonable width and height:
      // Note in multimonitor setups this screen is likely the whole virtual
      // screen encompassing both monitors. We should really figure out the
      // primary monitor and size ourself to fit onto that:
      // https://stackoverflow.com/questions/36966900/xcb-get-all-monitors-ands-their-x-y-coordinates
      const unsigned windowClientWidth  = std::min(1280u, unsigned(Screen()->width_in_pixels * 0.75f));
      const unsigned windowClientHeight = std::min(windowClientWidth * 0.625f,  Screen()->height_in_pixels * 0.75f);
      KRUST_LOG_INFO << "windowClientWidth: "  << windowClientWidth  << '.' << endlog;
      KRUST_LOG_INFO << "windowClientHeight: " << windowClientHeight << '.' << endlog;
      mWidth = windowClientWidth;
      mHeight = windowClientHeight;

      xcb_create_window(Connection(),
          XCB_COPY_FROM_PARENT, ///< Depth
          mXcbWindow,
          Screen()->root, ///< Parent to root of screen
          0, ///< X
          0, ///< Y
          windowClientWidth, ///< Width
          windowClientHeight, ///< Height
          0, ///< Border
          XCB_WINDOW_CLASS_INPUT_OUTPUT, ///< Class
          Screen()->root_visual, ///> Visual
          mask, values.values );

      // Setup the window to receive window close events:
      // (see: http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.2.7 )

      // We need to specify window properties using X11 Atoms which are interned
      // strings, so lets get the atoms we need (WM_PROTOCOLS, WM_DELETE_WINDOW):
      const xcb_intern_atom_cookie_t wm_protocols_cookie =
          xcb_intern_atom(Connection(), 1, sizeof("WM_PROTOCOLS")-1, "WM_PROTOCOLS");
      const xcb_intern_atom_cookie_t wm_delete_window_cookie =
          xcb_intern_atom(Connection(), 0, sizeof("WM_DELETE_WINDOW")-1, "WM_DELETE_WINDOW");
      xcb_generic_error_t* wm_protocols_error = 0;
      xcb_intern_atom_reply_t* wm_protocols_reply = xcb_intern_atom_reply(Connection(), wm_protocols_cookie, &wm_protocols_error);
      ScopedFree free_wm_protocols_reply(wm_protocols_reply);
      xcb_generic_error_t* wm_delete_window_error = 0;
      xcb_intern_atom_reply_t* wm_delete_window_reply = xcb_intern_atom_reply(Connection(), wm_delete_window_cookie, &wm_delete_window_error);
      ScopedFree free_wm_delete_window_reply(wm_delete_window_reply);
      mDeleteWindowEventAtom = wm_delete_window_reply->atom;

      // Finally append the WM_DELETE_WINDOW atom to the WM_PROTOCOLS property of the
      // window so client message events will be sent:
      xcb_change_property(
        Connection(),
        XCB_PROP_MODE_APPEND, /// XCB_PROP_MODE_REPLACE
        mXcbWindow,
        wm_protocols_reply->atom,
        XCB_ATOM_ATOM/*4*/, sizeof(mDeleteWindowEventAtom) * 8, 1,
        &mDeleteWindowEventAtom
      );

      // Set the title of the window:
      if(title && *title)
      {
      //xcb_void_cookie_t title_cookie =
      xcb_change_property(
        Connection(),
        XCB_PROP_MODE_REPLACE,
        mXcbWindow,
        XCB_ATOM_WM_NAME,
        XCB_ATOM_STRING,
        8,
        strlen(title),
        title);
      }

      // Show the window:
      xcb_map_window(Connection(), mXcbWindow);

      // Position the window centred in screen:
      const uint32_t winXY[] = { (windowClientWidth / 3) / 2, (windowClientHeight / 3) / 2 };
      xcb_configure_window(Connection(), mXcbWindow, XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y, winXY);

      // Sync:
      xcb_flush(Connection());
    }
  }
}

WindowPlatform::~WindowPlatform() {
  KRUST_LOG_INFO << "WindowPlatform destroyed.\n";
}

xcb_connection_t* WindowPlatform::Connection() const {
  return mApplication.mPlatformApplication.mXcbConnection;
}

xcb_screen_t* WindowPlatform::Screen() const {
  return mApplication.mPlatformApplication.mXcbScreen;
}

} /* namespace Krust::IO */

} /* namespace Krust */
<|endoftext|>