<commit_before>
// This work derives from Vittorio Romeo's code used for cppcon 2015 licensed under the Academic Free License.
// His code is available here: https://github.com/SuperV1234/cppcon2015

#ifndef EC_MANAGER_HPP
#define EC_MANAGER_HPP

#define EC_INIT_ENTITIES_SIZE 256
#define EC_GROW_SIZE_AMOUNT 256

#include <cstddef>
#include <vector>
#include <tuple>
#include <utility>

#include "Meta/Combine.hpp"
#include "Meta/Matching.hpp"
#include "Bitset.hpp"

namespace EC
{
    template <typename ComponentsList, typename TagsList>
    struct Manager
    {
    public:
        using Combined = EC::Meta::Combine<ComponentsList, TagsList>;
        using BitsetType = EC::Bitset<ComponentsList, TagsList>;

    private:
        template <typename... Types>
        struct Storage
        {
            using type = std::tuple<std::vector<Types>... >;
        };
        using ComponentsStorage = typename EC::Meta::Morph<ComponentsList, Storage<> >::type;
        // Entity: isAlive, dataIndex, ComponentsTags Info
        using EntitiesTupleType = std::tuple<bool, std::size_t, BitsetType>;
        using EntitiesType = std::vector<EntitiesTupleType>;

        EntitiesType entities;
        ComponentsStorage componentsStorage;
        std::size_t currentCapacity = 0;
        std::size_t currentSize = 0;

    public:
        Manager()
        {
            resize(EC_INIT_ENTITIES_SIZE);
        }

    private:
        void resize(std::size_t newCapacity)
        {
            if(currentCapacity >= newCapacity)
            {
                return;
            }

            EC::Meta::forEach<ComponentsList>([this, newCapacity] (auto t) {
                std::get<std::vector<decltype(t)> >(this->componentsStorage).resize(newCapacity);
            });

            entities.resize(newCapacity);
            for(std::size_t i = currentCapacity; i < newCapacity; ++i)
            {
                entities[i] = std::make_tuple(false, i, BitsetType{});
            }

            currentCapacity = newCapacity;
        }

    public:
        std::size_t addEntity()
        {
            if(currentSize == currentCapacity)
            {
                resize(currentCapacity + EC_GROW_SIZE_AMOUNT);
            }

            std::get<bool>(entities[currentSize]) = true;

            return currentSize++;
        }

        void deleteEntity(std::size_t index)
        {
            std::get<bool>(entities.at(index)) = false;
        }

        bool hasEntity(std::size_t index) const
        {
            return index < currentSize;
        }

        bool isAlive(std::size_t index) const
        {
            return hasEntity(index) && std::get<bool>(entities.at(index));
        }

        const EntitiesTupleType& getEntityInfo(std::size_t index) const
        {
            return entities.at(index);
        }

        template <typename Component>
        Component& getEntityData(std::size_t index)
        {
            return std::get<std::vector<Component> >(componentsStorage).at(std::get<std::size_t>(entities.at(index)));
        }

        template <typename Component>
        bool hasComponent(std::size_t index) const
        {
            return std::get<BitsetType>(entities.at(index)).template getComponentBit<Component>();
        }

        template <typename Tag>
        bool hasTag(std::size_t index) const
        {
            return std::get<BitsetType>(entities.at(index)).template getTagBit<Tag>();
        }

        void cleanup()
        {
            if(currentSize == 0)
            {
                return;
            }

            std::size_t rhs = currentSize - 1;
            std::size_t lhs = 0;

            while(lhs < rhs)
            {
                while(!std::get<bool>(entities[rhs]))
                {
                    if(rhs == 0)
                    {
                        currentSize = 0;
                        return;
                    }
                    --rhs;
                }
                if(lhs >= rhs)
                {
                    break;
                }
                else if(!std::get<bool>(entities[lhs]))
                {
                    // lhs is marked for deletion
                    // swap lhs entity with rhs entity
                    std::swap(entities[lhs], entities.at(rhs));

                    // clear deleted bitset
                    std::get<BitsetType>(entities[rhs]).reset();

                    // inc/dec pointers
                    ++lhs; --rhs;
                }
                else
                {
                    ++lhs;
                }
            }
            currentSize = rhs + 1;
        }

        template <typename Component, typename... Args>
        void addComponent(std::size_t entityID, Args&&... args)
        {
            if(!hasEntity(entityID) || !isAlive(entityID))
            {
                return;
            }

            Component component(std::forward<Args>(args)...);

            std::get<BitsetType>(entities[entityID]).template getComponentBit<Component>() = true;
            std::get<std::vector<Component> >(componentsStorage)[std::get<std::size_t>(entities[entityID])] = std::move(component);
        }

        template <typename Component>
        void removeComponent(std::size_t entityID)
        {
            if(!hasEntity(entityID) || !isAlive(entityID))
            {
                return;
            }

            std::get<BitsetType>(entities[entityID]).template getComponentBit<Component>() = false;
        }

        template <typename Tag>
        void addTag(std::size_t entityID)
        {
            if(!hasEntity(entityID) || !isAlive(entityID))
            {
                return;
            }

            std::get<BitsetType>(entities[entityID]).template getTagBit<Tag>() = true;
        }

        template <typename Tag>
        void removeTag(std::size_t entityID)
        {
            if(!hasEntity(entityID) || !isAlive(entityID))
            {
                return;
            }

            std::get<BitsetType>(entities[entityID]).template getTagBit<Tag>() = false;
        }

    private:
        template <typename... Types>
        struct ForMatchingSignatureHelper
        {
            template <typename CType, typename Function>
            static void call(std::size_t entityID, CType& ctype, Function&& function)
            {
                function(
                    entityID,
                    ctype.template getEntityData<Types>(entityID)...
                );
            }
        };

    public:
        template <typename Signature, typename Function>
        void forMatchingSignature(Function&& function)
        {
            using SignatureComponents = typename EC::Meta::Matching<Signature, ComponentsList>::type;
            using Helper = EC::Meta::Morph<SignatureComponents, ForMatchingSignatureHelper<> >;

            BitsetType signatureBitset = BitsetType::template generateBitset<Signature>();
            for(std::size_t i = 0; i < currentSize; ++i)
            {
                if(!std::get<bool>(entities[i]))
                {
                    continue;
                }

                if((signatureBitset & std::get<BitsetType>(entities[i])) == signatureBitset)
                {
                    Helper::call(i, *this, std::forward<Function>(function));
                }
            }
        }

    };
}

#endif

/*! \class EC::Manager
    \brief Manages an EntityComponent system.

    EC::Manager must be created with a list of all used Components and all used tags.

    Note that all components must have a default constructor.

    Example:
    \code{.cpp}
        EC::Manager<TypeList<C0, C1, C2>, TypeList<T0, T1>> manager;
    \endcode
*/

/*! \fn EC::Manager::Manager()
    \brief Initializes the manager with a default capacity.

    The default capacity is set with macro EC_INIT_ENTITIES_SIZE,
    and will grow by amounts of EC_GROW_SIZE_AMOUNT when needed.
*/

/*! \fn std::size_t EC::Manager::addEntity()
    \brief Adds an entity to the system, returning the ID of the entity.

    WARNING: The ID of an entity may change after calls to cleanup().
    Usage of entity IDs should be safe during initialization.
    Otherwise, only use the ID given during usage of forMatchingSignature().
*/

/*! \fn void EC::Manager::deleteEntity(std::size_t index)
    \brief Marks an entity for deletion.

    A deleted Entity is not actually deleted until cleanup() is called.
    While an Entity is "deleted" but still in the system, calls to forMatchingSignature()
    will ignore the Entity.
*/

/*! \fn bool EC::Manager::hasEntity(std::size_t index) const
    \brief Checks if the Entity with the given ID is in the system.

    Note that deleted Entities that haven't yet been cleaned up (via cleanup()) are
    considered still in the system.
*/

/*! \fn bool EC::Manager::isAlive(std::size_t index) const
    \brief Checks if the Entity is not marked as deleted.

    Note that invalid Entities (Entities where calls to hasEntity() returns false)
    will return false.
*/

/*! \fn const EntitiesTupleType& EC::Manager::getEntityInfo(std::size_t index) const
    \brief Returns a const reference to an Entity's info.

    An Entity's info is a std::tuple with a bool, std::size_t, and a bitset.
    \n The bool determines if the Entity is alive.
    \n The std::size_t is the ID to this Entity's data in the system.
    \n The bitset shows what Components and Tags belong to the Entity.
*/

/*! \fn Component& EC::Manager::getEntityData(std::size_t index)
    \brief Returns a reference to a component belonging to the given Entity.

    This function will return a reference to a Component regardless of whether or
    not the Entity actually owns the reference. If the Entity doesn't own the Component,
    changes to the Component will not affect any Entity. It is recommended to use
    hasComponent() to determine if the Entity actually owns that Component.
*/

/*! \fn bool EC::Manager::hasComponent(std::size_t index) const
    \brief Checks whether or not the given Entity has the given Component.

    Example:
    \code{.cpp}
        manager.hasComponent<C0>(entityID);
    \endcode
*/

/*! \fn bool EC::Manager::hasTag(std::size_t index) const
    \brief Checks whether or not the given Entity has the given Tag.

    Example:
    \code{.cpp}
        manager.hasTag<T0>(entityID);
    \endcode
*/

/*! \fn void EC::Manager::cleanup()
    \brief Does garbage collection on Entities.

    Does housekeeping on the vector containing Entities that will result in
    entity IDs changing if some Entities were marked for deletion.
    <b>This function should be called periodically to correctly handle deletion of entities.</b>
*/

/*! \fn void EC::Manager::addComponent(std::size_t entityID, Args&&... args)
    \brief Adds a component to the given Entity.

    Additional parameters given to this function will construct the Component with those
    parameters.

    Note that if the Entity already has the same component, then it will be overwritten
    by the newly created Component with the given arguments.

    Example:
    \code{.cpp}
        struct C0
        {
            // constructor is compatible as a default constructor
            C0(int a = 0, char b = 'b') :
            a(a), b(b)
            {}

            int a;
            char b;
        }

        manager.addComponent<C0>(entityID, 10, 'd');
    \endcode
*/

/*! \fn void EC::Manager::removeComponent(std::size_t entityID)
    \brief Removes the given Component from the given Entity.

    If the Entity does not have the Component given, nothing will change.

    Example:
    \code{.cpp}
        manager.removeComponent<C0>(entityID);
    \endcode
*/

/*! \fn void EC::Manager::addTag(std::size_t entityID)
    \brief Adds the given Tag to the given Entity.

    Example:
    \code{.cpp}
        manager.addTag<T0>(entityID);
    \endcode
*/

/*! \fn void EC::Manager::removeTag(std::size_t entityID)
    \brief Removes the given Tag from the given Entity.

    If the Entity does not have the Tag given, nothing will change.

    Example:
    \code{.cpp}
        manager.removeTag<T0>(entityID);
    \endcode
*/

/*! \fn void EC::Manager::forMatchingSignature(Function&& function)
    \brief Calls the given function on all Entities matching the given Signature.

    The function object given to this function must accept std::size_t as its first
    parameter and Component references for the rest of the parameters. Tags specified in the
    Signature are only used as filters and will not be given as a parameter to the function.

    Example:
    \code{.cpp}
        manager.forMatchingSignature<TypeList<C0, C1, T0>>([] (std::size_t ID, C0& component0, C1& component1) {
            // Lambda function contents here.
        });
    \endcode
    Note, the ID given to the function is not permanent. An entity's ID may change when cleanup() is called.
*/

