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

#include "../scene_subdiv_mesh.h"
#include "subdivpatch1base.h"
#include "../scene.h"

namespace embree
{

  SubdivPatch1Base::SubdivPatch1Base (const unsigned int gID,
                                      const unsigned int pID,
                                      const unsigned int subPatch,
                                      const SubdivMesh *const mesh,
                                      const Vec2f uv[4],
                                      const float edge_level[4],
                                      const int subdiv[4],
                                      const int simd_width)
    : geom(gID),prim(pID),flags(0),type(INVALID_PATCH)
  {
    static_assert(sizeof(SubdivPatch1Base) == 5 * 64, "SubdivPatch1Base has wrong size");
    mtx.reset();

    const SubdivMesh::HalfEdge* edge = mesh->getHalfEdge(pID);

    if (edge->patch_type == SubdivMesh::REGULAR_QUAD_PATCH)
    {
#if PATCH_USE_BEZIER_PATCH
      type = BEZIER_PATCH;
      new (patch_v) BezierPatch3fa(BSplinePatch3fa(CatmullClarkPatch3fa(edge,mesh->getVertexBuffer())));
#else
      type = BSPLINE_PATCH;
      new (patch_v) BSplinePatch3fa(CatmullClarkPatch3fa(edge,mesh->getVertexBuffer()));
#endif
    }
#if PATCH_USE_GREGORY == 2
    else if (edge->patch_type == SubdivMesh::IRREGULAR_QUAD_PATCH)
    {
      type = GREGORY_PATCH;
      new (patch_v) DenseGregoryPatch3fa(GregoryPatch3fa(CatmullClarkPatch3fa(edge,mesh->getVertexBuffer())));
    }
#endif
    else
    {
      type = EVAL_PATCH;
      this->edge = mesh->getHalfEdge(pID);
      this->subPatch = subPatch;
    }

    for (size_t i=0; i<4; i++) {
      u[i] = (unsigned short)(uv[i].x * 65535.0f);
      v[i] = (unsigned short)(uv[i].y * 65535.0f);
    }

    updateEdgeLevels(edge_level,subdiv,mesh,simd_width);
  }

  /*! Construction from vertices and IDs. */
  SubdivPatch1Base::SubdivPatch1Base (const CatmullClarkPatch3fa& ipatch,
                                      const int fas_depth,
                                      const unsigned int gID,
                                      const unsigned int pID,
                                      const SubdivMesh *const mesh,
                                      const Vec2f uv[4],
                                      const float edge_level[4],
                                      const int neighborSubdiv[4],
                                      const BezierCurve3fa *border,
                                      const int border_flags,
                                      const int simd_width)
    : geom(gID),prim(pID),flags(0)
  {
    static_assert(sizeof(SubdivPatch1Base) == 5 * 64, "SubdivPatch1Base has wrong size");
    mtx.reset();

    for (size_t i=0; i<4; i++) {
      u[i] = (unsigned short)(uv[i].x * 65535.0f);
      v[i] = (unsigned short)(uv[i].y * 65535.0f);
    }

    updateEdgeLevels(edge_level,neighborSubdiv,mesh,simd_width);

    /* determine whether patch is regular or not */
    if (fas_depth == 0 && ipatch.isRegular1() && !ipatch.hasBorder()) /* only select b-spline/bezier in the interior and not FAS-based patches*/
    {
#if 0
      type = BEZIER_PATCH;
      new (patch_v) BezierPatch3fa(BSplinePatch3fa(ipatch));
#else
      type = BSPLINE_PATCH;
      new (patch_v) BSplinePatch3fa(ipatch);
#endif
    }
    else
    {
      type = GREGORY_PATCH;
      GregoryPatch3fa gpatch;
      gpatch.init_crackfix( ipatch, fas_depth, neighborSubdiv, border, border_flags );
      new (patch_v) DenseGregoryPatch3fa(gpatch);
    }
  }

  void SubdivPatch1Base::updateEdgeLevels(const float edge_level[4], const int subdiv[4], const SubdivMesh *const mesh, const int simd_width)
  {
    /* init discrete edge tessellation levels and grid resolution */

    assert( edge_level[0] >= 0.0f );
    assert( edge_level[1] >= 0.0f );
    assert( edge_level[2] >= 0.0f );
    assert( edge_level[3] >= 0.0f );

    level[0] = adjustTessellationLevel(edge_level[0],subdiv[0]);
    level[1] = adjustTessellationLevel(edge_level[1],subdiv[1]);
    level[2] = adjustTessellationLevel(edge_level[2],subdiv[2]);
    level[3] = adjustTessellationLevel(edge_level[3],subdiv[3]);

    level[0] = max(ceilf(level[0]),1.0f);
    level[1] = max(ceilf(level[1]),1.0f);
    level[2] = max(ceilf(level[2]),1.0f);
    level[3] = max(ceilf(level[3]),1.0f);

    grid_u_res = max(level[0],level[2])+1; // n segments -> n+1 points
    grid_v_res = max(level[1],level[3])+1;

    /* workaround for 2x2 intersection stencil */
#if !defined(__MIC__)
    grid_u_res = max(grid_u_res,3); // FIXME: this triggers stitching
    grid_v_res = max(grid_v_res,3);
#endif
    grid_size_simd_blocks = ((grid_u_res*grid_v_res+simd_width-1)&(-simd_width)) / simd_width;
    grid_bvh_size_64b_blocks = getSubTreeSize64bBlocks( 0 );
    const size_t grid_size_xyzuv = (grid_size_simd_blocks * simd_width) * 4;
    grid_subtree_size_64b_blocks = grid_bvh_size_64b_blocks + ((grid_size_xyzuv+15) / 16);

    /* need stiching? */
    flags &= ~TRANSITION_PATCH;
    const unsigned int int_edge_points0 = (unsigned int)level[0] + 1;
    const unsigned int int_edge_points1 = (unsigned int)level[1] + 1;
    const unsigned int int_edge_points2 = (unsigned int)level[2] + 1;
    const unsigned int int_edge_points3 = (unsigned int)level[3] + 1;
    if (int_edge_points0 < (unsigned int)grid_u_res ||
	int_edge_points2 < (unsigned int)grid_u_res ||
	int_edge_points1 < (unsigned int)grid_v_res ||
	int_edge_points3 < (unsigned int)grid_v_res) {
      flags |= TRANSITION_PATCH;
    }
  }
}
<commit_msg>cleanups in subdivpatch1base.cpp<commit_after>// ======================================================================== //
// Copyright 2009-2015 Intel Corporation                                    //
//                                                                          //
// Licensed under the Apache License, Version 2.0 (the "License");          //
// you may not use this file except in compliance with the License.         //
// You may obtain a copy of the License at                                  //
//                                                                          //
//     http://www.apache.org/licenses/LICENSE-2.0                           //
//                                                                          //
// Unless required by applicable law or agreed to in writing, software      //
// distributed under the License is distributed on an "AS IS" BASIS,        //
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
// See the License for the specific language governing permissions and      //
// limitations under the License.                                           //
// ======================================================================== //

#include "../scene_subdiv_mesh.h"
#include "subdivpatch1base.h"
#include "../scene.h"

namespace embree
{

  SubdivPatch1Base::SubdivPatch1Base (const unsigned int gID,
                                      const unsigned int pID,
                                      const unsigned int subPatch,
                                      const SubdivMesh *const mesh,
                                      const Vec2f uv[4],
                                      const float edge_level[4],
                                      const int subdiv[4],
                                      const int simd_width)
    : geom(gID),prim(pID),flags(0),type(INVALID_PATCH)
  {
    static_assert(sizeof(SubdivPatch1Base) == 5 * 64, "SubdivPatch1Base has wrong size");
    mtx.reset();

    const SubdivMesh::HalfEdge* edge = mesh->getHalfEdge(pID);

    if (edge->patch_type == SubdivMesh::REGULAR_QUAD_PATCH)
    {
#if PATCH_USE_BEZIER_PATCH
      type = BEZIER_PATCH;
      new (patch_v) BezierPatch3fa(BSplinePatch3fa(CatmullClarkPatch3fa(edge,mesh->getVertexBuffer())));
#else
      type = BSPLINE_PATCH;
      new (patch_v) BSplinePatch3fa(CatmullClarkPatch3fa(edge,mesh->getVertexBuffer()));
#endif
    }
#if PATCH_USE_GREGORY == 2
    else if (edge->patch_type == SubdivMesh::IRREGULAR_QUAD_PATCH)
    {
      type = GREGORY_PATCH;
      new (patch_v) DenseGregoryPatch3fa(GregoryPatch3fa(CatmullClarkPatch3fa(edge,mesh->getVertexBuffer())));
    }
#endif
    else
    {
      type = EVAL_PATCH;
      this->edge = mesh->getHalfEdge(pID);
      this->subPatch = subPatch;
    }

    for (size_t i=0; i<4; i++) {
      u[i] = (unsigned short)(uv[i].x * 65535.0f);
      v[i] = (unsigned short)(uv[i].y * 65535.0f);
    }

    updateEdgeLevels(edge_level,subdiv,mesh,simd_width);
  }

  /*! Construction from vertices and IDs. */
  SubdivPatch1Base::SubdivPatch1Base (const CatmullClarkPatch3fa& ipatch,
                                      const int fas_depth,
                                      const unsigned int gID,
                                      const unsigned int pID,
                                      const SubdivMesh *const mesh,
                                      const Vec2f uv[4],
                                      const float edge_level[4],
                                      const int neighborSubdiv[4],
                                      const BezierCurve3fa *border,
                                      const int border_flags,
                                      const int simd_width)
    : geom(gID),prim(pID),flags(0)
  {
    static_assert(sizeof(SubdivPatch1Base) == 5 * 64, "SubdivPatch1Base has wrong size");
    mtx.reset();

    for (size_t i=0; i<4; i++) {
      u[i] = (unsigned short)(uv[i].x * 65535.0f);
      v[i] = (unsigned short)(uv[i].y * 65535.0f);
    }

    updateEdgeLevels(edge_level,neighborSubdiv,mesh,simd_width);

    /* determine whether patch is regular or not */
    if (fas_depth == 0 && ipatch.isRegular1() && !ipatch.hasBorder()) /* only select b-spline/bezier in the interior and not FAS-based patches*/
    {
#if 0
      type = BEZIER_PATCH;
      new (patch_v) BezierPatch3fa(BSplinePatch3fa(ipatch));
#else
      type = BSPLINE_PATCH;
      new (patch_v) BSplinePatch3fa(ipatch);
#endif
    }
    else
    {
      type = GREGORY_PATCH;
      GregoryPatch3fa gpatch;
      gpatch.init_crackfix( ipatch, fas_depth, neighborSubdiv, border, border_flags );
      new (patch_v) DenseGregoryPatch3fa(gpatch);
    }
  }

