<commit_before>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2014
Raffaello D. Di Napoli

This file is part of Abaclade.

Abaclade is free software: you can redistribute it and/or modify it under the terms of the GNU
General Public License as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

Abaclade is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.

You should have received a copy of the GNU General Public License along with Abaclade. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#ifndef _ABACLADE_HXX_INTERNAL
   #error Please #include <abaclade.hxx> instead of this file
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::static_list

namespace abc {

//! Base for classes containing static lists of other (node) classes.
template <class TContainer, class TValue>
class static_list {
public:
   //! Base class for nodes of static_list.
   class node {
   private:
      friend class static_list;
      friend class iterator;

   protected:
      //! Constructor.
      node() {
         static_list::append(this);
      }
      node(node const &) {
         // Skip copying the source’s links.
         static_list::append(this);
      }

      //! Destructor.
      ~node() {
         static_list::remove(this);
      }

      /*! Assignment operator.

      @return
         *this.
      */
      node & operator=(node const &) {
         // Skip copying the source’s links.
         return *this;
      }

   private:
      /*! Returns a pointer to the next node.

      @param pnPrev
         Pointer to the previous node.
      */
      node * get_next(node * pnPrev) {
         return reinterpret_cast<node *>(
            m_iPrevXorNext ^ reinterpret_cast<std::uintptr_t>(pnPrev)
         );
      }

      /*! Returns a pointer to the previous node.

      @param pnNext
         Pointer to the next node.
      */
      node * get_prev(node * pnNext) {
         return reinterpret_cast<node *>(
            m_iPrevXorNext ^ reinterpret_cast<std::uintptr_t>(pnNext)
         );
      }

      /*! Updates the previous/next pointer.

      @param pnPrev
         Pointer to the previous node.
      @param pnNext
         Pointer to the next node.
      */
      void set_prev_next(node * pnPrev, node * pnNext) {
         m_iPrevXorNext = reinterpret_cast<std::uintptr_t>(pnPrev) ^
                          reinterpret_cast<std::uintptr_t>(pnNext);
      }

   private:
      //! Pointer to the previous node XOR pointer to the next node.
      std::uintptr_t m_iPrevXorNext;
   };

   //! Iterator for static_list::node subclasses.
   class iterator : public std::iterator<std::bidirectional_iterator_tag, TValue> {
   public:
      /*! Constructor.

      @param pnCurr
         Pointer to the current node.
      @param pnNext
         Pointer to the node following *pnCurr.
      */
      iterator(node * pnCurr, node * pnNext) :
         m_pnCurr(pnCurr),
         m_pnNext(pnNext) {
      }

      /*! Dereferencing operator.

      @return
         Reference to the current node.
      */
      TValue & operator*() const {
         return *static_cast<TValue *>(m_pnCurr);
      }

      /*! Dereferencing member access operator.

      @return
         Pointer to the current node.
      */
      TValue * operator->() const {
         return static_cast<TValue *>(m_pnCurr);
      }

      /*! Preincrement operator.

      @return
         *this after it’s moved to the node following the one currently pointed to by.
      */
      iterator & operator++() {
         node * pnNewPrev = m_pnCurr;
         m_pnCurr = m_pnNext;
         m_pnNext = m_pnCurr->get_next(pnNewPrev);
         return *this;
      }

      /*! Postincrement operator.

      @return
         Iterator pointing to the node following the one pointed to by this iterator.
      */
      iterator operator++(int) {
         node * pnNewPrev = m_pnCurr;
         m_pnCurr = m_pnNext;
         m_pnNext = m_pnCurr->get_next(pnNewPrev);
         return iterator(pnNewPrev, m_pnCurr);
      }

      /*! Predecrement operator.

      @return
         *this after it’s moved to the node preceding the one currently pointed to by.
      */
      iterator & operator--() {
         node * pnNewNext = m_pnCurr;
         m_pnCurr = m_pnCurr->get_prev(m_pnNext);
         m_pnNext = pnNewNext;
         return *this;
      }

      /*! Postdecrement operator.

      @return
         Iterator pointing to the node preceding the one pointed to by this iterator.
      */
      iterator operator--(int) {
         node * pnNewNextNext = m_pnNext;
         m_pnNext = m_pnCurr;
         m_pnCurr = m_pnCurr->get_prev(pnNewNextNext);
         return iterator(m_pnNext, pnNewNextNext);
      }

// Relational operators.
#define ABC_RELOP_IMPL(op) \
      bool operator op(iterator const & it) const { \
         return m_pnCurr op it.m_pnCurr; \
      }
ABC_RELOP_IMPL(==)
ABC_RELOP_IMPL(!=)
#undef ABC_RELOP_IMPL

      /*! Returns the underlying iterator type.

      @return
         Pointer to the current node.
      */
      node * base() const {
         return m_pnCurr;
      }

   private:
      //! Pointer to the current node.
      node * m_pnCurr;
      //! Pointer to the next node.
      node * m_pnNext;
   };

   typedef std::reverse_iterator<iterator> reverse_iterator;

public:
   /*! Returns a forward iterator to the start of the list.

   @return
      Iterator to the first node in the list.
   */
   static iterator begin() {
      node * pnFirst = TContainer::sm_pnFirst;
      return iterator(pnFirst, pnFirst ? pnFirst->get_next(nullptr) : nullptr);
   }

   /*! Returns a forward iterator to the end of the list.

   @return
      Iterator to the beyond the last node in the list.
   */
   static iterator end() {
      return iterator(TContainer::sm_pnLast, nullptr);
   }

   /*! Returns a reverse iterator to the end of the list.

   @return
      Reverse Iterator to the last node in the list.
   */
   static reverse_iterator rbegin() {
      return reverse_iterator(end());
   }

   /*! Returns a reverse iterator to the start of the list.

   @return
      Reverse iterator to the before the first node in the list.
   */
   static reverse_iterator rend() {
      return reverse_iterator(begin());
   }

private:
   /*! Add a node to the end of the list.

   @param pn
      Pointer to the node to append.
   */
   static void append(node * pn) {
      pn->set_prev_next(nullptr, TContainer::sm_pnLast);
      if (!TContainer::sm_pnFirst) {
         TContainer::sm_pnFirst = pn;
      } else if (node * pnLast = TContainer::sm_pnLast) {
         pnLast->set_prev_next(pn, pnLast->get_next(nullptr));
      }
      TContainer::sm_pnLast = pn;
   }

   /*! Removes a node from the list.

   @param pn
      Pointer to the node to remove.
   */
   static void remove(node * pn) {
      // Find pn in the list.
      for (
         node * pnCurr = TContainer::sm_pnFirst, * pnPrev = nullptr;
         pnCurr != TContainer::sm_pnLast;
         std::tie(pnPrev, pnCurr) = std::make_tuple(pnCurr, pnCurr->get_next(pnPrev))
      ) {
         if (pnCurr == pn) {
            node * pnNext = pn->get_next(pnPrev);
            if (pnPrev) {
               pnPrev->set_prev_next(pnPrev->get_prev(pn), pnNext);
            } else if (TContainer::sm_pnFirst == pn) {
               TContainer::sm_pnFirst = pnNext;
            }
            if (pnNext) {
               pnNext->set_prev_next(pnPrev, pnNext->get_next(pn));
            } else if (TContainer::sm_pnLast == pn) {
               TContainer::sm_pnLast = pnPrev;
            }
            pn->set_prev_next(nullptr, nullptr);
            break;
         }
      }
   }
};

} //namespace abc

/*! Declares the static member variables for the specified abc::static_list-derived class.

@param container
   Class derived from abc::static_list.
*/
#define ABC_STATIC_LIST_DECLARE_SUBCLASS_STATIC_MEMBERS(container) \
   static node * sm_pnFirst; \
   static node * sm_pnLast;

/*! Defines the static member variables for the specified abc::static_list-derived class.

@param container
   Class derived from abc::static_list.
*/
#define ABC_STATIC_LIST_DEFINE_SUBCLASS_STATIC_MEMBERS(container) \
   container::node * container::sm_pnFirst = nullptr; \
   container::node * container::sm_pnLast = nullptr;

////////////////////////////////////////////////////////////////////////////////////////////////////
<commit_msg>Fix abc::static_list::iterator skipping last list element<commit_after>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2014
Raffaello D. Di Napoli

This file is part of Abaclade.

Abaclade is free software: you can redistribute it and/or modify it under the terms of the GNU
General Public License as published by the Free Software Foundation, either version 3 of the
License, or (at your option) any later version.

Abaclade is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
Public License for more details.

You should have received a copy of the GNU General Public License along with Abaclade. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#ifndef _ABACLADE_HXX_INTERNAL
   #error Please #include <abaclade.hxx> instead of this file
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::static_list

namespace abc {

//! Base for classes containing static lists of other (node) classes.
template <class TContainer, class TValue>
class static_list {
public:
   //! Base class for nodes of static_list.
   class node {
   private:
      friend class static_list;
      friend class iterator;

   protected:
      //! Constructor.
      node() {
         static_list::append(this);
      }
      node(node const &) {
         // Skip copying the source’s links.
         static_list::append(this);
      }

      //! Destructor.
      ~node() {
         static_list::remove(this);
      }

      /*! Assignment operator.

      @return
         *this.
      */
      node & operator=(node const &) {
         // Skip copying the source’s links.
         return *this;
      }

   private:
      /*! Returns a pointer to the next node.

      @param pnPrev
         Pointer to the previous node.
      */
      node * get_next(node * pnPrev) {
         return reinterpret_cast<node *>(
            m_iPrevXorNext ^ reinterpret_cast<std::uintptr_t>(pnPrev)
         );
      }