<commit_msg>Temporary(?) bugfix<commit_after>
// This work derives from Vittorio Romeo's code used for cppcon 2015 licensed under the Academic Free License.
// His code is available here: https://github.com/SuperV1234/cppcon2015

#ifndef EC_MANAGER_HPP
#define EC_MANAGER_HPP

#define EC_INIT_ENTITIES_SIZE 256
#define EC_GROW_SIZE_AMOUNT 256

#include <cstddef>
#include <vector>
#include <tuple>
#include <utility>

#include "Meta/Combine.hpp"
#include "Meta/Matching.hpp"
#include "Bitset.hpp"

namespace EC
{
    template <typename ComponentsList, typename TagsList>
    struct Manager
    {
    public:
        using Combined = EC::Meta::Combine<ComponentsList, TagsList>;
        using BitsetType = EC::Bitset<ComponentsList, TagsList>;

    private:
        template <typename... Types>
        struct Storage
        {
            using type = std::tuple<std::vector<Types>... >;
        };
        using ComponentsStorage = typename EC::Meta::Morph<ComponentsList, Storage<> >::type;
        // Entity: isAlive, dataIndex, ComponentsTags Info
        using EntitiesTupleType = std::tuple<bool, std::size_t, BitsetType>;
        using EntitiesType = std::vector<EntitiesTupleType>;

        EntitiesType entities;
        ComponentsStorage componentsStorage;
        std::size_t currentCapacity = 0;
        std::size_t currentSize = 0;

    public:
        Manager()
        {
            resize(EC_INIT_ENTITIES_SIZE);
        }

    private:
        void resize(std::size_t newCapacity)
        {
            if(currentCapacity >= newCapacity)
            {
                return;
            }

            EC::Meta::forEach<ComponentsList>([this, newCapacity] (auto t) {
                std::get<std::vector<decltype(t)> >(this->componentsStorage).resize(newCapacity);
            });

            entities.resize(newCapacity);
            for(std::size_t i = currentCapacity; i < newCapacity; ++i)
            {
                entities[i] = std::make_tuple(false, i, BitsetType{});
            }

            currentCapacity = newCapacity;
        }

    public:
        std::size_t addEntity()
        {
            if(currentSize == currentCapacity)
            {
                resize(currentCapacity + EC_GROW_SIZE_AMOUNT);
            }

            std::get<bool>(entities[currentSize]) = true;

            // TODO This shouldn't be necessary, but there is a bug
            std::get<BitsetType>(entities[currentSize]).reset();

            return currentSize++;
        }

        void deleteEntity(std::size_t index)
        {
            std::get<bool>(entities.at(index)) = false;
        }

        bool hasEntity(std::size_t index) const
        {
            return index < currentSize;
        }

        bool isAlive(std::size_t index) const
        {
            return hasEntity(index) && std::get<bool>(entities.at(index));
        }

        const EntitiesTupleType& getEntityInfo(std::size_t index) const
        {
            return entities.at(index);
        }

        template <typename Component>
        Component& getEntityData(std::size_t index)
        {
            return std::get<std::vector<Component> >(componentsStorage).at(std::get<std::size_t>(entities.at(index)));
        }

        template <typename Component>
        bool hasComponent(std::size_t index) const
        {
            return std::get<BitsetType>(entities.at(index)).template getComponentBit<Component>();
        }

        template <typename Tag>
        bool hasTag(std::size_t index) const
        {
            return std::get<BitsetType>(entities.at(index)).template getTagBit<Tag>();
        }

        void cleanup()
        {
            if(currentSize == 0)
            {
                return;
            }

            std::size_t rhs = currentSize - 1;
            std::size_t lhs = 0;

            while(lhs < rhs)
            {
                while(!std::get<bool>(entities[rhs]))
                {
                    if(rhs == 0)
                    {
                        currentSize = 0;
                        return;
                    }
                    --rhs;
                }
                if(lhs >= rhs)
                {
                    break;
                }
                else if(!std::get<bool>(entities[lhs]))
                {
                    // lhs is marked for deletion
                    // swap lhs entity with rhs entity
                    std::swap(entities[lhs], entities.at(rhs));

                    // clear deleted bitset
                    std::get<BitsetType>(entities[rhs]).reset();

                    // inc/dec pointers
                    ++lhs; --rhs;
                }
                else
                {
                    ++lhs;
                }
            }
            currentSize = rhs + 1;
        }

        template <typename Component, typename... Args>
        void addComponent(std::size_t entityID, Args&&... args)
        {
            if(!hasEntity(entityID) || !isAlive(entityID))
            {
                return;
            }

            Component component(std::forward<Args>(args)...);

            std::get<BitsetType>(entities[entityID]).template getComponentBit<Component>() = true;
            std::get<std::vector<Component> >(componentsStorage)[std::get<std::size_t>(entities[entityID])] = std::move(component);
        }

        template <typename Component>
        void removeComponent(std::size_t entityID)
        {
            if(!hasEntity(entityID) || !isAlive(entityID))
            {
                return;
            }

            std::get<BitsetType>(entities[entityID]).template getComponentBit<Component>() = false;
        }

        template <typename Tag>
        void addTag(std::size_t entityID)
        {
            if(!hasEntity(entityID) || !isAlive(entityID))
            {
                return;
            }

            std::get<BitsetType>(entities[entityID]).template getTagBit<Tag>() = true;
        }

        template <typename Tag>
        void removeTag(std::size_t entityID)
        {
            if(!hasEntity(entityID) || !isAlive(entityID))
            {
                return;
            }

            std::get<BitsetType>(entities[entityID]).template getTagBit<Tag>() = false;
        }

    private:
        template <typename... Types>
        struct ForMatchingSignatureHelper
        {
            template <typename CType, typename Function>
            static void call(std::size_t entityID, CType& ctype, Function&& function)
            {
                function(
                    entityID,
                    ctype.template getEntityData<Types>(entityID)...
                );
            }
        };

    public:
        template <typename Signature, typename Function>
        void forMatchingSignature(Function&& function)
        {
            using SignatureComponents = typename EC::Meta::Matching<Signature, ComponentsList>::type;
            using Helper = EC::Meta::Morph<SignatureComponents, ForMatchingSignatureHelper<> >;

            BitsetType signatureBitset = BitsetType::template generateBitset<Signature>();
            for(std::size_t i = 0; i < currentSize; ++i)
            {
                if(!std::get<bool>(entities[i]))
                {
                    continue;
                }

                if((signatureBitset & std::get<BitsetType>(entities[i])) == signatureBitset)
                {
                    Helper::call(i, *this, std::forward<Function>(function));
                }
            }
        }

    };
}

#endif

/*! \class EC::Manager
    \brief Manages an EntityComponent system.

    EC::Manager must be created with a list of all used Components and all used tags.

    Note that all components must have a default constructor.

    Example:
    \code{.cpp}
        EC::Manager<TypeList<C0, C1, C2>, TypeList<T0, T1>> manager;
    \endcode
*/

/*! \fn EC::Manager::Manager()
    \brief Initializes the manager with a default capacity.

    The default capacity is set with macro EC_INIT_ENTITIES_SIZE,
    and will grow by amounts of EC_GROW_SIZE_AMOUNT when needed.
*/

/*! \fn std::size_t EC::Manager::addEntity()
    \brief Adds an entity to the system, returning the ID of the entity.

    WARNING: The ID of an entity may change after calls to cleanup().
    Usage of entity IDs should be safe during initialization.
    Otherwise, only use the ID given during usage of forMatchingSignature().
*/

/*! \fn void EC::Manager::deleteEntity(std::size_t index)
    \brief Marks an entity for deletion.

    A deleted Entity is not actually deleted until cleanup() is called.
    While an Entity is "deleted" but still in the system, calls to forMatchingSignature()
    will ignore the Entity.
*/

/*! \fn bool EC::Manager::hasEntity(std::size_t index) const
    \brief Checks if the Entity with the given ID is in the system.

    Note that deleted Entities that haven't yet been cleaned up (via cleanup()) are
    considered still in the system.
*/

/*! \fn bool EC::Manager::isAlive(std::size_t index) const
    \brief Checks if the Entity is not marked as deleted.

    Note that invalid Entities (Entities where calls to hasEntity() returns false)
    will return false.
*/

/*! \fn const EntitiesTupleType& EC::Manager::getEntityInfo(std::size_t index) const
    \brief Returns a const reference to an Entity's info.

    An Entity's info is a std::tuple with a bool, std::size_t, and a bitset.
    \n The bool determines if the Entity is alive.
    \n The std::size_t is the ID to this Entity's data in the system.
    \n The bitset shows what Components and Tags belong to the Entity.
*/

/*! \fn Component& EC::Manager::getEntityData(std::size_t index)
    \brief Returns a reference to a component belonging to the given Entity.

    This function will return a reference to a Component regardless of whether or
    not the Entity actually owns the reference. If the Entity doesn't own the Component,
    changes to the Component will not affect any Entity. It is recommended to use
    hasComponent() to determine if the Entity actually owns that Component.
*/

/*! \fn bool EC::Manager::hasComponent(std::size_t index) const
    \brief Checks whether or not the given Entity has the given Component.

    Example:
    \code{.cpp}
        manager.hasComponent<C0>(entityID);
    \endcode
*/

/*! \fn bool EC::Manager::hasTag(std::size_t index) const
    \brief Checks whether or not the given Entity has the given Tag.

    Example:
    \code{.cpp}
        manager.hasTag<T0>(entityID);
    \endcode
*/

/*! \fn void EC::Manager::cleanup()
    \brief Does garbage collection on Entities.

    Does housekeeping on the vector containing Entities that will result in
    entity IDs changing if some Entities were marked for deletion.
    <b>This function should be called periodically to correctly handle deletion of entities.</b>
*/

/*! \fn void EC::Manager::addComponent(std::size_t entityID, Args&&... args)
    \brief Adds a component to the given Entity.

    Additional parameters given to this function will construct the Component with those
    parameters.

    Note that if the Entity already has the same component, then it will be overwritten
    by the newly created Component with the given arguments.

    Example:
    \code{.cpp}
        struct C0
        {
            // constructor is compatible as a default constructor
            C0(int a = 0, char b = 'b') :
            a(a), b(b)
            {}

            int a;
            char b;
        }

        manager.addComponent<C0>(entityID, 10, 'd');
    \endcode
*/

/*! \fn void EC::Manager::removeComponent(std::size_t entityID)
    \brief Removes the given Component from the given Entity.

    If the Entity does not have the Component given, nothing will change.

    Example:
    \code{.cpp}
        manager.removeComponent<C0>(entityID);
    \endcode
*/

/*! \fn void EC::Manager::addTag(std::size_t entityID)
    \brief Adds the given Tag to the given Entity.

    Example:
    \code{.cpp}
        manager.addTag<T0>(entityID);
    \endcode
*/

/*! \fn void EC::Manager::removeTag(std::size_t entityID)
    \brief Removes the given Tag from the given Entity.

    If the Entity does not have the Tag given, nothing will change.

    Example:
    \code{.cpp}
        manager.removeTag<T0>(entityID);
    \endcode
*/

/*! \fn void EC::Manager::forMatchingSignature(Function&& function)
    \brief Calls the given function on all Entities matching the given Signature.

    The function object given to this function must accept std::size_t as its first
    parameter and Component references for the rest of the parameters. Tags specified in the
    Signature are only used as filters and will not be given as a parameter to the function.

    Example:
    \code{.cpp}
        manager.forMatchingSignature<TypeList<C0, C1, T0>>([] (std::size_t ID, C0& component0, C1& component1) {
            // Lambda function contents here.
        });
    \endcode
    Note, the ID given to the function is not permanent. An entity's ID may change when cleanup() is called.
*/

<|endoftext|>