  void SubdivPatch1Base::updateEdgeLevels(const float edge_level[4], const int subdiv[4], const SubdivMesh *const mesh, const int simd_width)
  {
    /* init discrete edge tessellation levels and grid resolution */
    assert( edge_level[0] >= 0.0f );
    assert( edge_level[1] >= 0.0f );
    assert( edge_level[2] >= 0.0f );
    assert( edge_level[3] >= 0.0f );

    level[0] = max(ceilf(adjustTessellationLevel(edge_level[0],subdiv[0])),1.0f);
    level[1] = max(ceilf(adjustTessellationLevel(edge_level[1],subdiv[1])),1.0f);
    level[2] = max(ceilf(adjustTessellationLevel(edge_level[2],subdiv[2])),1.0f);
    level[3] = max(ceilf(adjustTessellationLevel(edge_level[3],subdiv[3])),1.0f);

    grid_u_res = max(level[0],level[2])+1; // n segments -> n+1 points
    grid_v_res = max(level[1],level[3])+1;

    /* workaround for 2x2 intersection stencil */
#if !defined(__MIC__)
    grid_u_res = max(grid_u_res,3); // FIXME: this triggers stitching
    grid_v_res = max(grid_v_res,3);
#endif
    grid_size_simd_blocks = ((grid_u_res*grid_v_res+simd_width-1)&(-simd_width)) / simd_width;
    grid_bvh_size_64b_blocks = getSubTreeSize64bBlocks( 0 );
    const size_t grid_size_xyzuv = (grid_size_simd_blocks * simd_width) * 4;
    grid_subtree_size_64b_blocks = grid_bvh_size_64b_blocks + ((grid_size_xyzuv+15) / 16);

    /* need stiching? */
    flags &= ~TRANSITION_PATCH;
    const unsigned int int_edge_points0 = (unsigned int)level[0] + 1;
    const unsigned int int_edge_points1 = (unsigned int)level[1] + 1;
    const unsigned int int_edge_points2 = (unsigned int)level[2] + 1;
    const unsigned int int_edge_points3 = (unsigned int)level[3] + 1;
    if (int_edge_points0 < (unsigned int)grid_u_res ||
	int_edge_points2 < (unsigned int)grid_u_res ||
	int_edge_points1 < (unsigned int)grid_v_res ||
	int_edge_points3 < (unsigned int)grid_v_res) {
      flags |= TRANSITION_PATCH;
    }
  }
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 Steinwurf ApS
// All Rights Reserved
//
// Distributed under the "BSD License". See the accompanying LICENSE.rst file.

#pragma once

#include <functional>
#include <memory>
#include <list>

namespace sak
{
    /// @brief The resource pool stores value objects and recycles them.
    template<class Value>
    class resource_pool
    {
    public:

        /// The type managed
        using value_type = Value;

        /// The pointer to the resource
        using value_ptr = std::shared_ptr<value_type>;

        /// The allocate function type
        /// Should take no arguments and return an std::shared_ptr to the Value
        using allocate_function = std::function<value_ptr()>;

        /// The recycle function type
        /// If specified the recycle function will be called every time a
        /// resource gets recycled into the pool. This allows temporary
        /// resources, e.g., file handles to be closed when an object is longer
        /// used.
        using recycle_function = std::function<void(value_ptr)>;

    public:

        /// Default constructor, we only want this to be available
        /// i.e. the resource_pool to be default constructible if the
        /// value_type we build is default constructible.
        ///
        /// This means that we only want
        /// std::is_default_constructible<resource_pool<T>>::value to
        /// be true if the type T is default constructible.
        ///
        /// Unfortunately this does not work if we don't do the
        /// template magic seen below. What we do there is to use
        /// SFINAE to disable the default constructor for non default
        /// constructible types.
        ///
        /// It looks quite ugly and if somebody can fix in a simpler way
        /// please do :)
        template
        <
            class T = Value,
            typename std::enable_if<
                std::is_default_constructible<T>::value, uint8_t>::type = 0
        >
        resource_pool() :
            m_pool(std::make_shared<impl>(
                       allocate_function(std::make_shared<value_type>)))
        { }

        /// Create a resource pool using a specific allocate function.
        /// @param allocate Allocation function
        resource_pool(allocate_function allocate) :
            m_pool(std::make_shared<impl>(std::move(allocate)))
        { }

        /// Create a resource pool using a specific allocate function and
        /// recycle function.
        /// @param allocate Allocation function
        /// @param recycle Recycle function
        resource_pool(allocate_function allocate, recycle_function recycle) :
            m_pool(std::make_shared<impl>(std::move(allocate),
                                          std::move(recycle)))
        { }

        /// Copy constructor
        resource_pool(const resource_pool& other) :
            m_pool(std::make_shared<impl>(*other.m_pool))
        { }

        /// Move constructor
        resource_pool(resource_pool&& other) :
            m_pool(std::move(other.m_pool))
        {
            assert(m_pool);
        }

        /// Copy assignment
        resource_pool& operator=(const resource_pool& other)
        {
            resource_pool tmp(other);
            std::swap(*this, tmp);
            return *this;
        }

        /// Move assignment
        resource_pool& operator=(resource_pool&& other)
        {
            m_pool = std::move(other.m_pool);
            return *this;
        }

        /// @returns the number of unused resources
        uint32_t unused_resources() const
        {
            assert(m_pool);
            return m_pool->unused_resources();
        }

        /// Frees all unused resources
        void free_unused()
        {
            assert(m_pool);
            m_pool->free_unused();
        }

        /// @return A resource from the pool.
        value_ptr allocate()
        {
            assert(m_pool);
            return m_pool->allocate();
        }

    private:

        /// The actual pool implementation. We use the
        /// enable_shared_from_this helper to make sure we can pass a
        /// "back-pointer" to the pooled objects. The idea behind this
        /// is that we need objects to be able to add themselves back
        /// into the pool once they go out of scope.
        struct impl : public std::enable_shared_from_this<impl>
        {

            /// @copydoc resource_pool::resource_pool(allocate_function)
            impl(allocate_function allocate) :
                m_allocate(std::move(allocate))
            {
                assert(m_allocate);
            }

            /// @copydoc resource_pool::resource_pool(allocate_function,
            ///                                       recycle_function)
            impl(allocate_function allocate, recycle_function recycle) :
                m_allocate(std::move(allocate)),
                m_recycle(std::move(recycle))
            {
                assert(m_allocate);
                assert(m_recycle);
            }

            /// Copy constructor
            impl(const impl& other) :
                std::enable_shared_from_this<impl>(other),
                m_allocate(other.m_allocate),
                m_recycle(other.m_recycle)
            {
                for (uint32_t i = 0; i < other.unused_resources(); ++i)
                {
                    m_free_list.push_back(m_allocate());
                }
            }

            /// Move constructor
            impl(impl&& other) :
                std::enable_shared_from_this<impl>(other),
                m_allocate(std::move(other.m_allocate)),
                m_recycle(std::move(other.m_recycle)),
                m_free_list(std::move(other.m_free_list))
            { }

            /// Copy assignment
            impl& operator=(const impl& other)
            {
                impl tmp(other);
                std::swap(*this, tmp);
                return *this;
            }

            /// Move assignment
            impl& operator=(impl&& other)
            {
                m_allocate = std::move(other.m_allocate);
                m_recycle = std::move(other.m_recycle);
                m_free_list = std::move(other.m_free_list);
                return *this;
            }

            /// Allocate a new value from the pool
            value_ptr allocate()
            {
                value_ptr resource;

                if (m_free_list.size() > 0)
                {
                    resource = m_free_list.back();
                    m_free_list.pop_back();
                }
                else
                {
                    assert(m_allocate);
                    resource = m_allocate();
                }

                auto pool = impl::shared_from_this();

                // Here we create a std::shared_ptr<T> with a naked
                // pointer to the resource and a custom deleter
                // object. The custom deleter object stores two
                // things:
                //
                //   1. A std::weak_ptr<T> to the pool (used when we
                //      need to put the resource back in the pool). If
                //      the pool dies before the resource then we can
                //      detect this with the weak_ptr and no try to
                //      access it.
                //
                //   2. A std::shared_ptr<T> that points to the actual
                //      resource and is the one actually keeping it alive.

                return value_ptr(resource.get(), deleter(pool, resource));
            }

            /// @copydoc resource_pool::free_unused()
            void free_unused()
            {
                m_free_list.clear();
            }

            /// @copydoc resource_pool::unused_resources()
            uint32_t unused_resources() const
            {
                return static_cast<uint32_t>(m_free_list.size());
            }

            /// This function called when a resource should be added
            /// back into the pool
            void recycle(const value_ptr& resource)
            {
                if (m_recycle)
                {
                    m_recycle(resource);
                }

                m_free_list.push_back(resource);
            }

        private:

            // The allocator to use
            allocate_function m_allocate;

            // The allocator to use
            recycle_function m_recycle;

            // Stores all the free resources
            std::list<value_ptr> m_free_list;

        };

        /// The custom deleter object used by the std::shared_ptr<T>
        /// to de-allocate the object if the pool goes out of
        /// scope. When a std::shared_ptr wants to de-allocate the
        /// object contained it will call the operator() define here.
        struct deleter
        {
            /// @param pool. A weak_ptr to the pool
            deleter(const std::weak_ptr<impl>& pool,
                    const value_ptr& resource)
                : m_pool(pool),
                  m_resource(resource)
            {
                assert(!m_pool.expired());
                assert(m_resource);
            }

            /// Call operator called by std::shared_ptr<T> when
            /// de-allocating the object.
            void operator()(value_type*)
            {
                // Place the resource in the free list
                auto pool = m_pool.lock();

                if (pool)
                {
                    pool->recycle(m_resource);
                }
            }

            // Poiner to the pool needed for recycling
            std::weak_ptr<impl> m_pool;

            // The resource object
            value_ptr m_resource;
        };

    private:

        // The pool impl
        std::shared_ptr<impl> m_pool;

    };
}
<commit_msg>fix includes<commit_after>// Copyright (c) 2012 Steinwurf ApS
// All Rights Reserved
//
// Distributed under the "BSD License". See the accompanying LICENSE.rst file.

#pragma once

#include <algorithm>
#include <cassert>
#include <cstdint>
#include <functional>
#include <list>
#include <memory>
#include <utility>

namespace sak
{
    /// @brief The resource pool stores value objects and recycles them.
    template<class Value>
    class resource_pool
    {
    public:

        /// The type managed
        using value_type = Value;

        /// The pointer to the resource
        using value_ptr = std::shared_ptr<value_type>;

        /// The allocate function type
        /// Should take no arguments and return an std::shared_ptr to the Value
        using allocate_function = std::function<value_ptr()>;

        /// The recycle function type
        /// If specified the recycle function will be called every time a
        /// resource gets recycled into the pool. This allows temporary
        /// resources, e.g., file handles to be closed when an object is longer
        /// used.
        using recycle_function = std::function<void(value_ptr)>;

    public:

        /// Default constructor, we only want this to be available
        /// i.e. the resource_pool to be default constructible if the
        /// value_type we build is default constructible.
        ///
        /// This means that we only want
        /// std::is_default_constructible<resource_pool<T>>::value to
        /// be true if the type T is default constructible.
        ///
        /// Unfortunately this does not work if we don't do the
        /// template magic seen below. What we do there is to use
        /// SFINAE to disable the default constructor for non default
        /// constructible types.
        ///
        /// It looks quite ugly and if somebody can fix in a simpler way
        /// please do :)
        template
        <
            class T = Value,
            typename std::enable_if<
                std::is_default_constructible<T>::value, uint8_t>::type = 0
        >
        resource_pool() :
            m_pool(std::make_shared<impl>(
                       allocate_function(std::make_shared<value_type>)))
        { }

        /// Create a resource pool using a specific allocate function.
        /// @param allocate Allocation function
        resource_pool(allocate_function allocate) :
            m_pool(std::make_shared<impl>(std::move(allocate)))
        { }

        /// Create a resource pool using a specific allocate function and
        /// recycle function.
        /// @param allocate Allocation function
        /// @param recycle Recycle function
        resource_pool(allocate_function allocate, recycle_function recycle) :
            m_pool(std::make_shared<impl>(std::move(allocate),
                                          std::move(recycle)))
        { }

        /// Copy constructor
        resource_pool(const resource_pool& other) :
            m_pool(std::make_shared<impl>(*other.m_pool))
        { }

        /// Move constructor
        resource_pool(resource_pool&& other) :
            m_pool(std::move(other.m_pool))
        {
            assert(m_pool);
        }

        /// Copy assignment
        resource_pool& operator=(const resource_pool& other)
        {
            resource_pool tmp(other);
            std::swap(*this, tmp);
            return *this;
        }

        /// Move assignment
        resource_pool& operator=(resource_pool&& other)
        {
            m_pool = std::move(other.m_pool);
            return *this;
        }

        /// @returns the number of unused resources
        uint32_t unused_resources() const
        {
            assert(m_pool);
            return m_pool->unused_resources();
        }

        /// Frees all unused resources
        void free_unused()
        {
            assert(m_pool);
            m_pool->free_unused();
        }

        /// @return A resource from the pool.
        value_ptr allocate()
        {
            assert(m_pool);
            return m_pool->allocate();
        }

    private:

        /// The actual pool implementation. We use the
        /// enable_shared_from_this helper to make sure we can pass a
        /// "back-pointer" to the pooled objects. The idea behind this
        /// is that we need objects to be able to add themselves back
        /// into the pool once they go out of scope.
        struct impl : public std::enable_shared_from_this<impl>
        {

            /// @copydoc resource_pool::resource_pool(allocate_function)
            impl(allocate_function allocate) :
                m_allocate(std::move(allocate))
            {
                assert(m_allocate);
            }

            /// @copydoc resource_pool::resource_pool(allocate_function,
            ///                                       recycle_function)
            impl(allocate_function allocate, recycle_function recycle) :
                m_allocate(std::move(allocate)),
                m_recycle(std::move(recycle))
            {
                assert(m_allocate);
                assert(m_recycle);
            }

            /// Copy constructor
            impl(const impl& other) :
                std::enable_shared_from_this<impl>(other),
                m_allocate(other.m_allocate),
                m_recycle(other.m_recycle)
            {
                for (uint32_t i = 0; i < other.unused_resources(); ++i)
                {
                    m_free_list.push_back(m_allocate());
                }
            }

            /// Move constructor
            impl(impl&& other) :
                std::enable_shared_from_this<impl>(other),
                m_allocate(std::move(other.m_allocate)),
                m_recycle(std::move(other.m_recycle)),
                m_free_list(std::move(other.m_free_list))
            { }

            /// Copy assignment
            impl& operator=(const impl& other)
            {
                impl tmp(other);
                std::swap(*this, tmp);
                return *this;
            }

            /// Move assignment
            impl& operator=(impl&& other)
            {
                m_allocate = std::move(other.m_allocate);
                m_recycle = std::move(other.m_recycle);
                m_free_list = std::move(other.m_free_list);
                return *this;
            }

            /// Allocate a new value from the pool
            value_ptr allocate()
            {
                value_ptr resource;

                if (m_free_list.size() > 0)
                {
                    resource = m_free_list.back();
                    m_free_list.pop_back();
                }
                else
                {
                    assert(m_allocate);
                    resource = m_allocate();
                }

                auto pool = impl::shared_from_this();

                // Here we create a std::shared_ptr<T> with a naked
                // pointer to the resource and a custom deleter
                // object. The custom deleter object stores two
                // things:
                //
                //   1. A std::weak_ptr<T> to the pool (used when we
                //      need to put the resource back in the pool). If
                //      the pool dies before the resource then we can
                //      detect this with the weak_ptr and no try to
                //      access it.
                //
                //   2. A std::shared_ptr<T> that points to the actual
                //      resource and is the one actually keeping it alive.

                return value_ptr(resource.get(), deleter(pool, resource));
            }

            /// @copydoc resource_pool::free_unused()
            void free_unused()
            {
                m_free_list.clear();
            }

            /// @copydoc resource_pool::unused_resources()
            uint32_t unused_resources() const
            {
                return static_cast<uint32_t>(m_free_list.size());
            }

            /// This function called when a resource should be added
            /// back into the pool
            void recycle(const value_ptr& resource)
            {
                if (m_recycle)
                {
                    m_recycle(resource);
                }

                m_free_list.push_back(resource);
            }

        private:

            // The allocator to use
            allocate_function m_allocate;

            // The allocator to use
            recycle_function m_recycle;

            // Stores all the free resources
            std::list<value_ptr> m_free_list;

        };

        /// The custom deleter object used by the std::shared_ptr<T>
        /// to de-allocate the object if the pool goes out of
        /// scope. When a std::shared_ptr wants to de-allocate the
        /// object contained it will call the operator() define here.
        struct deleter
        {
            /// @param pool. A weak_ptr to the pool
            deleter(const std::weak_ptr<impl>& pool,
                    const value_ptr& resource)
                : m_pool(pool),
                  m_resource(resource)
            {
                assert(!m_pool.expired());
                assert(m_resource);
            }

            /// Call operator called by std::shared_ptr<T> when
            /// de-allocating the object.
            void operator()(value_type*)
            {
                // Place the resource in the free list
                auto pool = m_pool.lock();

                if (pool)
                {
                    pool->recycle(m_resource);
                }
            }

            // Poiner to the pool needed for recycling
            std::weak_ptr<impl> m_pool;

            // The resource object
            value_ptr m_resource;
        };

    private:

        // The pool impl
        std::shared_ptr<impl> m_pool;

    };
}
<|endoftext|>


<commit_before>// CS 4365.HON HW 1: Basic Search
// Josh Cai

// compile with:
//   g++ -o search search.cpp
// run with:
//   ./search [-cost] <BFS|DFS|UCS|GS|A-star|HCS|SA> <inputfile>
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <queue>

using namespace std;

struct node
{
	struct node *parent;
	string state;
	int depth;
	double h;
};

class compareNode {
    public:
    bool operator()(node& x, node& y)
    {
    	return x.h > y.h;
    }
};

bool goal_test(string state)
{
	int n = state.length() / 2;
	bool flag = true;
	for(int i = 0; i < n; i++)
	{
		if(state[i]!='B')
		{
			flag = false;
			break;
		}
	}
	return flag && state[n]=='x';

}

int main(int argc, char* argv[])
{
	if(argc < 3 || argc > 4)
	{
		cout << "Invalid argument numbers" << endl;
	}
	else
	{
		int i = 1;
		int length;
		bool cost = false;
		if(string(argv[i]) == "-cost")
		{
			i++;
			cost = true;
		}
		string search_strat = string(argv[i++]);
		cout << search_strat << endl;
		ifstream fin (argv[i]);

		node initial;
		fin >> initial.state;
		length = initial.state.length();
		initial.parent = NULL;
		initial.depth = 0;
		initial.h = 0;
		cout << initial.state << endl;
		priority_queue<node, vector<node>, compareNode> L;
		L.push(initial);
		while(!L.empty())
		{
			node current = L.top();
			L.pop();
			cout << current.state << "  " << current.depth << " ";
			if(goal_test(current.state))
			{

				cout << "found goal";
				break;
			}
			int k = 0;
			while(current.state[k]!='x')
			{
				k++;
			}
			cout << k << endl;
			for(int j = 0; j < length; j++)
			{
				if(j == k)
					continue;
				string temp = current.state;
				node successor;
				successor.parent = &current;
				temp[k] = temp[j];
				temp[j] = 'x';
				successor.state = temp;
				successor.depth = current.depth+1;
				// cout << temp << "   " << successor.depth << endl;
				successor.h = (double) successor.depth;
				L.push(successor);
			}

		}
		cout << "success" << endl;

	}

	return 0;
}<commit_msg>added queue/stack/HCS<commit_after>// CS 4365.HON HW 1: Basic Search
// Josh Cai

// compile with:
//   g++ -o search search.cpp
// run with:
//   ./search [-cost] <BFS|DFS|UCS|GS|A-star|HCS|SA> <inputfile>
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <queue>
#include <stack>
#include <map>

using namespace std;

struct node
{
	struct node *parent;
	string state;
	int depth, move, cost;
	double h;
};

bool cost;

// own compare function for the node struct
class compareNode {
    public:
    bool operator()(node* x, node* y)
    {
    	return x->h > y->h;
    }
};

double h(string state)
{
	int total = 0;
	int w = 0;
	int b = 0;
	int n = state.length() / 2;
	for(int i = 0; i < n; i++)
	{
		if(state[i] == 'B')
			b++;
		else if(state[i] == 'W')
			w++;
	}
	total = w+n-b; // w white tiles out of place and (n-b) black tiles out of place
	if(state[n] == 'W') // have to consider the char in the middle - if it's white, it didn't get counted
		total++;
	return (double) total;

}

bool goal_test(string state)
{
	int n = state.length() / 2;
	bool flag = true;
	for(int i = 0; i < n; i++)
	{
		if(state[i]!='B')
		{
			flag = false;
			break;
		}
	}
	return flag && state[n]=='x';

}

void print_path(node* current)
{
	if(current->parent != NULL)
	{
		print_path(current->parent);
		cout << "Step " << current->depth << ":   move " << current->move << " " << current->state;
		if(cost)
		{
			cout << " (c=" << current->cost << ")";
		}
		cout << endl;
	}
	else
	{
		cout << "head";
		cout << "Step 0:   " << current->state << endl;
	}
	return;

}

int main(int argc, char* argv[])
{
	if(argc < 3 || argc > 4)
	{
		cout << "Invalid argument numbers" << endl;
	}
	else
	{
		int i = 1;
		int length, strat;
		cost = false;
		if(string(argv[i]) == "-cost")
		{
			i++;
			cost = true;
		}
		string search_strat = string(argv[i++]);
		cout << search_strat << endl;
		strat = 0;
		if(search_strat == "BFS")
			strat = 1;
		else if(search_strat == "DFS")
			strat = 2;
		else if(search_strat == "UCS")
			strat = 3;
		else if(search_strat == "GS")
			strat = 4;
		else if(search_strat == "A-star")
			strat = 5;
		else if(search_strat == "HCS")
			strat = 6;
		else if(search_strat == "SA")
			strat = 7;
		ifstream fin (argv[i]);

		node* initial = new node;
		fin >> initial->state;
		length = initial->state.length();
		initial->parent = NULL;
		initial->depth = 0;
		initial->move = -1;
		initial->h = 0;
		cout << initial->state << endl;

		priority_queue<node*, vector<node*>, compareNode> L;
		L.push(initial);

		stack<node*> S;
		S.push(initial);

		queue<node*> Q;
		Q.push(initial);

		map<string, bool> checked;
		node* current;

		while(!L.empty())
		{
			switch(strat)
			{
				case 1:
					current = Q.front();
					Q.pop();
					break;
				case 2:
					current = S.top();
					S.pop();
					break;
				case 3:
				case 4:
				case 5:
					current = L.top();
					L.pop();
					break;
				case 6:
					current = L.top();
					L = priority_queue<node*, vector<node*>, compareNode>();
					break;

			}

			if(checked.count(current->state) == 0)
			{
				checked[current->state] = true;
				cout << current->state << "  " << current->depth << " ";
				// if(current->parent!=NULL)
				// {
				// 	cout << " parent " << current->parent->state << " ";
				// 	cout << &current << "  " << current->parent << " ";
				// }
				if(goal_test(current->state))
				{
					print_path(current);
					cout << "found goal";
					break;
				}
				int k = 0;
				while(current->state[k]!='x')
				{
					k++;
				}
				cout << k << endl;
				for(int j = 0; j < length; j++)
				{
					if(j == k)
						continue;
					string temp = current->state;
					node* successor = new node;
					successor->parent = current;
					successor->move = j;
					temp[k] = temp[j];
					temp[j] = 'x';
					successor->cost = ((j < k) ? k-j : j-k); // finds absolute value of j-k
					successor->state = temp;
					successor->depth = current->depth+1;
					// cout << temp << "   " << successor->depth << endl;
					switch(strat)
					{
						case 1:
							Q.push(successor);
							break;
						case 2:
							S.push(successor);
							break;
						case 3:  // UCS
							if(cost)
							{
								successor->h = (double) successor->cost;
							}
							else
							{
								successor->h = (double) successor->depth;
							}
							break;
						case 4: // GS
						case 6:
							successor->h = h(successor->state);
							break;
						case 5: // A-star
							if(cost)
							{
								successor->h = (double) successor->cost + h(successor->state);
							}
							else
							{
								successor->h = (double) successor->depth + h(successor->state);
							}
							break;
					}
					if(strat>2 && strat<7)
					{
						L.push(successor);
					}

				}
			}

		}
		cout << "success" << endl;

	}

	//remember to deallocate memory

	return 0;
}<|endoftext|>


<commit_before>#include "imagereader.h"
#include <iostream>

#include <Magick++.h>

#include <list>
#include <chrono>

void setup_imagemagick()
{
    Magick::InitializeMagick(NULL);
}

static Magick::Image empty_image()
{
    return Magick::Image("1024x1024","rgba(0,0,0,0.0)");
}

bool read_image_blob(const char *blob_data, int blob_size, std::vector<float> &data, int &width, int &height)
{

    Magick::Blob blob(blob_data, blob_size);
    Magick::Image image;
    std::chrono::time_point<std::chrono::system_clock> start;
    start = std::chrono::system_clock::now();
    std::cerr << "reading " << "blob" << "\n";

    bool result = false;
    try {
        image.read(blob);
    } catch (...) {
        std::cerr << "error reading" << "blob" << "\n";
        image = empty_image();
        //return false;
    }

    image.resize("1024x1024!");
    width = image.size().width();
    height = image.size().height();

    data.resize(width * height * 4 );
    image.write(0, 0, width, height, "RGBA",  Magick::FloatPixel, &data[0]);

    std::chrono::duration<double> elapsed_seconds = std::chrono::system_clock::now()-start;
    std::cerr << "image read in " << elapsed_seconds.count() << " secs\n";

    return true;
}

bool write_image_blob(const char *blob_data, int blob_size, const std::string &path)
{
    Magick::Blob blob(blob_data, blob_size);
    Magick::Image image;

    try {
        image.read(blob);
    } catch (...) {
        std::cerr << "error reading" << "blob" << "\n";
        return false;
    }

    image.depth(8);
    image.write(path);
}

bool read_image(const std::string &path,
                std::vector<float> &data,
                int &width, int &height)
{
    Magick::Image image;
    std::chrono::time_point<std::chrono::system_clock> start;
    start = std::chrono::system_clock::now();
    std::cerr << "reading " << path << "\n";

    bool result = false;
    try {
        if (path.empty()) {
            image = empty_image();
        } else {
            image.read( path);
            result = true;
        }
    }
    catch (...) {
        std::cerr << "error reading" << path << "\n";
        image = empty_image();
        //return false;
    }
    image.resize("1024x1024!");
    width = image.size().width();
    height = image.size().height();

    data.resize(width * height * 4 );
    image.write(0, 0, width, height, "RGBA",  Magick::FloatPixel, &data[0]);

    std::chrono::duration<double> elapsed_seconds = std::chrono::system_clock::now()-start;
    std::cerr << "image read in " << elapsed_seconds.count() << " secs\n";

    return result;

}

bool read_image(const std::string &path, FloatImageData &image)
{
    return read_image(path, image.data, image.width, image.height);
}

static Magick::Image montage_tiles(const std::vector<FloatImageData> &data, int tiles)
{
    Magick::Image image;

    std::vector<Magick::Image> images;

    images.resize(data.size());
    for (int i = 0; i < data.size(); i++) {

        const FloatImageData &d = data[i];

        images[i].read(d.width, d.height, "RGBA", Magick::FloatPixel, &d.data[0]);
        char buff[100];
        snprintf(buff, sizeof(buff), "%04d", i);
        std::string pad = buff;
        std::string path = "tile" +  pad + ".jpg";
        //images[i].write(path);
    }

    Magick::Montage opts;
    Magick::Geometry t;
    t.width(tiles);
    t.height(tiles);

    opts.tile(t);

    opts.geometry(images[0].size());
    opts.backgroundColor("rgba(0, 0, 0, 0.0)");

    std::vector<Magick::Image> result;
    Magick::montageImages(&result, images.begin(), images.end(), opts);

    result[0].flip();

    //result[0].write("montage.png");
    return result[0];
}

static void prep_image(Magick::Image &image, const std::string &label)
{
    /*
    image.modifyImage();

    Magick::PixelPacket *pixels = image.getPixels(0, 0, image.size().width(), 1);
    for (int i = 0; i < image.size().width(); i++ ) {
        float alpha = .01 * 1.0 / (i+1);
        Magick::Color c = pixels[i];
        c.alpha(1.0 - alpha + c.alpha());
        pixels[i] = c;
    }
    image.syncPixels(); */

    image.strip();
    image.attribute("colorspace", "srgb");
    image.attribute("label", label);
    image.filterType(Magick::TriangleFilter);
    image.depth(16);
    image.magick("PSD");
    image.backgroundColor("rgba(0, 0, 0, 0.0)");
    image.compressType(Magick::RLECompression);
    image.type(Magick::TrueColorMatteType);
    image.verbose(true);

}

void write_template_psd(const std::string &imageplane,
                        const std::string &dest,
                        const std::string &data_dir,
                        const std::vector<FloatImageData> &color_tiles,
                        const std::vector<FloatImageData> &alpha_tiles,
                        const std::vector<FloatImageData> &contour_tiles,
                        int tiles,
                        Progress &p)
{
    Magick::Image plane;

    p.set_value(50);
    Magick::Image color = montage_tiles(color_tiles, tiles);
    p.set_value(52);
    Magick::Image alpha = montage_tiles(alpha_tiles, tiles);
    p.set_value(54);
    Magick::Image contour = montage_tiles(contour_tiles, tiles);
    p.set_value(58);

    Magick::Geometry geo("1920x1080!");

    alpha.channel(Magick::RedChannel);
    color.composite(alpha, 0, 0, Magick::CopyOpacityCompositeOp);
    color.resize(geo);
    //color.flip();
    p.set_value(60);
    //contour.flip();
    contour.resize(geo);
    p.set_value(65);
    Magick::Image empty(geo,"rgba(0,0,0,0.0)" );

    prep_image(empty, "clones");
    p.set_value(68);
    prep_image(color, "guides");
    p.set_value(68);
    prep_image(contour, "contour");

    p.set_value(77);

    if (imageplane.empty())
        plane = empty;
    else
        plane.read(imageplane);

    prep_image(plane, "background");
    p.set_value(80);
    //plane.write(data_dir + "/plane.png");
    //alpha.write(data_dir + "/alpha.png");
    //color.write(data_dir + "/color.png");
    //contour.write(data_dir + "/contour.png");
    //empty.write(data_dir + "/empty.png");

    p.set_value(85);

    Magick::Image liquify = plane;
    liquify.attribute("label", "liquify");

    std::list<Magick::Image> images;
    images.push_back(plane);
    images.push_back(plane);
    images.push_back(liquify);
    images.push_back(empty);
    images.push_back(color);
    images.push_back(contour);
    p.set_value(90);
    Magick::writeImages(images.begin(), images.end(), dest);
}
<commit_msg>resize layers to match imageplane size<commit_after>#include "imagereader.h"
#include <iostream>

#include <Magick++.h>

#include <list>
#include <chrono>

void setup_imagemagick()
{
    Magick::InitializeMagick(NULL);
}

static Magick::Image empty_image()
{
    return Magick::Image("1024x1024","rgba(0,0,0,0.0)");
}

bool read_image_blob(const char *blob_data, int blob_size, std::vector<float> &data, int &width, int &height)
{

    Magick::Blob blob(blob_data, blob_size);
    Magick::Image image;
    std::chrono::time_point<std::chrono::system_clock> start;
    start = std::chrono::system_clock::now();
    std::cerr << "reading " << "blob" << "\n";

    bool result = false;
    try {
        image.read(blob);
    } catch (...) {
        std::cerr << "error reading" << "blob" << "\n";
        image = empty_image();
        //return false;
    }

    image.resize("1024x1024!");
    width = image.size().width();
    height = image.size().height();

    data.resize(width * height * 4 );
    image.write(0, 0, width, height, "RGBA",  Magick::FloatPixel, &data[0]);

    std::chrono::duration<double> elapsed_seconds = std::chrono::system_clock::now()-start;
    std::cerr << "image read in " << elapsed_seconds.count() << " secs\n";

    return true;
}

bool write_image_blob(const char *blob_data, int blob_size, const std::string &path)
{
    Magick::Blob blob(blob_data, blob_size);
    Magick::Image image;

    try {
        image.read(blob);
    } catch (...) {
        std::cerr << "error reading" << "blob" << "\n";
        return false;
    }

    image.depth(8);
    image.write(path);
    return true;
}

bool read_image(const std::string &path,
                std::vector<float> &data,
                int &width, int &height)
{
    Magick::Image image;
    std::chrono::time_point<std::chrono::system_clock> start;
    start = std::chrono::system_clock::now();
    std::cerr << "reading " << path << "\n";

    bool result = false;
    try {
        if (path.empty()) {
            image = empty_image();
        } else {
            image.read( path);
            result = true;
        }
    }
    catch (...) {
        std::cerr << "error reading" << path << "\n";
        image = empty_image();
        //return false;
    }
    image.resize("1024x1024!");
    width = image.size().width();
    height = image.size().height();

    data.resize(width * height * 4 );
    image.write(0, 0, width, height, "RGBA",  Magick::FloatPixel, &data[0]);

    std::chrono::duration<double> elapsed_seconds = std::chrono::system_clock::now()-start;
    std::cerr << "image read in " << elapsed_seconds.count() << " secs\n";

    return result;

}

bool read_image(const std::string &path, FloatImageData &image)
{
    return read_image(path, image.data, image.width, image.height);
}

static Magick::Image montage_tiles(const std::vector<FloatImageData> &data, int tiles)
{
    Magick::Image image;

    std::vector<Magick::Image> images;

    images.resize(data.size());
    for (int i = 0; i < data.size(); i++) {

        const FloatImageData &d = data[i];

        images[i].read(d.width, d.height, "RGBA", Magick::FloatPixel, &d.data[0]);
        char buff[100];
        snprintf(buff, sizeof(buff), "%04d", i);
        std::string pad = buff;
        std::string path = "tile" +  pad + ".jpg";
        //images[i].write(path);
    }

    Magick::Montage opts;
    Magick::Geometry t;
    t.width(tiles);
    t.height(tiles);

    opts.tile(t);

    opts.geometry(images[0].size());
    opts.backgroundColor("rgba(0, 0, 0, 0.0)");

    std::vector<Magick::Image> result;
    Magick::montageImages(&result, images.begin(), images.end(), opts);

    result[0].flip();

    //result[0].write("montage.png");
    return result[0];
}

static void prep_image(Magick::Image &image, const std::string &label)
{
    /*
    image.modifyImage();

    Magick::PixelPacket *pixels = image.getPixels(0, 0, image.size().width(), 1);
    for (int i = 0; i < image.size().width(); i++ ) {
        float alpha = .01 * 1.0 / (i+1);
        Magick::Color c = pixels[i];
        c.alpha(1.0 - alpha + c.alpha());
        pixels[i] = c;
    }
    image.syncPixels(); */

    image.strip();
    image.attribute("colorspace", "srgb");
    image.attribute("label", label);
    image.filterType(Magick::TriangleFilter);
    image.depth(16);
    image.magick("PSD");
    image.backgroundColor("rgba(0, 0, 0, 0.0)");
    image.compressType(Magick::RLECompression);
    image.type(Magick::TrueColorMatteType);
    image.verbose(true);

}

void write_template_psd(const std::string &imageplane,
                        const std::string &dest,
                        const std::string &data_dir,
                        const std::vector<FloatImageData> &color_tiles,
                        const std::vector<FloatImageData> &alpha_tiles,
                        const std::vector<FloatImageData> &contour_tiles,
                        int tiles,
                        Progress &p)
{
    Magick::Image plane;

    p.set_value(50);
    Magick::Image color = montage_tiles(color_tiles, tiles);
    p.set_value(52);
    Magick::Image alpha = montage_tiles(alpha_tiles, tiles);
    p.set_value(54);
    Magick::Image contour = montage_tiles(contour_tiles, tiles);
    p.set_value(58);

    Magick::Geometry geo("1920x1080!");
    Magick::Image empty(geo,"rgba(0,0,0,0.0)" );

    if (imageplane.empty()) {
        plane = empty;
    } else {
        plane.read(imageplane);
        geo = plane.size();
        geo.aspect(true);
    }

    alpha.channel(Magick::RedChannel);
    color.composite(alpha, 0, 0, Magick::CopyOpacityCompositeOp);
    color.resize(geo);
    //color.flip();
    p.set_value(60);
    //contour.flip();
    contour.resize(geo);
    p.set_value(65);

    prep_image(empty, "clones");
    p.set_value(68);
    prep_image(color, "guides");
    p.set_value(68);
    prep_image(contour, "contour");

    p.set_value(77);

    prep_image(plane, "background");
    p.set_value(80);
    //plane.write(data_dir + "/plane.png");
    //alpha.write(data_dir + "/alpha.png");
    //color.write(data_dir + "/color.png");
    //contour.write(data_dir + "/contour.png");
    //empty.write(data_dir + "/empty.png");

    p.set_value(85);

    Magick::Image liquify = plane;
    liquify.attribute("label", "liquify");

    std::list<Magick::Image> images;
    images.push_back(plane);
    images.push_back(plane);
    images.push_back(liquify);
    images.push_back(empty);
    images.push_back(color);
    images.push_back(contour);
    p.set_value(90);
    Magick::writeImages(images.begin(), images.end(), dest);
}
<|endoftext|>


<commit_before>//===- PowerPCRegisterInfo.cpp - PowerPC Register Information ---*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the PowerPC implementation of the MRegisterInfo class.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "reginfo"
#include "PowerPC.h"
#include "PowerPCRegisterInfo.h"
#include "PowerPCInstrBuilder.h"
#include "llvm/Constants.h"
#include "llvm/Type.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/Target/TargetFrameInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "Support/CommandLine.h"
#include "Support/Debug.h"
#include "Support/STLExtras.h"
#include <iostream>
using namespace llvm;

PowerPCRegisterInfo::PowerPCRegisterInfo()
  : PowerPCGenRegisterInfo(PPC32::ADJCALLSTACKDOWN,
                           PPC32::ADJCALLSTACKUP) {}

static unsigned getIdx(const TargetRegisterClass *RC) {
  if (RC == PowerPC::GPRCRegisterClass) {
    switch (RC->getSize()) {
      default: assert(0 && "Invalid data size!");
      case 1:  return 0;
      case 2:  return 1;
      case 4:  return 2;
    }
  } else if (RC == PowerPC::FPRCRegisterClass) {
    switch (RC->getSize()) {
      default: assert(0 && "Invalid data size!");
      case 4:  return 3;
      case 8:  return 4;
    }
  }
  std::cerr << "Invalid register class to getIdx()!\n";
  abort();
}

int
PowerPCRegisterInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
                                         MachineBasicBlock::iterator MI,
                                         unsigned SrcReg, int FrameIdx,
                                         const TargetRegisterClass *RC) const {
  static const unsigned Opcode[] = {
    PPC32::STB, PPC32::STH, PPC32::STW, PPC32::STFS, PPC32::STFD
  };
  unsigned OC = Opcode[getIdx(RC)];
  MBB.insert(MI, addFrameReference(BuildMI(OC, 3).addReg(SrcReg),FrameIdx));
  return 1;
}

int PowerPCRegisterInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
                                          MachineBasicBlock::iterator MI,
                                          unsigned DestReg, int FrameIdx,
                                          const TargetRegisterClass *RC) const{
  static const unsigned Opcode[] = {
    PPC32::LBZ, PPC32::LHZ, PPC32::LWZ, PPC32::LFS, PPC32::LFD
  };
  unsigned OC = Opcode[getIdx(RC)];
  MBB.insert(MI, addFrameReference(BuildMI(OC, 2, DestReg), FrameIdx));
  return 1;
}

int PowerPCRegisterInfo::copyRegToReg(MachineBasicBlock &MBB,
                                      MachineBasicBlock::iterator MI,
                                      unsigned DestReg, unsigned SrcReg,
                                      const TargetRegisterClass *RC) const {
  MachineInstr *I;

  if (RC == PowerPC::GPRCRegisterClass) {
    I = BuildMI(PPC32::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg);
  } else if (RC == PowerPC::FPRCRegisterClass) {
    I = BuildMI(PPC32::FMR, 1, DestReg).addReg(SrcReg);
  } else {
    std::cerr << "Attempt to copy register that is not GPR or FPR";
    abort();
  }
  MBB.insert(MI, I);
  return 1;
}

//===----------------------------------------------------------------------===//
// Stack Frame Processing methods
//===----------------------------------------------------------------------===//

// hasFP - Return true if the specified function should have a dedicated frame
// pointer register.  This is true if the function has variable sized allocas or
// if frame pointer elimination is disabled.
//
static bool hasFP(MachineFunction &MF) {
  return NoFramePointerElim || MF.getFrameInfo()->hasVarSizedObjects();
}

void PowerPCRegisterInfo::
eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
                              MachineBasicBlock::iterator I) const {
  if (hasFP(MF)) {
    // If we have a frame pointer, convert as follows:
    // adjcallstackdown instruction => 'sub r1, r1, <amt>' and
    // adjcallstackup instruction   => 'add r1, r1, <amt>'
    MachineInstr *Old = I;
    int Amount = Old->getOperand(0).getImmedValue();
    if (Amount != 0) {
      // We need to keep the stack aligned properly.  To do this, we round the
      // amount of space needed for the outgoing arguments up to the next
      // alignment boundary.
      unsigned Align = MF.getTarget().getFrameInfo()->getStackAlignment();
      Amount = (Amount+Align-1)/Align*Align;

      MachineInstr *New;
      if (Old->getOpcode() == PPC32::ADJCALLSTACKDOWN) {
        New = BuildMI(PPC32::ADDI, 2, PPC32::R1).addReg(PPC32::R1)
                .addSImm(-Amount);
      } else {
        assert(Old->getOpcode() == PPC32::ADJCALLSTACKUP);
        New = BuildMI(PPC32::ADDI, 2, PPC32::R1).addReg(PPC32::R1)
                .addSImm(Amount);
      }

      // Replace the pseudo instruction with a new instruction...
      MBB.insert(I, New);
    }
  }

  MBB.erase(I);
}

void
PowerPCRegisterInfo::eliminateFrameIndex(MachineFunction &MF,
                                         MachineBasicBlock::iterator II) const {
  unsigned i = 0;
  MachineInstr &MI = *II;
  while (!MI.getOperand(i).isFrameIndex()) {
    ++i;
    assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!");
  }

  int FrameIndex = MI.getOperand(i).getFrameIndex();

  // Replace the FrameIndex with base register with GPR1.
  MI.SetMachineOperandReg(i, PPC32::R1);

  // Take into account whether it's an add or mem instruction
  unsigned OffIdx = (i == 2) ? 1 : 2;
  // Now add the frame object offset to the offset from r1.
  int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex) +
               MI.getOperand(OffIdx).getImmedValue()+4;

  if (!hasFP(MF))
    Offset += MF.getFrameInfo()->getStackSize();

  MI.SetMachineOperandConst(OffIdx, MachineOperand::MO_SignExtendedImmed, Offset);
  DEBUG(std::cerr << "offset = " << Offset << std::endl);
}