      /*! Returns a pointer to the previous node.

      @param pnNext
         Pointer to the next node.
      */
      node * get_prev(node * pnNext) {
         return reinterpret_cast<node *>(
            m_iPrevXorNext ^ reinterpret_cast<std::uintptr_t>(pnNext)
         );
      }

      /*! Updates the previous/next pointer.

      @param pnPrev
         Pointer to the previous node.
      @param pnNext
         Pointer to the next node.
      */
      void set_prev_next(node * pnPrev, node * pnNext) {
         m_iPrevXorNext = reinterpret_cast<std::uintptr_t>(pnPrev) ^
                          reinterpret_cast<std::uintptr_t>(pnNext);
      }

   private:
      //! Pointer to the previous node XOR pointer to the next node.
      std::uintptr_t m_iPrevXorNext;
   };

   //! Iterator for static_list::node subclasses.
   class iterator : public std::iterator<std::bidirectional_iterator_tag, TValue> {
   public:
      /*! Constructor.

      @param pnPrev
         Pointer to the node preceding *pnCurr.
      @param pnCurr
         Pointer to the current node.
      @param pnNext
         Pointer to the node following *pnCurr.
      */
      iterator(node * pnPrev, node * pnCurr, node * pnNext) :
         m_pnPrev(pnPrev),
         m_pnCurr(pnCurr),
         m_pnNext(pnNext) {
      }

      /*! Dereferencing operator.

      @return
         Reference to the current node.
      */
      TValue & operator*() const {
         return *static_cast<TValue *>(m_pnCurr);
      }

      /*! Dereferencing member access operator.

      @return
         Pointer to the current node.
      */
      TValue * operator->() const {
         return static_cast<TValue *>(m_pnCurr);
      }

      /*! Preincrement operator.

      @return
         *this after it’s moved to the node following the one currently pointed to by.
      */
      iterator & operator++() {
         m_pnPrev = m_pnCurr;
         m_pnCurr = m_pnNext;
         m_pnNext = m_pnCurr ? m_pnCurr->get_next(m_pnPrev) : nullptr;
         return *this;
      }

      /*! Postincrement operator.

      @return
         Iterator pointing to the node following the one pointed to by this iterator.
      */
      iterator operator++(int) {
         node * pnPrevPrev = m_pnPrev;
         operator++();
         return iterator(pnPrevPrev, m_pnPrev, m_pnCurr);
      }

      /*! Predecrement operator.

      @return
         *this after it’s moved to the node preceding the one currently pointed to by.
      */
      iterator & operator--() {
         m_pnNext = m_pnCurr;
         m_pnCurr = m_pnPrev;
         m_pnPrev = m_pnCurr ? m_pnCurr->get_prev(m_pnNext) : nullptr;
         return *this;
      }

      /*! Postdecrement operator.

      @return
         Iterator pointing to the node preceding the one pointed to by this iterator.
      */
      iterator operator--(int) {
         node * pnNextNext = m_pnNext;
         operator--();
         return iterator(m_pnCurr, m_pnNext, pnNextNext);
      }

// Relational operators.
#define ABC_RELOP_IMPL(op) \
      bool operator op(iterator const & it) const { \
         return m_pnCurr op it.m_pnCurr; \
      }
ABC_RELOP_IMPL(==)
ABC_RELOP_IMPL(!=)
#undef ABC_RELOP_IMPL

      /*! Returns the underlying iterator type.

      @return
         Pointer to the current node.
      */
      node * base() const {
         return m_pnCurr;
      }

   private:
      //! Pointer to the previous node.
      node * m_pnPrev;
      //! Pointer to the current node.
      node * m_pnCurr;
      //! Pointer to the next node.
      node * m_pnNext;
   };

   typedef std::reverse_iterator<iterator> reverse_iterator;

public:
   /*! Returns a forward iterator to the start of the list.

   @return
      Iterator to the first node in the list.
   */
   static iterator begin() {
      node * pnFirst = TContainer::sm_pnFirst;
      return iterator(nullptr, pnFirst, pnFirst ? pnFirst->get_next(nullptr) : nullptr);
   }

   /*! Returns a forward iterator to the end of the list.

   @return
      Iterator to the beyond the last node in the list.
   */
   static iterator end() {
      return iterator(TContainer::sm_pnLast, nullptr, nullptr);
   }

   /*! Returns a reverse iterator to the end of the list.

   @return
      Reverse Iterator to the last node in the list.
   */
   static reverse_iterator rbegin() {
      return reverse_iterator(end());
   }

   /*! Returns a reverse iterator to the start of the list.

   @return
      Reverse iterator to the before the first node in the list.
   */
   static reverse_iterator rend() {
      return reverse_iterator(begin());
   }

private:
   /*! Add a node to the end of the list.

   @param pn
      Pointer to the node to append.
   */
   static void append(node * pn) {
      pn->set_prev_next(nullptr, TContainer::sm_pnLast);
      if (!TContainer::sm_pnFirst) {
         TContainer::sm_pnFirst = pn;
      } else if (node * pnLast = TContainer::sm_pnLast) {
         pnLast->set_prev_next(pn, pnLast->get_next(nullptr));
      }
      TContainer::sm_pnLast = pn;
   }

   /*! Removes a node from the list.

   @param pn
      Pointer to the node to remove.
   */
   static void remove(node * pn) {
      // Find pn in the list.
      for (
         node * pnCurr = TContainer::sm_pnFirst, * pnPrev = nullptr;
         pnCurr != TContainer::sm_pnLast;
         std::tie(pnPrev, pnCurr) = std::make_tuple(pnCurr, pnCurr->get_next(pnPrev))
      ) {
         if (pnCurr == pn) {
            node * pnNext = pn->get_next(pnPrev);
            if (pnPrev) {
               pnPrev->set_prev_next(pnPrev->get_prev(pn), pnNext);
            } else if (TContainer::sm_pnFirst == pn) {
               TContainer::sm_pnFirst = pnNext;
            }
            if (pnNext) {
               pnNext->set_prev_next(pnPrev, pnNext->get_next(pn));
            } else if (TContainer::sm_pnLast == pn) {
               TContainer::sm_pnLast = pnPrev;
            }
            pn->set_prev_next(nullptr, nullptr);
            break;
         }
      }
   }
};

} //namespace abc

/*! Declares the static member variables for the specified abc::static_list-derived class.

@param container
   Class derived from abc::static_list.
*/
#define ABC_STATIC_LIST_DECLARE_SUBCLASS_STATIC_MEMBERS(container) \
   static node * sm_pnFirst; \
   static node * sm_pnLast;

/*! Defines the static member variables for the specified abc::static_list-derived class.

@param container
   Class derived from abc::static_list.
*/
#define ABC_STATIC_LIST_DEFINE_SUBCLASS_STATIC_MEMBERS(container) \
   container::node * container::sm_pnFirst = nullptr; \
   container::node * container::sm_pnLast = nullptr;

////////////////////////////////////////////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before>/* Copyright 2019 Axel Huebl, Benjamin Worpitz, René Widera
 *
 * This file is part of Alpaka.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#pragma once

#include <alpaka/vec/Vec.hpp>
#include <alpaka/core/Common.hpp>
#include <alpaka/core/Unused.hpp>

#include <alpaka/dim/Traits.hpp>
#include <alpaka/idx/Traits.hpp>
#include <alpaka/queue/Traits.hpp>

#include <alpaka/core/BoostPredef.hpp>
#include <alpaka/core/Debug.hpp>
#if ALPAKA_DEBUG >= ALPAKA_DEBUG_FULL
    #include <alpaka/workdiv/Traits.hpp>
#endif

#include <type_traits>

//-----------------------------------------------------------------------------
//! The alpaka accelerator library.
namespace alpaka
{
    //-----------------------------------------------------------------------------
    //! The kernel specifics.
    namespace kernel
    {
        //-----------------------------------------------------------------------------
        //! The kernel traits.
        namespace traits
        {
            //#############################################################################
            //! The kernel execution task creation trait.
            template<
                typename TAcc,
                typename TWorkDiv,
                typename TKernelFnObj,
                typename... TArgs/*,
                typename TSfinae = void*/>
            struct CreateTaskKernel;

