/* CONFIGFLAGS.hpp - Building classes based on configuration cases Copyright (C) Lumiera.org 2008, Hermann Vosseler 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 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::ID , typename Flag::ID , typename Flag::ID , typename Flag::ID , typename Flag::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::Tuple Flags; typedef Flags List; }; template 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 > { typedef typelist::Config Config; }; /** build a configuration type from a list-of-flags */ template > struct BuildConfigFromFlags { typedef CONF Config; typedef Config Type; }; template struct BuildConfigFromFlags< Node,FLAGS>, CONF> { typedef typename ConfigSetFlag< Fl , typename BuildConfigFromFlags::Config >::Config Config; typedef Config Type; }; /** create a configuration type for the given list-of-flags */ template struct DefineConfigByFlags : BuildConfigFromFlags { }; namespace { /** helper comparing enum values and chars (flags) */ template 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 struct FlagInfo; template struct FlagInfo, FLAGS> > { enum{ BITS = maxC< ff, FlagInfo::BITS> ::VAL , CODE = (1<::CODE }; }; template<> struct FlagInfo { enum{ BITS = 0 , CODE = 0 }; template static typename FUNC::Ret accept (FUNC& functor) { return functor.done(); } }; template struct FlagInfo > { typedef typename CONF::Flags ThisFlags; enum{ BITS = maxC< FlagInfo::BITS, FlagInfo::BITS > ::VAL }; template static typename FUNC::Ret accept (FUNC& functor) { functor.template visit(FlagInfo::CODE); return FlagInfo::accept (functor); } }; } // namespace typelist } // namespace lumiera #endif