void
PowerPCRegisterInfo::processFunctionBeforeFrameFinalized(MachineFunction &MF)
  const {
  // Do Nothing
}

void PowerPCRegisterInfo::emitPrologue(MachineFunction &MF) const {
  MachineBasicBlock &MBB = MF.front();   // Prolog goes in entry BB
  MachineBasicBlock::iterator MBBI = MBB.begin();
  MachineFrameInfo *MFI = MF.getFrameInfo();
  MachineInstr *MI;

  // Get the number of bytes to allocate from the FrameInfo
  unsigned NumBytes = MFI->getStackSize();

  // FIXME: the assembly printer inserts "calls" aka branch-and-link to get the
  // PC address. We may not know about those calls at this time, so be
  // conservative.
  if (MFI->hasCalls() || true) {
    // When we have no frame pointer, we reserve argument space for call sites
    // in the function immediately on entry to the current function.  This
    // eliminates the need for add/sub brackets around call sites.
    //
    NumBytes += MFI->getMaxCallFrameSize() +
                24   /* Predefined PowerPC link area */ +
                // FIXME: must calculate #non-volatile int regs actually spilled
                19*4 /* Spilled int regs */ +
                // FIXME: must calculate #non-volatile fp regs actually spilled
                0*8  /* Spilled fp regs */;

    // Round the size to a multiple of the alignment (don't forget the 4 byte
    // offset though).
    unsigned Align = MF.getTarget().getFrameInfo()->getStackAlignment();
    NumBytes = ((NumBytes+4)+Align-1)/Align*Align - 4;

    // Store the incoming LR so it is preserved across calls
    MI = BuildMI(PPC32::MFLR, 0, PPC32::R0);
    MBB.insert(MBBI, MI);
    // FIXME: store only CLOBBERED registers in R[13-31]
    MI = BuildMI(PPC32::STMW, 3).addReg(PPC32::R13).addSImm(-76)
           .addReg(PPC32::R1);
    MBB.insert(MBBI, MI);
    MI = BuildMI(PPC32::STW, 3).addReg(PPC32::R0).addSImm(8).addReg(PPC32::R1);
    MBB.insert(MBBI, MI);
  }

  // Update frame info to pretend that this is part of the stack...
  MFI->setStackSize(NumBytes);

  // adjust stack pointer: r1 -= numbytes
  if (NumBytes) {
    MI = BuildMI(PPC32::STWU, 2, PPC32::R1).addImm(-NumBytes).addReg(PPC32::R1);
    MBB.insert(MBBI, MI);
  }
}

void PowerPCRegisterInfo::emitEpilogue(MachineFunction &MF,
                                       MachineBasicBlock &MBB) const {
  const MachineFrameInfo *MFI = MF.getFrameInfo();
  MachineBasicBlock::iterator MBBI = prior(MBB.end());
  MachineInstr *MI;
  assert(MBBI->getOpcode() == PPC32::BLR &&
         "Can only insert epilog into returning blocks");

  // Get the number of bytes allocated from the FrameInfo...
  unsigned NumBytes = MFI->getStackSize();

  // Adjust stack pointer back
  MI = BuildMI(PPC32::LWZ, 2, PPC32::R1).addImm(0).addReg(PPC32::R1);
  MBB.insert(MBBI, MI);

  // If we have calls, restore the LR value before we branch to it
  // FIXME: the assembly printer inserts "calls" aka branch-and-link to get the
  // PC address. We may not know about those calls at this time, so be
  // conservative.
  if (MFI->hasCalls() || true) {
    // Read old LR from stack into R0
    MI = BuildMI(PPC32::LWZ, 2, PPC32::R0).addSImm(8).addReg(PPC32::R1);
    MBB.insert(MBBI, MI);
    // FIXME: restore only SAVED registers in R[13-31]
    MI = BuildMI(PPC32::LMW, 2, PPC32::R13).addSImm(-76).addReg(PPC32::R1);
    MBB.insert(MBBI, MI);
    MI = BuildMI(PPC32::MTLR, 1).addReg(PPC32::R0);
    MBB.insert(MBBI, MI);
  }
}

#include "PowerPCGenRegisterInfo.inc"

const TargetRegisterClass*
PowerPCRegisterInfo::getRegClassForType(const Type* Ty) const {
  switch (Ty->getTypeID()) {
    case Type::LongTyID:
    case Type::ULongTyID: assert(0 && "Long values can't fit in registers!");
    default:              assert(0 && "Invalid type to getClass!");
    case Type::BoolTyID:
    case Type::SByteTyID:
    case Type::UByteTyID:
    case Type::ShortTyID:
    case Type::UShortTyID:
    case Type::IntTyID:
    case Type::UIntTyID:
    case Type::PointerTyID: return &GPRCInstance;

    case Type::FloatTyID:
    case Type::DoubleTyID: return &FPRCInstance;
  }
}

<commit_msg>Fix stack frame layout in prologue/epilogue.  Patch courtesy of Nate Begeman.<commit_after>//===- PowerPCRegisterInfo.cpp - PowerPC Register Information ---*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file contains the PowerPC implementation of the MRegisterInfo class.
//
//===----------------------------------------------------------------------===//

#define DEBUG_TYPE "reginfo"
#include "PowerPC.h"
#include "PowerPCRegisterInfo.h"
#include "PowerPCInstrBuilder.h"
#include "llvm/Constants.h"
#include "llvm/Type.h"
#include "llvm/CodeGen/ValueTypes.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/Target/TargetFrameInfo.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "Support/CommandLine.h"
#include "Support/Debug.h"
#include "Support/STLExtras.h"
#include <iostream>
using namespace llvm;

PowerPCRegisterInfo::PowerPCRegisterInfo()
  : PowerPCGenRegisterInfo(PPC32::ADJCALLSTACKDOWN,
                           PPC32::ADJCALLSTACKUP) {}

static unsigned getIdx(const TargetRegisterClass *RC) {
  if (RC == PowerPC::GPRCRegisterClass) {
    switch (RC->getSize()) {
      default: assert(0 && "Invalid data size!");
      case 1:  return 0;
      case 2:  return 1;
      case 4:  return 2;
    }
  } else if (RC == PowerPC::FPRCRegisterClass) {
    switch (RC->getSize()) {
      default: assert(0 && "Invalid data size!");
      case 4:  return 3;
      case 8:  return 4;
    }
  }
  std::cerr << "Invalid register class to getIdx()!\n";
  abort();
}

int
PowerPCRegisterInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
                                         MachineBasicBlock::iterator MI,
                                         unsigned SrcReg, int FrameIdx,
                                         const TargetRegisterClass *RC) const {
  static const unsigned Opcode[] = {
    PPC32::STB, PPC32::STH, PPC32::STW, PPC32::STFS, PPC32::STFD
  };
  unsigned OC = Opcode[getIdx(RC)];
  MBB.insert(MI, addFrameReference(BuildMI(OC, 3).addReg(SrcReg),FrameIdx));
  return 1;
}

int PowerPCRegisterInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
                                          MachineBasicBlock::iterator MI,
                                          unsigned DestReg, int FrameIdx,
                                          const TargetRegisterClass *RC) const{
  static const unsigned Opcode[] = {
    PPC32::LBZ, PPC32::LHZ, PPC32::LWZ, PPC32::LFS, PPC32::LFD
  };
  unsigned OC = Opcode[getIdx(RC)];
  MBB.insert(MI, addFrameReference(BuildMI(OC, 2, DestReg), FrameIdx));
  return 1;
}

int PowerPCRegisterInfo::copyRegToReg(MachineBasicBlock &MBB,
                                      MachineBasicBlock::iterator MI,
                                      unsigned DestReg, unsigned SrcReg,
                                      const TargetRegisterClass *RC) const {
  MachineInstr *I;

  if (RC == PowerPC::GPRCRegisterClass) {
    I = BuildMI(PPC32::OR, 2, DestReg).addReg(SrcReg).addReg(SrcReg);
  } else if (RC == PowerPC::FPRCRegisterClass) {
    I = BuildMI(PPC32::FMR, 1, DestReg).addReg(SrcReg);
  } else {
    std::cerr << "Attempt to copy register that is not GPR or FPR";
    abort();
  }
  MBB.insert(MI, I);
  return 1;
}

//===----------------------------------------------------------------------===//
// Stack Frame Processing methods
//===----------------------------------------------------------------------===//

// hasFP - Return true if the specified function should have a dedicated frame
// pointer register.  This is true if the function has variable sized allocas or
// if frame pointer elimination is disabled.
//
static bool hasFP(MachineFunction &MF) {
  return NoFramePointerElim || MF.getFrameInfo()->hasVarSizedObjects();
}

void PowerPCRegisterInfo::
eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
                              MachineBasicBlock::iterator I) const {
  if (hasFP(MF)) {
    // If we have a frame pointer, convert as follows:
    // adjcallstackdown instruction => 'sub r1, r1, <amt>' and
    // adjcallstackup instruction   => 'add r1, r1, <amt>'
    MachineInstr *Old = I;
    int Amount = Old->getOperand(0).getImmedValue();
    if (Amount != 0) {
      // We need to keep the stack aligned properly.  To do this, we round the
      // amount of space needed for the outgoing arguments up to the next
      // alignment boundary.
      unsigned Align = MF.getTarget().getFrameInfo()->getStackAlignment();
      Amount = (Amount+Align-1)/Align*Align;

      MachineInstr *New;
      if (Old->getOpcode() == PPC32::ADJCALLSTACKDOWN) {
        New = BuildMI(PPC32::ADDI, 2, PPC32::R1).addReg(PPC32::R1)
                .addSImm(-Amount);
      } else {
        assert(Old->getOpcode() == PPC32::ADJCALLSTACKUP);
        New = BuildMI(PPC32::ADDI, 2, PPC32::R1).addReg(PPC32::R1)
                .addSImm(Amount);
      }

      // Replace the pseudo instruction with a new instruction...
      MBB.insert(I, New);
    }
  }

  MBB.erase(I);
}

void
PowerPCRegisterInfo::eliminateFrameIndex(MachineFunction &MF,
                                         MachineBasicBlock::iterator II) const {
  unsigned i = 0;
  MachineInstr &MI = *II;
  while (!MI.getOperand(i).isFrameIndex()) {
    ++i;
    assert(i < MI.getNumOperands() && "Instr doesn't have FrameIndex operand!");
  }

  int FrameIndex = MI.getOperand(i).getFrameIndex();

  // Replace the FrameIndex with base register with GPR1.
  MI.SetMachineOperandReg(i, PPC32::R1);

  // Take into account whether it's an add or mem instruction
  unsigned OffIdx = (i == 2) ? 1 : 2;
  // Now add the frame object offset to the offset from r1.
  int Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex) +
               MI.getOperand(OffIdx).getImmedValue()+4;

  if (!hasFP(MF))
    Offset += MF.getFrameInfo()->getStackSize();

  MI.SetMachineOperandConst(OffIdx, MachineOperand::MO_SignExtendedImmed, Offset);
  DEBUG(std::cerr << "offset = " << Offset << std::endl);
}