            //#############################################################################
            //! The trait for getting the size of the block shared dynamic memory of a kernel.
            //!
            //! \tparam TKernelFnObj The kernel function object.
            //! \tparam TAcc The accelerator.
            //!
            //! The default implementation returns 0.
            template<
                typename TKernelFnObj,
                typename TAcc,
                typename TSfinae = void>
            struct BlockSharedMemDynSizeBytes
            {
#if BOOST_COMP_CLANG
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wdocumentation"  // clang does not support the syntax for variadic template arguments "args,..."
#endif
                //-----------------------------------------------------------------------------
                //! \param kernelFnObj The kernel object for which the block shared memory size should be calculated.
                //! \param blockThreadExtent The block thread extent.
                //! \param threadElemExtent The thread element extent.
                //! \tparam TArgs The kernel invocation argument types pack.
                //! \param args,... The kernel invocation arguments.
                //! \return The size of the shared memory allocated for a block in bytes.
                //! The default version always returns zero.
#if BOOST_COMP_CLANG
    #pragma clang diagnostic pop
#endif
                ALPAKA_NO_HOST_ACC_WARNING
                template<
                    typename TDim,
                    typename... TArgs>
                ALPAKA_FN_HOST_ACC static auto getBlockSharedMemDynSizeBytes(
                    TKernelFnObj const & kernelFnObj,
                    vec::Vec<TDim, idx::Idx<TAcc>> const & blockThreadExtent,
                    vec::Vec<TDim, idx::Idx<TAcc>> const & threadElemExtent,
                    TArgs const & ... args)
                -> idx::Idx<TAcc>
                {
                    alpaka::ignore_unused(kernelFnObj);
                    alpaka::ignore_unused(blockThreadExtent);
                    alpaka::ignore_unused(threadElemExtent);
                    alpaka::ignore_unused(args...);

                    return 0;
                }
            };
        }

#if BOOST_COMP_CLANG
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wdocumentation"  // clang does not support the syntax for variadic template arguments "args,..."
#endif
        //-----------------------------------------------------------------------------
        //! \tparam TAcc The accelerator type.
        //! \param kernelFnObj The kernel object for which the block shared memory size should be calculated.
        //! \param blockThreadExtent The block thread extent.
        //! \param threadElemExtent The thread element extent.
        //! \param args,... The kernel invocation arguments.
        //! \return The size of the shared memory allocated for a block in bytes.
        //! The default implementation always returns zero.
#if BOOST_COMP_CLANG
    #pragma clang diagnostic pop
#endif
        ALPAKA_NO_HOST_ACC_WARNING
        template<
            typename TAcc,
            typename TKernelFnObj,
            typename TDim,
            typename... TArgs>
        ALPAKA_FN_HOST_ACC auto getBlockSharedMemDynSizeBytes(
            TKernelFnObj const & kernelFnObj,
            vec::Vec<TDim, idx::Idx<TAcc>> const & blockThreadExtent,
            vec::Vec<TDim, idx::Idx<TAcc>> const & threadElemExtent,
            TArgs const & ... args)
        -> idx::Idx<TAcc>
        {
            return
                traits::BlockSharedMemDynSizeBytes<
                    TKernelFnObj,
                    TAcc>
                ::getBlockSharedMemDynSizeBytes(
                    kernelFnObj,
                    blockThreadExtent,
                    threadElemExtent,
                    args...);
        }

#if BOOST_COMP_CLANG
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wdocumentation"  // clang does not support the syntax for variadic template arguments "args,..."
#endif

        namespace detail
        {
            //#############################################################################
            //! Check that the return of TKernelFnObj is void
            template<
                typename TAcc,
                typename TSfinae = void>
            struct CheckFnReturnType
            {
                template<
                    typename TKernelFnObj,
                    typename... TArgs>
                void operator()(
                    TKernelFnObj const &,
                    TArgs const & ...)
                {
                    static_assert(
                        std::is_same<std::result_of_t<TKernelFnObj(TAcc const &, TArgs const & ...)>, void>::value,
                        "The TKernelFnObj is required to return void!");
                }
            };
        }
        //-----------------------------------------------------------------------------
        //! Creates a kernel execution task.
        //!
        //! \tparam TAcc The accelerator type.
        //! \param workDiv The index domain work division.
        //! \param kernelFnObj The kernel function object which should be executed.
        //! \param args,... The kernel invocation arguments.
        //! \return The kernel execution task.
#if BOOST_COMP_CLANG
    #pragma clang diagnostic pop
#endif
        template<
            typename TAcc,
            typename TWorkDiv,
            typename TKernelFnObj,
            typename... TArgs>
        ALPAKA_FN_HOST auto createTaskKernel(
            TWorkDiv const & workDiv,
            TKernelFnObj const & kernelFnObj,
            TArgs && ... args)
        {
            // check for void return type
            detail::CheckFnReturnType<TAcc>{}(kernelFnObj, args...);

            static_assert(
                dim::Dim<std::decay_t<TWorkDiv>>::value == dim::Dim<TAcc>::value,
                "The dimensions of TAcc and TWorkDiv have to be identical!");
            static_assert(
                std::is_same<idx::Idx<std::decay_t<TWorkDiv>>, idx::Idx<TAcc>>::value,
                "The idx type of TAcc and the idx type of TWorkDiv have to be identical!");

#if ALPAKA_DEBUG >= ALPAKA_DEBUG_FULL
            std::cout << __func__
                << " workDiv: " << workDiv
                << ", kernelFnObj: " << typeid(kernelFnObj).name()
                << std::endl;
#endif
            return
                traits::CreateTaskKernel<
                    TAcc,
                    TWorkDiv,
                    TKernelFnObj,
                    TArgs...>::createTaskKernel(
                        workDiv,
                        kernelFnObj,
                        std::forward<TArgs>(args)...);
        }

#if BOOST_COMP_CLANG
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wdocumentation"  // clang does not support the syntax for variadic template arguments "args,..."
#endif
        //-----------------------------------------------------------------------------
        //! Executes the given kernel in the given queue.
        //!
        //! \tparam TAcc The accelerator type.
        //! \param queue The queue to enqueue the view copy task into.
        //! \param workDiv The index domain work division.
        //! \param kernelFnObj The kernel function object which should be executed.
        //! \param args,... The kernel invocation arguments.
#if BOOST_COMP_CLANG
    #pragma clang diagnostic pop
#endif
        template<
            typename TAcc,
            typename TQueue,
            typename TWorkDiv,
            typename TKernelFnObj,
            typename... TArgs>
        ALPAKA_FN_HOST auto exec(
            TQueue & queue,
            TWorkDiv const & workDiv,
            TKernelFnObj const & kernelFnObj,
            TArgs && ... args)
        -> void
        {
            queue::enqueue(
                queue,
                kernel::createTaskKernel<
                    TAcc>(
                    workDiv,
                    kernelFnObj,
                    std::forward<TArgs>(args)...));
        }
    }
}
<commit_msg>Use std::invoke_result_t instead of std::result_of_t when available<commit_after>/* Copyright 2019 Axel Huebl, Benjamin Worpitz, René Widera
 *
 * This file is part of Alpaka.
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */

#pragma once

#include <alpaka/vec/Vec.hpp>
#include <alpaka/core/Common.hpp>
#include <alpaka/core/Unused.hpp>

#include <alpaka/dim/Traits.hpp>
#include <alpaka/idx/Traits.hpp>
#include <alpaka/queue/Traits.hpp>

#include <alpaka/core/BoostPredef.hpp>
#include <alpaka/core/Debug.hpp>
#if ALPAKA_DEBUG >= ALPAKA_DEBUG_FULL
    #include <alpaka/workdiv/Traits.hpp>
#endif

#include <type_traits>

//-----------------------------------------------------------------------------
//! The alpaka accelerator library.
namespace alpaka
{
    //-----------------------------------------------------------------------------
    //! The kernel specifics.
    namespace kernel
    {
        //-----------------------------------------------------------------------------
        //! The kernel traits.
        namespace traits
        {
            //#############################################################################
            //! The kernel execution task creation trait.
            template<
                typename TAcc,
                typename TWorkDiv,
                typename TKernelFnObj,
                typename... TArgs/*,
                typename TSfinae = void*/>
            struct CreateTaskKernel;

            //#############################################################################
            //! The trait for getting the size of the block shared dynamic memory of a kernel.
            //!
            //! \tparam TKernelFnObj The kernel function object.
            //! \tparam TAcc The accelerator.
            //!
            //! The default implementation returns 0.
            template<
                typename TKernelFnObj,
                typename TAcc,
                typename TSfinae = void>
            struct BlockSharedMemDynSizeBytes
            {
#if BOOST_COMP_CLANG
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wdocumentation"  // clang does not support the syntax for variadic template arguments "args,..."
#endif
                //-----------------------------------------------------------------------------
                //! \param kernelFnObj The kernel object for which the block shared memory size should be calculated.
                //! \param blockThreadExtent The block thread extent.
                //! \param threadElemExtent The thread element extent.
                //! \tparam TArgs The kernel invocation argument types pack.
                //! \param args,... The kernel invocation arguments.
                //! \return The size of the shared memory allocated for a block in bytes.
                //! The default version always returns zero.
#if BOOST_COMP_CLANG
    #pragma clang diagnostic pop
#endif
                ALPAKA_NO_HOST_ACC_WARNING
                template<
                    typename TDim,
                    typename... TArgs>
                ALPAKA_FN_HOST_ACC static auto getBlockSharedMemDynSizeBytes(
                    TKernelFnObj const & kernelFnObj,
                    vec::Vec<TDim, idx::Idx<TAcc>> const & blockThreadExtent,
                    vec::Vec<TDim, idx::Idx<TAcc>> const & threadElemExtent,
                    TArgs const & ... args)
                -> idx::Idx<TAcc>
                {
                    alpaka::ignore_unused(kernelFnObj);
                    alpaka::ignore_unused(blockThreadExtent);
                    alpaka::ignore_unused(threadElemExtent);
                    alpaka::ignore_unused(args...);

                    return 0;
                }
            };
        }

#if BOOST_COMP_CLANG
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wdocumentation"  // clang does not support the syntax for variadic template arguments "args,..."
#endif
        //-----------------------------------------------------------------------------
        //! \tparam TAcc The accelerator type.
        //! \param kernelFnObj The kernel object for which the block shared memory size should be calculated.
        //! \param blockThreadExtent The block thread extent.
        //! \param threadElemExtent The thread element extent.
        //! \param args,... The kernel invocation arguments.
        //! \return The size of the shared memory allocated for a block in bytes.
        //! The default implementation always returns zero.
#if BOOST_COMP_CLANG
    #pragma clang diagnostic pop
#endif
        ALPAKA_NO_HOST_ACC_WARNING
        template<
            typename TAcc,
            typename TKernelFnObj,
            typename TDim,
            typename... TArgs>
        ALPAKA_FN_HOST_ACC auto getBlockSharedMemDynSizeBytes(
            TKernelFnObj const & kernelFnObj,
            vec::Vec<TDim, idx::Idx<TAcc>> const & blockThreadExtent,
            vec::Vec<TDim, idx::Idx<TAcc>> const & threadElemExtent,
            TArgs const & ... args)
        -> idx::Idx<TAcc>
        {
            return
                traits::BlockSharedMemDynSizeBytes<
                    TKernelFnObj,
                    TAcc>
                ::getBlockSharedMemDynSizeBytes(
                    kernelFnObj,
                    blockThreadExtent,
                    threadElemExtent,
                    args...);
        }

#if BOOST_COMP_CLANG
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wdocumentation"  // clang does not support the syntax for variadic template arguments "args,..."
#endif

