diff --git a/bricks/brick-compose b/bricks/brick-compose new file mode 100644 index 0000000000000000000000000000000000000000..a6a0327cb55f67b6f430dbb57c3b2ba7f646055b --- /dev/null +++ b/bricks/brick-compose @@ -0,0 +1,94 @@ +// -*- mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- + +/* + * (c) 2019 Petr RoÄŤkai <code@fixp.eu> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#pragma once + +/* Utilities for composing modules into stacks. This code composition approach + * uses 'late' (but still static) inheritance to allow both a fair degree of + * flexibility without compromising performance by using references and + * pointers. See the code in the brq_t namespace for an example of how this can + * be used. */ + +namespace brq +{ + template< typename... > struct compose {}; + + template< typename head, typename... tail > + struct compose< head, tail... > + { + template< typename next > + struct module : head::template module< typename compose< tail... >::template module< next > > + {}; + }; + + template<> + struct compose<> + { + template< typename next > + struct module : next {}; + }; + + struct unit {}; + + template< typename... comps > + using compose_stack = typename compose< comps... >::template module< unit >; + + template< template< typename... > class mod, typename... x > + struct module_ + { + template < typename next > + using module = mod< x..., next >; + }; + + template< template< typename... > class mod, typename... x > + using module = module_< mod, x... >; +} + +namespace brq_t +{ + template< typename next > + struct m0_ : next + { + static const bool has_m1 = false, has_m2 = false; + }; + + template< typename next > + struct m1_ : next { static const bool has_m1 = true; }; + + template< typename foo, typename next > + struct m2_ : next { static const bool has_m2 = true; }; + + using m0 = brq::module< m0_ >; + using m1 = brq::module< m1_ >; + template< typename foo > + using m2 = brq::module< m2_, foo >; + + struct compose + { + using m01 = brq::compose_stack< m1, m0 >; + static_assert( m01::has_m1 ); + static_assert( !m01::has_m2 ); + using m012 = brq::compose_stack< m2< void >, m1, m0 >; + static_assert( m012::has_m1 ); + static_assert( m012::has_m2 ); + + TEST( empty ) {} + }; +} + +// vim: syntax=cpp tabstop=4 shiftwidth=4 expandtab ft=cpp