void
PowerPCRegisterInfo::processFunctionBeforeFrameFinalized(MachineFunction &MF)
  const {
  // Do Nothing
}

void PowerPCRegisterInfo::emitPrologue(MachineFunction &MF) const {
  MachineBasicBlock &MBB = MF.front();   // Prolog goes in entry BB
  MachineBasicBlock::iterator MBBI = MBB.begin();
  MachineFrameInfo *MFI = MF.getFrameInfo();
  MachineInstr *MI;

  // Get the number of bytes to allocate from the FrameInfo
  unsigned NumBytes = MFI->getStackSize();

  // FIXME: the assembly printer inserts "calls" aka branch-and-link to get the
  // PC address. We may not know about those calls at this time, so be
  // conservative.
  if (MFI->hasCalls() || true) {
    // When we have no frame pointer, we reserve argument space for call sites
    // in the function immediately on entry to the current function.  This
    // eliminates the need for add/sub brackets around call sites.
    //
    NumBytes += MFI->getMaxCallFrameSize() +
                24   /* Predefined PowerPC link area */ +
                32   /* Predefined PowerPC params area */ +
                 0   /* local variables - managed by llvm*/ +
             0 * 4   /* volatile GPRs used - managed by llvm */ +
             0 * 8   /* volatile FPRs used - managed by llvm */;

    // Round the size to a multiple of the alignment (don't forget the 4 byte
    // offset though).
    unsigned Align = MF.getTarget().getFrameInfo()->getStackAlignment();
    NumBytes = ((NumBytes+4)+Align-1)/Align*Align - 4;

    // Store the incoming LR so it is preserved across calls
    MI = BuildMI(PPC32::MFLR, 0, PPC32::R0);
    MBB.insert(MBBI, MI);
    MI = BuildMI(PPC32::STW, 3).addReg(PPC32::R0).addImm(8).addReg(PPC32::R1);
    MBB.insert(MBBI, MI);
  }

  // Update frame info to pretend that this is part of the stack...
  MFI->setStackSize(NumBytes);

  // adjust stack pointer: r1 -= numbytes
  if (NumBytes) {
    MI = BuildMI(PPC32::STWU, 2, PPC32::R1).addImm(-NumBytes).addReg(PPC32::R1);
    MBB.insert(MBBI, MI);
  }
}

void PowerPCRegisterInfo::emitEpilogue(MachineFunction &MF,
                                       MachineBasicBlock &MBB) const {
  const MachineFrameInfo *MFI = MF.getFrameInfo();
  MachineBasicBlock::iterator MBBI = prior(MBB.end());
  MachineInstr *MI;
  assert(MBBI->getOpcode() == PPC32::BLR &&
         "Can only insert epilog into returning blocks");

  // Get the number of bytes allocated from the FrameInfo...
  unsigned NumBytes = MFI->getStackSize();

  // If we have calls, restore the LR value before we branch to it
  // FIXME: the assembly printer inserts "calls" aka branch-and-link to get the
  // PC address. We may not know about those calls at this time, so be
  // conservative.
  if (MFI->hasCalls() || true) {
    // Restore LR
    MI = BuildMI(PPC32::LWZ, 2, PPC32::R0).addSImm(NumBytes+8).addReg(PPC32::R1);
    MBB.insert(MBBI, MI);
    MI = BuildMI(PPC32::MTLR, 1).addReg(PPC32::R0);
    MBB.insert(MBBI, MI);
  }
  // Adjust stack pointer back
  MI = BuildMI(PPC32::ADDI, 2, PPC32::R1).addReg(PPC32::R1).addImm(NumBytes);
  MBB.insert(MBBI, MI);
}

#include "PowerPCGenRegisterInfo.inc"

const TargetRegisterClass*
PowerPCRegisterInfo::getRegClassForType(const Type* Ty) const {
  switch (Ty->getTypeID()) {
    case Type::LongTyID:
    case Type::ULongTyID: assert(0 && "Long values can't fit in registers!");
    default:              assert(0 && "Invalid type to getClass!");
    case Type::BoolTyID:
    case Type::SByteTyID:
    case Type::UByteTyID:
    case Type::ShortTyID:
    case Type::UShortTyID:
    case Type::IntTyID:
    case Type::UIntTyID:
    case Type::PointerTyID: return &GPRCInstance;

    case Type::FloatTyID:
    case Type::DoubleTyID: return &FPRCInstance;
  }
}

<|endoftext|>


<commit_before>/*
  Copyright © 2014 Jesse 'Jeaye' Wilkerson
  See licensing in LICENSE file, or at:
    http://www.opensource.org/licenses/MIT

  File: logger.cpp
  Author: Jesse 'Jeaye' Wilkerson
*/

#include <iomanip>
#include <ctime>
#include <chrono>
#include <array>

#include "logger.h"

namespace server
{
  namespace logging
  {
    std::vector<std::reference_wrapper<std::string const>> chrono_buffer;
    std::map<net::address, std::deque<std::string>> address_buffer;

    void save(net::address const &a, std::string const &log)
    {
      std::stringstream ss;
#ifdef __APPLE__
      auto const now(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()));
      ss << std::put_time(std::localtime(&now), "[%T] ");
#else
      std::time_t t{ std::time(nullptr) };
      std::array<char, 256> buff;
      if(std::strftime(buff.data(), buff.size(), "[%T] ", std::localtime(&t)))
      { ss << buff.data(); }
#endif

      if(a == net::address{})
      { ss << "(system) "; }
      else
      { ss << "(" << a << ") "; }
      ss << log << std::endl;

      address_buffer[a].push_back(ss.str());
      chrono_buffer.push_back(address_buffer[a].back());

      /* TODO: Write to file. */
    }
  }
}
<commit_msg>Better logger time formatting<commit_after>/*
  Copyright © 2014 Jesse 'Jeaye' Wilkerson
  See licensing in LICENSE file, or at:
    http://www.opensource.org/licenses/MIT

  File: logger.cpp
  Author: Jesse 'Jeaye' Wilkerson
*/

#include <iomanip>
#include <ctime>
#include <chrono>
#include <array>

#include "logger.h"

namespace server
{
  namespace logging
  {
    std::vector<std::reference_wrapper<std::string const>> chrono_buffer;
    std::map<net::address, std::deque<std::string>> address_buffer;

    void save(net::address const &a, std::string const &log)
    {
      std::stringstream ss;
      auto const now(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()));
#ifdef __APPLE__
      ss << std::put_time(std::localtime(&now), "[%T] ");
#else
      /* XXX: GCC 4.8 does not have std::put_time -_- */
      std::array<char, 256> buff;
      if(std::strftime(buff.data(), buff.size(), "[%T] ", std::localtime(&now)))
      { ss << buff.data(); }
      else
      { ss << "[error]"; }
#endif

      if(a == net::address{})
      { ss << "(system) "; }
      else
      { ss << "(" << a << ") "; }
      ss << log << std::endl;

      address_buffer[a].push_back(ss.str());
      chrono_buffer.push_back(address_buffer[a].back());

      /* TODO: Write to file. */
    }
  }
}
<|endoftext|>


<commit_before>#pragma once

#include "gcd_utility.hpp"
#include "human_interface_device.hpp"
#include "spdlog_utility.hpp"

namespace krbn {
class hid_grabber final {
public:
  struct signal2_combiner_call_while_grabbable {
    typedef grabbable_state result_type;

    template <typename input_iterator>
    result_type operator()(input_iterator first_observer,
                           input_iterator last_observer) const {
      result_type value = grabbable_state::grabbable;
      for (;
           first_observer != last_observer && value == grabbable_state::grabbable;
           std::advance(first_observer, 1)) {
        value = *first_observer;
      }
      return value;
    }
  };

  // Signals

  boost::signals2::signal<grabbable_state(human_interface_device&),
                          signal2_combiner_call_while_grabbable>
      device_grabbing;

  boost::signals2::signal<void(human_interface_device&)> device_grabbed;

  boost::signals2::signal<void(human_interface_device&)> device_ungrabbed;

  // Methods

  hid_grabber(human_interface_device& human_interface_device) : human_interface_device_(human_interface_device),
                                                                grabbed_(false) {
  }

  bool get_grabbed(void) const {
    return grabbed_;
  }

  void grab(void) {
    gcd_utility::dispatch_sync_in_main_queue(^{
      log_reducer_.reset();

      timer_ = nullptr;

      timer_ = std::make_unique<gcd_utility::fire_while_false_timer>(
          1 * NSEC_PER_SEC,
          ^{
            if (human_interface_device_.get_removed()) {
              return true;
            }

            if (grabbed_) {
              return true;
            }

            switch (device_grabbing(human_interface_device_)) {
              case grabbable_state::grabbable:
                break;

              case grabbable_state::ungrabbable_temporarily:
              case grabbable_state::device_error:
                // Retry
                return false;

              case grabbable_state::ungrabbable_permanently:
                return true;
            }

            // ----------------------------------------
            auto r = human_interface_device_.open(kIOHIDOptionsTypeSeizeDevice);
            if (r != kIOReturnSuccess) {
              auto message = fmt::format("IOHIDDeviceOpen error: {0} ({1}) {2}",
                                         iokit_utility::get_error_name(r),
                                         r,
                                         human_interface_device_.get_name_for_log());
              log_reducer_.error(message);
              return false;
            }

            // ----------------------------------------
            grabbed_ = true;

            device_grabbed(human_interface_device_);

            human_interface_device_.queue_start();
            human_interface_device_.schedule();

            return true;
          });
    });
  }

  void ungrab(void) {
    gcd_utility::dispatch_sync_in_main_queue(^{
      timer_ = nullptr;

      if (!grabbed_) {
        return;
      }

      human_interface_device_.unschedule();
      human_interface_device_.queue_stop();
      human_interface_device_.close();

      grabbed_ = false;

      device_ungrabbed(human_interface_device_);
    });
  }

private:
  human_interface_device& human_interface_device_;
  bool grabbed_;
  std::unique_ptr<gcd_utility::fire_while_false_timer> timer_;
  spdlog_utility::log_reducer log_reducer_;
};
} // namespace krbn
<commit_msg>ungrab in destructor<commit_after>#pragma once

#include "gcd_utility.hpp"
#include "human_interface_device.hpp"
#include "spdlog_utility.hpp"

namespace krbn {
class hid_grabber final {
public:
  struct signal2_combiner_call_while_grabbable {
    typedef grabbable_state result_type;

    template <typename input_iterator>
    result_type operator()(input_iterator first_observer,
                           input_iterator last_observer) const {
      result_type value = grabbable_state::grabbable;
      for (;
           first_observer != last_observer && value == grabbable_state::grabbable;
           std::advance(first_observer, 1)) {
        value = *first_observer;
      }
      return value;
    }
  };

  // Signals