        namespace detail
        {
            //#############################################################################
            //! Check that the return of TKernelFnObj is void
            template<
                typename TAcc,
                typename TSfinae = void>
            struct CheckFnReturnType
            {
                template<
                    typename TKernelFnObj,
                    typename... TArgs>
                void operator()(
                    TKernelFnObj const &,
                    TArgs const & ...)
                {
#if defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable >= 201703
                    using Result = std::invoke_result_t<TKernelFnObj, TAcc const &, TArgs const & ...>;
#else
                    using Result = std::result_of_t<TKernelFnObj(TAcc const &, TArgs const & ...)>;
#endif
                    static_assert(
                        std::is_same<Result, void>::value,
                        "The TKernelFnObj is required to return void!");
                }
            };
        }
        //-----------------------------------------------------------------------------
        //! Creates a kernel execution task.
        //!
        //! \tparam TAcc The accelerator type.
        //! \param workDiv The index domain work division.
        //! \param kernelFnObj The kernel function object which should be executed.
        //! \param args,... The kernel invocation arguments.
        //! \return The kernel execution task.
#if BOOST_COMP_CLANG
    #pragma clang diagnostic pop
#endif
        template<
            typename TAcc,
            typename TWorkDiv,
            typename TKernelFnObj,
            typename... TArgs>
        ALPAKA_FN_HOST auto createTaskKernel(
            TWorkDiv const & workDiv,
            TKernelFnObj const & kernelFnObj,
            TArgs && ... args)
        {
            // check for void return type
            detail::CheckFnReturnType<TAcc>{}(kernelFnObj, args...);

            static_assert(
                dim::Dim<std::decay_t<TWorkDiv>>::value == dim::Dim<TAcc>::value,
                "The dimensions of TAcc and TWorkDiv have to be identical!");
            static_assert(
                std::is_same<idx::Idx<std::decay_t<TWorkDiv>>, idx::Idx<TAcc>>::value,
                "The idx type of TAcc and the idx type of TWorkDiv have to be identical!");

#if ALPAKA_DEBUG >= ALPAKA_DEBUG_FULL
            std::cout << __func__
                << " workDiv: " << workDiv
                << ", kernelFnObj: " << typeid(kernelFnObj).name()
                << std::endl;
#endif
            return
                traits::CreateTaskKernel<
                    TAcc,
                    TWorkDiv,
                    TKernelFnObj,
                    TArgs...>::createTaskKernel(
                        workDiv,
                        kernelFnObj,
                        std::forward<TArgs>(args)...);
        }

#if BOOST_COMP_CLANG
    #pragma clang diagnostic push
    #pragma clang diagnostic ignored "-Wdocumentation"  // clang does not support the syntax for variadic template arguments "args,..."
#endif
        //-----------------------------------------------------------------------------
        //! Executes the given kernel in the given queue.
        //!
        //! \tparam TAcc The accelerator type.
        //! \param queue The queue to enqueue the view copy task into.
        //! \param workDiv The index domain work division.
        //! \param kernelFnObj The kernel function object which should be executed.
        //! \param args,... The kernel invocation arguments.
#if BOOST_COMP_CLANG
    #pragma clang diagnostic pop
#endif
        template<
            typename TAcc,
            typename TQueue,
            typename TWorkDiv,
            typename TKernelFnObj,
            typename... TArgs>
        ALPAKA_FN_HOST auto exec(
            TQueue & queue,
            TWorkDiv const & workDiv,
            TKernelFnObj const & kernelFnObj,
            TArgs && ... args)
        -> void
        {
            queue::enqueue(
                queue,
                kernel::createTaskKernel<
                    TAcc>(
                    workDiv,
                    kernelFnObj,
                    std::forward<TArgs>(args)...));
        }
    }
}
<|endoftext|>


<commit_before>#ifndef APOLLO_CLASS_UTILITY_HPP_INCLUDED
#define APOLLO_CLASS_UTILITY_HPP_INCLUDED APOLLO_CLASS_UTILITY_HPP_INCLUDED

#include <apollo/class.hpp>
#include <apollo/create_table.hpp>
#include <apollo/function.hpp>
#include <apollo/implicit_ctor.hpp>

namespace apollo {

namespace detail {

template <typename Cls, typename Parent>
class class_creator;

template <typename Derived>
class basic_classes_creator: public basic_table_setter<Derived>
{
public:
      basic_classes_creator(lua_State* L, int table_idx)
        : basic_table_setter<Derived>(L, table_idx)
    { }

    template <typename Cls, typename... Bases, typename K>
    class_creator<Cls, Derived> cls(K&& key);
};

class classes_creator: public basic_classes_creator<classes_creator>
{
public:
      classes_creator(lua_State* L, int idx)
        : basic_classes_creator<classes_creator>(L, idx)
    { }
};

template <typename T, typename Parent=void>
class class_creator: public basic_classes_creator<class_creator<T, Parent>> {
public:
    class_creator(lua_State* L, Parent* parent)
        : basic_classes_creator<class_creator<T, Parent>>(L, lua_gettop(L))
        , m_parent(parent)
    { }

    ~class_creator()
    {
        if (!m_parent)
            this->pop_table();
    }

    template<typename... Args>
    class_creator&& ctor(char const* name = "new")
    {
        return (*this)(name, get_raw_ctor_wrapper<T, Args...>());
    }

    // Implicit constructors //

    template<typename... Args>
    class_creator&& implicit_ctor(char const* name)
    {
        implicit_only_ctor<Args...>();
        return ctor<Args...>(name);
    }

    template<typename F>
    class_creator&& implicit_ctor_f(char const* name, F f)
    {
        implicit_only_ctor_f(f);
        return (*this)(name, f);
    }

    template<typename... Args>
    class_creator&& implicit_only_ctor()
    {
        add_implicit_ctor(m_L, &ctor_wrapper<T, Args...>);
        return std::move(*this);
    }

    template<typename F>
    class_creator&& implicit_only_ctor_f(F f)
    {
        add_implicit_ctor(m_L, f);
        return std::move(*this);
    }

    // Misc //

    typename std::add_rvalue_reference<Parent>::type end_cls()
    {
        m_parent->end_subtable();
        return std::move(*m_parent);
        // If you get an error about void here, you called end_cls() after
        // using export_class, but this is only neccessary to end the classes
        // created by .cls().
    }

private:
    Parent* const m_parent; // variant class[es]_creator?

};

template <typename Derived>
template <typename Cls, typename... Bases, typename K>
class_creator<Cls, Derived> basic_classes_creator<Derived>::cls(K&& key)
{
    register_class<Cls, Bases...>(this->m_L);
    push_class_metatable<Cls>(this->m_L);
    this->top_subtable(std::forward<K>(key));
    return {this->m_L, static_cast<Derived*>(this)};
}

} // namespace detail

template <typename T>
struct converter<detail::class_creator<T>>
    : public converter<detail::table_setter>
{};

inline detail::classes_creator export_classes(lua_State* L, int into = 0)
{
    if (!into) {
        lua_newtable(L);
        into = lua_gettop(L);
    }
    return detail::classes_creator(L, lua_absindex(L, into));
}

template <typename T, typename... Bases>
detail::class_creator<T> export_class(lua_State* L)
{
    register_class<T, Bases...>(L);
    push_class_metatable<T>(L);
    return detail::class_creator<T>(L, nullptr);
}

} // namespace apollo

#endif // APOLLO_CLASS_UTILITY_HPP_INCLUDED
<commit_msg>class_utility: Fix clang build.<commit_after>#ifndef APOLLO_CLASS_UTILITY_HPP_INCLUDED
#define APOLLO_CLASS_UTILITY_HPP_INCLUDED APOLLO_CLASS_UTILITY_HPP_INCLUDED

#include <apollo/class.hpp>
#include <apollo/create_table.hpp>
#include <apollo/function.hpp>
#include <apollo/implicit_ctor.hpp>

namespace apollo {

namespace detail {

template <typename Cls, typename Parent>
class class_creator;

template <typename Derived>
class basic_classes_creator: public basic_table_setter<Derived>
{
public:
      basic_classes_creator(lua_State* L, int table_idx)
        : basic_table_setter<Derived>(L, table_idx)
    { }

    template <typename Cls, typename... Bases, typename K>
    class_creator<Cls, Derived> cls(K&& key);
};

class classes_creator: public basic_classes_creator<classes_creator>
{
public:
      classes_creator(lua_State* L, int idx)
        : basic_classes_creator<classes_creator>(L, idx)
    { }
};

template <typename T, typename Parent=void>
class class_creator: public basic_classes_creator<class_creator<T, Parent>> {
public:
    class_creator(lua_State* L, Parent* parent)
        : basic_classes_creator<class_creator<T, Parent>>(L, lua_gettop(L))
        , m_parent(parent)
    { }

    ~class_creator()
    {
        if (!m_parent)
            this->pop_table();
    }

    template<typename... Args>
    class_creator&& ctor(char const* name = "new")
    {
        return (*this)(name, get_raw_ctor_wrapper<T, Args...>());
    }

    // Implicit constructors //

    template<typename... Args>
    class_creator&& implicit_ctor(char const* name)
    {
        implicit_only_ctor<Args...>();
        return ctor<Args...>(name);
    }