<commit_before>/****************************************************************************
** libebml : parse EBML files, see http://embl.sourceforge.net/
**
** <file/class description>
**
** Copyright (C) 2002-2010 Steve Lhomme.  All rights reserved.
**
** This file is part of libebml.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; if not, write to the Free Software
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
**
** See http://www.gnu.org/licenses/lgpl-2.1.html for LGPL licensing information.
**
** Contact license@matroska.org if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/

/*!
  \file
  \version \$Id$
  \author Steve Lhomme     <robux4 @ users.sf.net>
  \author Julien Coloos  <suiryc @ users.sf.net>
*/
#include <cassert>
#include <string>

#include "ebml/EbmlBinary.h"
#include "ebml/StdIOCallback.h"

START_LIBEBML_NAMESPACE

EbmlBinary::EbmlBinary()
  :EbmlElement(0, false), Data(NULL)
{}

EbmlBinary::EbmlBinary(const EbmlBinary & ElementToClone)
  :EbmlElement(ElementToClone)
{
  if (ElementToClone.Data == NULL)
    Data = NULL;
  else {
    Data = (binary *)malloc(GetSize() * sizeof(binary));
    assert(Data != NULL);
    memcpy(Data, ElementToClone.Data, GetSize());
  }
}

EbmlBinary::~EbmlBinary(void) {
  if(Data)
    free(Data);
}

EbmlBinary::operator const binary &() const {return *Data;}

filepos_t EbmlBinary::RenderData(IOCallback & output, bool /* bForceRender */, bool /* bWithDefault */)
{
  output.writeFully(Data,GetSize());

  return GetSize();
}

/*!
  \note no Default binary value handled
*/
uint64 EbmlBinary::UpdateSize(bool /* bWithDefault */, bool /* bForceRender */)
{
  return GetSize();
}

filepos_t EbmlBinary::ReadData(IOCallback & input, ScopeMode ReadFully)
{
  if (Data != NULL)
    free(Data);

  if (ReadFully == SCOPE_NO_DATA) {
    Data = NULL;
    return GetSize();
  }

  Data = (binary *)malloc(GetSize());
  if (Data == NULL)
    throw CRTError(std::string("Error allocating data"));
  SetValueIsSet();
  return input.read(Data, GetSize());
}

bool EbmlBinary::operator==(const EbmlBinary & ElementToCompare) const
{
  return ((GetSize() == ElementToCompare.GetSize()) && (GetSize() == 0 || !memcmp(Data, ElementToCompare.Data, GetSize())));
}

END_LIBEBML_NAMESPACE
<commit_msg>EbmlBinary: don't do I/O with a size of 0<commit_after>/****************************************************************************
** libebml : parse EBML files, see http://embl.sourceforge.net/
**
** <file/class description>
**
** Copyright (C) 2002-2010 Steve Lhomme.  All rights reserved.
**
** This file is part of libebml.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License as published by the Free Software Foundation; either
** version 2.1 of the License, or (at your option) any later version.
**
** This library is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
** Lesser General Public License for more details.
**
** You should have received a copy of the GNU Lesser General Public
** License along with this library; if not, write to the Free Software
** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
**
** See http://www.gnu.org/licenses/lgpl-2.1.html for LGPL licensing information.
**
** Contact license@matroska.org if any conditions of this licensing are
** not clear to you.
**
**********************************************************************/

/*!
  \file
  \version \$Id$
  \author Steve Lhomme     <robux4 @ users.sf.net>
  \author Julien Coloos  <suiryc @ users.sf.net>
*/
#include <cassert>
#include <string>

#include "ebml/EbmlBinary.h"
#include "ebml/StdIOCallback.h"

START_LIBEBML_NAMESPACE

EbmlBinary::EbmlBinary()
  :EbmlElement(0, false), Data(NULL)
{}

EbmlBinary::EbmlBinary(const EbmlBinary & ElementToClone)
  :EbmlElement(ElementToClone)
{
  if (ElementToClone.Data == NULL)
    Data = NULL;
  else {
    Data = (binary *)malloc(GetSize() * sizeof(binary));
    assert(Data != NULL);
    memcpy(Data, ElementToClone.Data, GetSize());
  }
}

EbmlBinary::~EbmlBinary(void) {
  if(Data)
    free(Data);
}

EbmlBinary::operator const binary &() const {return *Data;}

filepos_t EbmlBinary::RenderData(IOCallback & output, bool /* bForceRender */, bool /* bWithDefault */)
{
  output.writeFully(Data,GetSize());

  return GetSize();
}

/*!
  \note no Default binary value handled
*/
uint64 EbmlBinary::UpdateSize(bool /* bWithDefault */, bool /* bForceRender */)
{
  return GetSize();
}

filepos_t EbmlBinary::ReadData(IOCallback & input, ScopeMode ReadFully)
{
  if (Data != NULL)
    free(Data);

  if (ReadFully == SCOPE_NO_DATA) {
    Data = NULL;
    return GetSize();
  }

  if (!GetSize()) {
    SetValueIsSet();
    Data = NULL;
    return 0;
  }

  Data = (binary *)malloc(GetSize());
  if (Data == NULL)
    throw CRTError(std::string("Error allocating data"));
  SetValueIsSet();
  return input.read(Data, GetSize());
}

bool EbmlBinary::operator==(const EbmlBinary & ElementToCompare) const
{
  return ((GetSize() == ElementToCompare.GetSize()) && (GetSize() == 0 || !memcmp(Data, ElementToCompare.Data, GetSize())));
}

END_LIBEBML_NAMESPACE
<|endoftext|>


<commit_before>
#include "density_clustering_opencl.hpp"
#include "tools.hpp"

#define __CL_ENABLE_EXCEPTIONS

#include <utility>
#include <CL/cl.hpp>
#include <CL/opencl.h>

#include <omp.h>

#include <iostream>
#include <string>
#include <fstream>
#include <map>
#include <tuple>

namespace DC_OpenCL {

std::tuple<cl::Context, cl::Kernel, cl::CommandQueue>
setup_cl(std::string kernel_name, std::string src) {
  std::vector<cl::Platform> platforms;
  std::vector<cl::Device> devices;
  cl::Program program;
  cl::Context context;
  cl::CommandQueue q;
  cl::Kernel kernel;
  try {
    // create platform
    cl::Platform::get(&platforms);
    platforms[0].getDevices(CL_DEVICE_TYPE_GPU, &devices);
    // create context
    context = cl::Context(devices);
    // create cmd queue
    // TODO: if that stuff works, scale to multiple devices
    q = cl::CommandQueue(context, devices[0]);
    // setup kernel source
    cl::Program::Sources source(1, std::make_pair(src.c_str(), src.length() + 1));
    // create program
    program = cl::Program(context, source);
    program.build(devices);
    // load kernel
    kernel = cl::Kernel(program, kernel_name.c_str());
  } catch (cl::Error e) {
    std::cout << e.what() << " :  " << e.err() << std::endl;
    if (e.err() == CL_BUILD_PROGRAM_FAILURE) {
      cl::STRING_CLASS buildlog;
      program.getBuildInfo(devices[0], (cl_program_build_info)CL_PROGRAM_BUILD_LOG, &buildlog);
      std::cerr << buildlog << std::endl;
    }
    exit(EXIT_FAILURE);
  }
  return std::make_tuple(context, kernel, q);
}

std::vector<std::size_t>
calculate_populations(const float* coords,
                      const std::size_t n_rows,
                      const std::size_t n_cols,
                      const float radius) {
  ASSUME_ALIGNED(coords);
  // vector for final results
  std::vector<std::size_t> pops(n_rows);
  // kernel calculates population of frame i
  // by comparing distances to all frames j.
  // population is stored in integer-array of length n_rows.
  // every field of the array gets a zero if j is not in
  // range of i and a one if it is.
  // to get the total population of i, reduce array with a simple
  // sum on the host.
  std::string src =
    "__kernel void pop_i (__global float* coords,\n"
    "                     ulong n_cols,\n"
    "                     float rad2,\n"
    "                     __global uint* in_range,\n"
    "                     ulong i) {\n"
    "  ulong j = get_global_id(0);\n"
    "  float dist = 0.0f;\n"
    "  float d;\n"
    "  ulong k;\n"
    "  for (k=0; k < n_cols; ++k) {\n"
    "    d = coords[i*n_cols+k] - coords[j*n_cols+k];\n"
    "    dist += d*d;\n"
    "  }\n"
    "  in_range[j] = dist < rad2 ? 1 : 0;\n"
    "}\n"
  ;
  try {
    auto cl_context_kernel_queue = setup_cl("pop_i", src);
    cl::Context context = std::get<0>(cl_context_kernel_queue);
    cl::Kernel kernel = std::get<1>(cl_context_kernel_queue);
    cl::CommandQueue q = std::get<2>(cl_context_kernel_queue);
    ulong ulong_n_cols = (ulong) n_cols;
    ulong ulong_n_rows = (ulong) n_rows;
    // setup buffers on device
    cl::Buffer d_coords(context,
                        CL_MEM_READ_ONLY,
                        sizeof(float) * ulong_n_rows * ulong_n_cols,
                        NULL,
                        NULL);
    cl::Buffer d_in_range(context,
                          CL_MEM_WRITE_ONLY,
                          sizeof(uint) * ulong_n_rows,
                          NULL,
                          NULL);
    // transmit coords to device
    q.enqueueWriteBuffer(d_coords,
                         CL_TRUE,
                         0,
                         sizeof(float) * ulong_n_rows * ulong_n_cols,
                         coords,
                         NULL,
                         NULL);
    q.finish();
    // set common arguments
    float rad2 = radius*radius;
    kernel.setArg(0, d_coords);
    kernel.setArg(1, ulong_n_cols);
    kernel.setArg(2, rad2);
    kernel.setArg(3, d_in_range);
    // screen all frames i
    for (ulong i=0; i < ulong_n_rows; ++i) {
      kernel.setArg(4, i);
      // run kernel
      q.enqueueNDRangeKernel(kernel, cl::NullRange, cl::NDRange(ulong_n_rows), cl::NullRange, NULL, NULL);
      // wait for completion
      q.finish();
      std::vector<uint> buf(ulong_n_rows);
      q.enqueueReadBuffer(d_in_range, CL_TRUE, 0, sizeof(uint) * ulong_n_rows, buf.data(), NULL, NULL);

      //TODO: run reduction on device instead of host

      std::size_t j;
      std::size_t pop_i = 0;
      #pragma omp parallel for default(none) \
                               private(j) \
                               firstprivate(n_rows) \
                               shared(pops,buf) \
                               reduction(+:pop_i)
      for (j=0; j < n_rows; ++j) {
        pop_i += buf[j];
      }
      pops[i] = pop_i;
    }
  } catch (cl::Error e) {
    std::cout << e.what() << " :  " << e.err() << std::endl;
    exit(EXIT_FAILURE);
  }
  return pops;
}

} // end namespace DC_OpenCL
<commit_msg>refactoring OpenCL code (unfinished)<commit_after>
#include "density_clustering_opencl.hpp"
#include "tools.hpp"

#define __CL_ENABLE_EXCEPTIONS

#include <utility>
#include <CL/cl.hpp>
#include <CL/opencl.h>

#include <omp.h>

#include <iostream>
#include <string>
#include <fstream>
#include <map>
#include <tuple>

namespace DC_OpenCL {

namespace {
  std::map<std::string, cl::Kernel> kernels;

  // device buffer for coordinates
  cl::Buffer d_coords;

  std::vector<cl::Platform> platforms;
  cl::Context context;
  std::vector<cl::Device> devices;
  std::vector<cl::CommandQueue> queues;

