diff --git a/AutoRAII.test/0.cc b/AutoRAII.test/0.cc index d137327..2397ac0 100644 --- a/AutoRAII.test/0.cc +++ b/AutoRAII.test/0.cc @@ -3,7 +3,7 @@ static_assert( __cplusplus > 2020'00 ); #include #include -#include +#include int main( const int argcnt, const char *const argvec[] ) diff --git a/Console.cpp b/Console.cpp index 5a1600c..7b08a48 100644 --- a/Console.cpp +++ b/Console.cpp @@ -15,6 +15,8 @@ static_assert( __cplusplus > 2020'00 ); #include +#include + #include "Enum.h" #include "ProgramOptions.h" #include "StaticValue.h" @@ -43,6 +45,8 @@ namespace Alepha::Cavorite ::detail:: console { using namespace std::literals::string_literals; + using namespace Utility::exports::evaluation_helpers; + namespace C { const bool debug= false; diff --git a/Exception.test/exception.cc b/Exception.test/exception.cc index 55f1eef..7c4a39b 100644 --- a/Exception.test/exception.cc +++ b/Exception.test/exception.cc @@ -6,7 +6,7 @@ static_assert( __cplusplus > 2020'00 ); #include #include -#include +#include namespace { diff --git a/Meta/Meta.test/traits.cc b/Meta/Meta.test/traits.cc index a992feb..1f1a919 100644 --- a/Meta/Meta.test/traits.cc +++ b/Meta/Meta.test/traits.cc @@ -7,7 +7,7 @@ static_assert( __cplusplus > 2020'00 ); #include -#include +#include #include @@ -19,7 +19,7 @@ main( const int argcnt, const char *const *const argvec ) namespace { - using namespace Alepha::Utility::evaluation; + using namespace Alepha::Utility::exports::evaluation_helpers; using namespace Alepha::Testing::literals; using std::begin, std::end; diff --git a/ProgramOptions.h b/ProgramOptions.h index ecbf3a5..090b9ff 100644 --- a/ProgramOptions.h +++ b/ProgramOptions.h @@ -91,12 +91,15 @@ static_assert( __cplusplus > 2020'00 ); #include #include #include -#include + +#include namespace Alepha::inline Cavorite ::detail:: program_options { inline namespace exports {} + using namespace Utility::exports::evaluation_helpers; + /*! * User created unique symbols can be bound to options to build classes of options. * diff --git a/Testing/TableTest.h b/Testing/TableTest.h index bb66064..93dd3b0 100644 --- a/Testing/TableTest.h +++ b/Testing/TableTest.h @@ -29,7 +29,7 @@ static_assert( __cplusplus > 2020'00 ); #include #include -#include +#include #include #include @@ -64,7 +64,7 @@ namespace Alepha::Hydrogen::Testing ::detail:: table_test } using std::begin, std::end; - using namespace Utility::exports::evaluation; + using namespace Utility::exports::evaluation_helpers; using namespace std::literals::string_literals; template< template< typename, typename... > class Sequence, typename ... TupleArgs > diff --git a/Testing/TableTest.test/test.cc b/Testing/TableTest.test/test.cc index ea34279..3395444 100644 --- a/Testing/TableTest.test/test.cc +++ b/Testing/TableTest.test/test.cc @@ -2,7 +2,7 @@ static_assert( __cplusplus > 2020'00 ); #include #include -#include +#include namespace { @@ -17,7 +17,7 @@ main( const int argcnt, const char *const *const argvec ) namespace { - using namespace Alepha::Utility::exports::evaluation; + using namespace Alepha::Utility::exports::evaluation_helpers; using namespace UnitTest::literals; using UnitTest::TableTest; diff --git a/Testing/TableTest.test/test2.cc b/Testing/TableTest.test/test2.cc index 820b101..ff3972a 100644 --- a/Testing/TableTest.test/test2.cc +++ b/Testing/TableTest.test/test2.cc @@ -2,7 +2,7 @@ static_assert( __cplusplus > 2020'00 ); #include #include -#include +#include int @@ -15,7 +15,7 @@ main( const int argcnt, const char *const *const argvec ) namespace { using namespace Alepha::Testing::exports; - using namespace Alepha::Utility::exports::evaluation; + using namespace Alepha::Utility::exports::evaluation_helpers; int add( int a, int b ) diff --git a/Testing/test.h b/Testing/test.h index 453258f..36c706f 100644 --- a/Testing/test.h +++ b/Testing/test.h @@ -15,7 +15,8 @@ static_assert( __cplusplus > 2020'00 ); #include #include -#include + +#include #include namespace Alepha::Hydrogen::Testing @@ -36,7 +37,7 @@ namespace Alepha::Hydrogen::Testing } using namespace std::literals::string_literals; - using namespace Utility::exports::evaluation; + using namespace Utility::exports::evaluation_helpers; using namespace Utility::exports::static_value; struct TestName diff --git a/Utility/StackableStreambuf.test/0.cc b/Utility/StackableStreambuf.test/0.cc index 36d1ad7..ed08245 100644 --- a/Utility/StackableStreambuf.test/0.cc +++ b/Utility/StackableStreambuf.test/0.cc @@ -6,7 +6,7 @@ static_assert( __cplusplus > 2020'00 ); #include #include -#include +#include #include "../word_wrap.h" diff --git a/Utility/evaluation.h b/Utility/evaluation.h deleted file mode 100644 index 78979b0..0000000 --- a/Utility/evaluation.h +++ /dev/null @@ -1,57 +0,0 @@ -static_assert( __cplusplus > 2020'00 ); - -#pragma once - -#include - -#include -#include - -namespace Alepha::Hydrogen::Utility -{ - inline namespace exports { inline namespace evaluation {} } - - namespace detail::evaluation - { - struct evaluate_t {}; - struct enroll_t {}; - struct lambaste_t {}; - - inline namespace exports - { - inline constexpr evaluate_t evaluate; - inline constexpr enroll_t enroll; - inline constexpr lambaste_t lambaste; - } - - template< typename Function > - decltype( auto ) - operator <=( evaluate_t, Function &&init ) - { - return std::forward< Function >( init )(); - } - - template< typename Init > - auto - operator <=( enroll_t, Init init ) - { - struct {} registration; - - (void) ( evaluate <=init ); - - return registration; - } - - template< typename Value > - auto - operator <=( lambaste_t, Value value ) - { - return [value]{ return value; }; - } - } - - namespace exports::evaluation - { - using namespace detail::evaluation::exports; - } -} diff --git a/Utility/evaluation_helpers.h b/Utility/evaluation_helpers.h new file mode 100644 index 0000000..b3039e8 --- /dev/null +++ b/Utility/evaluation_helpers.h @@ -0,0 +1,171 @@ +static_assert( __cplusplus > 2020'00 ); + +#pragma once + +#include + +#include +#include + +namespace Alepha::Hydrogen::Utility ::detail:: evaluation_helpers +{ + inline namespace exports + { + /*! + * Mechanism to clarify immediately-invoked lambdas. + * + * Immediately invoked lambdas are a very useful tool. + * + * ``` + * const auto mySortedArray= [&] + * { + * std::vector< std::string > rv; + * // Populate it... + * std::sort( begin( rv ), end( rv ) ); + * return rv; + * }(); + * ``` + * + * The above code defines a sorted vector as const by immediately invoking a lambda to do it. The problem, + * however, is that it is entirely unclear whether a lambda is being invoked or defined until the very end + * of the lambda's definition is reached. This can become very confusing when there are several nested + * levels of lambdas and they get a bit large. + * + * `evaluate` creates a hook that makes it more clear that it is an immediately-invoked lambda: + * + * ``` + * const auto mySortedArray= evaluate <=[&] + * { + * std::vector< std::string > rv; + * // Populate it... + * std::sort( begin( rv ), end( rv ) ); + * return rv; + * }; + * ``` + * + * Because `evaluate <=` precedes the lambda definition, it is quite clear that something else is going on + * here. The `<=` in this case should be thought of as a `fat left arrow` -- the lambda is being put + * through an evaluation operation. + */ + inline struct evaluate_t {} evaluate; + + /*! + * Mechanism to define initializer blocks. + * + * C++ does not have initializer blocks, but it does have the ability to define variables that are set to + * values before `main` is invoked. It is possible to use constructors or functions to leverage this fact + * and make blocks of code that run before main: + * + * ``` + * struct MyThing + * { + * MyThing() + * { + * std::cout << "Hello World, before main!" << std::endl; + * } + * } beforeMain; + * ``` + * + * The above code works such that, as a side-effect of the construction of `beforeMain`, the desired code is + * run. However, it is rather cumbersome. There are ways of simplifying this: + * + * ``` + * int beforeMainFunction() { std::cout << "Hello World, before main!" << std::endl; return 42; } + * const int beforeMain= beforeMainFunction(); + * ``` + * + * While this is a bit less confusing, there's still a need to define a function and return a dummy + * variable. Lambdas with immediate invocation syntax (see `evaluate`) can make this nicer still: + * + * ``` + * const int beforeMain= evaluate <=[] { std::cout << "Hello World, before main!" << std::endl; return 0; }; + * ``` + * + * That is a bit better, but that pesky dummy value is still there. The fact that this is an int is going + * to be a potential source of confusion. Instead, we want to keep the reader focused on the fact that code + * is being run, and disguise the fact that there's a variable involved. + * + * `enroll` creates a hook by which the above techniques can be made more clear that it one is running + * pre-main code. + * + * ``` + * auto myInitBlock= enroll <=[] + * { + * std::cout << "Hello World, before main!" << std::endl; + * }; + * ``` + * + * Because `enroll <=` precedes the lambda definition it is quite clear that something else is going on + * here. The `<=` in this case should be thought of as a `fat left arrow` -- the lambda is being given + * to `enroll` to be used as an initializer block. + */ + inline struct enroll_t {} enroll; + + /*! + * Mechanism to define lambda capture of a value. + * + * Sometimes it's useful or necessary to take a known value and wrap it in a function-like interface. Some + * APIs let programmers provide functions which act as customization points. Sometimes the value is already + * at hand, and it needs to be wrapped in a lambda. + * + * For example: + * + * ``` + * auto wrapped= [myValue] { return myValue; }; + * ``` + * + * While the above is perfectly adequate, it is a bit cumbersome. `myValue` is used twice, there's a lot of + * mechanical syntax for lambda function definition, etc. `lambaste` provides a simpler alternative: + * + * ``` + * auto wrapped= lambaste <=myValue; + * ``` + * + * Because `lambaste <=` precedes the variable, it is clear that something is going on here. The `<=` in + * this case should be thought of as a `fat left arrow` -- the value is being given to `lambaste` to be used + * in constructing a function-object. + * + * @note Lambaste is a stupid pun -- a better name might be in order. + */ + inline struct lambaste_t {} lambaste; + } + + template< typename Function > + constexpr decltype( auto ) + operator <=( evaluate_t, Function &&func ) noexcept( noexcept( std::forward< Function >( func )() ) ) + { + return std::forward< Function >( func )(); + } + + template< typename Function > + struct registration + { + explicit registration( Function f ) { evaluate <=f; } + }; + + template< typename Function > + constexpr auto + operator <=( enroll_t, Function &&func ) noexcept + { + return registration{ std::forward< Function >( func ) }; + } + + template< typename ValueType > + constexpr auto + as_func( ValueType value ) noexcept( std::is_nothrow_move_constructible_v< ValueType > ) + { + return [value= std::move( value )]() -> std::decay_t< ValueType > { return value; }; + } + + template< typename ValueType > + constexpr decltype( auto ) + operator <=( lambaste_t, ValueType value ) noexcept( noexcept( as_func( std::move( value ) ) ) ) + { + return as_func( std::move( value ) ); + } +} + +namespace Alepha::Hydrogen::Utility::inline exports::inline evaluation_helpers +{ + using namespace detail::evaluation_helpers::exports; +} diff --git a/comparisons.test/0.cc b/comparisons.test/0.cc index e804ec9..d43d61a 100644 --- a/comparisons.test/0.cc +++ b/comparisons.test/0.cc @@ -4,7 +4,7 @@ static_assert( __cplusplus > 2020'00 ); #include #include -#include +#include namespace { diff --git a/evaluation_helpers.h b/evaluation_helpers.h index de49684..65ccf6a 100644 --- a/evaluation_helpers.h +++ b/evaluation_helpers.h @@ -5,165 +5,3 @@ static_assert( __cplusplus > 2020'00 ); #include #include -namespace Alepha::inline Cavorite ::detail:: evaluation_helpers -{ - inline namespace exports - { - /*! - * Mechanism to clarify immediately-invoked lambdas. - * - * Immediately invoked lambdas are a very useful tool. - * - * ``` - * const auto mySortedArray= [&] - * { - * std::vector< std::string > rv; - * // Populate it... - * std::sort( begin( rv ), end( rv ) ); - * return rv; - * }(); - * ``` - * - * The above code defines a sorted vector as const by immediately invoking a lambda to do it. The problem, - * however, is that it is entirely unclear whether a lambda is being invoked or defined until the very end - * of the lambda's definition is reached. This can become very confusing when there are several nested - * levels of lambdas and they get a bit large. - * - * `evaluate` creates a hook that makes it more clear that it is an immediately-invoked lambda: - * - * ``` - * const auto mySortedArray= evaluate <=[&] - * { - * std::vector< std::string > rv; - * // Populate it... - * std::sort( begin( rv ), end( rv ) ); - * return rv; - * }; - * ``` - * - * Because `evaluate <=` precedes the lambda definition, it is quite clear that something else is going on - * here. The `<=` in this case should be thought of as a `fat left arrow` -- the lambda is being put - * through an evaluation operation. - */ - inline struct evaluate_t {} evaluate; - - /*! - * Mechanism to define initializer blocks. - * - * C++ does not have initializer blocks, but it does have the ability to define variables that are set to - * values before `main` is invoked. It is possible to use constructors or functions to leverage this fact - * and make blocks of code that run before main: - * - * ``` - * struct MyThing - * { - * MyThing() - * { - * std::cout << "Hello World, before main!" << std::endl; - * } - * } beforeMain; - * ``` - * - * The above code works such that, as a side-effect of the construction of `beforeMain`, the desired code is - * run. However, it is rather cumbersome. There are ways of simplifying this: - * - * ``` - * int beforeMainFunction() { std::cout << "Hello World, before main!" << std::endl; return 42; } - * const int beforeMain= beforeMainFunction(); - * ``` - * - * While this is a bit less confusing, there's still a need to define a function and return a dummy - * variable. Lambdas with immediate invocation syntax (see `evaluate`) can make this nicer still: - * - * ``` - * const int beforeMain= evaluate <=[] { std::cout << "Hello World, before main!" << std::endl; return 0; }; - * ``` - * - * That is a bit better, but that pesky dummy value is still there. The fact that this is an int is going - * to be a potential source of confusion. Instead, we want to keep the reader focused on the fact that code - * is being run, and disguise the fact that there's a variable involved. - * - * `enroll` creates a hook by which the above techniques can be made more clear that it one is running - * pre-main code. - * - * ``` - * auto myInitBlock= enroll <=[] - * { - * std::cout << "Hello World, before main!" << std::endl; - * }; - * ``` - * - * Because `enroll <=` precedes the lambda definition it is quite clear that something else is going on - * here. The `<=` in this case should be thought of as a `fat left arrow` -- the lambda is being given - * to `enroll` to be used as an initializer block. - */ - inline struct enroll_t {} enroll; - - /*! - * Mechanism to define lambda capture of a value. - * - * Sometimes it's useful or necessary to take a known value and wrap it in a function-like interface. Some - * APIs let programmers provide functions which act as customization points. Sometimes the value is already - * at hand, and it needs to be wrapped in a lambda. - * - * For example: - * - * ``` - * auto wrapped= [myValue] { return myValue; }; - * ``` - * - * While the above is perfectly adequate, it is a bit cumbersome. `myValue` is used twice, there's a lot of - * mechanical syntax for lambda function definition, etc. `lambaste` provides a simpler alternative: - * - * ``` - * auto wrapped= lambaste <=myValue; - * ``` - * - * Because `lambaste <=` precedes the variable, it is clear that something is going on here. The `<=` in - * this case should be thought of as a `fat left arrow` -- the value is being given to `lambaste` to be used - * in constructing a function-object. - * - * @note Lambaste is a stupid pun -- a better name might be in order. - */ - inline struct lambaste_t {} lambaste; - } - - template< typename Function > - constexpr decltype( auto ) - operator <=( evaluate_t, Function &&func ) noexcept( noexcept( std::forward< Function >( func )() ) ) - { - return std::forward< Function >( func )(); - } - - template< typename Function > - struct registration - { - explicit registration( Function f ) { evaluate <=f; } - }; - - template< typename Function > - constexpr auto - operator <=( enroll_t, Function &&func ) noexcept - { - return registration{ std::forward< Function >( func ) }; - } - - template< typename ValueType > - constexpr auto - as_func( ValueType value ) noexcept( std::is_nothrow_move_constructible_v< ValueType > ) - { - return [value= std::move( value )]() -> std::decay_t< ValueType > { return value; }; - } - - template< typename ValueType > - constexpr decltype( auto ) - operator <=( lambaste_t, ValueType value ) noexcept( noexcept( as_func( std::move( value ) ) ) ) - { - return as_func( std::move( value ) ); - } -} - -namespace Alepha::Cavorite::inline exports::inline evaluation_helpers -{ - using namespace detail::evaluation_helpers::exports; -} diff --git a/example.cc b/example.cc index 07efc88..77da993 100644 --- a/example.cc +++ b/example.cc @@ -2,15 +2,19 @@ static_assert( __cplusplus > 2020'00 ); #include "ProgramOptions.h" +#include + namespace { using namespace Alepha::literals::option_literals; using namespace std::literals::string_literals; + using namespace Alepha::Utility::exports::evaluation_helpers; + int optionA= 42; std::optional< std::string > optionB; - auto init= Alepha::enroll <=[] + auto init= enroll <=[] { --"set-a"_option << optionA << "The option is an integer. !default!"; --"set-b"_option << optionB << "The option is a string, no defaults."; diff --git a/string_algorithms.test/0.cc b/string_algorithms.test/0.cc index ac49301..c3494c1 100644 --- a/string_algorithms.test/0.cc +++ b/string_algorithms.test/0.cc @@ -5,7 +5,7 @@ static_assert( __cplusplus > 2020'00 ); #include #include -#include +#include namespace { diff --git a/word_wrap.cpp b/word_wrap.cpp index 820042a..9c234b9 100644 --- a/word_wrap.cpp +++ b/word_wrap.cpp @@ -10,12 +10,14 @@ static_assert( __cplusplus > 2020 ); #include #include -#include "evaluation_helpers.h" +#include namespace Alepha::Cavorite ::detail:: word_wrap { namespace { + using namespace Utility::exports::evaluation_helpers; + // Returns the number of chars in the line just written to. std::size_t applyWordToLine( const std::size_t maximumWidth, const std::size_t nextLineOffset, const std::size_t currentLineWidth, std::string &&word, std::ostream &result ) diff --git a/word_wrap.test/0.cc b/word_wrap.test/0.cc index fa07326..86d89fd 100644 --- a/word_wrap.test/0.cc +++ b/word_wrap.test/0.cc @@ -4,7 +4,7 @@ static_assert( __cplusplus > 2020'00 ); #include #include -#include +#include namespace {