    template<typename F>
    class_creator&& implicit_ctor_f(char const* name, F f)
    {
        implicit_only_ctor_f(f);
        return (*this)(name, f);
    }

    template<typename... Args>
    class_creator&& implicit_only_ctor()
    {
        add_implicit_ctor(this->m_L, &ctor_wrapper<T, Args...>);
        return std::move(*this);
    }

    template<typename F>
    class_creator&& implicit_only_ctor_f(F f)
    {
        add_implicit_ctor(this->m_L, f);
        return std::move(*this);
    }

    // Misc //

    typename std::add_rvalue_reference<Parent>::type end_cls()
    {
        m_parent->end_subtable();
        return std::move(*m_parent);
        // If you get an error about void here, you called end_cls() after
        // using export_class, but this is only neccessary to end the classes
        // created by .cls().
    }

private:
    Parent* const m_parent; // variant class[es]_creator?

};

template <typename Derived>
template <typename Cls, typename... Bases, typename K>
class_creator<Cls, Derived> basic_classes_creator<Derived>::cls(K&& key)
{
    register_class<Cls, Bases...>(this->m_L);
    push_class_metatable<Cls>(this->m_L);
    this->top_subtable(std::forward<K>(key));
    return {this->m_L, static_cast<Derived*>(this)};
}

} // namespace detail

template <typename T>
struct converter<detail::class_creator<T>>
    : public converter<detail::table_setter>
{};

inline detail::classes_creator export_classes(lua_State* L, int into = 0)
{
    if (!into) {
        lua_newtable(L);
        into = lua_gettop(L);
    }
    return detail::classes_creator(L, lua_absindex(L, into));
}

template <typename T, typename... Bases>
detail::class_creator<T> export_class(lua_State* L)
{
    register_class<T, Bases...>(L);
    push_class_metatable<T>(L);
    return detail::class_creator<T>(L, nullptr);
}

} // namespace apollo

#endif // APOLLO_CLASS_UTILITY_HPP_INCLUDED
<|endoftext|>


<commit_before>//  (C) Copyright Gennadiy Rozental 2005-2014.
//  Distributed under the Boost Software License, Version 1.0.
//  (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)

//  See http://www.boost.org/libs/test for the library home page.
//
//!@file
//!@brief Defines Unit Test Framework mono-state interfaces.
//! The framework interfaces are based on Monostate design pattern.
// ***************************************************************************

#ifndef BOOST_TEST_FRAMEWORK_HPP_020805GER
#define BOOST_TEST_FRAMEWORK_HPP_020805GER

// Boost.Test
#include <boost/test/detail/global_typedef.hpp>
#include <boost/test/detail/fwd_decl.hpp>
#include <boost/test/detail/throw_exception.hpp>

#include <boost/test/utils/trivial_singleton.hpp>

#include <boost/test/detail/suppress_warnings.hpp>

// STL
#include <stdexcept>

//____________________________________________________________________________//

namespace boost {

/// Main namespace for the Unit Test Framework interfaces and implementation
namespace unit_test {

// ************************************************************************** //
// **************              init_unit_test_func             ************** //
// ************************************************************************** //

/// Test module initialization routine signature

/// Different depending on whether BOOST_TEST_ALTERNATIVE_INIT_API is defined or not
#ifdef BOOST_TEST_ALTERNATIVE_INIT_API
typedef bool        (*init_unit_test_func)();
#else
typedef test_suite* (*init_unit_test_func)( int, char* [] );
#endif

// ************************************************************************** //
// **************                   framework                  ************** //
// ************************************************************************** //

/// Namespace of the Unit Test Framework mono-state
namespace framework {

/// @name Unit Test Framework initialization and shutdown
/// @{

/// @brief This function performs initialization of the framework mono-state.
///
/// It needs to be called every time before the test is started.
/// @param[in] init_func test module initialization routine
/// @param[in] argc command line arguments collection
/// @param[in] argv command line arguments collection
BOOST_TEST_DECL void                init( init_unit_test_func init_func, int argc, char* argv[] );

/// This function applies all the decorators and figures out default run status. This argument facilitates an
/// ability of the test cases to prepare some other test units (primarily used internally for self testing)
/// @param[in] tu Optional id of the test unit representing root of test tree. If absent, master test suite is used
BOOST_TEST_DECL void                finalize_setup_phase( test_unit_id tu = INV_TEST_UNIT_ID);

/// This function returns true when testing is in progress (setup is finished)
BOOST_TEST_DECL bool                test_in_progress();

/// This function shuts down the framework and clears up its mono-state.
///
/// It needs to be at the very end of test module execution
BOOST_TEST_DECL void    shutdown();
/// @}

/// @name Test unit registration
/// @{

/// Provides both read and write access to current "leaf" auto test suite during the test unit registration phase.
///
/// During auto-registration phase the framework maintain a FIFO queue of test units being registered. New test units become children
/// of the current "leaf" test suite and if this is test suite it is pushed back into queue and becomes a new leaf.
/// When test suite registration is completed, a test suite is popped from the back of the queue. Only automatically registered test suites
/// should be added to this queue. Master test suite is always a zero element in this queue, so if no other test suites are registered
/// all test cases are added to master test suite.

/// This function facilitates all three possible actions:
///    - if no argument are provided it returns the current queue leaf test suite
///    - if test suite is provided and no second argument are set, test suite is added to the queue
///    - if no test suite are provided and last argument is false, the semantic of this function is similar to queue pop: last element is popped from the queue
/// @param[in] ts test suite to push back to the queue
/// @param[in] push_or_pop should we push ts to the queue or pop leaf test suite instead
/// @returns a reference to the currently active/"leaf" test suite
BOOST_TEST_DECL test_suite&         current_auto_test_suite( test_suite* ts = 0, bool push_or_pop = true );

/// This function add new test case into the global collection of test units the framework aware of.

/// This function also assignes unique test unit id for every test case. Later on one can use this id to locate
/// the test case if necessary. This is the way for the framework to maintain weak references between test units.
/// @param[in]  tc  test case to register
BOOST_TEST_DECL void                register_test_unit( test_case* tc );

/// This function add new test suite into the global collection of test units the framework aware of.

/// This function also assignes unique test unit id for every test suite. Later on one can use this id to locate
/// the test case if necessary. This is the way for the framework to maintain weak references between test units.
/// @param[in]  ts  test suite to register
BOOST_TEST_DECL void                register_test_unit( test_suite* ts );

/// This function removes the test unit from the collection of known test units and destroys the test unit object.

/// This function also assigns unique test unit id for every test case. Later on one can use this id to located
/// the test case if necessary. This is the way for the framework to maintain weak references between test units.
/// @param[in]  tu  test unit to deregister
BOOST_TEST_DECL void                deregister_test_unit( test_unit* tu );

// This function clears up the framework mono-state.

/// Afer this call the framework can be reinitialized to perform a second test run during the same program lifetime
BOOST_TEST_DECL void                clear();
/// @}

/// @name Test observer registration
/// @{
/// Adds new test execution observer object into the framework's list of test observers.

/// Observer lifetime should exceed the the testing execution timeframe
/// @param[in]  to  test observer object to add
BOOST_TEST_DECL void                register_observer( test_observer& to );

/// Excldes the observer object form the framework's list of test observers
/// @param[in]  to  test observer object to exclude
BOOST_TEST_DECL void                deregister_observer( test_observer& to );

/// @}

/// @name Assertion/uncaught exception context support
/// @{
/// Context accessor
struct BOOST_TEST_DECL context_generator {
    context_generator() : m_curr_frame( 0 ) {}

    /// Is there any context?
    bool            is_empty() const;