  void
  setup_context() {
    try {
      // create platform
      cl::Platform::get(&platforms);
      platforms[0].getDevices(CL_DEVICE_TYPE_GPU, &devices);
      // create context
      context = cl::Context(devices);
      // create cmd queue
      // TODO: if that stuff works, scale to multiple devices
      qs.push_back(cl::CommandQueue(context, devices[0]));
    catch (cl::Error e) {
      std::cerr << "error during OpenCL setup" << std::endl;
      std::cerr << e.what() << " :  " << e.err() << std::endl;
      exit(EXIT_FAILURE);
    }
  }

  void
  upload_coords(const float* coords,
                const std::size_t n_rows,
                const std::size_t n_cols) {
    // setup buffers on device
    cl::Buffer d_coords(context,
                        CL_MEM_READ_ONLY,
                        sizeof(float) * n_rows * n_cols,
                        NULL,
                        NULL);
    // transmit coords to device
    q.enqueueWriteBuffer(d_coords,
                         CL_TRUE,
                         0,
                         sizeof(float) * n_rows * n_cols,
                         coords,
                         NULL,
                         NULL);
    q.finish();
  }

  void
  build_kernel(std::string name, std::string src) {
    cl::Program program;
    try {
      // setup kernel source
      cl::Program::Sources source(1, std::make_pair(src.c_str(), src.length() + 1));
      // create program
      program = cl::Program(context, source);
      program.build(devices);
      // load kernel
      kernel[name] = cl::Kernel(program, name.c_str());
    } catch (cl::Error e) {
      std::cout << e.what() << " :  " << e.err() << std::endl;
      if (e.err() == CL_BUILD_PROGRAM_FAILURE) {
        cl::STRING_CLASS buildlog;
        program.getBuildInfo(devices[0], (cl_program_build_info)CL_PROGRAM_BUILD_LOG, &buildlog);
        std::cerr << buildlog << std::endl;
      }
      exit(EXIT_FAILURE);
    }
  }

  void
  setup_kernels() {
    std::string src;

    //// pop_i
    //
    // kernel calculates population of frame i
    // by comparing distances to all frames j.
    // population is stored in integer-array of length n_rows.
    // every field of the array gets a zero if j is not in
    // range of i and a one if it is.
    src =
      "__kernel void pop_i (__global float* coords,\n"
      "                     ulong n_cols,\n"
      "                     float rad2,\n"
      "                     __global uint* in_range,\n"
      "                     ulong i) {\n"
      "  ulong j = get_global_id(0);\n"
      "  float dist = 0.0f;\n"
      "  float d;\n"
      "  ulong k;\n"
      "  for (k=0; k < n_cols; ++k) {\n"
      "    d = coords[i*n_cols+k] - coords[j*n_cols+k];\n"
      "    dist += d*d;\n"
      "  }\n"
      "  in_range[j] = dist < rad2 ? 1 : 0;\n"
      "}\n"
    ;
    build_kernel("pop_i", src);

    //// sum_uints (single task kernel)
    //
    // kernel calculates total sum of unsigned integer array.
    src =
      "__kernel void sum_uints (__global uint* uints,\n"
      "                         ulong n_rows,\n"
      "                         __global ulong* result) {\n"
      "  ulong r=0;\n"
      "  for(ulong i=0; i < n_rows; ++i) {\n"
      "    r += uints[i]\n"
      "  }\n"
      "  *result = r;\n"
      "}\n"
    build_kernel("sum_uints", src);
  }
} // end local namespace

void
setup(const float* coords,
      const std::size_t n_rows,
      const std::size_t n_cols) {

}

std::vector<std::size_t>
calculate_populations(const float radius) {
  // vector for final results
  std::vector<std::size_t> pops(n_rows);

  try {
    ulong ulong_n_cols = (ulong) n_cols;
    ulong ulong_n_rows = (ulong) n_rows;
    cl::Buffer d_in_range(context,
                          CL_MEM_WRITE_ONLY,
                          sizeof(uint) * ulong_n_rows,
                          NULL,
                          NULL);
    // set common arguments
    float rad2 = radius*radius;
    kernel.setArg(0, d_coords);
    kernel.setArg(1, ulong_n_cols);
    kernel.setArg(2, rad2);
    kernel.setArg(3, d_in_range);
    // screen all frames i
    for (ulong i=0; i < ulong_n_rows; ++i) {
      kernel.setArg(4, i);
      // run kernel
      q.enqueueNDRangeKernel(kernel, cl::NullRange, cl::NDRange(ulong_n_rows), cl::NullRange, NULL, NULL);
      // wait for completion
      q.finish();
      std::vector<uint> buf(ulong_n_rows);
      q.enqueueReadBuffer(d_in_range, CL_TRUE, 0, sizeof(uint) * ulong_n_rows, buf.data(), NULL, NULL);

      //TODO: run reduction on device instead of host

      std::size_t j;
      std::size_t pop_i = 0;
      #pragma omp parallel for default(none) \
                               private(j) \
                               firstprivate(n_rows) \
                               shared(pops,buf) \
                               reduction(+:pop_i)
      for (j=0; j < n_rows; ++j) {
        pop_i += buf[j];
      }
      pops[i] = pop_i;
    }
  } catch (cl::Error e) {
    std::cout << e.what() << " :  " << e.err() << std::endl;
    exit(EXIT_FAILURE);
  }
  return pops;
}

} // end namespace DC_OpenCL
<|endoftext|>


<commit_before>#include "ofApp.h"

// Configuration
int imgcount = 326;
bool usePort = false;
bool fullscreen = false;
int maxDistance = 1000;
int sleepMillis = 100;

// Serial port, for reading distance from ultrasonic sensor.
// Optional.
ofSerial serialPort;

// Images that make up the animation sequence
std::map<int, ofImage> images;

// App state, you should not touch these;
int currentDistance = 0;
long previousMillis = 0;
int frame = 0;
float period = 1;
float distanceOfFrame = maxDistance / imgcount;
int loadTime = -1;
int destinationFrame = frame;

// HUD
ofTrueTypeFont f;

//--------------------------------------------------------------
void ofApp::setup(){
    //Set screen frame rate
    ofSetFrameRate( 60 );

    ofSetFullscreen(fullscreen);

    ofSetDataPathRoot("../Resources/data/");

    // FIXME: draws all shapes with smooth edges.

    if (usePort) {
        // FIXME: serialPort = new Serial(this, "/dev/tty.usbmodem1411", 9600);
        // FIXME: serialPort.bufferUntil('\n'); // Trigger a SerialEvent on new line
    }

    if (!usePort) {
        currentDistance = maxDistance; // fake initial distance for simulation
    }

    assert(f.loadFont("verdana.ttf", 16, true, true));
    f.setLineHeight(18.0f);
    f.setLetterSpacing(1.037);
}

//--------------------------------------------------------------
void ofApp::update(){
    currentDistance = ofClamp(currentDistance, 0, maxDistance);

    calculateFrame();
}

ofImage *ofApp::getImage(const int i) {
    if (images.end() == images.find(i)) {
        ofImage img;
        assert(img.loadImage(ofToString(i) + ".jpg"));
        images[i] = img;
    }
    return &images[i];
}

// Frame for current distance
// Note that this is not the actual frame that will be animated.
// Instead will start to animate towards this frame.
int ofApp::frameForDistance() const {
    int result = imgcount - int(currentDistance / distanceOfFrame);
    if (result < 0) {
        result = 0;
    }
    if (result >= imgcount - 1) {
        result = imgcount - 1;
    }
    return result;
}

void ofApp::calculateFrame() {
        long now = ofGetElapsedTimef();

        long timePassed = now - previousMillis;

        destinationFrame = frameForDistance();

        if (timePassed > sleepMillis) {
            // move towards destination
            if (destinationFrame > frame) {
                frame = frame + 1;
            } else if (destinationFrame > frame) {
                frame = frame + 1;
            } else {
                // User is not moving, attempt some random stuff
                int r = int(ofRandom(4));
                if (r == 0) {
                    r = int(ofRandom(3));
                    if (0 == r) {
                        frame = frame + 1;
                    } else {
                        frame = frame - 1;
                    }
                }
            }

            previousMillis = now;
        }

        if (frame < 0) {
            frame = 0;
        } else if (frame >= imgcount) {
            frame = imgcount - 1;
        }

}

//--------------------------------------------------------------
void ofApp::draw(){
    // Update HUD
    f.drawString("distance=" + ofToString(currentDistance), 10, 40);
    f.drawString("max=" + ofToString(maxDistance), 210, 40);
    f.drawString("framelen=" + ofToString(distanceOfFrame), 410, 40);
    f.drawString("frame=" + ofToString(frame) + "/" + ofToString(imgcount), 610, 40);
    f.drawString("destination=" + ofToString(destinationFrame), 810, 40);

    // Draw the current animation frame
    ofImage *img = getImage(frame);
    assert(img);
    img->draw( 0, 60, ofGetWidth(), ofGetHeight() - 60 );
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){

}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){

}
<commit_msg>fix timing<commit_after>#include "ofApp.h"

// Configuration
int imgcount = 326;
bool usePort = false;
bool fullscreen = false;
int maxDistance = 1000;
int sleepMillis = 100;

// Serial port, for reading distance from ultrasonic sensor.
// Optional.
ofSerial serialPort;

// Images that make up the animation sequence
std::map<int, ofImage> images;

// App state, you should not touch these;
int currentDistance = 0;
long previousMillis = 0;
int frame = 0;
float period = 1;
float distanceOfFrame = maxDistance / imgcount;
int loadTime = -1;
int destinationFrame = frame;

// HUD
ofTrueTypeFont f;

//--------------------------------------------------------------
void ofApp::setup(){
    //Set screen frame rate
    ofSetFrameRate( 60 );

    ofSetFullscreen(fullscreen);

    ofSetDataPathRoot("../Resources/data/");

    // FIXME: draws all shapes with smooth edges.

    if (usePort) {
        // FIXME: serialPort = new Serial(this, "/dev/tty.usbmodem1411", 9600);
        // FIXME: serialPort.bufferUntil('\n'); // Trigger a SerialEvent on new line
    }

    if (!usePort) {
        currentDistance = maxDistance; // fake initial distance for simulation
    }

    assert(f.loadFont("verdana.ttf", 16, true, true));
    f.setLineHeight(18.0f);
    f.setLetterSpacing(1.037);
}

//--------------------------------------------------------------
void ofApp::update(){
    currentDistance = ofClamp(currentDistance, 0, maxDistance);

    calculateFrame();
}

ofImage *ofApp::getImage(const int i) {
    if (images.end() == images.find(i)) {
        ofImage img;
        assert(img.loadImage(ofToString(i) + ".jpg"));
        images[i] = img;
    }
    return &images[i];
}

// Frame for current distance
// Note that this is not the actual frame that will be animated.
// Instead will start to animate towards this frame.
int ofApp::frameForDistance() const {
    int result = imgcount - int(currentDistance / distanceOfFrame);
    if (result < 0) {
        result = 0;
    }
    if (result >= imgcount - 1) {
        result = imgcount - 1;
    }
    return result;
}

void ofApp::calculateFrame() {
        long now = ofGetElapsedTimeMillis();

        long timePassed = now - previousMillis;

        destinationFrame = frameForDistance();

        if (timePassed > sleepMillis) {
            // move towards destination
            if (destinationFrame > frame) {
                frame = frame + 1;
            } else if (destinationFrame > frame) {
                frame = frame + 1;
            } else {
                // User is not moving, attempt some random stuff
                int r = int(ofRandom(4));
                if (r == 0) {
                    r = int(ofRandom(3));
                    if (0 == r) {
                        frame = frame + 1;
                    } else {
                        frame = frame - 1;
                    }
                }
            }

            previousMillis = now;
        }

        if (frame < 0) {
            frame = 0;
        } else if (frame >= imgcount) {
            frame = imgcount - 1;
        }

}

