LUMIERA.clone/src/lib/meta/configflags.hpp

205 lines
6.2 KiB
C++

/*
CONFIGFLAGS.hpp - Building classes based on configuration cases
Copyright (C) Lumiera.org
2008, Hermann Vosseler <Ichthyostega@web.de>
This program 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 2 of the
License, or (at your option) any later version.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/** @file configflags.hpp
** Under some circumstances it is necessary to assemble functionality
** out of elementary building blocks. Especially, this assembly can be
** expressed as template specialisations directed by a configuration type.
** Thus, the purpose of this header is to encode flag-like configurations
** as distinct types, which can be used to select such specialisations.
** Each possible configuration can be encoded as a list of flags, which allows
** to generate, filter and process those configurations. The final goal is to
** automatically generate a factory which is able to deliver objects
** configured according to the situation encoded in the flags.
**
** @note currently there is an inherent limitation to configurations defined by
** a maximum of 5 independent flags. While it is easy to increase this limit,
** you should consider that the final goal is to generate template instantiations,
** which would lead to more and more code bloat with growing number of possible
** combination.
**
** @see proc::engine::config::Strategy usage example
** @see proc::engine::config::ConfigSelector
** @see typelist.hpp
**
*/
#ifndef LUMIERA_META_CONFIGFLAGS_H
#define LUMIERA_META_CONFIGFLAGS_H
#include "lib/meta/typelist.hpp"
namespace lumiera {
namespace typelist {
const size_t CONFIG_FLAGS_MAX = 5;
template<char bit> struct Flag { typedef Flag ID; };
template<> struct Flag<0> { typedef NullType ID; };
template< char f1=0
, char f2=0
, char f3=0
, char f4=0
, char f5=0
>
struct Flags
{
typedef typename Types< typename Flag<f1>::ID
, typename Flag<f2>::ID
, typename Flag<f3>::ID
, typename Flag<f4>::ID
, typename Flag<f5>::ID
>::List
Tuple;
typedef Tuple List;
};
template< char f1=0
, char f2=0
, char f3=0
, char f4=0
, char f5=0
>
struct Config ///< distinct type representing a configuration
{
typedef typename Flags<f1,f2,f3,f4,f5>::Tuple Flags;
typedef Flags List;
};
template<char Fl, class CONF>
struct ConfigSetFlag; ///< set (prepend) the Flag to the given config
template< char Fl
, char f1
, char f2
, char f3
, char f4
, char IGN
>
struct ConfigSetFlag<Fl, Config<f1,f2,f3,f4,IGN> >
{
typedef typelist::Config<Fl,f1,f2,f3,f4> Config;
};
/** build a configuration type from a list-of-flags */
template<class FLAGS, class CONF=typelist::Config<> >
struct BuildConfigFromFlags
{
typedef CONF Config;
typedef Config Type;
};
template<char Fl, class FLAGS, class CONF>
struct BuildConfigFromFlags< Node<Flag<Fl>,FLAGS>, CONF>
{
typedef typename ConfigSetFlag< Fl
, typename BuildConfigFromFlags<FLAGS,CONF>::Config
>::Config Config;
typedef Config Type;
};
/** create a configuration type for the given list-of-flags */
template<class FLAGS>
struct DefineConfigByFlags : BuildConfigFromFlags<FLAGS> { };
namespace {
/** helper comparing enum values and chars (flags) */
template<char ii, char jj>
struct maxC
{
enum{ VAL = ii < jj? jj : ii };
};
}
/**
* Helper for calculating values and for
* invoking runtime code based on a given FlagTuple.
* Can also be used on a Typelist of several Configs.
* The latter case is typically used to invoke an operation
* while enumerating all Flag-Configurations defined in Code.
* An example would be to build (at runtime) an dispatcher table.
* Explanation: For the Case covering a List of Configs, we provide
* a templated visitation function, which can accept a functor object
* to be invoked on each Configuration.
*/
template<class FLAGS>
struct FlagInfo;
template<char ff, class FLAGS>
struct FlagInfo<Node<Flag<ff>, FLAGS> >
{
enum{ BITS = maxC< ff, FlagInfo<FLAGS>::BITS> ::VAL
, CODE = (1<<ff) | FlagInfo<FLAGS>::CODE
};
};
template<>
struct FlagInfo<NullType>
{
enum{ BITS = 0
, CODE = 0
};
template<class FUNC>
static typename FUNC::Ret
accept (FUNC& functor)
{
return functor.done();
}
};
template<class CONF, class TAIL>
struct FlagInfo<Node<CONF, TAIL> >
{
typedef typename CONF::Flags ThisFlags;
enum{
BITS = maxC< FlagInfo<ThisFlags>::BITS, FlagInfo<TAIL>::BITS > ::VAL
};
template<class FUNC>
static typename FUNC::Ret
accept (FUNC& functor)
{
functor.template visit<CONF>(FlagInfo<ThisFlags>::CODE);
return FlagInfo<TAIL>::accept (functor);
}
};
} // namespace typelist
} // namespace lumiera
#endif