    /// Give me next frame; empty - last frame
    const_string    next() const;

private:
    // Data members
    mutable unsigned m_curr_frame;
};

/// Records context frame message

/// Some context frames are sticky - they can only explicitly cleared by specifying context id. Other (non sticky) context frames cleared after every assertion.
/// @param[in] context_descr context frame message
/// @param[in] sticky is this sticky frame or not
/// @returns id of the newly created frame
BOOST_TEST_DECL int                 add_context( lazy_ostream const& context_descr, bool sticky );
/// Erases context frame (when test exits context scope)

/// If context_id is passed clears that specific context frame identified by this id, otherwise clears all non sticky contexts
BOOST_TEST_DECL void                clear_context( int context_id = -1 );
/// Produces an instance of small "delegate" object, which facilitates access to collected context
BOOST_TEST_DECL context_generator   get_context();
/// @}

/// @name Access to registered test units
/// @{
/// This function provides access to the master test suite.

/// There is only only master test suite per test module.
/// @returns a reference the master test suite instance
BOOST_TEST_DECL master_test_suite_t& master_test_suite();

/// This function provides an access to the test case currently being executed

/// This function is only valid  during test execution phase
/// @see current_test_case_id
BOOST_TEST_DECL test_case const&    current_test_case();

/// This function provides an access to an id of the test case currently being executed

/// This function safer than current_test_case, cause if wont throw if no test case is being executed.
/// @see current_test_case
BOOST_TEST_DECL test_unit_id        current_test_case_id(); /* safe version of above */

/// This function provides access to a test unit by id and type combination. It will throw if no test unit located
/// @param[in]  tu_id    id of a test unit to locate
/// @param[in]  tu_type  type of a test unit to locate
/// @returns located test unit
BOOST_TEST_DECL test_unit&          get( test_unit_id tu_id, test_unit_type tu_type );

/// This function template provides access to a typed test unit by id

/// It will throw if you specify incorrect test unit type
/// @tparam UnitType compile time type of test unit to get (test_suite or test_case)
/// @param  id id of test unit to get
template<typename UnitType>
inline UnitType&                    get( test_unit_id id )
{
    return static_cast<UnitType&>( get( id, static_cast<test_unit_type>(UnitType::type) ) );
}
///@}

/// @name Test initiation interface
/// @{

/// Initiates test execution

/// This function is used to start the test execution from a specific "root" test unit.
/// If no root provided, test is started from master test suite. This second argument facilitates an ability of the test cases to
/// start some other test units (primarily used internally for self testing)
/// @param[in] tu Optional id of the test unit or test unit itself from which the test is started. If absent, master test suite is used
/// @param[in] continue_test true == continue test if it was already started, false == restart the test from scratch regardless
BOOST_TEST_DECL void                run( test_unit_id tu = INV_TEST_UNIT_ID, bool continue_test = true );
/// Initiates test execution. Same as other overload
BOOST_TEST_DECL void                run( test_unit const* tu, bool continue_test = true );
/// @}

/// @name Test events dispatchers
/// @{
/// Reports results of assertion to all test observers
BOOST_TEST_DECL void                assertion_result( unit_test::assertion_result ar );
/// Reports uncaught exception to all test observers
BOOST_TEST_DECL void                exception_caught( execution_exception const& );
/// Reports aborted test unit to all test observers
BOOST_TEST_DECL void                test_unit_aborted( test_unit const& );
/// @}

namespace impl {
// exclusively for self test
BOOST_TEST_DECL void                setup_for_execution( test_unit const& );
} // namespace impl

// ************************************************************************** //
// **************                framework errors              ************** //
// ************************************************************************** //

/// This exception type is used to report internal Boost.Test framework errors
struct BOOST_TEST_DECL internal_error : public std::runtime_error {
    internal_error( const_string m ) : std::runtime_error( std::string( m.begin(), m.size() ) ) {}
};

//____________________________________________________________________________//

/// This exception type is used to report test module setup errors
struct BOOST_TEST_DECL setup_error : public std::runtime_error {
    setup_error( const_string m ) : std::runtime_error( std::string( m.begin(), m.size() ) ) {}
};

#define BOOST_TEST_SETUP_ASSERT( cond, msg ) \
    if( cond ) {} \
    else BOOST_TEST_IMPL_THROW( unit_test::framework::setup_error( msg ) )

//____________________________________________________________________________//

struct nothing_to_test {}; // not really an error

//____________________________________________________________________________//

} // namespace framework
} // unit_test
} // namespace boost

#include <boost/test/detail/enable_warnings.hpp>

#endif // BOOST_TEST_FRAMEWORK_HPP_020805GER

<commit_msg>few comments fixed<commit_after>//  (C) Copyright Gennadiy Rozental 2005-2014.
//  Distributed under the Boost Software License, Version 1.0.
//  (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)

//  See http://www.boost.org/libs/test for the library home page.
//
//!@file
//!@brief Defines Unit Test Framework mono-state interfaces.
//! The framework interfaces are based on Monostate design pattern.
// ***************************************************************************

#ifndef BOOST_TEST_FRAMEWORK_HPP_020805GER
#define BOOST_TEST_FRAMEWORK_HPP_020805GER

// Boost.Test
#include <boost/test/detail/global_typedef.hpp>
#include <boost/test/detail/fwd_decl.hpp>
#include <boost/test/detail/throw_exception.hpp>

#include <boost/test/utils/trivial_singleton.hpp>

#include <boost/test/detail/suppress_warnings.hpp>

// STL
#include <stdexcept>

//____________________________________________________________________________//

namespace boost {

/// Main namespace for the Unit Test Framework interfaces and implementation
namespace unit_test {

// ************************************************************************** //
// **************              init_unit_test_func             ************** //
// ************************************************************************** //

/// Test module initialization routine signature

/// Different depending on whether BOOST_TEST_ALTERNATIVE_INIT_API is defined or not
#ifdef BOOST_TEST_ALTERNATIVE_INIT_API
typedef bool        (*init_unit_test_func)();
#else
typedef test_suite* (*init_unit_test_func)( int, char* [] );
#endif

// ************************************************************************** //
// **************                   framework                  ************** //
// ************************************************************************** //

/// Namespace of the Unit Test Framework mono-state
namespace framework {

/// @name Unit Test Framework initialization and shutdown
/// @{

/// @brief This function performs initialization of the framework mono-state.
///
/// It needs to be called every time before the test is started.
/// @param[in] init_func test module initialization routine
/// @param[in] argc command line arguments collection
/// @param[in] argv command line arguments collection
BOOST_TEST_DECL void                init( init_unit_test_func init_func, int argc, char* argv[] );

/// This function applies all the decorators and figures out default run status. This argument facilitates an
/// ability of the test cases to prepare some other test units (primarily used internally for self testing).
/// @param[in] tu Optional id of the test unit representing root of test tree. If absent, master test suite is used
BOOST_TEST_DECL void                finalize_setup_phase( test_unit_id tu = INV_TEST_UNIT_ID);

/// This function returns true when testing is in progress (setup is finished).
BOOST_TEST_DECL bool                test_in_progress();

/// This function shuts down the framework and clears up its mono-state.
///
/// It needs to be at the very end of test module execution
BOOST_TEST_DECL void    shutdown();
/// @}

/// @name Test unit registration
/// @{

/// Provides both read and write access to current "leaf" auto test suite during the test unit registration phase.
///
/// During auto-registration phase the framework maintain a FIFO queue of test units being registered. New test units become children
/// of the current "leaf" test suite and if this is test suite it is pushed back into queue and becomes a new leaf.
/// When test suite registration is completed, a test suite is popped from the back of the queue. Only automatically registered test suites
/// should be added to this queue. Master test suite is always a zero element in this queue, so if no other test suites are registered
/// all test cases are added to master test suite.

/// This function facilitates all three possible actions:
///    - if no argument are provided it returns the current queue leaf test suite
///    - if test suite is provided and no second argument are set, test suite is added to the queue
///    - if no test suite are provided and last argument is false, the semantic of this function is similar to queue pop: last element is popped from the queue
/// @param[in] ts test suite to push back to the queue
/// @param[in] push_or_pop should we push ts to the queue or pop leaf test suite instead
/// @returns a reference to the currently active/"leaf" test suite
BOOST_TEST_DECL test_suite&         current_auto_test_suite( test_suite* ts = 0, bool push_or_pop = true );

/// This function add new test case into the global collection of test units the framework aware of.

/// This function also assignes unique test unit id for every test case. Later on one can use this id to locate
/// the test case if necessary. This is the way for the framework to maintain weak references between test units.
/// @param[in]  tc  test case to register
BOOST_TEST_DECL void                register_test_unit( test_case* tc );

/// This function add new test suite into the global collection of test units the framework aware of.

/// This function also assignes unique test unit id for every test suite. Later on one can use this id to locate
/// the test case if necessary. This is the way for the framework to maintain weak references between test units.
/// @param[in]  ts  test suite to register
BOOST_TEST_DECL void                register_test_unit( test_suite* ts );

/// This function removes the test unit from the collection of known test units and destroys the test unit object.

/// This function also assigns unique test unit id for every test case. Later on one can use this id to located
/// the test case if necessary. This is the way for the framework to maintain weak references between test units.
/// @param[in]  tu  test unit to deregister
BOOST_TEST_DECL void                deregister_test_unit( test_unit* tu );

// This function clears up the framework mono-state.

/// Afer this call the framework can be reinitialized to perform a second test run during the same program lifetime.
BOOST_TEST_DECL void                clear();
/// @}

/// @name Test observer registration
/// @{
/// Adds new test execution observer object into the framework's list of test observers.

/// Observer lifetime should exceed the the testing execution timeframe
/// @param[in]  to  test observer object to add
BOOST_TEST_DECL void                register_observer( test_observer& to );

/// Excldes the observer object form the framework's list of test observers
/// @param[in]  to  test observer object to exclude
BOOST_TEST_DECL void                deregister_observer( test_observer& to );

/// @}

/// @name Assertion/uncaught exception context support
/// @{
/// Context accessor
struct BOOST_TEST_DECL context_generator {
    context_generator() : m_curr_frame( 0 ) {}

    /// Is there any context?
    bool            is_empty() const;