//--------------------------------------------------------------
void ofApp::draw(){
    // Update HUD
    f.drawString("distance=" + ofToString(currentDistance), 10, 40);
    f.drawString("max=" + ofToString(maxDistance), 210, 40);
    f.drawString("framelen=" + ofToString(distanceOfFrame), 410, 40);
    f.drawString("frame=" + ofToString(frame) + "/" + ofToString(imgcount), 610, 40);
    f.drawString("destination=" + ofToString(destinationFrame), 810, 40);

    // Draw the current animation frame
    ofImage *img = getImage(frame);
    assert(img);
    img->draw( 0, 60, ofGetWidth(), ofGetHeight() - 60 );
}

//--------------------------------------------------------------
void ofApp::keyPressed(int key){

}

//--------------------------------------------------------------
void ofApp::keyReleased(int key){

}

//--------------------------------------------------------------
void ofApp::mouseMoved(int x, int y ){

}

//--------------------------------------------------------------
void ofApp::mouseDragged(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mousePressed(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::mouseReleased(int x, int y, int button){

}

//--------------------------------------------------------------
void ofApp::windowResized(int w, int h){

}

//--------------------------------------------------------------
void ofApp::gotMessage(ofMessage msg){

}

//--------------------------------------------------------------
void ofApp::dragEvent(ofDragInfo dragInfo){

}
<|endoftext|>


<commit_before>/**
 * @file device_properties.hxx
 * @author Muhammad Osama (mosama@ucdavis.edu)
 * @brief
 * @version 0.1
 * @date 2020-10-05
 *
 * @copyright Copyright (c) 2020
 *
 */
#pragma once
#include <iostream>
#include <gunrock/cuda/device.hxx>
#include <gunrock/error.hxx>

namespace gunrock {
namespace cuda {

typedef cudaDeviceProp device_properties_t;

typedef struct {
  unsigned major;
  unsigned minor;
  constexpr unsigned as_combined_number() const {
    return major * 10 + minor;
  }
  constexpr bool operator==(int i) { return (int)as_combined_number() == i; }
  constexpr bool operator!=(int i) { return (int)as_combined_number() != i; }
  constexpr bool operator>(int i) { return (int)as_combined_number() > i; }
  constexpr bool operator<(int i) { return (int)as_combined_number() < i; }
  constexpr bool operator>=(int i) { return (int)as_combined_number() >= i; }
  constexpr bool operator<=(int i) { return (int)as_combined_number() <= i; }
} compute_capability_t;

/**
 * @brief Make compute capability from major and minor versions.
 * @param major Compute capability major version
 * @param minor Compute capability minor version
 * \return compute_capability_t
 */
constexpr compute_capability_t make_compute_capability(unsigned major,
                                                       unsigned minor) {
  return compute_capability_t{major, minor};
}

/**
 * @brief Make compute capability from combined major and minor version.
 * @param combined Combined major and minor value, e.g. 86 for 8.6
 * \return compute_capability_t
 */
constexpr compute_capability_t make_compute_capability(unsigned combined) {
  return compute_capability_t{combined / 10, combined % 10};
}

/**
 * @brief Get compute capability from SM_TARGET macro.
 * \return compute_capabilty_t
 */
constexpr compute_capability_t get_compute_capability() {
  return make_compute_capability(SM_TARGET);
}

/**
 * @namespace properties
 * C++ based CUDA device properties.
 */
namespace properties {

/**
 * @brief Enums for units used by device property values.
 */
enum : size_t {
  KiB = 1024,
  K   = 1024
};

/**
 * @brief Architecture name based on compute capability.
 * https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#compute-capability
 * @param capability Compute capability from which to get the result
 * \return const char* architecture name or nullptr if capability is invalid
 */
inline constexpr const char* arch_name(compute_capability_t capability) {
  return
    (capability.major == 8) ?  "Ampere" :
    (capability.major == 7 && capability.minor == 5) ? "Turing" :
    (capability.major == 7) ?   "Volta" :
    (capability.major == 6) ?  "Pascal" :
    (capability.major == 5) ? "Maxwell" :
    (capability.major == 3) ?  "Kepler" :
                                nullptr ;
}

// Device properties retrieved from:
// https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#features-and-technical-specifications

/**
 * @brief Maximum number of threads per block.
 * \return unsigned
 */
inline constexpr unsigned cta_max_threads() {
  return 1 << 10;  // 1024 threads per CTA
}

/**
 * @brief Warp size (has always been 32, but is subject to change).
 * \return unsigned
 */
inline constexpr unsigned warp_max_threads() {
  return 1 << 5;
}

/**
 * @brief Maximum number of resident blocks per SM.
 * @param capability Compute capability from which to get the result
 * \return unsigned
 */
inline constexpr unsigned sm_max_ctas(compute_capability_t capability) {
  return
    (capability >= 86) ? 16 :  // SM86+
    (capability >= 80) ? 32 :  // SM80
    (capability >= 75) ? 16 :  // SM75
    (capability >= 50) ? 32 :  // SM50-SM72
                         16 ;  // SM30-SM37
}

/**
 * @brief Maximum number of resident threads per SM.
 * @param capability Compute capability from which to get the result
 * \return unsigned
 */
inline constexpr unsigned sm_max_threads(compute_capability_t capability) {
  return
    (capability >= 86) ? 1536 :  // SM86+
    (capability >= 80) ? 2048 :  // SM80
    (capability >= 75) ? 1024 :  // SM75
                         2048 ;  // SM30-SM72
}

/**
 * @brief Number of 32-bit registers per SM.
 * @param capability Compute capability from which to get the result
 * \return unsigned
 */
inline constexpr unsigned sm_registers(compute_capability_t capability) {
  return
    (capability >= 50) ?  64 * K :  // SM50+
    (capability >= 37) ? 128 * K :  // SM37
                          64 * K ;  // SM30-SM35
}

/**
 * @brief Maximum amount of shared memory per SM.
 * @tparam sm3XCacheConfig cudaFuncCache enum representing the shared data
 *                         cache configuration used when called on compute
 *                         capability 3.x
 * @param capability       Compute capability from which to get the result
 * \return unsigned
 * @todo Test if this function can be resolved at compile time
 */
template<enum cudaFuncCache sm3XCacheConfig = cudaFuncCachePreferNone>
inline constexpr unsigned sm_max_shared_memory_bytes(
  compute_capability_t capability
) {
  unsigned sm3XConfiguredSmem =
    (sm3XCacheConfig == cudaFuncCachePreferNone)   ? 48 * KiB :
    (sm3XCacheConfig == cudaFuncCachePreferShared) ? 48 * KiB :
    (sm3XCacheConfig == cudaFuncCachePreferL1)     ? 16 * KiB :
    (sm3XCacheConfig == cudaFuncCachePreferEqual)  ? 32 * KiB :
                                                     48 * KiB ;

  return
    (capability >= 86) ? 100 * KiB :  // SM86+
    (capability >= 80) ? 164 * KiB :  // SM80
    (capability >= 75) ?  64 * KiB :  // SM75
    (capability >= 70) ?  96 * KiB :  // SM70-SM72
    (capability >= 62) ?  64 * KiB :  // SM62
    (capability >= 61) ?  96 * KiB :  // SM61
    (capability >= 53) ?  64 * KiB :  // SM53
    (capability >= 52) ?  96 * KiB :  // SM52
    (capability >= 50) ?  64 * KiB :  // SM50
    (capability >= 37) ?  64 * KiB + sm3XConfiguredSmem :  // SM37
                sm3XConfiguredSmem ;  // SM30-SM35
}

/**
 * @brief Number of shared memory banks.
 * \return unsigned
 */
inline constexpr unsigned shared_memory_banks() {
  return 1 << 5;  // 32 memory banks per SM
}

/**
 * @brief Stride length (number of bytes per word) of shared memory in bytes.
 * @tparam sm3XSmemConfig cudaSharedMemConfig enum representing the shared
 *                        memory bank size (stride) used when called on compute
 *                        capability 3.x
 * \return unsigned
 */
template<enum cudaSharedMemConfig sm3XSmemConfig = cudaSharedMemBankSizeDefault>
inline constexpr unsigned shared_memory_bank_stride() {
  // The default config on 3.x is the same constant value for later archs
  // Only let 3.x be configurable if stride later becomes dependent on arch
  return
    (sm3XSmemConfig == cudaSharedMemBankSizeDefault)   ? 1 << 2 :
    (sm3XSmemConfig == cudaSharedMemBankSizeFourByte)  ? 1 << 2 :
    (sm3XSmemConfig == cudaSharedMemBankSizeEightByte) ? 1 << 3 :
                                                         1 << 2 ;
}

void print(device_properties_t& prop) {
  device_id_t ordinal;
  cudaGetDevice(&ordinal);

  size_t freeMem, totalMem;
  error::error_t status = cudaMemGetInfo(&freeMem, &totalMem);
  error::throw_if_exception(status);

  double memBandwidth =
      (prop.memoryClockRate * 1000.0) * (prop.memoryBusWidth / 8 * 2) / 1.0e9;

  std::cout << prop.name << " : " << prop.clockRate / 1000.0 << " Mhz "
            << "(Ordinal " << ordinal << ")" << std::endl;
  std::cout << "FreeMem: " << (int)(freeMem / (1 << 20)) << " MB "
            << "TotalMem: " << (int)(totalMem / (1 << 20)) << " MB "
            << ((int)8 * sizeof(int*)) << "-bit pointers." << std::endl;
  std::cout << prop.multiProcessorCount
            << " SMs enabled, Compute Capability sm_" << prop.major
            << prop.minor << std::endl;
  std::cout << "Mem Clock: " << prop.memoryClockRate / 1000.0 << " Mhz x "
            << prop.memoryBusWidth << " bits (" << memBandwidth << " GB/s)"
            << std::endl;
  std::cout << "ECC " << (prop.ECCEnabled ? "Enabled" : "Disabled")
            << std::endl;
}

}  // namespace properties

}  // namespace cuda
}  // namespace gunrock
<commit_msg>Rename function<commit_after>/**
 * @file device_properties.hxx
 * @author Muhammad Osama (mosama@ucdavis.edu)
 * @brief
 * @version 0.1
 * @date 2020-10-05
 *
 * @copyright Copyright (c) 2020
 *
 */
#pragma once
#include <iostream>
#include <gunrock/cuda/device.hxx>
#include <gunrock/error.hxx>

namespace gunrock {
namespace cuda {

typedef cudaDeviceProp device_properties_t;

typedef struct {
  unsigned major;
  unsigned minor;
  constexpr unsigned as_combined_number() const {
    return major * 10 + minor;
  }
  constexpr bool operator==(int i) { return (int)as_combined_number() == i; }
  constexpr bool operator!=(int i) { return (int)as_combined_number() != i; }
  constexpr bool operator>(int i) { return (int)as_combined_number() > i; }
  constexpr bool operator<(int i) { return (int)as_combined_number() < i; }
  constexpr bool operator>=(int i) { return (int)as_combined_number() >= i; }
  constexpr bool operator<=(int i) { return (int)as_combined_number() <= i; }
} compute_capability_t;

/**
 * @brief Make compute capability from major and minor versions.
 * @param major Compute capability major version
 * @param minor Compute capability minor version
 * \return compute_capability_t
 */
constexpr compute_capability_t make_compute_capability(unsigned major,
                                                       unsigned minor) {
  return compute_capability_t{major, minor};
}

/**
 * @brief Make compute capability from combined major and minor version.
 * @param combined Combined major and minor value, e.g. 86 for 8.6
 * \return compute_capability_t
 */
constexpr compute_capability_t make_compute_capability(unsigned combined) {
  return compute_capability_t{combined / 10, combined % 10};
}

/**
 * @brief Fetch compute capability from SM_TARGET macro.
 * \return compute_capabilty_t
 */
constexpr compute_capability_t fetch_compute_capability() {
  return make_compute_capability(SM_TARGET);
}

/**
 * @namespace properties
 * C++ based CUDA device properties.
 */
namespace properties {

/**
 * @brief Enums for units used by device property values.
 */
enum : size_t {
  KiB = 1024,
  K   = 1024
};

/**
 * @brief Architecture name based on compute capability.
 * https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#compute-capability
 * @param capability Compute capability from which to get the result
 * \return const char* architecture name or nullptr if capability is invalid
 */
inline constexpr const char* arch_name(compute_capability_t capability) {
  return
    (capability.major == 8) ?  "Ampere" :
    (capability.major == 7 && capability.minor == 5) ? "Turing" :
    (capability.major == 7) ?   "Volta" :
    (capability.major == 6) ?  "Pascal" :
    (capability.major == 5) ? "Maxwell" :
    (capability.major == 3) ?  "Kepler" :
                                nullptr ;
}

// Device properties retrieved from:
// https://docs.nvidia.com/cuda/cuda-c-programming-guide/index.html#features-and-technical-specifications

/**
 * @brief Maximum number of threads per block.
 * \return unsigned
 */
inline constexpr unsigned cta_max_threads() {
  return 1 << 10;  // 1024 threads per CTA
}

/**
 * @brief Warp size (has always been 32, but is subject to change).
 * \return unsigned
 */
inline constexpr unsigned warp_max_threads() {
  return 1 << 5;
}

/**
 * @brief Maximum number of resident blocks per SM.
 * @param capability Compute capability from which to get the result
 * \return unsigned
 */
inline constexpr unsigned sm_max_ctas(compute_capability_t capability) {
  return
    (capability >= 86) ? 16 :  // SM86+
    (capability >= 80) ? 32 :  // SM80
    (capability >= 75) ? 16 :  // SM75
    (capability >= 50) ? 32 :  // SM50-SM72
                         16 ;  // SM30-SM37
}

/**
 * @brief Maximum number of resident threads per SM.
 * @param capability Compute capability from which to get the result
 * \return unsigned
 */
inline constexpr unsigned sm_max_threads(compute_capability_t capability) {
  return
    (capability >= 86) ? 1536 :  // SM86+
    (capability >= 80) ? 2048 :  // SM80
    (capability >= 75) ? 1024 :  // SM75
                         2048 ;  // SM30-SM72
}

/**
 * @brief Number of 32-bit registers per SM.
 * @param capability Compute capability from which to get the result
 * \return unsigned
 */
inline constexpr unsigned sm_registers(compute_capability_t capability) {
  return
    (capability >= 50) ?  64 * K :  // SM50+
    (capability >= 37) ? 128 * K :  // SM37
                          64 * K ;  // SM30-SM35
}

/**
 * @brief Maximum amount of shared memory per SM.
 * @tparam sm3XCacheConfig cudaFuncCache enum representing the shared data
 *                         cache configuration used when called on compute
 *                         capability 3.x
 * @param capability       Compute capability from which to get the result
 * \return unsigned
 * @todo Test if this function can be resolved at compile time
 */
template<enum cudaFuncCache sm3XCacheConfig = cudaFuncCachePreferNone>
inline constexpr unsigned sm_max_shared_memory_bytes(
  compute_capability_t capability
) {
  unsigned sm3XConfiguredSmem =
    (sm3XCacheConfig == cudaFuncCachePreferNone)   ? 48 * KiB :
    (sm3XCacheConfig == cudaFuncCachePreferShared) ? 48 * KiB :
    (sm3XCacheConfig == cudaFuncCachePreferL1)     ? 16 * KiB :
    (sm3XCacheConfig == cudaFuncCachePreferEqual)  ? 32 * KiB :
                                                     48 * KiB ;

  return
    (capability >= 86) ? 100 * KiB :  // SM86+
    (capability >= 80) ? 164 * KiB :  // SM80
    (capability >= 75) ?  64 * KiB :  // SM75
    (capability >= 70) ?  96 * KiB :  // SM70-SM72
    (capability >= 62) ?  64 * KiB :  // SM62
    (capability >= 61) ?  96 * KiB :  // SM61
    (capability >= 53) ?  64 * KiB :  // SM53
    (capability >= 52) ?  96 * KiB :  // SM52
    (capability >= 50) ?  64 * KiB :  // SM50
    (capability >= 37) ?  64 * KiB + sm3XConfiguredSmem :  // SM37
                sm3XConfiguredSmem ;  // SM30-SM35
}

/**
 * @brief Number of shared memory banks.
 * \return unsigned
 */
inline constexpr unsigned shared_memory_banks() {
  return 1 << 5;  // 32 memory banks per SM
}

/**
 * @brief Stride length (number of bytes per word) of shared memory in bytes.
 * @tparam sm3XSmemConfig cudaSharedMemConfig enum representing the shared
 *                        memory bank size (stride) used when called on compute
 *                        capability 3.x
 * \return unsigned
 */
template<enum cudaSharedMemConfig sm3XSmemConfig = cudaSharedMemBankSizeDefault>
inline constexpr unsigned shared_memory_bank_stride() {
  // The default config on 3.x is the same constant value for later archs
  // Only let 3.x be configurable if stride later becomes dependent on arch
  return
    (sm3XSmemConfig == cudaSharedMemBankSizeDefault)   ? 1 << 2 :
    (sm3XSmemConfig == cudaSharedMemBankSizeFourByte)  ? 1 << 2 :
    (sm3XSmemConfig == cudaSharedMemBankSizeEightByte) ? 1 << 3 :
                                                         1 << 2 ;
}

void print(device_properties_t& prop) {
  device_id_t ordinal;
  cudaGetDevice(&ordinal);

  size_t freeMem, totalMem;
  error::error_t status = cudaMemGetInfo(&freeMem, &totalMem);
  error::throw_if_exception(status);

  double memBandwidth =
      (prop.memoryClockRate * 1000.0) * (prop.memoryBusWidth / 8 * 2) / 1.0e9;

  std::cout << prop.name << " : " << prop.clockRate / 1000.0 << " Mhz "
            << "(Ordinal " << ordinal << ")" << std::endl;
  std::cout << "FreeMem: " << (int)(freeMem / (1 << 20)) << " MB "
            << "TotalMem: " << (int)(totalMem / (1 << 20)) << " MB "
            << ((int)8 * sizeof(int*)) << "-bit pointers." << std::endl;
  std::cout << prop.multiProcessorCount
            << " SMs enabled, Compute Capability sm_" << prop.major
            << prop.minor << std::endl;
  std::cout << "Mem Clock: " << prop.memoryClockRate / 1000.0 << " Mhz x "
            << prop.memoryBusWidth << " bits (" << memBandwidth << " GB/s)"
            << std::endl;
  std::cout << "ECC " << (prop.ECCEnabled ? "Enabled" : "Disabled")
            << std::endl;
}

}  // namespace properties

}  // namespace cuda
}  // namespace gunrock
<|endoftext|>


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

#include "FbTime.hh"

#include <cstdlib>
#include <sys/time.h>

#ifdef HAVE_CLOCK_GETTIME // linux|*bsd|solaris
#include <time.h>

namespace {

uint64_t _mono() {

    uint64_t t = 0L;
    timespec ts;

    if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
        t = (ts.tv_sec * FbTk::FbTime::IN_SECONDS) + (ts.tv_nsec / 1000L);
    }

    return t;
}

}

#endif // HAVE_CLOCK_GETTIME

#ifdef HAVE_MACH_ABSOLUTE_TIME // macosx

// http://stackoverflow.com/questions/5167269/clock-gettime-alternative-in-mac-os-x
// https://github.com/ThomasHabets/monotonic_clock/blob/master/src/monotonic_mach.c
// http://shiftedbits.org/2008/10/01/mach_absolute_time-on-the-iphone/

#include <mach/mach_time.h>

namespace {

uint64_t _mono() {

    // mach_absolute_time() * info.numer / info.denom yields
    // nanoseconds.

    static double micro_scale = 0.001;  // 1000ms == 1ns
    static bool initial = true;

    if (initial) {
        initial = false;
        mach_timebase_info_data_t info;
        if (mach_timebase_info(&info) == 0) {
            micro_scale *= static_cast<double>(info.numer) / static_cast<double>(info.denom);
        }
    }

    return static_cast<uint64_t>(mach_absolute_time() * micro_scale);
}

}

#endif // HAVE_MACH_ABSOLUTE_TIME

uint64_t FbTk::FbTime::mono() {
    return ::_mono();
}

uint64_t FbTk::FbTime::system() {
    static timeval v;
    gettimeofday(&v, NULL);
    return (v.tv_sec * FbTk::FbTime::IN_SECONDS) + v.tv_usec;
}

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

#include "FbTime.hh"

#include <cstdlib>
#include <sys/time.h>

#ifdef HAVE_CLOCK_GETTIME // linux|*bsd|solaris
#include <time.h>

namespace {

uint64_t _mono() {

    uint64_t t = 0L;
    timespec ts;

    if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
        t = (ts.tv_sec * FbTk::FbTime::IN_SECONDS) + (ts.tv_nsec / 1000L);
    }

    return t;
}

}