  boost::signals2::signal<grabbable_state(human_interface_device&),
                          signal2_combiner_call_while_grabbable>
      device_grabbing;

  boost::signals2::signal<void(human_interface_device&)> device_grabbed;

  boost::signals2::signal<void(human_interface_device&)> device_ungrabbed;

  // Methods

  hid_grabber(human_interface_device& human_interface_device) : human_interface_device_(human_interface_device),
                                                                grabbed_(false) {
  }

  ~hid_grabber(void) {
    ungrab();
  }

  bool get_grabbed(void) const {
    return grabbed_;
  }

  void grab(void) {
    gcd_utility::dispatch_sync_in_main_queue(^{
      log_reducer_.reset();

      timer_ = nullptr;

      timer_ = std::make_unique<gcd_utility::fire_while_false_timer>(
          1 * NSEC_PER_SEC,
          ^{
            if (human_interface_device_.get_removed()) {
              return true;
            }

            if (grabbed_) {
              return true;
            }

            switch (device_grabbing(human_interface_device_)) {
              case grabbable_state::grabbable:
                break;

              case grabbable_state::ungrabbable_temporarily:
              case grabbable_state::device_error:
                // Retry
                return false;

              case grabbable_state::ungrabbable_permanently:
                return true;
            }

            // ----------------------------------------
            auto r = human_interface_device_.open(kIOHIDOptionsTypeSeizeDevice);
            if (r != kIOReturnSuccess) {
              auto message = fmt::format("IOHIDDeviceOpen error: {0} ({1}) {2}",
                                         iokit_utility::get_error_name(r),
                                         r,
                                         human_interface_device_.get_name_for_log());
              log_reducer_.error(message);
              return false;
            }

            // ----------------------------------------
            grabbed_ = true;

            device_grabbed(human_interface_device_);

            human_interface_device_.queue_start();
            human_interface_device_.schedule();

            return true;
          });
    });
  }

  void ungrab(void) {
    gcd_utility::dispatch_sync_in_main_queue(^{
      timer_ = nullptr;

      if (!grabbed_) {
        return;
      }

      human_interface_device_.unschedule();
      human_interface_device_.queue_stop();
      human_interface_device_.close();

      grabbed_ = false;

      device_ungrabbed(human_interface_device_);
    });
  }

private:
  human_interface_device& human_interface_device_;
  bool grabbed_;
  std::unique_ptr<gcd_utility::fire_while_false_timer> timer_;
  spdlog_utility::log_reducer log_reducer_;
};
} // namespace krbn
<|endoftext|>


<commit_before>#include <smooth/core/network/MbedTLSContext.h>
#include <memory>
#include <smooth/core/logging/log.h>

using namespace smooth::core::logging;

namespace smooth
{
    namespace core
    {
        namespace network
        {
            // Things to improve:
            // https://tls.mbed.org/discussions/generic/one-time-and-per-session-initialization-functions

            static constexpr const char* tag = "MBedTLSContext";
#ifndef ESP_PLATFORM
            static void mbedtls_debug(void* ctx, int level, const char* file, int line, const char* str)
            {
                (void) ctx;
                (void) level;
                (void) file;
                (void) line;

                Log::debug(tag, str);
            }
#endif

            bool MBedTLSContext::init()
            {
                mbedtls_ssl_init(&ssl);
                mbedtls_ssl_config_init(&conf);
                mbedtls_x509_crt_init(&ca_cert);
                mbedtls_entropy_init(&entropy);
                mbedtls_ctr_drbg_init(&ctr_drbg);
#ifndef ESP_PLATFORM
                mbedtls_ssl_conf_dbg(&conf, mbedtls_debug, stdout);
                mbedtls_debug_set_threshold(0);
#endif
                auto res = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, nullptr, 0);

                if (res != 0)
                {
                    Log::error(tag, Format("mbedtls_ctr_drbg_seed returned {1}", Int32(res)));
                }
                else
                {
                    res = mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM,
                                                      MBEDTLS_SSL_PRESET_DEFAULT);
                    if (res != 0)
                    {
                        Log::error("MBedTLSContext", Format("mbedtls_ssl_config_defaults returned {1}", Int32(res)));
                    }
                    else
                    {
                        // TODO: Implement auth: MBEDTLS_SSL_VERIFY_REQUIRED
                        mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_NONE);

                        mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
                        mbedtls_ssl_conf_ca_chain(&conf, &ca_cert, nullptr);

                        res = mbedtls_ssl_setup(&ssl, &conf);

                        if (res != 0)
                        {
                            Log::error("MBedTLSContext", Format("mbedtls_ssl_setup returned {1}", Int32(res)));
                        }
                    }
                }

                return res == 0;
            }

            MBedTLSContext::~MBedTLSContext()
            {
                mbedtls_ctr_drbg_free(&ctr_drbg);
                mbedtls_entropy_free(&entropy);
                mbedtls_x509_crt_free(&ca_cert);
                mbedtls_ssl_config_free(&conf);
                mbedtls_ssl_free(&ssl);
            }
        }
    }
}<commit_msg>#10 - Set debug level.<commit_after>#include <smooth/core/network/MbedTLSContext.h>
#include <memory>
#include <smooth/core/logging/log.h>

using namespace smooth::core::logging;

namespace smooth
{
    namespace core
    {
        namespace network
        {
            // Things to improve:
            // https://tls.mbed.org/discussions/generic/one-time-and-per-session-initialization-functions

            static constexpr const char* tag = "MBedTLSContext";
#ifndef ESP_PLATFORM
            static void mbedtls_debug(void* ctx, int level, const char* file, int line, const char* str)
            {
                (void) ctx;
                (void) level;
                (void) file;
                (void) line;

                Log::debug(tag, str);
            }
#endif

            bool MBedTLSContext::init()
            {
                mbedtls_ssl_init(&ssl);
                mbedtls_ssl_config_init(&conf);
                mbedtls_x509_crt_init(&ca_cert);
                mbedtls_entropy_init(&entropy);
                mbedtls_ctr_drbg_init(&ctr_drbg);
#ifndef ESP_PLATFORM
                mbedtls_ssl_conf_dbg(&conf, mbedtls_debug, stdout);
                mbedtls_debug_set_threshold(1);
#endif
                auto res = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, nullptr, 0);

                if (res != 0)
                {
                    Log::error(tag, Format("mbedtls_ctr_drbg_seed returned {1}", Int32(res)));
                }
                else
                {
                    res = mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM,
                                                      MBEDTLS_SSL_PRESET_DEFAULT);
                    if (res != 0)
                    {
                        Log::error("MBedTLSContext", Format("mbedtls_ssl_config_defaults returned {1}", Int32(res)));
                    }
                    else
                    {
                        // TODO: Implement auth: MBEDTLS_SSL_VERIFY_REQUIRED
                        mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_NONE);

                        mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
                        mbedtls_ssl_conf_ca_chain(&conf, &ca_cert, nullptr);

                        res = mbedtls_ssl_setup(&ssl, &conf);

                        if (res != 0)
                        {
                            Log::error("MBedTLSContext", Format("mbedtls_ssl_setup returned {1}", Int32(res)));
                        }
                    }
                }

                return res == 0;
            }

            MBedTLSContext::~MBedTLSContext()
            {
                mbedtls_ctr_drbg_free(&ctr_drbg);
                mbedtls_entropy_free(&entropy);
                mbedtls_x509_crt_free(&ca_cert);
                mbedtls_ssl_config_free(&conf);
                mbedtls_ssl_free(&ssl);
            }
        }
    }
}<|endoftext|>


<commit_before>#ifndef SRC_DRIVERS_BURTC_HPP_
#define SRC_DRIVERS_BURTC_HPP_

#pragma once

#include "base/os.h"

namespace devices
{
    namespace burtc
    {
        /**
         * @defgroup burtc Backup RTC Driver
         * @ingroup perhipheral_drivers
         *
         * @brief This library provides driver for built-in Backup Real Time Counter.
         *
         * @{
        */

        /**
         * @brief BURTC Device
         */
        class Burtc
        {
          public:
            /**
             * @brief Constructs @ref Burtc object
             * @param[in] tickCallback A pointer to function that will be notified about time changes
             */
            Burtc(TimeAction& tickCallback);

            /**
              * @brief Initializes Burtc device - setups the hardware and starts the FreeRTOS task.
              */
            OSResult Initialize();

            /**
             * @brief Starts ticking
             */
            void Start();

            /**
              * @brief Interrupt handler for BURTC hardware
              */
            void IRQHandler();

            /** @brief Compare value  */
            static constexpr uint32_t CompareValue = 205;

            /** @brief Prescaler divider */
            static constexpr uint32_t PrescalerDivider = 8;

          private:
            static constexpr uint32_t InterruptPriority = 6;

            TimeAction& _tickCallback;
            std::chrono::milliseconds _timeDelta;

            void ConfigureHardware();

            Task<Burtc*, 2_KB, TaskPriority::P6> _task;

            /** @brief Calculates current time interval based on selected oscillator frequency, prescaler and compare value **/
            static std::chrono::milliseconds CalculateCurrentTimeInterval();

            static void HandleTickTask(Burtc* burtcObject);
        };

        /** @} */
    }
}

#endif /* SRC_DRIVERS_BURTC_HPP_ */
<commit_msg>Fix stack size for BURTC task<commit_after>#ifndef SRC_DRIVERS_BURTC_HPP_
#define SRC_DRIVERS_BURTC_HPP_

#pragma once

#include "base/os.h"

namespace devices
{
    namespace burtc
    {
        /**
         * @defgroup burtc Backup RTC Driver
         * @ingroup perhipheral_drivers
         *
         * @brief This library provides driver for built-in Backup Real Time Counter.
         *
         * @{
        */

        /**
         * @brief BURTC Device
         */
        class Burtc
        {
          public:
            /**
             * @brief Constructs @ref Burtc object
             * @param[in] tickCallback A pointer to function that will be notified about time changes
             */
            Burtc(TimeAction& tickCallback);

            /**
              * @brief Initializes Burtc device - setups the hardware and starts the FreeRTOS task.
              */
            OSResult Initialize();

            /**
             * @brief Starts ticking
             */
            void Start();

            /**
              * @brief Interrupt handler for BURTC hardware
              */
            void IRQHandler();

            /** @brief Compare value  */
            static constexpr uint32_t CompareValue = 205;

            /** @brief Prescaler divider */
            static constexpr uint32_t PrescalerDivider = 8;

          private:
            static constexpr uint32_t InterruptPriority = 6;

            TimeAction& _tickCallback;
            std::chrono::milliseconds _timeDelta;

            void ConfigureHardware();

            Task<Burtc*, 4_KB, TaskPriority::P6> _task;

            /** @brief Calculates current time interval based on selected oscillator frequency, prescaler and compare value **/
            static std::chrono::milliseconds CalculateCurrentTimeInterval();

            static void HandleTickTask(Burtc* burtcObject);
        };

        /** @} */
    }
}

#endif /* SRC_DRIVERS_BURTC_HPP_ */
<|endoftext|>