    /// Give me next frame; empty - last frame
    const_string    next() const;

private:
    // Data members
    mutable unsigned m_curr_frame;
};

/// Records context frame message.

/// Some context frames are sticky - they can only explicitly cleared by specifying context id. Other (non sticky) context frames cleared after every assertion.
/// @param[in] context_descr context frame message
/// @param[in] sticky is this sticky frame or not
/// @returns id of the newly created frame
BOOST_TEST_DECL int                 add_context( lazy_ostream const& context_descr, bool sticky );
/// Erases context frame (when test exits context scope)

/// If context_id is passed clears that specific context frame identified by this id, otherwise clears all non sticky contexts.
BOOST_TEST_DECL void                clear_context( int context_id = -1 );
/// Produces an instance of small "delegate" object, which facilitates access to collected context.
BOOST_TEST_DECL context_generator   get_context();
/// @}

/// @name Access to registered test units.
/// @{
/// This function provides access to the master test suite.

/// There is only only master test suite per test module.
/// @returns a reference the master test suite instance
BOOST_TEST_DECL master_test_suite_t& master_test_suite();

/// This function provides an access to the test case currently being executed.

/// This function is only valid during test execution phase.
/// @see current_test_case_id
BOOST_TEST_DECL test_case const&    current_test_case();

/// This function provides an access to an id of the test case currently being executed.

/// This function safer than current_test_case, cause if wont throw if no test case is being executed.
/// @see current_test_case
BOOST_TEST_DECL test_unit_id        current_test_case_id(); /* safe version of above */

/// This function provides access to a test unit by id and type combination. It will throw if no test unit located.
/// @param[in]  tu_id    id of a test unit to locate
/// @param[in]  tu_type  type of a test unit to locate
/// @returns located test unit
BOOST_TEST_DECL test_unit&          get( test_unit_id tu_id, test_unit_type tu_type );

/// This function template provides access to a typed test unit by id

/// It will throw if you specify incorrect test unit type
/// @tparam UnitType compile time type of test unit to get (test_suite or test_case)
/// @param  id id of test unit to get
template<typename UnitType>
inline UnitType&                    get( test_unit_id id )
{
    return static_cast<UnitType&>( get( id, static_cast<test_unit_type>(UnitType::type) ) );
}
///@}

/// @name Test initiation interface
/// @{

/// Initiates test execution

/// This function is used to start the test execution from a specific "root" test unit.
/// If no root provided, test is started from master test suite. This second argument facilitates an ability of the test cases to
/// start some other test units (primarily used internally for self testing).
/// @param[in] tu Optional id of the test unit or test unit itself from which the test is started. If absent, master test suite is used
/// @param[in] continue_test true == continue test if it was already started, false == restart the test from scratch regardless
BOOST_TEST_DECL void                run( test_unit_id tu = INV_TEST_UNIT_ID, bool continue_test = true );
/// Initiates test execution. Same as other overload
BOOST_TEST_DECL void                run( test_unit const* tu, bool continue_test = true );
/// @}

/// @name Test events dispatchers
/// @{
/// Reports results of assertion to all test observers
BOOST_TEST_DECL void                assertion_result( unit_test::assertion_result ar );
/// Reports uncaught exception to all test observers
BOOST_TEST_DECL void                exception_caught( execution_exception const& );
/// Reports aborted test unit to all test observers
BOOST_TEST_DECL void                test_unit_aborted( test_unit const& );
/// @}

namespace impl {
// exclusively for self test
BOOST_TEST_DECL void                setup_for_execution( test_unit const& );
} // namespace impl

// ************************************************************************** //
// **************                framework errors              ************** //
// ************************************************************************** //

/// This exception type is used to report internal Boost.Test framework errors.
struct BOOST_TEST_DECL internal_error : public std::runtime_error {
    internal_error( const_string m ) : std::runtime_error( std::string( m.begin(), m.size() ) ) {}
};

//____________________________________________________________________________//

/// This exception type is used to report test module setup errors.
struct BOOST_TEST_DECL setup_error : public std::runtime_error {
    setup_error( const_string m ) : std::runtime_error( std::string( m.begin(), m.size() ) ) {}
};

#define BOOST_TEST_SETUP_ASSERT( cond, msg ) \
    if( cond ) {} \
    else BOOST_TEST_IMPL_THROW( unit_test::framework::setup_error( msg ) )

//____________________________________________________________________________//

struct nothing_to_test {}; // not really an error

//____________________________________________________________________________//

} // namespace framework
} // unit_test
} // namespace boost

#include <boost/test/detail/enable_warnings.hpp>

#endif // BOOST_TEST_FRAMEWORK_HPP_020805GER

<|endoftext|>


<commit_before>#pragma once

/*
 * Factories for variable names.
 */

#include <crab/common/types.hpp>

#include <boost/optional.hpp>
#include <boost/range/iterator_range.hpp>

#include <functional>
#include <limits>
#include <unordered_map>
#include <vector>

namespace crab {
namespace cfg {
namespace var_factory_impl {
namespace indexed_string_impl {
template <typename T> inline std::string get_str(T e);

template <> inline std::string get_str(std::string e) { return e; }
} // namespace indexed_string_impl

// This variable factory creates a new variable associated to an
// element of type T. It can also create variables that are not
// associated to an element of type T. We call them shadow variables.
//
// The factory uses a counter of type index_t to generate variable
// id's that always increases.
template <class T> class variable_factory {
  typedef variable_factory<T> variable_factory_t;

public:
  class indexed_string {
    template <typename Any> friend class variable_factory;

  public:
    // FIXME: we should use some unlimited precision type to avoid
    // overflow. However, this change is a bit involving since we
    // need to change the algorithm api's in patricia_trees.hpp because
    // they assume ikos::index_t.
    typedef ikos::index_t index_t;

  private:
    boost::optional<T> _s;
    index_t _id;
    std::string _name; // optional string name associated with _id
    variable_factory *_vfac;

    // NOT IMPLEMENTED
    indexed_string();

    indexed_string(index_t id, variable_factory *vfac, std::string name = "")
        : _id(id), _name(name), _vfac(vfac) {}

    indexed_string(T s, index_t id, variable_factory *vfac)
        : _s(s), _id(id), _name(""), _vfac(vfac) {}

  public:
    ~indexed_string() {}

    indexed_string(const indexed_string &is)
        : _s(is._s), _id(is._id), _name(is._name), _vfac(is._vfac) {}

    indexed_string &operator=(const indexed_string &is) {
      if (this != &is) {
        _s = is._s;
        _id = is._id;
        _name = is._name;
        _vfac = is._vfac;
      }
      return *this;
    }

    index_t index() const { return this->_id; }

    std::string str() const {
      if (_s) {
        return indexed_string_impl::get_str<T>(*_s);
      } else {
        if (_name != "") {
          return _name;
        } else {
          // unlikely prefix
          return "@V_" + std::to_string(_id);
        }
      }
    }

    boost::optional<T> get() const { return _s ? *_s : boost::optional<T>(); }

    variable_factory &get_var_factory() { return *_vfac; }

    bool operator<(indexed_string s) const { return (_id < s._id); }

    bool operator==(indexed_string s) const { return (_id == s._id); }

    void write(crab_os &o) const { o << str(); }

    friend crab_os &operator<<(crab_os &o, indexed_string s) {
      o << s.str();
      return o;
    }

    friend size_t hash_value(indexed_string s) {
      std::hash<index_t> hasher;
      return hasher(s.index());
    }
  };

public:
  typedef typename indexed_string::index_t index_t;

private:
  typedef std::unordered_map<T, indexed_string> t_map_t;
  typedef std::unordered_map<index_t, indexed_string> shadow_map_t;

  index_t _next_id;
  t_map_t _map;
  shadow_map_t _shadow_map;
  std::vector<indexed_string> _shadow_vars;

  index_t get_and_increment_id(void) {
    if (_next_id == std::numeric_limits<index_t>::max()) {
      CRAB_ERROR("Reached limit of ", std::numeric_limits<index_t>::max(),
                 " variables");
    }
    index_t res = _next_id;
    ++_next_id;
    return res;
  }

public:
  typedef indexed_string varname_t;
  typedef boost::iterator_range<typename std::vector<indexed_string>::iterator>
      var_range;
  typedef boost::iterator_range<
      typename std::vector<indexed_string>::const_iterator>
      const_var_range;

public:
  variable_factory() : _next_id(1) {}

  variable_factory(index_t start_id) : _next_id(start_id) {}

  variable_factory(const variable_factory_t &o) = delete;

  variable_factory_t &operator=(const variable_factory_t &o) = delete;

  virtual ~variable_factory() {}

  // hook for generating indexed_string's without being
  // associated with a particular T (w/o caching).
  // XXX: do not use it unless strictly necessary.
  virtual indexed_string get(std::string name = "") {
    indexed_string is(get_and_increment_id(), this, name);
    _shadow_vars.push_back(is);
    return is;
  }

  // generate a shadow indexed_string's associated to some key
  virtual indexed_string get(index_t key, std::string name = "") {
    auto it = _shadow_map.find(key);
    if (it == _shadow_map.end()) {
      indexed_string is(get_and_increment_id(), this, name);
      _shadow_map.insert(typename shadow_map_t::value_type(key, is));
      _shadow_vars.push_back(is);
      return is;
    } else {
      return it->second;
    }
  }

  virtual indexed_string operator[](T s) {
    auto it = _map.find(s);
    if (it == _map.end()) {
      indexed_string is(s, get_and_increment_id(), this);
      _map.insert(typename t_map_t::value_type(s, is));
      return is;
    } else {
      return it->second;
    }
  }

  // return all the shadow variables created by the factory.
  virtual const_var_range get_shadow_vars() const {
    return boost::make_iterator_range(_shadow_vars.begin(), _shadow_vars.end());
  }
};

//! Specialized factory for strings
class str_variable_factory : public variable_factory<std::string> {
  typedef variable_factory<std::string> variable_factory_t;

public:
  typedef variable_factory_t::varname_t varname_t;
  typedef variable_factory_t::const_var_range const_var_range;
  typedef variable_factory_t::index_t index_t;

  str_variable_factory() : variable_factory_t() {}
};

//! Specialized factory for integers
class int_variable_factory {
public:
  typedef int varname_t;

  int_variable_factory() {}

  int_variable_factory(const int_variable_factory &o) = delete;

  int_variable_factory &operator=(const int_variable_factory &o) = delete;

  varname_t operator[](int v) { return v; }
};

inline int fresh_colour(int col_x, int col_y) {
  switch (col_x) {
  case 0:
    return col_y == 1 ? 2 : 1;
  case 1:
    return col_y == 0 ? 2 : 0;
  case 2:
    return col_y == 0 ? 1 : 0;
  default:
    CRAB_ERROR("Unreachable");
  }
}

//! Three-coloured variable allocation. So the number of variables
//  is bounded by 3|Tbl|, rather than always increasing.
class str_var_alloc_col {
  static const char **col_prefix;

public:
  typedef str_variable_factory::varname_t varname_t;
  static str_variable_factory vfac;

  str_var_alloc_col() : colour(0), next_id(0) {}