#endif // HAVE_CLOCK_GETTIME

#ifdef HAVE_MACH_ABSOLUTE_TIME // macosx

// http://stackoverflow.com/questions/5167269/clock-gettime-alternative-in-mac-os-x
// https://github.com/ThomasHabets/monotonic_clock/blob/master/src/monotonic_mach.c
// http://shiftedbits.org/2008/10/01/mach_absolute_time-on-the-iphone/

#include <mach/mach_time.h>

namespace {

uint64_t _mono() {

    // mach_absolute_time() * info.numer / info.denom yields
    // nanoseconds.

    static double micro_scale = 0.001;  // 1000ms == 1ns
    static bool initial = true;

    if (initial) {
        initial = false;
        mach_timebase_info_data_t info;
        if (mach_timebase_info(&info) == 0) {
            micro_scale *= static_cast<double>(info.numer) / static_cast<double>(info.denom);
        }
    }

    return static_cast<uint64_t>(mach_absolute_time() * micro_scale);
}

}

#endif // HAVE_MACH_ABSOLUTE_TIME

static uint64_t start = ::_mono();

uint64_t FbTk::FbTime::mono() {
    return ::_mono() - start;
}

uint64_t FbTk::FbTime::system() {
    static timeval v;
    gettimeofday(&v, NULL);
    return (v.tv_sec * FbTk::FbTime::IN_SECONDS) + v.tv_usec;
}

<|endoftext|>


<commit_before>#include "Filesystem.h"

#include <fstream>
#include <utility>

namespace tigl {
	auto readFile(const boost::filesystem::path& filename) -> std::string {
		std::ifstream existingFile(filename.string());
		if (!existingFile)
			return{};

		// read file to string
		existingFile.seekg(0, std::ifstream::end);
		const auto length = existingFile.tellg();
		existingFile.seekg(0, std::ifstream::beg);
		std::string content;
		content.reserve(length);
		content.assign(std::istreambuf_iterator<char>{existingFile}, std::istreambuf_iterator<char>{});
		return content;
	}

	File::File(boost::filesystem::path filename)
		: m_stream(new std::ostringstream), m_filename(std::move(filename)) {}

	auto File::stream() -> std::ostream& {
		return *m_stream;
	}

