// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
// All rights not expressly granted are reserved.
//
// This software is distributed under the terms of the GNU General Public
// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
//
// In applying this license CERN does not waive the privileges and immunities
// granted to it by virtue of its status as an Intergovernmental Organization
// or submit itself to any jurisdiction.
//-*- Mode: C++ -*-
#ifndef MPL_TOOLS_H
#define MPL_TOOLS_H
//****************************************************************************
//* This file 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. *
//* *
//* Primary Authors: Matthias Richter *
//* *
//* The authors make no claims about the suitability of this software for *
//* any purpose. It is provided "as is" without express or implied warranty. *
//****************************************************************************
// @file mpl_tools.h
// @author Matthias Richter
// @since 2016-09-09
// @brief Tools for using the boost MPL
#include
#include
#include
#include
#include
using boost::mpl::placeholders::_;
using boost::mpl::placeholders::_1;
using boost::mpl::placeholders::_2;
namespace o2
{
namespace mpl
{
/**
* @brief type trait to transparently use sequences of types
* This type trait simply forwards to the given type if it is already a
* sequence but wraps any non-sequence type into an mpl vector with one entry.
*
* Usage: make_mpl_vector::type
* make_mpl_vector::isSequence
*/
template
class make_mpl_vector
{
private:
// the default implementaton of this trait expects the type T to be an
// mpl sequence with a begin meta function.
template
struct VectorTraits {
enum { result = true };
using type = typename U::type;
};
// specialization for non sequences, for any data type which has no
// begin meta function defined, the iterator is void type and this
// specialization kicks in. The specialization wraps the type into
// a sequence with one entry
template
struct VectorTraits {
enum { result = false };
using type = typename boost::mpl::fold<:mpl::vector>, //
boost::mpl::set, //
boost::mpl::insert<:mpl::_1 u> //
>::type; //
};
public:
/// iSequence tells if the original type is a sequence
enum { isSequence = VectorTraits::type>::result };
/// the tarits type, always a sequence
using type = typename VectorTraits::type>::type;
};
/******************************************************************************
* @brief Meta program to create a vector of wrapped types from a sequencs
* of types. A new mpl vector containing Wrapper for every
* element of the original sequence is created
* mpl::fold recursivly applies the elements of the list to the previous result
* placeholder _2 refers to the element, placeholder _1 to the previous result
* or initial condition for the first element
*/
template
struct do_typewrap {
using type = typename boost::mpl::fold< //
Seq, //
boost::mpl::vector<>, //
boost::mpl::push_back<_1, boost::mpl::bind1> //
>::type;
};
/******************************************************************************
* @brief apply functor to element at mpl sequence position
* This meta function recurses through the list while incrementing the index
* and calls the functor at the required position
*
* @note this is a helper macro to the apply_at function
*/
template
struct apply_at_sequence_position {
static _ReturnT apply(_IndexT position, F f)
{
if (position == _Index) {
// this is the queried position, execute function and
// terminate loop by forwarding _End as _Iterator and thus
// calling the specialization
// TODO: check the performance penalty of the element instantiation
typename boost::mpl::deref<_Iterator>::type element;
return f(element);
} else {
// go to next element
return apply_at_sequence_position< //
_IndexT, //
typename boost::mpl::next<_Iterator>::type, //
_End, //
_ReturnT, //
_Index + 1, //
F //
>::apply(position, f);
}
}
};
// specialization: end of recursive loop, kicks in if _Iterator matches
// _End.
// here we end up if the position parameter is out of bounds
template
struct apply_at_sequence_position<_IndexT, _End, _End, _ReturnT, _Index, F> {
static _ReturnT apply(_IndexT position, F f)
{
// TODO: this is probably the place to through an exeption because
// we are out of bound
return _ReturnT(0);
}
};
/******************************************************************************
* @brief A default functor with void return type and no operation
*/
struct defaultFunctor {
using return_type = void;
template
return_type operator()(T)
{
}
};
/******************************************************************************
* @brief Apply a functor to an element of a compile time sequence
* This meta function is a bridge to the runtime environment to apply a functor
* to an element of a compile time list of types.
* Required template parameter: sequence - typename defining the list of types
*
* @arg position position of element in the list
* @arg f functor
*/
template
typename F::return_type apply_at(_IndexT position, F f)
{
return apply_at_sequence_position<_IndexT, typename boost::mpl::begin<_Sequence>::type,
typename boost::mpl::end<_Sequence>::type, typename F::return_type, 0,
F>::apply(position, f);
}
} // namespace mpl
} // namespace o2
#endif