  str_var_alloc_col(const str_var_alloc_col &o)
      : colour(o.colour), next_id(o.next_id) {}

  str_var_alloc_col(const str_var_alloc_col &x, const str_var_alloc_col &y)
      : colour(fresh_colour(x.colour, y.colour)), next_id(0) {
    assert(colour != x.colour);
    assert(colour != y.colour);
  }

  str_var_alloc_col &operator=(const str_var_alloc_col &x) {
    colour = x.colour;
    next_id = x.next_id;
    return *this;
  }

  str_variable_factory::varname_t next() {
    std::string v = col_prefix[colour] + std::to_string(next_id++);
    return vfac[v];
  }

protected:
  int colour;
  int next_id;
};

class int_var_alloc_col {
public:
  typedef int varname_t;
  static int_variable_factory vfac;

  int_var_alloc_col() : colour(0), next_id(0) {}

  int_var_alloc_col(const int_var_alloc_col &o)
      : colour(o.colour), next_id(o.next_id) {}

  int_var_alloc_col(const int_var_alloc_col &x, const int_var_alloc_col &y)
      : colour(fresh_colour(x.colour, y.colour)), next_id(0) {
    assert(colour != x.colour);
    assert(colour != y.colour);
  }

  int_var_alloc_col &operator=(const int_var_alloc_col &x) {
    colour = x.colour;
    next_id = x.next_id;
    return *this;
  }

  int_variable_factory::varname_t next() {
    int id = next_id++;
    return 3 * id + colour;
  }

protected:
  int colour;
  int next_id;
};

} // end namespace var_factory_impl
} // end namespace cfg
} // end namespace crab
<commit_msg>refactor(var_factory): add namespace to index_t<commit_after>#pragma once

/*
 * Factories for variable names.
 */

#include <crab/common/types.hpp>

#include <boost/optional.hpp>
#include <boost/range/iterator_range.hpp>

#include <functional>
#include <limits>
#include <unordered_map>
#include <vector>

namespace crab {
namespace cfg {
namespace var_factory_impl {
namespace indexed_string_impl {
template <typename T> inline std::string get_str(T e);

template <> inline std::string get_str(std::string e) { return e; }
} // namespace indexed_string_impl

// This variable factory creates a new variable associated to an
// element of type T. It can also create variables that are not
// associated to an element of type T. We call them shadow variables.
//
// The factory uses a counter of type index_t to generate variable
// id's that always increases.
template <class T> class variable_factory {
  typedef variable_factory<T> variable_factory_t;

public:
  class indexed_string {
    template <typename Any> friend class variable_factory;
    boost::optional<T> _s;
    ikos::index_t _id;
    std::string _name; // optional string name associated with _id
    variable_factory *_vfac;

    // NOT IMPLEMENTED
    indexed_string();

    indexed_string(ikos::index_t id, variable_factory *vfac, std::string name = "")
        : _id(id), _name(name), _vfac(vfac) {}

    indexed_string(T s, ikos::index_t id, variable_factory *vfac)
        : _s(s), _id(id), _name(""), _vfac(vfac) {}

  public:
    ~indexed_string() {}

    indexed_string(const indexed_string &is)
        : _s(is._s), _id(is._id), _name(is._name), _vfac(is._vfac) {}

    indexed_string &operator=(const indexed_string &is) {
      if (this != &is) {
        _s = is._s;
        _id = is._id;
        _name = is._name;
        _vfac = is._vfac;
      }
      return *this;
    }

    ikos::index_t index() const { return this->_id; }

    std::string str() const {
      if (_s) {
        return indexed_string_impl::get_str<T>(*_s);
      } else {
        if (_name != "") {
          return _name;
        } else {
          // unlikely prefix
          return "@V_" + std::to_string(_id);
        }
      }
    }

    boost::optional<T> get() const { return _s ? *_s : boost::optional<T>(); }

    variable_factory &get_var_factory() { return *_vfac; }

    bool operator<(indexed_string s) const { return (_id < s._id); }

    bool operator==(indexed_string s) const { return (_id == s._id); }

    void write(crab_os &o) const { o << str(); }

    friend crab_os &operator<<(crab_os &o, indexed_string s) {
      o << s.str();
      return o;
    }

    friend size_t hash_value(indexed_string s) {
      std::hash<ikos::index_t> hasher;
      return hasher(s.index());
    }
  };

private:
  typedef std::unordered_map<T, indexed_string> t_map_t;
  typedef std::unordered_map<ikos::index_t, indexed_string> shadow_map_t;

  ikos::index_t _next_id;
  t_map_t _map;
  shadow_map_t _shadow_map;
  std::vector<indexed_string> _shadow_vars;

  ikos::index_t get_and_increment_id(void) {
    if (_next_id == std::numeric_limits<ikos::index_t>::max()) {
      CRAB_ERROR("Reached limit of ", std::numeric_limits<ikos::index_t>::max(),
                 " variables");
    }
    ikos::index_t res = _next_id;
    ++_next_id;
    return res;
  }

public:
  typedef indexed_string varname_t;
  typedef boost::iterator_range<typename std::vector<indexed_string>::iterator>
      var_range;
  typedef boost::iterator_range<
      typename std::vector<indexed_string>::const_iterator>
      const_var_range;

public:
  variable_factory() : _next_id(1) {}

  variable_factory(ikos::index_t start_id) : _next_id(start_id) {}

  variable_factory(const variable_factory_t &o) = delete;

  variable_factory_t &operator=(const variable_factory_t &o) = delete;

  virtual ~variable_factory() {}

  // hook for generating indexed_string's without being
  // associated with a particular T (w/o caching).
  // XXX: do not use it unless strictly necessary.
  virtual indexed_string get(std::string name = "") {
    indexed_string is(get_and_increment_id(), this, name);
    _shadow_vars.push_back(is);
    return is;
  }

  // generate a shadow indexed_string's associated to some key
  virtual indexed_string get(ikos::index_t key, std::string name = "") {
    auto it = _shadow_map.find(key);
    if (it == _shadow_map.end()) {
      indexed_string is(get_and_increment_id(), this, name);
      _shadow_map.insert(typename shadow_map_t::value_type(key, is));
      _shadow_vars.push_back(is);
      return is;
    } else {
      return it->second;
    }
  }

  virtual indexed_string operator[](T s) {
    auto it = _map.find(s);
    if (it == _map.end()) {
      indexed_string is(s, get_and_increment_id(), this);
      _map.insert(typename t_map_t::value_type(s, is));
      return is;
    } else {
      return it->second;
    }
  }

  // return all the shadow variables created by the factory.
  virtual const_var_range get_shadow_vars() const {
    return boost::make_iterator_range(_shadow_vars.begin(), _shadow_vars.end());
  }
};

//! Specialized factory for strings
class str_variable_factory : public variable_factory<std::string> {
  typedef variable_factory<std::string> variable_factory_t;

public:
  typedef variable_factory_t::varname_t varname_t;
  typedef variable_factory_t::const_var_range const_var_range;

  str_variable_factory() : variable_factory_t() {}
};

//! Specialized factory for integers
class int_variable_factory {
public:
  typedef ikos::index_t varname_t;

  int_variable_factory() {}

  int_variable_factory(const int_variable_factory &o) = delete;

  int_variable_factory &operator=(const int_variable_factory &o) = delete;

  varname_t operator[](ikos::index_t v) { return v; }
};

inline int fresh_colour(int col_x, int col_y) {
  switch (col_x) {
  case 0:
    return col_y == 1 ? 2 : 1;
  case 1:
    return col_y == 0 ? 2 : 0;
  case 2:
    return col_y == 0 ? 1 : 0;
  default:
    CRAB_ERROR("Unreachable");
  }
}

//! Three-coloured variable allocation. So the number of variables
//  is bounded by 3|Tbl|, rather than always increasing.
class str_var_alloc_col {
  static const char **col_prefix;

public:
  typedef str_variable_factory::varname_t varname_t;
  static str_variable_factory vfac;

  str_var_alloc_col() : colour(0), next_id(0) {}

  str_var_alloc_col(const str_var_alloc_col &o)
      : colour(o.colour), next_id(o.next_id) {}

  str_var_alloc_col(const str_var_alloc_col &x, const str_var_alloc_col &y)
      : colour(fresh_colour(x.colour, y.colour)), next_id(0) {
    assert(colour != x.colour);
    assert(colour != y.colour);
  }

  str_var_alloc_col &operator=(const str_var_alloc_col &x) {
    colour = x.colour;
    next_id = x.next_id;
    return *this;
  }

  str_variable_factory::varname_t next() {
    std::string v = col_prefix[colour] + std::to_string(next_id++);
    return vfac[v];
  }

protected:
  int colour;
  ikos::index_t next_id;
};

class int_var_alloc_col {
public:
  typedef ikos::index_t varname_t;
  static int_variable_factory vfac;

  int_var_alloc_col() : colour(0), next_id(0) {}

  int_var_alloc_col(const int_var_alloc_col &o)
      : colour(o.colour), next_id(o.next_id) {}

  int_var_alloc_col(const int_var_alloc_col &x, const int_var_alloc_col &y)
      : colour(fresh_colour(x.colour, y.colour)), next_id(0) {
    assert(colour != x.colour);
    assert(colour != y.colour);
  }

  int_var_alloc_col &operator=(const int_var_alloc_col &x) {
    colour = x.colour;
    next_id = x.next_id;
    return *this;
  }

  int_variable_factory::varname_t next() {
    ikos::index_t id = next_id++;
    return 3 * id + colour;
  }

protected:
  int colour;
  ikos::index_t next_id;
};

} // end namespace var_factory_impl
} // end namespace cfg
} // end namespace crab
<|endoftext|>