	void Filesystem::flushToDisk() {
		for (auto& file : m_files) {
			const auto& newContent = file.m_stream->str();

			// check if a file already exists
			if (boost::filesystem::exists(file.m_filename)) {
				// read existing file to string and compare
				const auto& content = readFile(file.m_filename);

				// if existing file has same content, skip overwriting it
				if (content == newContent) {
					skipped++;
					continue;
				}

				overwritten++;
			}
			else
				newlywritten++;

			// write new content to file
			std::ofstream f(file.m_filename.string());
			f.exceptions(std::ios::failbit | std::ios::badbit);
			f.write(newContent.c_str(), newContent.size());
			f.close();
		}
	}

	auto Filesystem::newFile(boost::filesystem::path filename) -> File& {
		m_files.emplace_back(std::move(filename));
		return m_files.back();
	}

	void Filesystem::removeIfExists(const boost::filesystem::path& path) {
		if (boost::filesystem::exists(path)) {
			boost::filesystem::remove(path);
			deleted++;
		}
	}

	void Filesystem::mergeFilesInto(boost::filesystem::path filename) {
		std::ostringstream oss;
		for (auto& file : m_files) {
			auto str = file.m_stream->str();
			oss.write(str.c_str(), str.size());
		}
		*newFile(std::move(filename)).m_stream = std::move(oss);
	}
}
<commit_msg>fixed build gcc build issues<commit_after>#include "Filesystem.h"

#include <fstream>
#include <utility>

namespace tigl {
	auto readFile(const boost::filesystem::path& filename) -> std::string {
		std::ifstream existingFile(filename.string());
		if (!existingFile)
			return{};

		// read file to string
		existingFile.seekg(0, std::ifstream::end);
		const auto length = existingFile.tellg();
		existingFile.seekg(0, std::ifstream::beg);
		std::string content;
		content.reserve(length);
		content.assign(std::istreambuf_iterator<char>{existingFile}, std::istreambuf_iterator<char>{});
		return content;
	}

	File::File(boost::filesystem::path filename)
		: m_stream(new std::ostringstream), m_filename(std::move(filename)) {}

	auto File::stream() -> std::ostream& {
		return *m_stream;
	}

	void Filesystem::flushToDisk() {
		for (auto& file : m_files) {
			const auto& newContent = file.m_stream->str();

			// check if a file already exists
			if (boost::filesystem::exists(file.m_filename)) {
				// read existing file to string and compare
				const auto& content = readFile(file.m_filename);

				// if existing file has same content, skip overwriting it
				if (content == newContent) {
					skipped++;
					continue;
				}

				overwritten++;
			}
			else
				newlywritten++;

			// write new content to file
			std::ofstream f(file.m_filename.string());
			f.exceptions(std::ios::failbit | std::ios::badbit);
			f.write(newContent.c_str(), newContent.size());
			f.close();
		}
	}

	auto Filesystem::newFile(boost::filesystem::path filename) -> File& {
		m_files.emplace_back(std::move(filename));
		return m_files.back();
	}

	void Filesystem::removeIfExists(const boost::filesystem::path& path) {
		if (boost::filesystem::exists(path)) {
			boost::filesystem::remove(path);
			deleted++;
		}
	}

	void Filesystem::mergeFilesInto(boost::filesystem::path filename) {
		auto& f = newFile(std::move(filename));
		for (auto& file : m_files) {
			auto str = file.m_stream->str();
			f.m_stream->write(str.c_str(), str.size());
		}
	}
}
<|endoftext|>


<commit_before>/**
 * This file implements a command line utility to interact
 * with the d2 library.
 */

#include <d2/analysis.hpp>
#include <d2/event_repository.hpp>
#include <d2/graph_construction.hpp>

#include <boost/assert.hpp>
#include <boost/assign.hpp>
#include <boost/foreach.hpp>
#include <boost/function.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/graph/properties.hpp>
#include <boost/optional.hpp>
#include <boost/phoenix.hpp>
#include <boost/program_options.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <cstddef>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <map>
#include <string>
#include <utility>
#include <vector>

static std::string const VERSION = "0.1a";

namespace po = boost::program_options;
namespace phx = boost::phoenix;
using phx::arg_names::_1;

namespace {

// Dot rendering
template <typename LockGraph>
class LockGraphWriter {
    typedef typename boost::graph_traits<LockGraph>::edge_descriptor
                                                            EdgeDescriptor;
    typedef typename boost::graph_traits<LockGraph>::vertex_descriptor
                                                            VertexDescriptor;
    LockGraph const& graph_;

    // Silence MSVC warning C4512: assignment operator could not be generated
    LockGraphWriter& operator=(LockGraphWriter const&) /*= delete*/;

public:
    explicit LockGraphWriter(LockGraph const& lg) : graph_(lg) { }

    template <typename Ostream>
    void operator()(Ostream& os, EdgeDescriptor edge) const {
        os << "[label=\""
           << "from " << graph_[edge].l1_info.call_stack[0].function

           << " to " << graph_[edge].l2_info.call_stack[0].function
           << "\"]";
    }

    template <typename Ostream>
    void operator()(Ostream&, VertexDescriptor) const {

    }
};

template <typename LockGraph>
LockGraphWriter<LockGraph> render_dot(LockGraph const& lg) {
    return LockGraphWriter<LockGraph>(lg);
}

// Statistic gathering
template <typename LockGraph, typename SegmentationGraph>
struct Statistics {
    Statistics(LockGraph const& lg, SegmentationGraph const&)
        : number_of_lock_graph_vertices(num_vertices(lg)),
          number_of_lock_graph_edges(num_edges(lg))
    { }

    std::size_t number_of_lock_graph_vertices;
    std::size_t number_of_lock_graph_edges;
    boost::optional<std::size_t> number_of_distinct_cycles;

    template <typename Ostream>
    friend Ostream& operator<<(Ostream& os, Statistics const& self) {
        os << "number of vertices in the lock graph: " << self.number_of_lock_graph_vertices << '\n'
           << "number of edges in the lock graph: " << self.number_of_lock_graph_edges << '\n'
           << "number of distinct cycles in the lock graph: ";

        if (self.number_of_distinct_cycles)
            os << *self.number_of_distinct_cycles;
        else
            os << "not computed";

        return os;
    }
};

template <typename Stats>
class StatisticGatherer {
    Stats& stats_;

    // Silence MSVC warning C4512: assignment operator could not be generated
    StatisticGatherer& operator=(StatisticGatherer const&) /*= delete*/;

public:
    explicit StatisticGatherer(Stats& stats) : stats_(stats) {
        BOOST_ASSERT_MSG(!stats_.number_of_distinct_cycles,
        "gathering statistics on a statistic object that was already filled");
        stats_.number_of_distinct_cycles = 0;
    }

    template <typename EdgePath, typename LockGraph>
    void operator()(EdgePath const&, LockGraph const&) const {
        ++*stats_.number_of_distinct_cycles;
    }
};

template <typename Stats>
StatisticGatherer<Stats> gather_stats(Stats& stats) {
    return StatisticGatherer<Stats>(stats);
}

// Deadlock analysis
template <typename Ostream>
class CyclePrinter {
    Ostream& os_;

    // Silence MSVC warning C4512: assignment operator could not be generated
    CyclePrinter& operator=(CyclePrinter const&) /*= delete*/;

    void format_call_stack(d2::detail::LockDebugInfo const& info,
                           std::string const& indent = "") const {
        BOOST_FOREACH(d2::detail::StackFrame const& frame, info.call_stack) {
            os_ << indent
            << frame.ip << "    " << frame.function << " in " << frame.module
            << '\n';
        }
    }

public:
    explicit CyclePrinter(Ostream& os) : os_(os) { }

    template <typename EdgePath, typename LockGraph>
    void operator()(EdgePath const& cycle, LockGraph const& graph) const {
        typedef typename boost::graph_traits<LockGraph>::edge_descriptor
                                                    LockGraphEdgeDescriptor;
        typedef typename boost::edge_property_type<LockGraph>::type
                                                                LockGraphEdge;
        os_ << "----------------------------------------------------";

        BOOST_FOREACH(LockGraphEdgeDescriptor const& edge_desc, cycle) {
            LockGraphEdge const& edge = graph[edge_desc];
            d2::SyncObject const& l1 = graph[source(edge_desc, graph)];
            d2::SyncObject const& l2 = graph[target(edge_desc, graph)];

            os_ << '\n';

            os_ << "Thread " << edge.t << " acquired lock " << l2 << " in\n";
            format_call_stack(edge.l2_info, "    ");

            os_ << "while holding lock " << l1 << " taken in\n";
            format_call_stack(edge.l1_info, "    ");
        }

        os_ << "----------------------------------------------------\n\n";
    }
};

template <typename Ostream>
CyclePrinter<Ostream> print_cycle(Ostream& os) {
    return CyclePrinter<Ostream>(os);
}

} // end anonymous namespace

int main(int argc, char const* argv[]) {
    // Parse command line options.
    po::options_description global("Global options");
    global.add_options()
    (
        "help,h", "produce help message and exit"
    )(
        "version,v", "print version and exit"
    )(
        "output-file,o", po::value<std::string>(), "file to write the output to"
    )(
        "analyze", "perform the analysis for deadlocks"
    )(
        "dot", "produce a dot representation of the lock graph used during the analysis"
    )(
        "stats", "produce statistics about the usage of locks and threads"
    )
    ;

    po::options_description hidden;
    hidden.add_options()
        ("repo-path", po::value<std::string>(), "path of the repository to examine")
    ;
    po::positional_options_description positionals;
    positionals.add("repo-path", 1);

    po::options_description analysis("Analysis options");

    po::options_description dot("Dot rendering options");

    po::options_description statistics("Statistics options");

    po::options_description allowed;
    allowed.add(global).add(analysis).add(dot).add(statistics);

    po::options_description all;
    all.add(allowed).add(hidden);

    po::variables_map args;
    po::command_line_parser parser(argc, argv);
    try {
        po::store(parser.options(all).positional(positionals).run(), args);
        po::notify(args);
    } catch(po::error const& e) {
        std::cerr << e.what() << std::endl
                  << allowed << std::endl;
        return EXIT_FAILURE;
    }

    // Some options make us do something and exit right away. These cases
    // are handled here.
    {
        typedef boost::function<void(po::variable_value)> DieAction;
        std::map<std::string, DieAction> die_actions =
        boost::assign::map_list_of<std::string, DieAction>
            ("help", phx::ref(std::cout) << allowed << '\n')
            ("version", phx::ref(std::cout) << VERSION << '\n')
        ;
        typedef std::pair<std::string, DieAction> DieActionPair;
        BOOST_FOREACH(DieActionPair const& action, die_actions) {
            if (args.count(action.first)) {
                action.second(args[action.first]);
                return EXIT_FAILURE;
            }
        }
    }

    // Open the repository on which we must operate.
    if (!args.count("repo-path")) {
        std::cerr << "missing the path of a repository on which to operate "
                     "from the command line" << std::endl
                  << allowed << std::endl;
        return EXIT_FAILURE;
    }
    d2::EventRepository<> repository(args["repo-path"].as<std::string>());

    // Open the output stream to whatever passed on the command line or to
    // stdout if unspecified.
    std::ofstream output_ofs;
    if (args.count("output-file")) {
        std::string output_file = args["output-file"].as<std::string>();
        output_ofs.open(output_file.c_str());
        if (!output_ofs) {
            std::cerr << "Unable to open output file \"" << output_file <<'"';
            return EXIT_FAILURE;
        }
    }
    std::ostream& output = args.count("output-file") ? output_ofs : std::cout;

    // Build the segmentation and the lock graph. They are required no matter
    // the options we received on the command line.
    d2::SegmentationGraph sg;
    d2::LockGraph lg;
    try {
        d2::build_graphs(repository, lg, sg);
    } catch (d2::EventTypeException const& e) {
        using boost::get_error_info;
        char const* const* actual_type = get_error_info<d2::ActualType>(e);
        char const* const* expected_type = get_error_info<d2::ExpectedType>(e);

        char const* unavailable = "\"unavailable\"";
        if (!actual_type) actual_type = &unavailable;
        if (!expected_type) expected_type = &unavailable;

        std::cerr << "Error while building the graphs:\n"
                     "    encountered an event of type " << *actual_type
                  << " while expecting an event of type " << *expected_type
                  << "." << std::endl;

        return EXIT_FAILURE;
    }

    // Main switch dispatching to the right action to perform.
    if (args.count("analyze") || (!args.count("dot") && !args.count("stats"))) {
        d2::analyze(lg, sg, print_cycle(std::cout));
    }
    else if (args.count("dot")) {
        boost::write_graphviz(output, lg, render_dot(lg), render_dot(lg));
    }
    else if (args.count("stats")) {
        Statistics<d2::LockGraph, d2::SegmentationGraph> stats(lg, sg);
        d2::analyze(lg, sg, gather_stats(stats));
        output << stats << std::endl;
    }
    return EXIT_SUCCESS;
}
<commit_msg>Add error handling during the aperture of the repository in the command line utility.<commit_after>/**
 * This file implements a command line utility to interact
 * with the d2 library.
 */

#include <d2/analysis.hpp>
#include <d2/event_repository.hpp>
#include <d2/graph_construction.hpp>

#include <boost/assert.hpp>
#include <boost/assign.hpp>
#include <boost/foreach.hpp>
#include <boost/function.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/graphviz.hpp>
#include <boost/graph/properties.hpp>
#include <boost/optional.hpp>
#include <boost/phoenix.hpp>
#include <boost/program_options.hpp>
#include <boost/range/begin.hpp>
#include <boost/range/end.hpp>
#include <boost/scoped_ptr.hpp>
#include <cstddef>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <map>
#include <string>
#include <utility>
#include <vector>

static std::string const VERSION = "0.1a";

namespace po = boost::program_options;
namespace phx = boost::phoenix;
using phx::arg_names::_1;

namespace {

// Dot rendering
template <typename LockGraph>
class LockGraphWriter {
    typedef typename boost::graph_traits<LockGraph>::edge_descriptor
                                                            EdgeDescriptor;
    typedef typename boost::graph_traits<LockGraph>::vertex_descriptor
                                                            VertexDescriptor;
    LockGraph const& graph_;

    // Silence MSVC warning C4512: assignment operator could not be generated
    LockGraphWriter& operator=(LockGraphWriter const&) /*= delete*/;

public:
    explicit LockGraphWriter(LockGraph const& lg) : graph_(lg) { }

    template <typename Ostream>
    void operator()(Ostream& os, EdgeDescriptor edge) const {
        os << "[label=\""
           << "from " << graph_[edge].l1_info.call_stack[0].function

           << " to " << graph_[edge].l2_info.call_stack[0].function
           << "\"]";
    }

    template <typename Ostream>
    void operator()(Ostream&, VertexDescriptor) const {

    }
};

template <typename LockGraph>
LockGraphWriter<LockGraph> render_dot(LockGraph const& lg) {
    return LockGraphWriter<LockGraph>(lg);
}

// Statistic gathering
template <typename LockGraph, typename SegmentationGraph>
struct Statistics {
    Statistics(LockGraph const& lg, SegmentationGraph const&)
        : number_of_lock_graph_vertices(num_vertices(lg)),
          number_of_lock_graph_edges(num_edges(lg))
    { }

    std::size_t number_of_lock_graph_vertices;
    std::size_t number_of_lock_graph_edges;
    boost::optional<std::size_t> number_of_distinct_cycles;

    template <typename Ostream>
    friend Ostream& operator<<(Ostream& os, Statistics const& self) {
        os << "number of vertices in the lock graph: " << self.number_of_lock_graph_vertices << '\n'
           << "number of edges in the lock graph: " << self.number_of_lock_graph_edges << '\n'
           << "number of distinct cycles in the lock graph: ";

        if (self.number_of_distinct_cycles)
            os << *self.number_of_distinct_cycles;
        else
            os << "not computed";

        return os;
    }
};

template <typename Stats>
class StatisticGatherer {
    Stats& stats_;

    // Silence MSVC warning C4512: assignment operator could not be generated
    StatisticGatherer& operator=(StatisticGatherer const&) /*= delete*/;

public:
    explicit StatisticGatherer(Stats& stats) : stats_(stats) {
        BOOST_ASSERT_MSG(!stats_.number_of_distinct_cycles,
        "gathering statistics on a statistic object that was already filled");
        stats_.number_of_distinct_cycles = 0;
    }

    template <typename EdgePath, typename LockGraph>
    void operator()(EdgePath const&, LockGraph const&) const {
        ++*stats_.number_of_distinct_cycles;
    }
};

template <typename Stats>
StatisticGatherer<Stats> gather_stats(Stats& stats) {
    return StatisticGatherer<Stats>(stats);
}

// Deadlock analysis
template <typename Ostream>
class CyclePrinter {
    Ostream& os_;

    // Silence MSVC warning C4512: assignment operator could not be generated
    CyclePrinter& operator=(CyclePrinter const&) /*= delete*/;

    void format_call_stack(d2::detail::LockDebugInfo const& info,
                           std::string const& indent = "") const {
        BOOST_FOREACH(d2::detail::StackFrame const& frame, info.call_stack) {
            os_ << indent
            << frame.ip << "    " << frame.function << " in " << frame.module
            << '\n';
        }
    }

public:
    explicit CyclePrinter(Ostream& os) : os_(os) { }

    template <typename EdgePath, typename LockGraph>
    void operator()(EdgePath const& cycle, LockGraph const& graph) const {
        typedef typename boost::graph_traits<LockGraph>::edge_descriptor
                                                    LockGraphEdgeDescriptor;
        typedef typename boost::edge_property_type<LockGraph>::type
                                                                LockGraphEdge;
        os_ << "----------------------------------------------------";

        BOOST_FOREACH(LockGraphEdgeDescriptor const& edge_desc, cycle) {
            LockGraphEdge const& edge = graph[edge_desc];
            d2::SyncObject const& l1 = graph[source(edge_desc, graph)];
            d2::SyncObject const& l2 = graph[target(edge_desc, graph)];

            os_ << '\n';

            os_ << "Thread " << edge.t << " acquired lock " << l2 << " in\n";
            format_call_stack(edge.l2_info, "    ");

            os_ << "while holding lock " << l1 << " taken in\n";
            format_call_stack(edge.l1_info, "    ");
        }

        os_ << "----------------------------------------------------\n\n";
    }
};

template <typename Ostream>
CyclePrinter<Ostream> print_cycle(Ostream& os) {
    return CyclePrinter<Ostream>(os);
}

} // end anonymous namespace

int main(int argc, char const* argv[]) {
    // Parse command line options.
    po::options_description global("Global options");
    global.add_options()
    (
        "help,h", "produce help message and exit"
    )(
        "version,v", "print version and exit"
    )(
        "output-file,o", po::value<std::string>(), "file to write the output to"
    )(
        "analyze", "perform the analysis for deadlocks"
    )(
        "dot", "produce a dot representation of the lock graph used during the analysis"
    )(
        "stats", "produce statistics about the usage of locks and threads"
    )
    ;

    po::options_description hidden;
    hidden.add_options()
        ("repo-path", po::value<std::string>(), "path of the repository to examine")
        ("debug", "enable special debugging output")
    ;
    po::positional_options_description positionals;
    positionals.add("repo-path", 1);

    po::options_description analysis("Analysis options");

    po::options_description dot("Dot rendering options");

    po::options_description statistics("Statistics options");

    po::options_description allowed;
    allowed.add(global).add(analysis).add(dot).add(statistics);

    po::options_description all;
    all.add(allowed).add(hidden);

    po::variables_map args;
    po::command_line_parser parser(argc, argv);
    try {
        po::store(parser.options(all).positional(positionals).run(), args);
        po::notify(args);
    } catch (po::error const& e) {
        std::cerr << e.what() << std::endl
                  << allowed << std::endl;
        return EXIT_FAILURE;
    }

    // Some options make us do something and exit right away. These cases
    // are handled here.
    {
        typedef boost::function<void(po::variable_value)> DieAction;
        std::map<std::string, DieAction> die_actions =
        boost::assign::map_list_of<std::string, DieAction>
            ("help", phx::ref(std::cout) << allowed << '\n')
            ("version", phx::ref(std::cout) << VERSION << '\n')
        ;
        typedef std::pair<std::string, DieAction> DieActionPair;
        BOOST_FOREACH(DieActionPair const& action, die_actions) {
            if (args.count(action.first)) {
                action.second(args[action.first]);
                return EXIT_FAILURE;
            }
        }
    }

    // Open the repository on which we must operate.
    if (!args.count("repo-path")) {
        std::cerr << "missing the path of a repository on which to operate "
                     "from the command line" << std::endl
                  << allowed << std::endl;
        return EXIT_FAILURE;
    }
    std::string repo_path = args["repo-path"].as<std::string>();
    boost::scoped_ptr<d2::EventRepository<> > repository;
    try {
        repository.reset(new d2::EventRepository<>(repo_path));
    } catch (d2::RepositoryException const& e) {
        std::cerr << "unable to open the repository at \""
                  << repo_path << "\"\n";
        if (args.count("debug"))
            std::cerr << boost::diagnostic_information(e) << '\n';
        return EXIT_FAILURE;
    }

    // Open the output stream to whatever passed on the command line or to
    // stdout if unspecified.
    std::ofstream output_ofs;
    if (args.count("output-file")) {
        std::string output_file = args["output-file"].as<std::string>();
        output_ofs.open(output_file.c_str());
        if (!output_ofs) {
            std::cerr << "unable to open output file \"" << output_file << '"';
            return EXIT_FAILURE;
        }
    }
    std::ostream& output = args.count("output-file") ? output_ofs : std::cout;

    // Build the segmentation and the lock graph. They are required no matter
    // the options we received on the command line.
    d2::SegmentationGraph sg;
    d2::LockGraph lg;
    try {
        d2::build_graphs(*repository, lg, sg);
    } catch (d2::EventTypeException const& e) {
        using boost::get_error_info;
        char const* const* actual_type = get_error_info<d2::ActualType>(e);
        char const* const* expected_type = get_error_info<d2::ExpectedType>(e);

        char const* unavailable = "\"unavailable\"";
        if (!actual_type) actual_type = &unavailable;
        if (!expected_type) expected_type = &unavailable;

        std::cerr <<
        "error while building the graphs:\n"
        "    encountered an event of type " << *actual_type << '\n' <<
        "    while expecting an event of type " << *expected_type << '\n';
        return EXIT_FAILURE;
    }

    // Main switch dispatching to the right action to perform.
    if (args.count("analyze") || (!args.count("dot") && !args.count("stats"))) {
        d2::analyze(lg, sg, print_cycle(std::cout));
    }
    else if (args.count("dot")) {
        boost::write_graphviz(output, lg, render_dot(lg), render_dot(lg));
    }
    else if (args.count("stats")) {
        Statistics<d2::LockGraph, d2::SegmentationGraph> stats(lg, sg);
        d2::analyze(lg, sg, gather_stats(stats));
        output << stats << std::endl;
    }
    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before><commit_msg>Removed incorrect StyleInvalidator FIXME.<commit_after><|endoftext|>