diff --git a/src/Benchmarks/BLAS/tnl-benchmark-blas.h b/src/Benchmarks/BLAS/tnl-benchmark-blas.h index a1bd3e92b0d2e11ac3f5377ffcf199d8a873ad60..3e05da6304d48d581434716deb2e7929f2c83f79 100644 --- a/src/Benchmarks/BLAS/tnl-benchmark-blas.h +++ b/src/Benchmarks/BLAS/tnl-benchmark-blas.h @@ -16,8 +16,7 @@ #include <TNL/Allocators/CudaManaged.h> #include <TNL/Devices/Host.h> #include <TNL/Devices/Cuda.h> -#include <TNL/Config/ConfigDescription.h> -#include <TNL/Config/ParameterContainer.h> +#include <TNL/Config/parseCommandLine.h> #include "array-operations.h" #include "vector-operations.h" @@ -135,10 +134,8 @@ main( int argc, char* argv[] ) setupConfig( conf_desc ); - if( ! parseCommandLine( argc, argv, conf_desc, parameters ) ) { - conf_desc.printUsage( argv[ 0 ] ); + if( ! parseCommandLine( argc, argv, conf_desc, parameters ) ) return EXIT_FAILURE; - } if( ! Devices::Host::setup( parameters ) || ! Devices::Cuda::setup( parameters ) ) diff --git a/src/Benchmarks/DistSpMV/tnl-benchmark-distributed-spmv.h b/src/Benchmarks/DistSpMV/tnl-benchmark-distributed-spmv.h index b90b11088ef8f73511adb2ba5c58448e93e2bcf8..8aa22d6f72c78b5036047c63b71a1a2c5116c0a9 100644 --- a/src/Benchmarks/DistSpMV/tnl-benchmark-distributed-spmv.h +++ b/src/Benchmarks/DistSpMV/tnl-benchmark-distributed-spmv.h @@ -16,8 +16,7 @@ #include <TNL/Debugging/FPE.h> #endif -#include <TNL/Config/ConfigDescription.h> -#include <TNL/Config/ParameterContainer.h> +#include <TNL/Config/parseCommandLine.h> #include <TNL/Devices/Host.h> #include <TNL/Devices/Cuda.h> #include <TNL/Communicators/MpiCommunicator.h> @@ -309,10 +308,8 @@ main( int argc, char* argv[] ) Communicators::ScopedInitializer< CommunicatorType > scopedInit(argc, argv); const int rank = CommunicatorType::GetRank( CommunicatorType::AllGroup ); - if( ! parseCommandLine( argc, argv, conf_desc, parameters ) ) { - conf_desc.printUsage( argv[ 0 ] ); + if( ! parseCommandLine( argc, argv, conf_desc, parameters ) ) return EXIT_FAILURE; - } if( ! Devices::Host::setup( parameters ) || ! Devices::Cuda::setup( parameters ) || diff --git a/src/Benchmarks/HeatEquation/tnl-benchmark-simple-heat-equation.h b/src/Benchmarks/HeatEquation/tnl-benchmark-simple-heat-equation.h index 6824329226ab58be502f89e71387ad5749d4fa5d..46e89748de975d65fa3c5201fa4d08d0928bc838 100644 --- a/src/Benchmarks/HeatEquation/tnl-benchmark-simple-heat-equation.h +++ b/src/Benchmarks/HeatEquation/tnl-benchmark-simple-heat-equation.h @@ -13,8 +13,7 @@ #include <iostream> #include <stdio.h> -#include <TNL/Config/ConfigDescription.h> -#include <TNL/Config/ParameterContainer.h> +#include <TNL/Config/parseCommandLine.h> #include <TNL/Timer.h> #include <TNL/Devices/Cuda.h> #include <TNL/Containers/StaticVector.h> diff --git a/src/Benchmarks/LinearSolvers/tnl-benchmark-linear-solvers.h b/src/Benchmarks/LinearSolvers/tnl-benchmark-linear-solvers.h index ea39d80b7b8011f53e7187e53a62e8446bdb8b82..08f45683a338491b89be826cb148df37137e3699 100644 --- a/src/Benchmarks/LinearSolvers/tnl-benchmark-linear-solvers.h +++ b/src/Benchmarks/LinearSolvers/tnl-benchmark-linear-solvers.h @@ -21,8 +21,7 @@ #include <TNL/Debugging/FPE.h> #endif -#include <TNL/Config/ConfigDescription.h> -#include <TNL/Config/ParameterContainer.h> +#include <TNL/Config/parseCommandLine.h> #include <TNL/Devices/Host.h> #include <TNL/Devices/Cuda.h> #include <TNL/Communicators/MpiCommunicator.h> @@ -592,10 +591,8 @@ main( int argc, char* argv[] ) Communicators::ScopedInitializer< CommunicatorType > scopedInit(argc, argv); const int rank = CommunicatorType::GetRank( CommunicatorType::AllGroup ); - if( ! parseCommandLine( argc, argv, conf_desc, parameters ) ) { - conf_desc.printUsage( argv[ 0 ] ); + if( ! parseCommandLine( argc, argv, conf_desc, parameters ) ) return EXIT_FAILURE; - } if( ! Devices::Host::setup( parameters ) || ! Devices::Cuda::setup( parameters ) || ! CommunicatorType::setup( parameters ) ) diff --git a/src/Benchmarks/NDArray/tnl-benchmark-ndarray-boundary.h b/src/Benchmarks/NDArray/tnl-benchmark-ndarray-boundary.h index 285dd6f3d7f97aa9f90a0914ca88fe535661d7eb..29445234c60b9d036d52c2c755f36e838a801a86 100644 --- a/src/Benchmarks/NDArray/tnl-benchmark-ndarray-boundary.h +++ b/src/Benchmarks/NDArray/tnl-benchmark-ndarray-boundary.h @@ -14,6 +14,7 @@ #include <TNL/Assert.h> #include <TNL/Math.h> +#include <TNL/Config/parseCommandLine.h> #include <TNL/Containers/NDArray.h> @@ -423,10 +424,8 @@ int main( int argc, char* argv[] ) setupConfig( conf_desc ); - if( ! parseCommandLine( argc, argv, conf_desc, parameters ) ) { - conf_desc.printUsage( argv[ 0 ] ); + if( ! parseCommandLine( argc, argv, conf_desc, parameters ) ) return EXIT_FAILURE; - } if( ! Devices::Host::setup( parameters ) || ! Devices::Cuda::setup( parameters ) ) diff --git a/src/Benchmarks/NDArray/tnl-benchmark-ndarray.h b/src/Benchmarks/NDArray/tnl-benchmark-ndarray.h index 0c29b21b5894e46627f8c4f129eafc8697ae9aec..9f17b8b5c79b8a245a08551f4a51a597a05c059b 100644 --- a/src/Benchmarks/NDArray/tnl-benchmark-ndarray.h +++ b/src/Benchmarks/NDArray/tnl-benchmark-ndarray.h @@ -15,6 +15,7 @@ #include <TNL/Assert.h> #include <TNL/Math.h> #include <TNL/Algorithms/ParallelFor.h> +#include <TNL/Config/parseCommandLine.h> #include <TNL/Containers/NDArray.h> #include <TNL/Containers/ndarray/Operations.h> @@ -411,10 +412,8 @@ int main( int argc, char* argv[] ) setupConfig( conf_desc ); - if( ! parseCommandLine( argc, argv, conf_desc, parameters ) ) { - conf_desc.printUsage( argv[ 0 ] ); + if( ! parseCommandLine( argc, argv, conf_desc, parameters ) ) return EXIT_FAILURE; - } if( ! Devices::Host::setup( parameters ) || ! Devices::Cuda::setup( parameters ) ) diff --git a/src/Benchmarks/ODESolvers/tnl-benchmark-ode-solvers.h b/src/Benchmarks/ODESolvers/tnl-benchmark-ode-solvers.h index dad2cdd8dc309b38844c1c5eb27232f75d6092dc..94c452cc6836883af1af94935b0d736273a7b5ef 100644 --- a/src/Benchmarks/ODESolvers/tnl-benchmark-ode-solvers.h +++ b/src/Benchmarks/ODESolvers/tnl-benchmark-ode-solvers.h @@ -20,8 +20,7 @@ #include <TNL/Debugging/FPE.h> #endif -#include <TNL/Config/ConfigDescription.h> -#include <TNL/Config/ParameterContainer.h> +#include <TNL/Config/parseCommandLine.h> #include <TNL/Devices/Host.h> #include <TNL/Devices/Cuda.h> #include <TNL/Communicators/MpiCommunicator.h> @@ -193,7 +192,7 @@ configSetup( Config::ConfigDescription& config ) config.addEntryEnum( "overwrite" ); config.addEntry< int >( "loops", "Number of repetitions of the benchmark.", 10 ); config.addEntry< int >( "verbose", "Verbose mode.", 1 ); - config.addList< String >( "solvers", "Comma-separated list of solvers to run benchmarks for.", "all" ); + config.addList< String >( "solvers", "List of solvers to run benchmarks for.", {"all"} ); config.addEntryEnum< String >( "euler" ); config.addEntryEnum< String >( "merson" ); config.addEntryEnum< String >( "all" ); @@ -233,10 +232,8 @@ main( int argc, char* argv[] ) Communicators::ScopedInitializer< CommunicatorType > scopedInit(argc, argv); const int rank = CommunicatorType::GetRank( CommunicatorType::AllGroup ); - if( ! parseCommandLine( argc, argv, conf_desc, parameters ) ) { - conf_desc.printUsage( argv[ 0 ] ); + if( ! parseCommandLine( argc, argv, conf_desc, parameters ) ) return EXIT_FAILURE; - } if( ! Devices::Host::setup( parameters ) || ! Devices::Cuda::setup( parameters ) || ! CommunicatorType::setup( parameters ) ) diff --git a/src/Benchmarks/SpMV/tnl-benchmark-spmv.h b/src/Benchmarks/SpMV/tnl-benchmark-spmv.h index 65416f0432085f744ee66a80efb497242ef0db81..4c6aea68ed065d331fb0f34663c128f132ecb6e3 100644 --- a/src/Benchmarks/SpMV/tnl-benchmark-spmv.h +++ b/src/Benchmarks/SpMV/tnl-benchmark-spmv.h @@ -16,8 +16,7 @@ #include <TNL/Devices/Host.h> #include <TNL/Devices/Cuda.h> -#include <TNL/Config/ConfigDescription.h> -#include <TNL/Config/ParameterContainer.h> +#include <TNL/Config/parseCommandLine.h> #include <Benchmarks/BLAS/array-operations.h> #include <Benchmarks/BLAS/vector-operations.h> @@ -102,10 +101,8 @@ main( int argc, char* argv[] ) // terminate called after throwing an instance of 'int' // [1] 17156 abort (core dumped) ~/tnl-dev/Debug/bin/./tnl-benchmark-spmv-dbg --help - if( ! parseCommandLine( argc, argv, conf_desc, parameters ) ) { - conf_desc.printUsage( argv[ 0 ] ); + if( ! parseCommandLine( argc, argv, conf_desc, parameters ) ) return EXIT_FAILURE; - } if( ! Devices::Host::setup( parameters ) || ! Devices::Cuda::setup( parameters ) ) diff --git a/src/Benchmarks/Traversers/tnl-benchmark-traversers.h b/src/Benchmarks/Traversers/tnl-benchmark-traversers.h index dbe637d826fe4e0dcd593320fba11ad46588e9b3..30c364ac37f2bc32753a14c723ff2276332550c9 100644 --- a/src/Benchmarks/Traversers/tnl-benchmark-traversers.h +++ b/src/Benchmarks/Traversers/tnl-benchmark-traversers.h @@ -16,7 +16,7 @@ //#include "grid-traversing.h" #include "GridTraversersBenchmark.h" -#include <TNL/Config/ConfigDescription.h> +#include <TNL/Config/parseCommandLine.h> #include <TNL/Devices/Host.h> #include <TNL/Devices/Cuda.h> #include <TNL/Algorithms/ParallelFor.h> @@ -490,10 +490,8 @@ int main( int argc, char* argv[] ) Config::ParameterContainer parameters; setupConfig( config ); - if( ! parseCommandLine( argc, argv, config, parameters ) ) { - config.printUsage( argv[ 0 ] ); + if( ! parseCommandLine( argc, argv, config, parameters ) ) return EXIT_FAILURE; - } if( ! Devices::Host::setup( parameters ) || ! Devices::Cuda::setup( parameters ) ) diff --git a/src/Examples/ConfigDescriptionExample.cpp b/src/Examples/ConfigDescriptionExample.cpp index 59958f1d103458f247ec501b0bb08a1142eac8e6..210d36750d3485fe3fd29c680c58e0374f327b2a 100644 --- a/src/Examples/ConfigDescriptionExample.cpp +++ b/src/Examples/ConfigDescriptionExample.cpp @@ -1,9 +1,10 @@ #include <iostream> #include <TNL/Config/ConfigDescription.h> +#include <TNL/String.h> using namespace TNL; using namespace std; - + int main() { Config::ConfigDescription confd; diff --git a/src/TNL/Config/ConfigDelimiter.h b/src/TNL/Config/ConfigDelimiter.h index 2c102c77888c18114fe39272782b0386434685aa..3bf9888d22df561eb18b96a47ee5b92d021206d7 100644 --- a/src/TNL/Config/ConfigDelimiter.h +++ b/src/TNL/Config/ConfigDelimiter.h @@ -2,12 +2,14 @@ ConfigDelimiter.h - description ------------------- begin : Jul 5, 2014 - copyright : (C) 2014 by Tomas Oberhuber + copyright : (C) 2014 by Tomas Oberhuber et al. email : tomas.oberhuber@fjfi.cvut.cz ***************************************************************************/ /* See Copyright Notice in tnl/Copyright */ +// Implemented by: Tomáš Oberhuber, Jakub Klinkovský + #pragma once #include <TNL/Config/ConfigEntryBase.h> @@ -15,17 +17,16 @@ namespace TNL { namespace Config { -struct ConfigDelimiter : public ConfigEntryBase +class ConfigDelimiter : public ConfigEntryBase { - ConfigDelimiter( const String& delimiter ) +public: + ConfigDelimiter( const std::string& delimiter ) : ConfigEntryBase( "", delimiter, false ) {} - bool isDelimiter() const { return true; }; - - String getEntryType() const { return ""; }; + virtual bool isDelimiter() const override { return true; }; - String getUIEntryType() const { return ""; }; + virtual std::string getUIEntryType() const override { return ""; }; }; } //namespace Config diff --git a/src/TNL/Config/ConfigDescription.h b/src/TNL/Config/ConfigDescription.h index 648db1d445de1ef7362e0265927226e4ec734887..35165e8d1456fabbe8c2f4a5876574a5d947395a 100644 --- a/src/TNL/Config/ConfigDescription.h +++ b/src/TNL/Config/ConfigDescription.h @@ -1,27 +1,24 @@ /*************************************************************************** - Config::ConfigDescription.h - description + ConfigDescription.h - description ------------------- begin : 2007/06/09 - copyright : (C) 2007 by Tomas Oberhuber + copyright : (C) 2007 by Tomas Oberhuber et al. email : tomas.oberhuber@fjfi.cvut.cz ***************************************************************************/ /* See Copyright Notice in tnl/Copyright */ +// Implemented by: Tomáš Oberhuber, Jakub Klinkovský + #pragma once -#include <iomanip> -#include <string> #include <vector> #include <memory> -#include <TNL/Assert.h> -#include <TNL/String.h> -#include <TNL/Config/ConfigEntryType.h> #include <TNL/Config/ConfigEntry.h> #include <TNL/Config/ConfigEntryList.h> #include <TNL/Config/ConfigDelimiter.h> -#include <TNL/Config/ParameterContainer.h> +#include <TNL/Exceptions/ConfigError.h> namespace TNL { namespace Config { @@ -37,10 +34,11 @@ public: * \param description More specific information about the entry. */ template< typename EntryType > - void addEntry( const String& name, - const String& description ) + void addEntry( const std::string& name, + const std::string& description ) { - entries.push_back( std::make_unique< ConfigEntry< EntryType > >( name, description, false ) ); + using CoercedEntryType = typename ParameterTypeCoercion< EntryType >::type; + entries.push_back( std::make_unique< ConfigEntry< CoercedEntryType > >( name, description, false ) ); currentEntry = entries.back().get(); isCurrentEntryList = false; } @@ -53,10 +51,11 @@ public: * \param description More specific information about the entry. */ template< typename EntryType > - void addRequiredEntry( const String& name, - const String& description ) + void addRequiredEntry( const std::string& name, + const std::string& description ) { - entries.push_back( std::make_unique< ConfigEntry< EntryType > >( name, description, true ) ); + using CoercedEntryType = typename ParameterTypeCoercion< EntryType >::type; + entries.push_back( std::make_unique< ConfigEntry< CoercedEntryType > >( name, description, true ) ); currentEntry = entries.back().get(); isCurrentEntryList = false; } @@ -70,11 +69,13 @@ public: * \param defaultValue Default value of the entry. */ template< typename EntryType > - void addEntry( const String& name, - const String& description, + void addEntry( const std::string& name, + const std::string& description, const EntryType& defaultValue ) { - entries.push_back( std::make_unique< ConfigEntry< EntryType > >( name, description, false, defaultValue ) ); + using CoercedEntryType = typename ParameterTypeCoercion< EntryType >::type; + const auto convertedDefaultValue = ParameterTypeCoercion< EntryType >::convert( defaultValue ); + entries.push_back( std::make_unique< ConfigEntry< CoercedEntryType > >( name, description, false, convertedDefaultValue ) ); currentEntry = entries.back().get(); isCurrentEntryList = false; } @@ -87,10 +88,11 @@ public: * \param description More specific information about the list. */ template< typename EntryType > - void addList( const String& name, - const String& description ) + void addList( const std::string& name, + const std::string& description ) { - entries.push_back( std::make_unique< ConfigEntryList< EntryType > >( name, description, false ) ); + using CoercedEntryType = typename ParameterTypeCoercion< EntryType >::type; + entries.push_back( std::make_unique< ConfigEntryList< CoercedEntryType > >( name, description, false ) ); currentEntry = entries.back().get(); isCurrentEntryList = true; } @@ -103,10 +105,11 @@ public: * \param description More specific information about the list. */ template< typename EntryType > - void addRequiredList( const String& name, - const String& description ) + void addRequiredList( const std::string& name, + const std::string& description ) { - entries.push_back( std::make_unique< ConfigEntryList< EntryType > >( name, description, true ) ); + using CoercedEntryType = typename ParameterTypeCoercion< EntryType >::type; + entries.push_back( std::make_unique< ConfigEntryList< CoercedEntryType > >( name, description, true ) ); currentEntry = entries.back().get(); isCurrentEntryList = true; } @@ -120,11 +123,13 @@ public: * \param defaultValue Default value of the list. */ template< typename EntryType > - void addList( const String& name, - const String& description, - const EntryType& defaultValue ) + void addList( const std::string& name, + const std::string& description, + const std::vector< EntryType >& defaultValue ) { - entries.push_back( std::make_unique< ConfigEntryList< EntryType > >( name, description, false, defaultValue ) ); + using CoercedEntryType = typename ParameterTypeCoercion< EntryType >::type; + const auto convertedDefaultValue = ParameterTypeCoercion< std::vector< EntryType > >::convert( defaultValue ); + entries.push_back( std::make_unique< ConfigEntryList< CoercedEntryType > >( name, description, false, convertedDefaultValue ) ); currentEntry = entries.back().get(); isCurrentEntryList = true; } @@ -136,39 +141,29 @@ public: * \tparam EntryType Type of the entry enumeration. * \param entryEnum Value of the entry enumeration. */ - template< typename EntryType > - void addEntryEnum( const EntryType& entryEnum ) + template< typename EntryType = std::string > + void addEntryEnum( const EntryType entryEnum = EntryType{} ) { - TNL_ASSERT_TRUE( this->currentEntry, "there is no current entry" ); + if( this->currentEntry == nullptr ) + throw Exceptions::ConfigError( "there is no current entry" ); + + using CoercedEntryType = typename ParameterTypeCoercion< EntryType >::type; if( isCurrentEntryList ) { - ConfigEntryList< EntryType >& entry = dynamic_cast< ConfigEntryList< EntryType >& >( *currentEntry ); - entry.getEnumValues().push_back( entryEnum ); + ConfigEntryList< CoercedEntryType >& entry = dynamic_cast< ConfigEntryList< CoercedEntryType >& >( *currentEntry ); + entry.getEnumValues().push_back( ParameterTypeCoercion< EntryType >::convert( entryEnum ) ); } else { - ConfigEntry< EntryType >& entry = dynamic_cast< ConfigEntry< EntryType >& >( *currentEntry ); - entry.getEnumValues().push_back( entryEnum ); + ConfigEntry< CoercedEntryType >& entry = dynamic_cast< ConfigEntry< CoercedEntryType >& >( *currentEntry ); + entry.getEnumValues().push_back( ParameterTypeCoercion< EntryType >::convert( entryEnum ) ); } } - /** - * \brief Adds new entry enumeration of type \e char. - * - * Adds new option of setting an entry value. - * \param entryEnum Value of the entry enumeration. - */ - void addEntryEnum( const char* entryEnum ) - { - TNL_ASSERT_TRUE( this->currentEntry, "there is no current entry" ); - ConfigEntry< String >& entry = dynamic_cast< ConfigEntry< String >& >( *currentEntry ); - entry.getEnumValues().push_back( String( entryEnum ) ); - } - /** * \brief Adds delimeter/section to the configuration description. * * \param delimeter String that defines how the delimeter looks like. */ - void addDelimiter( const String& delimiter ) + void addDelimiter( const std::string& delimiter ) { entries.push_back( std::make_unique< ConfigDelimiter >( delimiter ) ); currentEntry = nullptr; @@ -179,227 +174,26 @@ public: * * \param name Name of the entry. */ - const ConfigEntryBase* getEntry( const String& name ) const + const ConfigEntryBase* getEntry( const std::string& name ) const { // ConfigDelimiter has empty name - if( ! name ) + if( name.empty() ) return nullptr; const int entries_num = entries.size(); for( int i = 0; i < entries_num; i++ ) - if( entries[ i ]->name == name ) + if( entries[ i ]->getName() == name ) return entries[ i ].get(); return nullptr; } - - //! Returns empty string if given entry does not exist - //const String getEntryType( const char* name ) const; - - //! Returns zero pointer if there is no default value - template< class T > - const T* getDefaultValue( const String& name ) const - { - // ConfigDelimiter has empty name - if( ! name ) - return nullptr; - - const int entries_num = entries.size(); - for( int i = 0; i < entries_num; i++ ) - if( entries[ i ]->name == name ) { - if( entries[ i ]->hasDefaultValue ) { - const ConfigEntry< T >& entry = dynamic_cast< ConfigEntry< T >& >( *entries[ i ] ); - return entry->default_value; - } - return nullptr; - } - std::cerr << "Asking for the default value of unknown parameter." << std::endl; - return nullptr; - } - - //! Returns zero pointer if there is no default value - template< class T > - T* getDefaultValue( const String& name ) - { - // ConfigDelimiter has empty name - if( ! name ) - return nullptr; - - const int entries_num = entries.size(); - for( int i = 0; i < entries_num; i++ ) - if( entries[ i ] -> name == name ) { - if( entries[ i ] -> hasDefaultValue ) { - ConfigEntry< T >& entry = dynamic_cast< ConfigEntry< T >& >( *entries[ i ] ); - return entry->default_value; - } - return nullptr; - } - std::cerr << "Asking for the default value of unknown parameter." << std::endl; - return nullptr; - } - - /** - * \brief Fills in the parameters from the \e parameter_container. - * - * Parameters which were not defined in the command line by user but have their default value are added to the congiguration description. - * If there is missing entry with defined default value in the Config::ParameterContainer it is going to be added. - * \param parameter_container Name of the ParameterContainer object. - */ - void addMissingEntries( Config::ParameterContainer& parameter_container ) const - { - const int size = entries.size(); - for( int i = 0; i < size; i++ ) - { - const char* entry_name = entries[ i ]->name.getString(); - if( entries[ i ]->hasDefaultValue && - ! parameter_container.checkParameter( entry_name ) ) - { - if( entries[ i ]->getEntryType() == "TNL::String" ) - { - ConfigEntry< String >& entry = dynamic_cast< ConfigEntry< String >& >( *entries[ i ] ); - parameter_container.addParameter< String >( entry_name, entry.defaultValue ); - continue; - } - else if( entries[ i ]->getEntryType() == "bool" ) - { - ConfigEntry< bool >& entry = dynamic_cast< ConfigEntry< bool >& >( *entries[ i ] ); - parameter_container.addParameter< bool >( entry_name, entry.defaultValue ); - continue; - } - else if( entries[ i ]->getEntryType() == "int" ) - { - ConfigEntry< int >& entry = dynamic_cast< ConfigEntry< int >& >( *entries[ i ] ); - parameter_container.addParameter< int >( entry_name, entry.defaultValue ); - continue; - } - else if( entries[ i ]->getEntryType() == "double" ) - { - ConfigEntry< double >& entry = dynamic_cast< ConfigEntry< double >& >( *entries[ i ] ); - parameter_container.addParameter< double >( entry_name, entry.defaultValue ); - continue; - } - else if( entries[ i ]->getEntryType() == "ConfigEntryList< TNL::String >" ) - { - ConfigEntryList< String >& entry = dynamic_cast< ConfigEntryList< String >& >( *entries[ i ] ); - parameter_container.addList< String >( entry_name, entry.defaultValue ); - continue; - } - else if( entries[ i ]->getEntryType() == "ConfigEntryList< bool >" ) - { - ConfigEntryList< bool >& entry = dynamic_cast< ConfigEntryList< bool >& >( *entries[ i ] ); - parameter_container.addList< bool >( entry_name, entry.defaultValue ); - continue; - } - else if( entries[ i ]->getEntryType() == "ConfigEntryList< int >" ) - { - ConfigEntryList< int >& entry = dynamic_cast< ConfigEntryList< int >& >( *entries[ i ] ); - parameter_container.addList< int >( entry_name, entry.defaultValue ); - continue; - } - else if( entries[ i ]->getEntryType() == "ConfigEntryList< double >" ) - { - ConfigEntryList< double >& entry = dynamic_cast< ConfigEntryList< double >& >( *entries[ i ] ); - parameter_container.addList< double >( entry_name, entry.defaultValue ); - continue; - } - else - { - throw std::runtime_error( "Method ConfigDescription::addMissingEntries encountered " - "unsupported entry type: " + entries[ i ]->getEntryType() ); - } - } - } - } - - //! Check for all entries with the flag 'required'. - /*! Returns false if any parameter is missing. - */ - bool checkMissingEntries( Config::ParameterContainer& parameter_container, - bool printUsage, - const char* programName ) const - { - const int size = entries.size(); - std::vector< std::string > missingParameters; - for( int i = 0; i < size; i++ ) - { - const char* entry_name = entries[ i ] -> name.getString(); - if( entries[ i ] -> required && - ! parameter_container.checkParameter( entry_name ) ) - missingParameters.push_back( entry_name ); - } - if( missingParameters.size() > 0 ) - { - std::cerr << "Some mandatory parameters are misssing. They are listed at the end. " << std::endl; - if( printUsage ) - this->printUsage( programName ); - std::cerr << "Add the following missing parameters to the command line: " << std::endl << " "; - for( int i = 0; i < (int) missingParameters.size(); i++ ) - std::cerr << "--" << missingParameters[ i ] << " ... "; - std::cerr << std::endl; - return false; - } - return true; - } - - /** - * \brief Prints configuration description with the \e program_name at the top. - * - * \param program_name Name of the program - */ - void printUsage( const char* program_name ) const - { - std::cout << "Usage of: " << program_name << std::endl << std::endl; - const int entries_num = entries.size(); - int max_name_length( 0 ); - int max_type_length( 0 ); - for( int j = 0; j < entries_num; j++ ) - if( ! entries[ j ]->isDelimiter() ) - { - max_name_length = std::max( max_name_length, - entries[ j ] -> name. getLength() ); - max_type_length = std::max( max_type_length, - entries[ j ] -> getUIEntryType().getLength() ); - } - max_name_length += 2; // this is for '--' - - for( int j = 0; j < entries_num; j++ ) - { - if( entries[ j ]->isDelimiter() ) - { - std::cout << std::endl; - std::cout << entries[ j ]->description; - std::cout << std::endl << std::endl; - } - else - { - std::cout << std::setw( max_name_length + 3 ) << String( "--" ) + entries[ j ]->name - << std::setw( max_type_length + 5 ) << entries[ j ] -> getUIEntryType() - << " " << entries[ j ]->description; - if( entries[ j ] -> required ) - std::cout << " *** REQUIRED ***"; - if( entries[ j ]->hasEnumValues() ) - { - std::cout << std::endl - << std::setw( max_name_length + 3 ) << "" - << std::setw( max_type_length + 5 ) << "" - << " "; - entries[ j ]->printEnumValues(); - } - if( entries[ j ]->hasDefaultValue ) - { - std::cout << std::endl - << std::setw( max_name_length + 3 ) << "" - << std::setw( max_type_length + 5 ) << "" - << " "; - std::cout << "- Default value is: " << entries[ j ]->printDefaultValue(); - } - std::cout << std::endl; - } - } - std::cout << std::endl; - } - - //bool parseConfigDescription( const char* file_name ); + // iterators + auto begin() noexcept { return entries.begin(); } + auto begin() const noexcept { return entries.begin(); } + auto cbegin() const noexcept { return entries.cbegin(); } + auto end() noexcept { return entries.end(); } + auto end() const noexcept { return entries.end(); } + auto cend() const noexcept { return entries.cend(); } protected: std::vector< std::unique_ptr< ConfigEntryBase > > entries; @@ -407,7 +201,5 @@ protected: bool isCurrentEntryList = false; }; -} //namespace Config -} //namespace TNL - -#include <TNL/Config/parseCommandLine.h> +} // namespace Config +} // namespace TNL diff --git a/src/TNL/Config/ConfigEntry.h b/src/TNL/Config/ConfigEntry.h index 370366e5ea3c7e906f948417d66c32de41b01aea..ff27d7708cdb2783bf5ce1869bb9a7ee290c3e9b 100644 --- a/src/TNL/Config/ConfigEntry.h +++ b/src/TNL/Config/ConfigEntry.h @@ -2,110 +2,119 @@ ConfigEntry.h - description ------------------- begin : Jul 5, 2014 - copyright : (C) 2014 by Tomas Oberhuber + copyright : (C) 2014 by Tomas Oberhuber et al. email : tomas.oberhuber@fjfi.cvut.cz ***************************************************************************/ /* See Copyright Notice in tnl/Copyright */ +// Implemented by: Tomáš Oberhuber, Jakub Klinkovský + #pragma once #include <vector> +#include <sstream> -#include <TNL/TypeInfo.h> #include <TNL/Config/ConfigEntryBase.h> +#include <TNL/Config/ConfigEntryType.h> namespace TNL { namespace Config { -template< typename EntryType > -struct ConfigEntry : public ConfigEntryBase +template< typename EntryType, typename DefaultValueType = EntryType > +class ConfigEntry : public ConfigEntryBase { - EntryType defaultValue; + static_assert( std::is_same< EntryType, DefaultValueType >::value || std::is_same< std::vector< EntryType >, DefaultValueType >::value, + "DefaultValueType must be the same as either EntryType or std::vector< EntryType >" ); - std::vector< EntryType > enumValues; + DefaultValueType defaultValue; - public: + std::vector< EntryType > enumValues; - ConfigEntry( const String& name, - const String& description, +public: + ConfigEntry( const std::string& name, + const std::string& description, bool required ) : ConfigEntryBase( name, description, required ) { - hasDefaultValue = false; + _hasDefaultValue = false; } - ConfigEntry( const String& name, - const String& description, + ConfigEntry( const std::string& name, + const std::string& description, bool required, - const EntryType& defaultValue) + const DefaultValueType& defaultValue) : ConfigEntryBase( name, description, required ), defaultValue( defaultValue ) { - hasDefaultValue = true; + _hasDefaultValue = true; } - String getEntryType() const + virtual std::string getUIEntryType() const override { - return TNL::getType< EntryType >(); + return Config::getUIEntryType< DefaultValueType >(); } - String getUIEntryType() const + virtual std::string printDefaultValue() const override { - return TNL::Config::getUIEntryType< EntryType >(); + // printDefaultValue must be compilable even if DefaultValueType is std::vector, + // so we can't override the method in ConfigEntryList + return _print_value( defaultValue ); } - String printDefaultValue() const + virtual bool hasEnumValues() const override { - return convertToString( defaultValue ); + if( enumValues.size() > 0 ) + return true; + return false; } - std::vector< EntryType >& getEnumValues() + virtual void printEnumValues( std::ostream& str ) const override { - return this->enumValues; + str << "- Can be: "; + int i; + for( i = 0; i < (int) enumValues.size() - 1; i++ ) + str << enumValues[ i ] << ", "; + str << enumValues[ i ]; + str << " "; } - bool hasEnumValues() const + virtual DefaultValueType getDefaultValue() const { - if( enumValues.size() > 0 ) - return true; - return false; + return defaultValue; } - void printEnumValues() const + virtual std::vector< EntryType >& getEnumValues() { - std::cout << "- Can be: "; - int i; - for( i = 0; i < (int) enumValues.size() - 1; i++ ) - std::cout << enumValues[ i ] << ", "; - std::cout << enumValues[ i ]; - std::cout << " "; + return enumValues; + } + + virtual const std::vector< EntryType >& getEnumValues() const + { + return enumValues; + } + +private: + static std::string _print_value( const EntryType& value ) + { + std::stringstream str; + str << value; + return str.str(); } - bool checkValue( const EntryType& value ) const + static std::string _print_value( const std::vector< EntryType >& vec ) { - if( this->enumValues.size() > 0 ) - { - bool found( false ); - for( int i = 0; i < (int) this->enumValues.size(); i++ ) - if( value == this->enumValues[ i ] ) - { - found = true; - break; - } - if( ! found ) - { - std::cerr << "The value " << value << " is not allowed for the config entry " << this->name << "." << std::endl; - this->printEnumValues(); - std::cerr << std::endl; - return false; - } - } - return true; + std::stringstream str; + str << "[ "; + for( std::size_t i = 0; i < vec.size() - 1; i++ ) + str << vec[ i ] << ", "; + str << vec[ vec.size() - 1 ]; + str << " ]"; + return str.str(); } }; diff --git a/src/TNL/Config/ConfigEntryBase.h b/src/TNL/Config/ConfigEntryBase.h index c6dc19fbfecaeb61a7dfcefcd2720522357e9922..8a38cb68377ced38cba8ba36e0af8fb085bcdb75 100644 --- a/src/TNL/Config/ConfigEntryBase.h +++ b/src/TNL/Config/ConfigEntryBase.h @@ -2,47 +2,59 @@ ConfigEntryBase.h - description ------------------- begin : Jul 5, 2014 - copyright : (C) 2014 by Tomas Oberhuber + copyright : (C) 2014 by Tomas Oberhuber et al. email : tomas.oberhuber@fjfi.cvut.cz ***************************************************************************/ /* See Copyright Notice in tnl/Copyright */ +// Implemented by: Tomáš Oberhuber, Jakub Klinkovský + #pragma once +#include <string> + namespace TNL { namespace Config { -struct ConfigEntryBase +class ConfigEntryBase { - String name; +protected: + std::string name; - String description; + std::string description; bool required; - bool hasDefaultValue; + bool _hasDefaultValue; - ConfigEntryBase( const String& name, - const String& description, +public: + ConfigEntryBase( const std::string& name, + const std::string& description, bool required ) : name( name ), description( description ), required( required ), - hasDefaultValue( false ) + _hasDefaultValue( false ) {} - virtual String getEntryType() const = 0; + const std::string& getName() const { return name; } + + const std::string& getDescription() const { return description; } + + bool isRequired() const { return required; } + + bool hasDefaultValue() const { return _hasDefaultValue; } - virtual String getUIEntryType() const = 0; + virtual std::string getUIEntryType() const = 0; virtual bool isDelimiter() const { return false; } - virtual String printDefaultValue() const { return ""; } + virtual std::string printDefaultValue() const { return ""; } virtual bool hasEnumValues() const { return false; } - virtual void printEnumValues() const {} + virtual void printEnumValues( std::ostream& str ) const {} virtual ~ConfigEntryBase() = default; }; diff --git a/src/TNL/Config/ConfigEntryList.h b/src/TNL/Config/ConfigEntryList.h index 86f2642349ad470f2a8fd268ad117b1d3baf268a..7d6c06c71fc0cd9ca2bd7958a79b21b0e9b1bcf7 100644 --- a/src/TNL/Config/ConfigEntryList.h +++ b/src/TNL/Config/ConfigEntryList.h @@ -2,115 +2,27 @@ ConfigEntryList.h - description ------------------- begin : Jul 5, 2014 - copyright : (C) 2014 by Tomas Oberhuber + copyright : (C) 2014 by Tomas Oberhuber et al. email : tomas.oberhuber@fjfi.cvut.cz ***************************************************************************/ /* See Copyright Notice in tnl/Copyright */ -#pragma once +// Implemented by: Tomáš Oberhuber, Jakub Klinkovský -#include <vector> +#pragma once -#include <TNL/TypeInfo.h> -#include <TNL/Config/ConfigEntryBase.h> +#include <TNL/Config/ConfigEntry.h> namespace TNL { namespace Config { template< typename EntryType > -struct ConfigEntryList : public ConfigEntryBase +class ConfigEntryList : public ConfigEntry< EntryType, std::vector< EntryType > > { - EntryType defaultValue; - - std::vector< EntryType > enumValues; - - public: - - ConfigEntryList( const String& name, - const String& description, - bool required ) - : ConfigEntryBase( name, - description, - required ) - { - hasDefaultValue = false; - } - - ConfigEntryList( const String& name, - const String& description, - bool required, - const EntryType& defaultValue) - : ConfigEntryBase( name, - description, - required ), - defaultValue( defaultValue ) - { - hasDefaultValue = true; - } - - String getEntryType() const - { - return String("ConfigEntryList< ") + TNL::getType< EntryType >() + " >"; - } - - String getUIEntryType() const - { - return TNL::Config::getUIEntryType< std::vector< EntryType > >(); - } - - String printDefaultValue() const - { - return convertToString( defaultValue ); - } - - std::vector< EntryType >& getEnumValues() - { - return this->enumValues; - } - - bool hasEnumValues() const - { - if( enumValues.size() > 0 ) - return true; - return false; - } - - void printEnumValues() const - { - std::cout << "- Can be: "; - int i; - for( i = 0; i < (int) enumValues.size() - 1; i++ ) - std::cout << enumValues[ i ] << ", "; - std::cout << enumValues[ i ]; - std::cout << " "; - } - - bool checkValue( const std::vector< EntryType >& values ) const - { - if( this->enumValues.size() != 0 ) - { - for( int j = 0; j < (int) values.size(); j++ ) - { - const EntryType& value = values[ j ]; - bool found( false ); - for( int i = 0; i < (int) this->enumValues.size(); i++ ) - if( value == this->enumValues[ i ] ) - { - found = true; - break; - } - if( ! found ) - { - std::cerr << "The value " << value << " is not allowed for the config entry " << this->name << "." << std::endl; - this->printEnumValues(); - std::cerr << std::endl; - return false; - } - } - } - return true; - } +public: + // inherit constructors + using ConfigEntry< EntryType, std::vector< EntryType > >::ConfigEntry; }; } // namespace Config diff --git a/src/TNL/Config/ConfigEntryType.h b/src/TNL/Config/ConfigEntryType.h index bb656f8fcf6b38d07e68bb06a3c65e11a90e0269..b93cdaffb731c1a1b9b22de03df603e9816eeb82 100644 --- a/src/TNL/Config/ConfigEntryType.h +++ b/src/TNL/Config/ConfigEntryType.h @@ -2,54 +2,105 @@ ConfigEntryType.h - description ------------------- begin : Jul 5, 2014 - copyright : (C) 2014 by Tomas Oberhuber + copyright : (C) 2014 by Tomas Oberhuber et al. email : tomas.oberhuber@fjfi.cvut.cz ***************************************************************************/ /* See Copyright Notice in tnl/Copyright */ +// Implemented by: Tomáš Oberhuber, Jakub Klinkovský + #pragma once +#include <type_traits> #include <vector> - -#include <TNL/String.h> +#include <TNL/variant.hpp> // backport of std::variant from C++17 namespace TNL { namespace Config { -template< typename EntryType > -inline String getUIEntryType() { return "Unknown type."; }; +using mpark::variant; +using mpark::get; +using mpark::monostate; +using mpark::holds_alternative; -template<> inline String getUIEntryType< String >() { return "string"; }; -template<> inline String getUIEntryType< bool >() { return "bool"; }; -template<> inline String getUIEntryType< int >() { return "integer"; }; -template<> inline String getUIEntryType< double >() { return "real"; }; +// aliases for integer types +using UnsignedInteger = std::size_t; +using Integer = std::make_signed_t< std::size_t >; -template<> inline String getUIEntryType< std::vector< String > >() { return "list of string"; }; -template<> inline String getUIEntryType< std::vector< bool > >() { return "list of bool"; }; -template<> inline String getUIEntryType< std::vector< int > >() { return "list of integer"; }; -template<> inline String getUIEntryType< std::vector< double > >() { return "list of real"; }; +using Parameter = variant< monostate, + bool, + Integer, + UnsignedInteger, + double, + std::string, + std::vector< bool >, + std::vector< Integer >, + std::vector< UnsignedInteger >, + std::vector< double >, + std::vector< std::string > + >; -struct ConfigEntryType +template< typename T > +struct ParameterTypeCoercion { - String basic_type; + using type = + std::conditional_t< std::is_same< T, bool >::value, bool, + std::conditional_t< std::is_integral< T >::value && std::is_signed< T >::value, Integer, + std::conditional_t< std::is_integral< T >::value && std::is_unsigned< T >::value, UnsignedInteger, + std::conditional_t< std::is_floating_point< T >::value, double, + std::conditional_t< std::is_base_of< std::string, T >::value, std::string, + std::conditional_t< std::is_same< std::decay_t< T >, const char* >::value, std::string, + T + > + > + > + > + > + >; - bool list_entry; + static type convert( const T& v ) { return v; } + template< typename Result > + static Result convert_back( const type& v ) { return v; } +}; - ConfigEntryType() = default; +template< typename T > +struct ParameterTypeCoercion< std::vector< T > > +{ + using type = std::vector< typename ParameterTypeCoercion< T >::type >; - ConfigEntryType( const String& _basic_type, - const bool _list_entry ) - : basic_type( _basic_type ), - list_entry( _list_entry ) - {} + static type convert( const std::vector< T >& vec ) + { + type new_vec; + for( auto value : vec ) + new_vec.push_back( value ); + return new_vec; + } - void Reset() + template< typename Result > + static Result convert_back( const type& vec ) { - basic_type.clear(); - list_entry = false; + Result new_vec; + for( auto value : vec ) + new_vec.push_back( value ); + return new_vec; } }; +template< typename EntryType > +std::string getUIEntryType() { throw std::logic_error( "getUIEntryType called with unknown type." ); }; + +template<> inline std::string getUIEntryType< bool >() { return "bool"; }; +template<> inline std::string getUIEntryType< Integer >() { return "integer"; }; +template<> inline std::string getUIEntryType< UnsignedInteger >() { return "unsigned integer"; }; +template<> inline std::string getUIEntryType< double >() { return "real"; }; +template<> inline std::string getUIEntryType< std::string >() { return "string"; }; + +template<> inline std::string getUIEntryType< std::vector< bool > >() { return "list of bool"; }; +template<> inline std::string getUIEntryType< std::vector< Integer > >() { return "list of integer"; }; +template<> inline std::string getUIEntryType< std::vector< UnsignedInteger > >() { return "list of unsigned integer"; }; +template<> inline std::string getUIEntryType< std::vector< double > >() { return "list of real"; }; +template<> inline std::string getUIEntryType< std::vector< std::string > >() { return "list of string"; }; + } // namespace Config } // namespace TNL diff --git a/src/TNL/Config/ParameterContainer.h b/src/TNL/Config/ParameterContainer.h index 79a50e151063cd9b5358add30422d713e40a0cc8..264842c9418f91aeac479dd5f1a686992dfc68d8 100644 --- a/src/TNL/Config/ParameterContainer.h +++ b/src/TNL/Config/ParameterContainer.h @@ -1,327 +1,186 @@ /*************************************************************************** - Config::ParameterContainer.h - description + ParameterContainer.h - description ------------------- begin : 2007/06/15 - copyright : (C) 2007 by Tomas Oberhuber + copyright : (C) 2007 by Tomas Oberhuber et al. email : tomas.oberhuber@fjfi.cvut.cz ***************************************************************************/ /* See Copyright Notice in tnl/Copyright */ +// Implemented by: Tomáš Oberhuber, Jakub Klinkovský + #pragma once +#include <unordered_map> #include <vector> -#include <memory> +#include <TNL/Config/ConfigEntryType.h> #include <TNL/TypeInfo.h> -#include <TNL/String.h> -//#include <TNL/Debugging/StackBacktrace.h> +#include <TNL/Exceptions/ConfigError.h> namespace TNL { namespace Config { -struct ParameterBase -{ - ParameterBase( const String& name, - const String& type ) - : name( name ), type( type ) - {} - - String name, type; - - // Virtual destructor is needed to avoid undefined behaviour when deleting the - // ParameterContainer::parameters vector, see https://stackoverflow.com/a/8752126 - virtual ~ParameterBase() = default; -}; - -template< class T > -struct Parameter : public ParameterBase -{ - Parameter( const String& name, - const String& type, - const T& value ) - : ParameterBase( name, type ), value( value ) - {} - - T value; -}; - class ParameterContainer { public: /** * \brief Adds new parameter to the ParameterContainer. * - * \tparam T Type of parameter value. * \param name Name of the new parameter. * \param value Value assigned to the parameter. */ template< class T > - bool addParameter( const String& name, + void addParameter( const std::string& name, const T& value ) { - parameters.push_back( std::make_unique< Parameter< T > >( name, TNL::getType< T >(), value ) ); - return true; + parameters.emplace( name, ParameterTypeCoercion< T >::convert( value ) ); } /** * \brief Adds new parameter to the ParameterContainer. * - * \tparam T Type of parameter value. * \param name Name of the new parameter. * \param value Value assigned to the parameter. */ template< class T > - bool addList( const String& name, - const T& value ) + void addParameter( const std::string& name, + const std::vector< T >& value ) { - std::vector< T > v; - v.push_back( value ); - parameters.push_back( std::make_unique< Parameter< std::vector< T > > >( name, TNL::getType< T >(), v ) ); - return true; + parameters.emplace( name, ParameterTypeCoercion< std::vector< T > >::convert( value ) ); } /** - * \brief Checks if the ParameterContainer contains a parameter specified by its name. + * \brief Adds new list parameter to the ParameterContainer. * - * \param name Name of the parameter. + * \param name Name of the new parameter. + * \param value Vector of values assigned to the parameter. */ - bool checkParameter( const String& name ) const + template< class T > + void addList( const std::string& name, + const std::vector< T >& value ) { - const int size = parameters.size(); - for( int i = 0; i < size; i++ ) - if( parameters[ i ]->name == name ) - return true; - return false; + addParameter( name, value ); } /** - * \brief Checks whether the ParameterContainer contains all specified parameter names. + * \brief Adds new list parameter to the ParameterContainer. * - * \param name Name of the parameter. + * \param name Name of the new parameter. + * \param value First value assigned to the parameter. + * \param values Other values assigned to the parameter. */ - bool checkParameters( std::initializer_list< String > names ) const + template< class T, class... Ts > + void addList( const std::string& name, + const T& value, + const Ts&... values ) { - for( auto name : names ) - if( ! checkParameter( name ) ) - return false; - return true; + addParameter( name, std::vector< T >{value, values...} ); } /** - * \brief Assigns new \e value to the parameter \e name. + * \brief Checks if the ParameterContainer contains a parameter specified by its name. * - * \tparam T Type of the parameter value. - * \param name Name of parameter. - * \param value Value of type T assigned to the parameter. + * \param name Name of the parameter. */ - template< class T > - bool setParameter( const String& name, - const T& value ) + bool checkParameter( const std::string& name ) const { - for( int i = 0; i < (int) parameters.size(); i++ ) { - if( parameters[ i ]->name == name ) { - if( parameters[ i ]->type == TNL::getType< T >() ) { - Parameter< T >& parameter = dynamic_cast< Parameter< T >& >( *parameters[ i ] ); - parameter.value = value; - return true; - } - else { - std::cerr << "Parameter " << name << " already exists with different type " - << parameters[ i ]->type << " not " - << TNL::getType< T >() << std::endl; - throw 0; - } - } - } - return addParameter< T >( name, value ); + return parameters.count( name ); } /** - * \brief Checks whether the parameter \e name is given the \e value. + * \brief Checks if the ParameterContainer contains all specified parameter names. * - * Returns \e true if the parameter \e name is given the \e value. - * If the parameter does not have any value or has different value then the given - * \e value the method returns \e false and shows message when \e verbose is \e true. - * - * \param name Name of parameter. - * \param value Value of type T we want to check whether is assigned to the parameter. - * \param verbose Boolean value defining whether to show error message (when true) or not (when false). + * \param names List of the parameter names. + */ + bool checkParameters( std::initializer_list< String > names ) const + { + for( auto name : names ) + if( ! checkParameter( name ) ) + return false; + return true; + } + + /** + * \brief Checks if the parameter \e name already exists in ParameterContainer and holds a value of type \e T. * - * \par Example - * \include ParameterContainerExample.cpp + * \param name Name of the parameter. */ template< class T > - bool getParameter( const String& name, - T& value, - bool verbose = true ) const + bool checkParameterType( const std::string& name ) const { - for( int i = 0; i < (int) parameters.size(); i++ ) - if( parameters[ i ]->name == name ) - { - // dynamic_cast throws std::bad_cast if parameters[i] does not have the type Parameter<T> - const Parameter< T >& parameter = dynamic_cast< Parameter< T >& >( *parameters[ i ] ); - value = parameter.value; + using CoercedType = typename ParameterTypeCoercion< T >::type; + auto search = parameters.find( name ); + if( search != parameters.end() ) { + if( holds_alternative< CoercedType >( search->second ) ) return true; - } - if( verbose ) - { - std::cerr << "Missing parameter '" << name << "'." << std::endl; - throw 0; //PrintStackBacktrace; } return false; } /** - * \brief Returns parameter value. + * \brief Assigns new \e value to the parameter \e name. * + * \tparam T Type of the parameter value. * \param name Name of parameter. + * \param value Value of type T assigned to the parameter. */ template< class T > - T getParameter( const String& name ) const + void setParameter( const std::string& name, + const T& value ) { - for( int i = 0; i < (int) parameters.size(); i++ ) { - if( parameters[ i ]->name == name ) { - // dynamic_cast throws std::bad_cast if parameters[i] does not have the type Parameter<T> - const Parameter< T >& parameter = dynamic_cast< Parameter< T >& >( *parameters[ i ] ); - return parameter.value; + using CoercedType = typename ParameterTypeCoercion< T >::type; + auto search = parameters.find( name ); + if( search != parameters.end() ) { + if( holds_alternative< CoercedType >( search->second ) ) { + search->second = (CoercedType) value; + } + else { + throw std::logic_error( "Parameter " + name + " already exists with different type. " + "Current type index is " + std::to_string( search->second.index() ) + + " (variant type is " + std::string( TNL::getType< Parameter >() ) + "), " + "tried to set value of type " + std::string( TNL::getType< T >() ) + "." ); } } - std::cerr << "The program attempts to get unknown parameter " << name << std::endl; - std::cerr << "Aborting the program." << std::endl; - throw 0; + addParameter< T >( name, value ); } /** - * \brief Checks whether the parameter list \e name is given the \e value. - * - * Returns \e true if the parameter list \e name is given the \e value. - * If the parameter list does not have any value or has different value then the given - * \e value the method returns \e false and shows message when \e verbose is \e true. - * - * \param name Name of parameter list. - * \param value Value of type T we want to check whether is assigned to the parameter. - * \param verbose Boolean value defining whether to show error message (when true) or not (when false). + * \brief Returns parameter value. * - * \par Example - * \include ParameterContainerExample.cpp + * \param name Name of the parameter. */ template< class T > - bool getParameter( const String& name, - std::vector< T >& value, - bool verbose = true ) const + T getParameter( const std::string& name ) const { - for( int i = 0; i < (int) parameters.size(); i++ ) - if( parameters[ i ]->name == name ) - { - // dynamic_cast throws std::bad_cast if parameters[i] does not have the type Parameter<T> - const Parameter< std::vector< T > >& parameter = dynamic_cast< Parameter< std::vector< T > >& >( *parameters[ i ] ); - value = parameter.value; - return true; - } - if( verbose ) - { - std::cerr << "Missing parameter '" << name << "'." << std::endl; - throw 0; //PrintStackBacktrace; + using CoercedType = typename ParameterTypeCoercion< T >::type; + auto search = parameters.find( name ); + if( search != parameters.end() ) { + if( holds_alternative< CoercedType >( search->second ) ) + return ParameterTypeCoercion< T >::template convert_back< T >( get< CoercedType >( search->second ) ); + else + throw Exceptions::ConfigError( "Parameter " + name + " holds a value of different type than requested. " + "Current type index is " + std::to_string( search->second.index() ) + + " (variant type is " + std::string( TNL::getType< Parameter >() ) + "), " + "tried to get value of type " + std::string( TNL::getType< T >() ) + "." ); } - return false; + throw Exceptions::ConfigError( "The program attempts to get unknown parameter " + name + "." ); } /** * \brief Returns parameter list. * - * \param name Name of parameter list. + * \param name Name of the parameter list. */ template< class T > - const std::vector< T >& getList( const String& name ) const - { - for( int i = 0; i < (int) parameters.size(); i++ ) { - if( parameters[ i ]->name == name ) { - // dynamic_cast throws std::bad_cast if parameters[i] does not have the type Parameter<T> - const Parameter< std::vector< T > >& parameter = dynamic_cast< Parameter< std::vector< T > >& >( *parameters[ i ] ); - return parameter.value; - } - } - std::cerr << "The program attempts to get unknown parameter " << name << std::endl; - std::cerr << "Aborting the program." << std::endl; - throw 0; - } - - -/* - //! Broadcast to other nodes in MPI cluster - void MPIBcast( int root, MPI_Comm mpi_comm = MPI_COMM_WORLD ) + std::vector< T > getList( const std::string& name ) const { - #ifdef USE_MPI - int i; - int size = parameters. getSize(); - :: MPIBcast( size, 1, root, mpi_comm ); - for( i = 0; i < size; i ++ ) - { - if( MPIGetRank() == root ) - { - tnlParameterBase* param = parameters[ i ]; - param -> type. MPIBcast( root, MPI_COMM_WORLD ); - param -> name. MPIBcast( root, MPI_COMM_WORLD ); - if( param -> type == "String" ) - { - ( ( tnlParameter< String >* ) param ) -> value. MPIBcast( root, mpi_comm ); - } - if( param -> type == "bool" ) - { - :: MPIBcast( ( ( tnlParameter< bool >* ) param ) -> value, 1, root, mpi_comm ); - } - if( param -> type == "int" ) - { - :: MPIBcast( ( ( tnlParameter< int >* ) param ) -> value, 1, root, mpi_comm ); - } - if( param -> type == "double" ) - { - :: MPIBcast( ( ( tnlParameter< double >* ) param ) -> value, 1, root, mpi_comm ); - } - } - else - { - String param_type, param_name; - param_type. MPIBcast( root, MPI_COMM_WORLD ); - param_name. MPIBcast( root, MPI_COMM_WORLD ); - if( param_type == "mString" ) - { - String val; - val. MPIBcast( root, mpi_comm ); - addParameter< String >( param_name. getString(), - val ); - } - if( param_type == "bool" ) - { - bool val; - :: MPIBcast( val, 1, root, mpi_comm ); - addParameter< bool >( param_name. getString(), - val ); - } - if( param_type == "int" ) - { - int val; - :: MPIBcast( val, 1, root, mpi_comm ); - addParameter< int >( param_name. getString(), - val ); - } - if( param_type == "double" ) - { - double val; - :: MPIBcast( val, 1, root, mpi_comm ); - addParameter< double >( param_name. getString(), - val ); - } - - } - } - #endif + return getParameter< std::vector< T > >( name ); } -*/ protected: - std::vector< std::unique_ptr< ParameterBase > > parameters; + std::unordered_map< std::string, Parameter > parameters; }; } // namespace Config diff --git a/src/TNL/Config/iniparser.hpp b/src/TNL/Config/iniparser.hpp new file mode 100644 index 0000000000000000000000000000000000000000..bfda58d79c0a560e7b617902aa754d04ad27f34e --- /dev/null +++ b/src/TNL/Config/iniparser.hpp @@ -0,0 +1,1508 @@ +/*==============================================================================================================/ +| _ _ _ ___ _ _ ___ ____ | +| | | ___| | _____ _ _ ___( ) |_ _| \ | |_ _| _ \ __ _ _ __ ___ ___ _ __ | +| | | / _ \ |/ / __| | | / __|/ | || \| || || |_) / _` | '__/ __|/ _ \ '__| | +| | |__| __/ <\__ \ |_| \__ \ | || |\ || || __/ (_| | | \__ \ __/ | | +| |_____\___|_|\_\___/\__, |___/ |___|_| \_|___|_| \__,_|_| |___/\___|_| | +| |___/ | +/===============================================================================================================/ +| All-in-one INI file parser | +| Provides convenient cross-platform class to load and save .INI files | +| Extends classic INI-file format with | +| -> arrays (comma (',') separated values: |val1, val2, val3|) | +| -> maps (declared as |key1:val1, key2:val2, ... , keyN:valN|) | +| -> nested sections (Section2 is considered child of Section1, if Section2 is defined as [Section1.Section2]) | +| -> file includes (use ";#include <file_path>" to include file with relative or full system path <file_path>) | +| Please look in provided file ini-test/test1.ini for extended ini examples, in test_app.cpp for usage examples | +| Language: C++, STL used | +| Version: 1.1 | +/===============================================================================================================/ +| Copyright (c) 2015 by Borovik Alexey +| MIT License +| +| Permission is hereby granted, free of charge, to any person obtaining a +| copy of this software and associated documentation files (the "Software"), +| to deal in the Software without restriction, including without limitation +| the rights to use, copy, modify, merge, publish, distribute, sublicense, +| and/or sell copies of the Software, and to permit persons to whom the +| Software is furnished to do so, subject to the following conditions: +| +| The above copyright notice and this permission notice shall be included in +| all copies or substantial portions of the Software. +| +| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +| FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +| DEALINGS IN THE SOFTWARE. +/===============================================================================================================*/ + +#ifndef _INIPARSER_H +#define _INIPARSER_H + +/*---------------------------------------------------------------------------------------------------------------/ +/ Includes +/---------------------------------------------------------------------------------------------------------------*/ +#include <string> // for std::string +#include <vector> // for std::vector +#include <map> // for std::map +#include <sstream> // for std::stringstream +#include <algorithm> // for std::transform +#include <functional> // for std::not1, std::ptr_fun +#include <cctype> // for std::isspace() +#include <ctype.h> // for tolower() and toupper() +#include <fstream> // for std::fstream +#include <string.h> // for strlen() +#include <iomanip> // for std::setprecision + +#include <TNL/TypeInfo.h> // for TNL::getType +/*---------------------------------------------------------------------------------------------------------------/ +/ Defines & Settings +/---------------------------------------------------------------------------------------------------------------*/ + +// Error codes +#define INI_ERR_INVALID_FILENAME -1 // Can't open file for reading or writing +#define INI_ERR_PARSING_ERROR -2 // File parse error + +// INI file syntax can be changed here +// NOTE: When saving INI files first characters of provided arrays are used + +/// Each of the characters in this string opens section +#define INI_SECTION_OPEN_CHARS "[{" +/// Each of the characters in this string closes section +#define INI_SECTION_CLOSE_CHARS "]}" +/// Each of the characters in this string starts comment +#define INI_COMMENT_CHARS ";#" +/// Each of the characters in this string separates entry's name from entry's value +#define INI_NAME_VALUE_SEP_CHARS "=:" +/// Each of the characters in this string when found last in input line tells that next line +/// should be considered as current line's continuation +#define INI_MULTILINE_CHARS "\\/" + +// Delimiter of values in array +#define INI_ARRAY_DELIMITER ',' +// Symbol, opening the segment of array (INI_ARRAY_DELIMITER in segment is not considered as delimiter) +#define INI_ARRAY_SEGMENT_OPEN '{' +// Symbol, closing the segment of array +#define INI_ARRAY_SEGMENT_CLOSE '}' +// Escape character in INI file (INI_ARRAY_SEGMENT_OPEN and INI_ARRAY_SEGMENT_CLOSE if found inside +// elements of array and maps should be escaped for proper parsing) +#define INI_ESCAPE_CHARACTER '\\' +// Symbol, separating key from value in map +#define INI_MAP_KEY_VAL_DELIMETER ':' +// Delimiter, separating parent name from child name in section full name +#define INI_SUBSECTION_DELIMETER '.' +// Delimiter to separate section name from value name when getting value directly from file +#define INI_SECTION_VALUE_DELIMETER ':' + +// Inclusion line +// Please note, that inclusion command must appear in comment section (i.e. ;INI_INCLUDE_SEQ) +#define INI_INCLUDE_SEQ "#include " + +// Path delimiter +#ifdef WIN32 +# define SYSTEM_PATH_DELIM '\\' +#else +# define SYSTEM_PATH_DELIM '/' +#endif + +/*---------------------------------------------------------------------------------------------------------------/ +/ Auxiliaries +/---------------------------------------------------------------------------------------------------------------*/ + +// All parser-related stuff is in INI namespace +namespace INI +{ + /// String to lower case + static inline void string_to_lower(std::string& str) + { + std::transform(str.begin(), str.end(), str.begin(), ::tolower); + } + + /// String to upper case + static inline void string_to_upper(std::string& str) + { + std::transform(str.begin(), str.end(), str.begin(), ::toupper); + } + + /// stream to be used for conversions + class convstream: public std::stringstream + { + public: + convstream() {*this << std::setprecision(17) << std::boolalpha;} + }; + + /// Convert anything (int, double etc) to string + template<class T> std::string t_to_string(const T& i) + { + convstream ss; + std::string s; + ss << i; + s = ss.str(); + return s; + } + /// Special case for string (to avoid overheat) + template<> inline std::string t_to_string<std::string>(const std::string& i) + { + return i; + } + + /// Convert string to anything (int, double, etc) + template<class T> T string_to_t(const std::string& v) + { + convstream ss; + T out; + ss << v; + ss >> out; + if (ss.fail()) + throw std::runtime_error("Value '" + v + "' could not be converted to type " + TNL::getType<T>().getString() + "."); + return out; + } + /// Special case for string + template<> inline std::string string_to_t<std::string>(const std::string& v) + { + return v; + } + /// Special case for boolean value + /// std::boolalpha only covers 'true' or 'false', while we have more cases + template<> inline bool string_to_t<bool>(const std::string& v) + { + if (!v.size()) + return false; + if (v[0] == '1' || v[0] == 't' || v[0] == 'T' || v[0] == 'Y' || v[0] == 'y') + return true; + return false; + } + + // Calling isspace with signed chars in Visual Studio causes assert failure in DEBUG builds + // This hack is approved by MS itself +#if defined (_MSC_VER) + static inline int __in_isspace(int ch) {return std::isspace((unsigned char)ch);} +#else +# define __in_isspace std::isspace +#endif + + // Trim string from start + static inline std::string <rim(std::string &s) { + s.erase(s.begin(), std::find_if(s.begin(), s.end(), std::not1(std::ptr_fun<int, int>(__in_isspace)))); + return s; + } + + // Trim string from end + static inline std::string &rtrim(std::string &s) { + s.erase(std::find_if(s.rbegin(), s.rend(), std::not1(std::ptr_fun<int, int>(__in_isspace))).base(), s.end()); + return s; + } + + // Trim string from both ends + static inline std::string &trim(std::string &s) { + return ltrim(rtrim(s)); + } + + /// Split strings (and trim result) based on the provided separator + /// Strings in the vector would be trimmed as well + static inline std::vector<std::string> split_string(const std::string& str, const std::string& sep) + { + std::vector<std::string> lst; + if (str.empty()) + return lst; + size_t cur_pos = 0; + size_t prev_pos = 0; + for (; ; cur_pos+=sep.size(),prev_pos = cur_pos) + { + cur_pos = str.find(sep,cur_pos); + if (cur_pos == std::string::npos) + break; + std::string out = str.substr(prev_pos,cur_pos-prev_pos); + trim(out); + lst.push_back(out); + } + std::string out = str.substr(prev_pos); + trim(out); + lst.push_back(out); + return lst; + } + + /// Join array of strings into one with specified separator + static inline std::string join_string(const std::vector<std::string>& array, const std::string& sep) + { + std::string ret; + if (!array.size()) + return ret; + for (size_t i = 0; i < array.size()-1; i++) + ret += array.at(i) + sep; + ret += array.at(array.size()-1); + return ret; + } + + /// Test whether provided char is in the charset + static inline bool char_is_one_of(int ch, const char* charset) + { + for (const char* it = charset; *it != '\0'; ++it) + if (ch == *it) + return true; + return false; + } + + // Replace every occurrence of @param what to @param ret in @param str + static inline std::string& str_replace(std::string& str, const std::string& what, const std::string& rep) + { + int diff = rep.size() - what.size() + 1; + for (size_t pos = 0; ;pos += diff) + { + pos = str.find(what.c_str(),pos); + if (pos == std::string::npos) + break; + str.replace(pos,what.size(),rep); + } + return str; + } + + // normalize path (for relative path to be system-independent) + static inline void normalize_path(std::string& path) + { +#ifdef WIN32 + str_replace(path,"/","\\"); +#else + str_replace(path,"\\","/"); +#endif + } + + // get file path (excluding file name) + static inline std::string file_path(const std::string& file_fullname) + { + size_t pos = file_fullname.rfind(SYSTEM_PATH_DELIM); + if (pos == std::string::npos) + return std::string(); + return file_fullname.substr(0,pos); + } + + // get file name (excluding file path) + static inline std::string file_name(const std::string& file_fullname) + { + size_t pos = file_fullname.rfind(SYSTEM_PATH_DELIM); + if (pos == std::string::npos) + return file_fullname; + return file_fullname.substr(pos+1); + } + + // check whether path is absolute + static inline bool path_is_absolute(const std::string& path) + { +#ifdef WIN32 + if (path.size() < 2) + return false; + // absolute filenames should start with drive letter (i.e. c:) + // or network path (\\) + if (path[1] == ':' || (path[0] == '\\' && path[1] == '\\')) + return true; + return false; +#else + // everything is simple under POSIX: absolute path should start with / + if (path.size() < 1) + return false; + if (path[0] == '/') + return true; + return false; +#endif + } + + // check whether path is relative + static inline bool path_is_relative(const std::string& path) {return !path_is_absolute(path);} + + /*---------------------------------------------------------------------------------------------------------------/ + / INI-related classes + /---------------------------------------------------------------------------------------------------------------*/ + + // forward declarations + class Value; + class Array; + class Map; + class Section; + class File; + typedef std::vector<Section*> SectionVector; + + /** + * Reference-counting helper class + * This should be used as a member in reference-counting classes Value, Array and Map + **/ + template<class T> class RefCountPtr + { + public: + RefCountPtr():_ptr(NULL){} + RefCountPtr(const RefCountPtr& cp):_ptr(cp._ptr) {Increment();} + RefCountPtr(const T& val):_ptr(NULL){_ptr = new refcont(val);} + virtual ~RefCountPtr() {Decrement();} + RefCountPtr& operator= (const RefCountPtr& rt) + { + Decrement(); + _ptr = rt._ptr; + Increment(); + return *this; + } + bool operator== (const RefCountPtr& val) const + { + if (_ptr == val._ptr) + return true; + if (!_ptr || !val._ptr) + return false; + return _ptr->val == val._ptr->val; + } + bool operator!= (const Value& val) const { return !(*this == val);} + bool IsValid() const {return (_ptr != NULL);} + T* DataPtr() {return (_ptr==NULL?NULL:&_ptr->val);} + const T* DataPtr() const { return (_ptr==NULL?NULL:&_ptr->val);} + T& Data() {return _ptr->val;} + const T& Data() const {return _ptr->val;} + T DataObj(const T& defval = T()) const {return (_ptr==NULL?defval:_ptr->val);} + T* operator->() {return DataPtr();} + const T* operator->() const {return DataPtr();} + void Copy() + { + if (!_ptr) + _ptr = new refcont(); + else if (_ptr->count > 1) + { + refcont* cp = new refcont(_ptr->val); + Decrement(); + _ptr = cp; + } + } + private: + void Decrement() + { + if (!_ptr) + return; + _ptr->count--; + if (!_ptr->count) + { + delete(_ptr); + _ptr = NULL; + } + } + void Increment() + { + if (_ptr) + _ptr->count++; + } + struct refcont + { + refcont() :count(1) {} + refcont(const T& pval) :val(pval), count(1) {} + T val; + size_t count; + }; + refcont* _ptr; + }; + + /** + * Value to be stored in INI-file + * This is a simple reference-counting class, storing a pointer to original string + * It has some functions for easy converting to\from other types + * Value can contain array (in string representation) and be converted to\from it + **/ + class Value + { + public: + Value(){} + Value(const Value& cp):_val(cp._val){} + template<class T> Value(const T& val){Set(val);} + Value(const char* value){Set(value);} + virtual ~Value(){} + + Value& operator= (const Value& rt) {_val = rt._val; return *this;} + template<class T> Value& operator= (const T& value) { Set(value); return *this;} + bool operator== (const Value& rgh) const { return _val == rgh._val;} + bool operator!= (const Value& val) const { return !(*this == val);} + bool operator< (const Value& rgh) const + { + if (!_val.IsValid()) + return true; + if (!rgh._val.IsValid()) + return false; + return (_val.Data() < rgh._val.Data()); + } + + /// Template function to convert value to any type + template<class T> T Get() const { return string_to_t<T>(_val.DataObj());} + void Set(const std::string& str) { _val = RefCountPtr<std::string>(str); } + /// Template function to set value + template<class T> void Set(const T& value) { Set(t_to_string(value)); } + // const char* (as any pointer) is defaulting in template to int or bool, which is not what we want + void Set(const char* value) { _val = RefCountPtr<std::string>(std::string(value)); } + + /// Converts Value to std::string + std::string AsString() const { return _val.DataObj();} + /// Converts Value to integer + int AsInt() const {return Get<int>();} + /// Converts Value to double + double AsDouble() const {return Get<double>();} + /// Converts Value to boolean + bool AsBool() const {return Get<bool>();} + /// Converts Value to Array + Array AsArray() const; + /// Converts Value to Map + Map AsMap() const; + /// Converts Value to specified type T + template<class T> T AsT() const {return Get<T>();} + + private: + RefCountPtr<std::string> _val; + }; + + /** + * Array of Values + * Reference-counting class + **/ + class Array + { + public: + Array(){} + Array(const Array& cp) :_val(cp._val){} + Array(const std::string& str, char sep = INI_ARRAY_DELIMITER, char seg_open = INI_ARRAY_SEGMENT_OPEN, + char seg_close = INI_ARRAY_SEGMENT_CLOSE, char esc = INI_ESCAPE_CHARACTER) + { + FromString(str,sep,seg_open,seg_close,esc); + } + template<class T> Array(const std::vector<T>& vect){FromVector(vect);} + virtual ~Array() {} + + Array& operator= (const Array& rt) {_val = rt._val; return *this;} + Array& operator<< (const Value & val) { return PushBack(val);} + /// Returns reference to value on specified position @param pos + /// Array is automatically widen (if needed) for that operation to always succeed + Value& operator[] (size_t pos) + { + _val.Copy(); + if (pos >= _val->size()) + _val->insert(_val->end(),pos-_val->size()+1,Value()); + return _val.Data()[pos]; + } + + /// Gets value with specified position @param pos + /// If @param pos is >= Size() returns @param def_val + Value GetValue(size_t pos, const Value& def_val = Value()) const + { + if (!_val.IsValid()) + return def_val; + if (pos >= _val->size()) + return def_val; + return _val->at(pos); + } + /// Sets value @param value to specified position @param pos + /// Array is automatically widen (if needed) to allow this operation + void SetValue(size_t pos, const Value& value) + { + _val.Copy(); + if (pos >= _val->size()) + { + _val->insert(_val->end(),pos-_val->size(),Value()); + _val->push_back(value); + } + else + _val->at(pos) = value; + } + /// Adds @param val to the end of the Array + Array& PushBack(const Value& val) + { + _val.Copy(); + _val->push_back(val); + return *this; + } + /// Returns array size + size_t Size() const { if (!_val.IsValid()) return 0; return _val->size(); } + + /// Formats string with all values of this array represented as strings, separated by @param sep + std::string ToString(char sep = INI_ARRAY_DELIMITER, char seg_open = INI_ARRAY_SEGMENT_OPEN, + char seg_close = INI_ARRAY_SEGMENT_CLOSE, char esc = INI_ESCAPE_CHARACTER) const + { + std::string ret; + if (!_val.IsValid()) + return ret; + for (size_t i = 0; i < _val->size(); i++) + { + std::string tmp = _val->at(i).AsString(); + std::string out; + bool has_delim = false; + for (size_t j = 0; j < tmp.size(); j++) + { + if (tmp[j] == seg_open || tmp[j] == seg_close) + out.push_back(esc); + else if (tmp[j] == sep) + has_delim = true; + out.push_back(tmp[j]); + } + if (has_delim) + ret += seg_open + out + seg_close; + else + ret += out; + if (i != _val->size()-1) + ret += sep; + } + return ret; + } + /// Fills array with values from string @param str, separated by @param sep + void FromString(const std::string& str, char sep = INI_ARRAY_DELIMITER, + char seg_open = INI_ARRAY_SEGMENT_OPEN, + char seg_close = INI_ARRAY_SEGMENT_CLOSE, char esc = INI_ESCAPE_CHARACTER) + { + _val.Copy(); + _val->clear(); + if (str.empty()) + return; + std::string cur_str; + int segm_cnt = 0; + bool escaped = false; + int preesc = 0; + for (size_t i = 0; i <= str.size(); ++i) + { + if (escaped && i < str.size()) + { + cur_str.push_back(str[i]); + escaped = false; + if (str[i] == esc) + preesc = 2; + } + else if ((i == str.size()) || (str[i] == sep && !segm_cnt)) + { + trim(cur_str); + _val->push_back(cur_str); + cur_str.clear(); + } + else if (str[i] == seg_open && !preesc) + { + if (segm_cnt) + cur_str.push_back(str[i]); + segm_cnt++; + } + else if (str[i] == seg_close && !preesc) + { + segm_cnt--; + if (segm_cnt < 0) + segm_cnt = 0; + if (segm_cnt) + cur_str.push_back(str[i]); + } + else if (str[i] == esc) + escaped = true; + else + cur_str.push_back(str[i]); + if (preesc) + preesc--; + } + } + template<class T> std::vector<T> ToVector() const + { + std::vector<T> ret; + if (!_val.IsValid()) + return ret; + for (size_t i = 0; i < _val->size(); ++i) + ret.push_back(_val->at(i).AsT<T>()); + return ret; + } + template<class T> void FromVector(const std::vector<T>& vect) + { + _val.Copy(); + _val->clear(); + for (size_t i = 0; i < vect.size(); ++i) + _val->push_back(Value(vect.at(i))); + } + /// Converts Array to Value + Value ToValue() const + { + return Value(ToString()); + } + /// Gets Array from Value + void FromValue(const Value& val) + { + FromString(val.AsString()); + } + private: + RefCountPtr<std::vector<Value> > _val; + }; + + template<> inline void Value::Set<Array> (const Array& value) + { + Set(value.ToString()); + } + template<> inline Array Value::Get<Array>() const + { + if (!_val.IsValid()) + return Array(); + return Array(_val.Data()); + } + inline Array Value::AsArray() const {return Get<Array>();} + + /** + * Map of Values + * Reference-counting class + **/ + class Map + { + public: + Map(){} + Map(const Map& cp) :_val(cp._val){} + Map(const std::string& str, char sep = INI_ARRAY_DELIMITER, char seg_open = INI_ARRAY_SEGMENT_OPEN, + char seg_close = INI_ARRAY_SEGMENT_CLOSE, char kval = INI_MAP_KEY_VAL_DELIMETER, + char esc = INI_ESCAPE_CHARACTER) + { + FromString(str,sep,seg_open,seg_close,kval,esc); + } + template<class T, class M> Map(const std::map<T,M>& mp){FromMap(mp);} + virtual ~Map(){} + Map& operator= (const Map& rt) {_val = rt._val; return *this;} + /// Returns reference to value of the specified key @param key + /// Map is automatically inserts entry for this operation to always succeed + Value& operator[] (const Value& key) + { + _val.Copy(); + return _val.Data()[key]; + } + + /// Gets value for specified key @param key + /// If there is no specified key - returns @param def_val + Value GetValue(const Value& key, const Value& def_val = Value()) const + { + if (!_val.IsValid()) + return def_val; + std::map<Value,Value>::const_iterator it = _val->find(key); + if (it == _val->end()) + return def_val; + return it->second; + } + /// Sets value @param value to specified key @param key + void SetValue(const Value& key, const Value& value) + { + _val.Copy(); + std::pair<std::map<Value,Value>::iterator,bool> res = + _val->insert(std::pair<Value,Value>(key,value)); + if (!res.second) + res.first->second = value; + } + /// Returns map size + size_t Size() const { if (!_val.IsValid()) return 0; return _val->size();} + + + /// Formats string with all values of this map + std::string ToString(char sep = INI_ARRAY_DELIMITER, char seg_open = INI_ARRAY_SEGMENT_OPEN, + char seg_close = INI_ARRAY_SEGMENT_CLOSE, char kval = INI_MAP_KEY_VAL_DELIMETER, + char esc = INI_ESCAPE_CHARACTER) const + { + std::string ret; + if (!_val.IsValid()) + return ret; + for (std::map<Value,Value>::const_iterator it = _val->begin(); it != _val->end(); ++it) + { + if (it != _val->begin()) + ret += sep; + std::string key = it->first.AsString(); + std::string out_key; + std::string val = it->second.AsString(); + std::string out_val; + // key + bool has_delim = false; + for (size_t j = 0; j < key.size(); j++) + { + if (key[j] == seg_open || key[j] == seg_close) + out_key.push_back(esc); + else if (key[j] == kval || key[j] == sep) + has_delim = true; + out_key.push_back(key[j]); + } + if (has_delim) + out_key = seg_open + out_key + seg_close; + // value + has_delim = false; + for (size_t j = 0; j < val.size(); j++) + { + if (val[j] == seg_open || val[j] == seg_close) + out_val.push_back(esc); + else if (val[j] == kval || val[j] == sep) + has_delim = true; + out_val.push_back(val[j]); + } + if (has_delim) + out_val = seg_open + out_val + seg_close; + // pair + ret += out_key + kval + out_val; + } + return ret; + } + /// Fills map with values from string @param str + void FromString(const std::string& str, char sep = INI_ARRAY_DELIMITER, + char seg_open = INI_ARRAY_SEGMENT_OPEN, + char seg_close = INI_ARRAY_SEGMENT_CLOSE, char kval = INI_MAP_KEY_VAL_DELIMETER, + char esc = INI_ESCAPE_CHARACTER) + { + _val.Copy(); + _val->clear(); + if (str.empty()) + return; + std::string cur_str; + std::string cur_key; + int segm_cnt = 0; + bool escaped = false; + int preesc = 0; + for (size_t i = 0; i <= str.size(); ++i) + { + if (escaped && i < str.size()) + { + cur_str.push_back(str[i]); + escaped = false; + if (str[i] == esc) + preesc = 2; + } + else if ((i==str.size()) || (str[i] == sep && !segm_cnt)) + { + trim(cur_str); + std::pair<std::map<Value,Value>::iterator,bool> res = + _val->insert(std::pair<Value,Value>(Value(cur_key),Value(cur_str))); + if (!res.second) + res.first->second = cur_str; + cur_str.clear(); + cur_key.clear(); + } + else if (str[i] == kval && !segm_cnt) + { + trim(cur_str); + cur_key = cur_str; + cur_str.clear(); + } + else if (str[i] == seg_open && !preesc) + { + if (segm_cnt) + cur_str.push_back(str[i]); + segm_cnt++; + } + else if (str[i] == seg_close && !preesc) + { + segm_cnt--; + if (segm_cnt < 0) + segm_cnt = 0; + if (segm_cnt) + cur_str.push_back(str[i]); + } + else if (str[i] == esc) + escaped = true; + else + cur_str.push_back(str[i]); + if (preesc) + preesc--; + } + } + template<class T, class M> std::map<T,M> ToMap() const + { + std::map<T,M> ret; + if (!_val.IsValid()) + return ret; + for (auto it = _val->begin(); it != _val->end(); ++it) + ret.insert(std::pair<T,M>(it->first.AsT<T>(),it->second.AsT<M>())); + return ret; + } + template<class T, class M> void FromMap(const std::map<T,M>& mp) + { + _val.Copy(); + _val->clear(); + for (typename std::map<T,M>::const_iterator it = mp.begin(); it != mp.end(); ++it) + _val->insert(std::pair<Value,Value>(Value(it->first),Value(it->second))); + } + /// Converts Array to Value + Value ToValue() const + { + return Value(ToString()); + } + /// Gets Array from Value + void FromValue(const Value& val) + { + FromString(val.AsString()); + } + private: + RefCountPtr<std::map<Value,Value> > _val; + }; + + template<> inline void Value::Set<Map> (const Map& value) + { + Set(value.ToString()); + } + template<> inline Map Value::Get<Map>() const + { + if (!_val.IsValid()) + return Map(); + return Map(_val.Data()); + } + inline Map Value::AsMap() const {return Get<Map>();} + + /*---------------------------------------------------------------------------------------------------------------/ + / INI file creation and parsing + /---------------------------------------------------------------------------------------------------------------*/ + + /** + * One section of the ini-file + * This can be created by INIFile class only + **/ + class Section + { + friend class File; + typedef std::map<std::string, Value> EntryMap; + typedef std::pair<std::string,Value> EntryPair; + typedef std::map<std::string, std::string> CommentMap; + typedef std::pair<std::string, std::string> CommentPair; + /*-----------------------------------------------------------------------------------------------------------/ + / General functions & iterators + /-----------------------------------------------------------------------------------------------------------*/ + public: + typedef EntryMap::iterator values_iter; + typedef EntryMap::const_iterator const_values_iter; + values_iter ValuesBegin() {return _entries.begin();} + const_values_iter ValuesBegin() const {return _entries.begin();} + values_iter ValuesEnd() {return _entries.end();} + const_values_iter ValuesEnd() const {return _entries.end();} + size_t ValuesSize() const {return _entries.size();} + + /// Returns full section name (subsection name will contain '.', separating subsection part) + const std::string& FullName() const { return _name;} + /// Return section name (will be parsed to get individual section name) + std::string Name() const + { + return _name.substr(_name.rfind(INI_SUBSECTION_DELIMETER)+1); + } + /// Get comment, associated with this section (written before the line with the section, or after it) + std::string Comment() const {return _comment;} + /// Return all keys in this section + std::vector<std::string> GetSectionKeys() const + { + std::vector<std::string> keys; + for (EntryMap::const_iterator it = _entries.begin(); it != _entries.end(); it++) + keys.push_back(it->first); + return keys; + } + /// Get Value + Value GetValue(const std::string& key, const Value& def_value = Value()) const + { + EntryMap::const_iterator it = _entries.find(key); + if (it == _entries.end()) + return def_value; + return it->second; + } + /// Set Value + void SetValue(const std::string& key, const Value& val, const std::string& comment = std::string()) + { + _entries[key] = val; + if (!comment.empty()) + _comments[key] = comment; + } + /// Set Value to array + void SetArrayValue(const std::string& key, size_t pos, const Value& val) + { + Array ar = GetValue(key).AsArray(); + ar.SetValue(pos,val); + SetValue(key,ar); + } + /// Remove value + void RemoveValue(const std::string& key) + { + EntryMap::iterator it = _entries.find(key); + if (it == _entries.end()) + return; + _entries.erase(it); + } + /// Get comment, associated with provided value + std::string GetComment(const std::string& key) const + { + CommentMap::const_iterator it = _comments.find(key); + if (it == _comments.end()) + return std::string(); + return it->second; + } + /// Set comment for specified key + void SetComment(const std::string& key, const std::string& comment) + { + _comments[key] = comment; + } + /// Save the section's contents to specified stream + void Save(std::ostream& stream) const; + /*-----------------------------------------------------------------------------------------------------------/ + / Parent & child parsing + /-----------------------------------------------------------------------------------------------------------*/ + public: + Section* FindParent() const; + Section* GetParent(); + Section* FindSubSection(const std::string& name) const; + Section* GetSubSection(const std::string& name); + SectionVector FindSubSections() const; + /*-----------------------------------------------------------------------------------------------------------/ + / Internal contents + /-----------------------------------------------------------------------------------------------------------*/ + private: + /// Only INI::File can create sections + Section(File* file, const std::string& name, const std::string& comment = std::string()): + _file(file),_name(name),_comment(comment){} + /// Class should be copied only by File class to properly handle _file + Section(const Section& cp):_file(cp._file),_name(cp._name),_comment(cp._comment),_entries(cp._entries), + _comments(cp._comments){} + File* _file; // file, this section is associated with + std::string _name; // name of the section + std::string _comment; // comment to the section + EntryMap _entries; // all entries in the section + CommentMap _comments; // all comments, associated with values in the section + }; + + /** + * Main class of the parser + * Provides way to load and save ini-files, as well as + * setting specific values in them + **/ + class File + { + public: + /// Sections stores all values and comments inside them + typedef std::map<std::string, Section*> SectionMap; + typedef std::pair<std::string, Section*> SectionPair; + typedef SectionMap::iterator sections_iter; + typedef SectionMap::const_iterator const_sections_iter; + /// Result of previous parse operation + struct PResult + { + PResult():error_code(0),error_line_num(0){} + void Set(int code, int line_num = 0, const std::string& line = std::string()) + { + error_code = code; + error_line_num = line_num; + error_line = line; + } + void Invalidate() {error_code = 0; error_line_num = 0; error_line.clear();} + std::string GetErrorDesc() const + { + if (!error_code) + return "No error"; + if (error_code == INI_ERR_INVALID_FILENAME) + return std::string("Failed to open file ") + file_name + "!"; + if (error_code == INI_ERR_PARSING_ERROR) + return std::string("Parse error in file ") + file_name + " on line " + + t_to_string(error_line) + ": \"" + error_line + "\""; + return "Unknown error!"; + } + int error_code; // code of the error. 0 if no error + int error_line_num; // number of line with the error + std::string error_line; // line with error + std::string file_name; // name of the file with error (will be empty for stream) + operator bool() const {return !error_code;} + }; + public: + File(){} + File(const std::string& fname) { Load(fname);} + File(const File& lf) { CopyFrom(lf); } + File& operator= (const File& lf) { Unload(); CopyFrom(lf); return *this; } + void CopyFrom(const File& lf) + { + for (SectionMap::const_iterator it = lf._sections.begin(); it != lf._sections.end(); it++) + { + Section* sect = new Section(*it->second); + sect->_file = this; + _sections.insert(SectionPair(it->first,sect)); + } + _result = lf._result; + } + virtual ~File() {Unload();} + /*---------------------------------------------------------------------------------------------------------------/ + / Section & values manipulations + /---------------------------------------------------------------------------------------------------------------*/ + public: + /// A way to iterate through all sections + /// Section pointer can be accesed as SectionMap::iterator::second, section name - as ::first + size_t SectionsSize() const {return _sections.size();} + sections_iter SectionsBegin() {return _sections.begin();} + const_sections_iter SectionsBegin() const {return _sections.begin();} + sections_iter SectionsEnd() {return _sections.end();} + const_sections_iter SectionsEnd() const {return _sections.end();} + + /// Get value from the file + /// Use INI_SECTION_VALUE_DELIMETER to separate section name from value name + Value GetValue(const std::string& name, const Value& def_val = Value()) + { + size_t pos = name.rfind(INI_SECTION_VALUE_DELIMETER); + std::string nm; + if (pos != std::string::npos) + nm = name.substr(0,pos); + SectionMap::iterator it = _sections.find(nm); + if (it == _sections.end()) + return def_val; + return it->second->GetValue(name.substr(pos+1),def_val); + } + + /// Set value to the file + /// Use INI_SECTION_VALUE_DELIMETER to separate section name from value name + void SetValue(const std::string& name, const Value& value, const std::string& comment = std::string()) + { + size_t pos = name.rfind(INI_SECTION_VALUE_DELIMETER); + std::string nm; + if (pos != std::string::npos) + nm = name.substr(0,pos); + Section* sect = GetSection(nm); + sect->SetValue(name.substr(pos+1),value,comment); + } + + /// Set array Value to array + void SetArrayValue(const std::string& key, size_t pos, const Value& val) + { + Array ar = GetValue(key).AsArray(); + ar.SetValue(pos,val); + SetValue(key,ar); + } + + /// Returns pointer to section with specified name + /// If section does not exists - creates it + Section* GetSection(const std::string& name) + { + SectionMap::iterator it = _sections.find(name); + if (it != _sections.end()) + return it->second; + Section* sc = new Section(this,name); + _sections.insert(SectionPair(name,sc)); + return sc; + } + + /// Find existing section by name + /// @return pointer to existing section or NULL + Section* FindSection(const std::string& name) const + { + SectionMap::const_iterator it = _sections.find(name); + if (it == _sections.end()) + return NULL; + return it->second; + } + + /// Deletes section with specified name + void DeleteSection(const std::string& name) + { + SectionMap::iterator it = _sections.find(name); + if (it != _sections.end()) + _sections.erase(it); + } + + /// Get subsection of specified section with specified name + Section* FindSubSection(const Section* sect, const std::string& name) const + { + return FindSection(sect->FullName() + INI_SUBSECTION_DELIMETER + name); + } + + /// If subsection does not exists, creates it + Section* GetSubSection(Section* sect, const std::string& name) + { + return GetSection(sect->FullName() + INI_SUBSECTION_DELIMETER + name); + } + + /// Get parent section of the specified section + Section* FindParentSection(const Section* sect) const + { + size_t pos = sect->FullName().rfind(INI_SUBSECTION_DELIMETER); + std::string nm; + if (pos != std::string::npos) + nm = sect->FullName().substr(0,pos); + return FindSection(nm); + } + /// Get parent section (created if needed) + Section* GetParentSection(const Section* sect) + { + size_t pos = sect->FullName().rfind(INI_SUBSECTION_DELIMETER); + std::string nm; + if (pos != std::string::npos) + nm = sect->FullName().substr(0,pos); + return GetSection(nm); + } + /// Find subsections of the specified section + SectionVector FindSubSections(const Section* sect) const + { + SectionVector ret; + if (sect->_file != this) + return ret; + for (SectionMap::const_iterator it = _sections.begin(); it != _sections.end(); ++it) + { + if (it->second == sect) + continue; + if (it->first.find(sect->FullName() + INI_SUBSECTION_DELIMETER) != std::string::npos) + ret.push_back(it->second); + } + return ret; + } + // Get top-level sections (not child of any other sections) + SectionVector GetTopLevelSections() const + { + SectionVector ret; + for (SectionMap::const_iterator it = _sections.begin(); it != _sections.end(); ++it) + { + if (it->first.find(INI_SUBSECTION_DELIMETER) == std::string::npos) + ret.push_back(it->second); + } + return ret; + } + /*---------------------------------------------------------------------------------------------------------------/ + / Load & Save functions + /---------------------------------------------------------------------------------------------------------------*/ + public: + /// Load file from input stream, that must be properly opened and prepared for reading + /// Set @param unload_prev to true for unloading any stuff currently in memory before loading + /// Set @param rpath to be used as relative path when searching for inclusions in files + /// @return 1 if load succeeds, 0 if not + /// in case load was not succesfull you can access extended information by calling ParseResult() + int Load(std::istream& stream, bool unload_prev = false, const std::string& rpath = std::string()) + { + if (unload_prev) + DeleteSections(_sections); + return ParseStream(stream,"",rpath,_sections); + } + /// Load ini from file in system + /// Set @param unload_prev to false for not unloading any stuff currently in memory before loading + int Load(const std::string& fname, bool unload_prev = true) + { + _result.file_name = fname; + normalize_path(_result.file_name); + std::ifstream file(_result.file_name.c_str(), std::ios::in); + if (!file.is_open()) + { + _result.Set(INI_ERR_INVALID_FILENAME); + return 0; + } + return Load(file,unload_prev,file_path(_result.file_name)); + } + + /// Save ini file to stream + void Save(std::ostream& stream) const + { + SaveStream(stream,_sections); + } + + /// Save ini file to file + int Save(const std::string& fname) + { + _result.file_name = fname; + normalize_path(_result.file_name); + std::ofstream file(_result.file_name.c_str(), std::ios::out); + if (!file.is_open()) + { + _result.Set(INI_ERR_INVALID_FILENAME); + return 0; + } + SaveStream(file,_sections); + return 1; + } + + /// Save only one section to specifed stream + void Save(std::ostream& stream, const Section* sect) const + { + SectionMap mp; + mp.insert(SectionPair(sect->FullName(),const_cast<Section*>(sect))); + SaveStream(stream,mp); + } + + /// Adds comment line to provided stream + /// For it to be not associated with anything you should add newline after it + static void AddCommentToStream(std::ostream& stream, const std::string& str) + { + std::vector<std::string> ar = split_string(str,"\n"); + for (size_t i = 0; i < ar.size(); i++) + stream << INI_COMMENT_CHARS[0] << ar.at(i) << std::endl; + } + + /// Adds inclusion line to stream + static void AddIncludeToStream(std::ostream& stream, const std::string& path) + { + stream << INI_COMMENT_CHARS[0] << INI_INCLUDE_SEQ << path << std::endl; + } + + /// Unload memory + void Unload() + { + DeleteSections(_sections); + } + /// Return last operation result + const PResult& LastResult() {return _result;} + /*---------------------------------------------------------------------------------------------------------------/ + / Parsing & Saving internals + /---------------------------------------------------------------------------------------------------------------*/ + protected: + enum LineType + { + EMPTY, + SECTION, + ENTRY, + COMMENT, + ERROR + }; + + /** + * Parse input line + * Line must be concatenated (if needed) and trimmed before passing to this function + * @param input_line - Line to parse + * @param section - will contain section name in case SECTION return + * @param key - will contain key in case ENTRY return + * @param value - will contain value in case ENTRY return + * @param comment - will contain comment in case of return != EMPTY and != ERROR + * @return type of the parsed line + **/ + LineType ParseLine(const std::string& input_line, std::string& section, + std::string& key, std::string& value, std::string& comment) const + { + LineType ret = EMPTY; + size_t last_pos = input_line.npos; + if (input_line.empty()) + return ret; + // comment parsing + if (char_is_one_of(input_line.at(0),INI_COMMENT_CHARS)) + { + ret = COMMENT; + // Can't do it that way, cause of 'initialization of non-const reference of type from a temporary of type' + // stupid GCC rule + //comment = trim(input_line.substr(1)); + comment = input_line.substr(1); + trim(comment); + return ret; + } + // section parsing + else if (char_is_one_of(input_line.at(0),INI_SECTION_OPEN_CHARS)) + { + last_pos = input_line.find_first_of(INI_SECTION_CLOSE_CHARS); + if (last_pos == input_line.npos) + return ERROR; + ret = SECTION; + section = input_line.substr(1,last_pos-1); + trim(section); + last_pos++; + } + // key-value pair parsing + else + { + size_t pos = input_line.find_first_of(INI_NAME_VALUE_SEP_CHARS); + // not section, not comment, not empty - error + if (pos == input_line.npos || pos == input_line.size()-1) + return ERROR; + ret = ENTRY; + key = input_line.substr(0,pos); + trim(key); + last_pos = input_line.find_first_of(INI_COMMENT_CHARS,pos+1); + value = input_line.substr(pos+1,last_pos-pos-1); + trim(value); + if (last_pos != input_line.npos) + last_pos--; + } + // get associated comment + last_pos = input_line.find_first_of(INI_COMMENT_CHARS,last_pos); + if (last_pos != input_line.npos) + { + comment = input_line.substr(last_pos+1); + trim(comment); + } + return ret; + } + + /// Parse provided input stream to specified section map + /// Comments separated from closest section or key-value pair by 1 or more empty strings + /// would be ignored + /// Default section will be created if needed + int ParseStream(std::istream& stream, const std::string& def_section, + const std::string& rpath, SectionMap& pmap) + { + Section* cur_sect = NULL; + std::string pcomment; + std::string prev_line; + _result.Invalidate(); + + // Find whether default section already exists in provided map + // if not - it will be created later if needed + SectionMap::iterator it = pmap.find(def_section); + if (it != pmap.end()) + cur_sect = it->second; + + for (int lnc = 1; !stream.eof(); lnc++) + { + std::string line; + std::getline(stream,line); + trim(line); + if (line.empty()) + { + pcomment.clear(); + continue; + } + // Handle multiline strings + if (char_is_one_of(line.at(line.size()-1),INI_MULTILINE_CHARS)) + { + prev_line = prev_line + line.substr(0,line.size()-1); + continue; + } + else if (!prev_line.empty()) + { + line = prev_line + line; + prev_line.clear(); + } + std::string section_key, value, comment; + LineType lt = ParseLine(line,section_key,section_key,value,comment); + if (lt == EMPTY) + { + pcomment.clear(); + continue; + } + else if (lt == ERROR) + { + _result.Set(INI_ERR_PARSING_ERROR,lnc,line); + return 0; + } + // Handle inclusion + else if (lt == COMMENT && comment.substr(0,strlen(INI_INCLUDE_SEQ)) == INI_INCLUDE_SEQ) + { + std::string incname = comment.substr(strlen(INI_INCLUDE_SEQ)); + trim(incname); + normalize_path(incname); + // try to open file + std::string fpath; + if (path_is_relative(incname) && !rpath.empty()) + fpath = rpath + SYSTEM_PATH_DELIM + incname; + else + fpath = incname; + std::ifstream file(fpath.c_str(), std::ios::in); + std::string prevfn = _result.file_name; + _result.file_name = fpath; + if (!file.is_open()) + { + _result.Set(INI_ERR_INVALID_FILENAME,lnc,line); + return 0; + } + std::string scname; + if (cur_sect) + scname = cur_sect->FullName(); + else + scname = def_section; + if (!ParseStream(file,scname,file_path(fpath),pmap)) + return 0; + _result.file_name = prevfn; + continue; + } + // Add comment (it can be set with any string type, other than EMPTY and ERROR) + pcomment += comment; + // Add section (or modify comment of existing one if needed) + if (lt == SECTION) + { + SectionMap::iterator it = pmap.find(section_key); + if (it == pmap.end()) + { + cur_sect = new Section(this,section_key,pcomment); + pmap.insert(SectionPair(section_key, cur_sect)); + } + else + { + cur_sect = it->second; + if (!pcomment.empty()) + { + if (!it->second->_comment.empty()) + it->second->_comment += stream.widen('\n') + pcomment; + else + it->second->_comment = pcomment; + } + } + pcomment.clear(); + } + else if (lt == ENTRY) + { + // Try to create default section if it is not already in the array + if (!cur_sect) + { + cur_sect = new Section(this,def_section); + pmap.insert(SectionPair(def_section, cur_sect)); + } + cur_sect->SetValue(section_key,value,pcomment); + pcomment.clear(); + } + } + // Clears eof flag for future usage of stream + stream.clear(); + return 1; + } + /// Save provided section map to stream + void SaveStream(std::ostream& stream, const SectionMap& pmap) const + { + for (SectionMap::const_iterator it = pmap.begin(); it != pmap.end(); ++it) + { + if (it->second->ValuesSize() == 0) + continue; + if (!it->second->Comment().empty()) + AddCommentToStream(stream,it->second->Comment()); + if (!it->first.empty()) + stream << INI_SECTION_OPEN_CHARS[0] << it->first << INI_SECTION_CLOSE_CHARS[0] << std::endl; + for (Section::values_iter vit = it->second->ValuesBegin(); vit != it->second->ValuesEnd(); vit++) + { + stream << vit->first << " " << INI_NAME_VALUE_SEP_CHARS[0] << " " << vit->second.AsString(); + std::string cmn = it->second->GetComment(vit->first); + if (!cmn.empty()) + stream << " " << INI_COMMENT_CHARS[0] << cmn; + stream << std::endl; + } + stream << std::endl; + } + } + private: + void DeleteSections(SectionMap& mp) + { + for (SectionMap::iterator it = mp.begin(); it != mp.end(); ++it) + delete(it->second); + mp.clear(); + } + // All sections (including subsections) in one map + SectionMap _sections; + PResult _result; + }; + + /*-----------------------------------------------------------------------------------------------------------/ + / Some functions left unimplemented + /-----------------------------------------------------------------------------------------------------------*/ + inline Section* Section::GetParent() {return _file->GetParentSection(this);} + inline Section* Section::FindParent() const {return _file->FindParentSection(this);} + inline Section* Section::GetSubSection(const std::string& name) {return _file->GetSubSection(this,name);} + inline Section* Section::FindSubSection(const std::string& name) const {return _file->FindSubSection(this,name);} + inline SectionVector Section::FindSubSections() const {return _file->FindSubSections(this);} + inline void Section::Save(std::ostream& stream) const {return _file->Save(stream,this);} +} +/*---------------------------------------------------------------------------------------------------------------/ +/ Stream operators +/---------------------------------------------------------------------------------------------------------------*/ +static inline std::ostream& operator<< (std::ostream& stream, const INI::File& file) +{ + file.Save(stream); + return stream; +} +static inline std::ostream& operator<< (std::ostream& stream, const INI::Section* sect) +{ + sect->Save(stream); + return stream; +} +static inline std::ostream& operator<< (std::ostream& stream, const INI::Array& ar) +{ + stream << ar.ToValue().AsString(); + return stream; +} +static inline std::istream& operator>> (std::istream& stream, INI::File& file) +{ + file.Load(stream,false); + return stream; +} + +/*---------------------------------------------------------------------------------------------------------------/ +/ Little tidying up +/---------------------------------------------------------------------------------------------------------------*/ +#undef INI_SECTION_OPEN_CHARS +#undef INI_SECTION_CLOSE_CHARS +#undef INI_COMMENT_CHARS +#undef INI_NAME_VALUE_SEP_CHARS +#undef INI_MULTILINE_CHARS +#undef INI_ARRAY_DELIMITER +#undef INI_ARRAY_SEGMENT_OPEN +#undef INI_ARRAY_SEGMENT_CLOSE +#undef INI_ESCAPE_CHARACTER +#undef INI_MAP_KEY_VAL_DELIMETER +#undef INI_SUBSECTION_DELIMETER +#undef INI_SECTION_VALUE_DELIMETER +#undef INI_INCLUDE_SEQ +#undef SYSTEM_PATH_DELIM +// Note: error definitions are left + +#endif diff --git a/src/TNL/Config/parseCommandLine.h b/src/TNL/Config/parseCommandLine.h index 8993de027b2d4149112a4d74098478d3bdee3268..afaf19ecc4ca5b1f33c6a197311a730da8cae52f 100644 --- a/src/TNL/Config/parseCommandLine.h +++ b/src/TNL/Config/parseCommandLine.h @@ -2,26 +2,220 @@ parseCommandLine.h - description ------------------- begin : 2007/06/15 - copyright : (C) 2007 by Tomas Oberhuber + copyright : (C) 2007 by Tomas Oberhuber et al. email : tomas.oberhuber@fjfi.cvut.cz ***************************************************************************/ /* See Copyright Notice in tnl/Copyright */ +// Implemented by: Tomáš Oberhuber, Jakub Klinkovský + #pragma once -#include <cstring> #include <string> +#include <sstream> +#include <iomanip> #include <TNL/Config/ConfigDescription.h> #include <TNL/Config/ParameterContainer.h> namespace TNL { +namespace Config { + +/** + * \brief Fills in the parameters from the \e parameters. + * + * Parameters which were not defined in the command line by user but have their default value are added to the congiguration description. + * If there is missing entry with defined default value in the Config::ParameterContainer it is going to be added. + * \param parameters Name of the ParameterContainer object. + */ +inline void +addDefaultValues( const ConfigDescription& config, ParameterContainer& parameters ) +{ + for( const auto& entryBase : config ) + { + const std::string entry_name = entryBase->getName(); + if( entryBase->hasDefaultValue() && ! parameters.checkParameter( entry_name ) ) + { + if( entryBase->getUIEntryType() == "bool" ) { + ConfigEntry< bool >& entry = dynamic_cast< ConfigEntry< bool >& >( *entryBase ); + parameters.addParameter< bool >( entry_name, entry.getDefaultValue() ); + continue; + } + else if( entryBase->getUIEntryType() == "integer" ) { + ConfigEntry< Integer >& entry = dynamic_cast< ConfigEntry< Integer >& >( *entryBase ); + parameters.addParameter< Integer >( entry_name, entry.getDefaultValue() ); + continue; + } + else if( entryBase->getUIEntryType() == "unsigned integer" ) { + ConfigEntry< UnsignedInteger >& entry = dynamic_cast< ConfigEntry< UnsignedInteger >& >( *entryBase ); + parameters.addParameter< UnsignedInteger >( entry_name, entry.getDefaultValue() ); + continue; + } + else if( entryBase->getUIEntryType() == "real" ) { + ConfigEntry< double >& entry = dynamic_cast< ConfigEntry< double >& >( *entryBase ); + parameters.addParameter< double >( entry_name, entry.getDefaultValue() ); + continue; + } + else if( entryBase->getUIEntryType() == "string" ) { + ConfigEntry< std::string >& entry = dynamic_cast< ConfigEntry< std::string >& >( *entryBase ); + parameters.addParameter< std::string >( entry_name, entry.getDefaultValue() ); + continue; + } + else if( entryBase->getUIEntryType() == "list of bool" ) { + ConfigEntryList< bool >& entry = dynamic_cast< ConfigEntryList< bool >& >( *entryBase ); + parameters.addList< bool >( entry_name, entry.getDefaultValue() ); + continue; + } + else if( entryBase->getUIEntryType() == "list of integer" ) { + ConfigEntryList< Integer >& entry = dynamic_cast< ConfigEntryList< Integer >& >( *entryBase ); + parameters.addList< Integer >( entry_name, entry.getDefaultValue() ); + continue; + } + else if( entryBase->getUIEntryType() == "list of unsigned integer" ) { + ConfigEntryList< UnsignedInteger >& entry = dynamic_cast< ConfigEntryList< UnsignedInteger >& >( *entryBase ); + parameters.addList< UnsignedInteger >( entry_name, entry.getDefaultValue() ); + continue; + } + else if( entryBase->getUIEntryType() == "list of real" ) { + ConfigEntryList< double >& entry = dynamic_cast< ConfigEntryList< double >& >( *entryBase ); + parameters.addList< double >( entry_name, entry.getDefaultValue() ); + continue; + } + else if( entryBase->getUIEntryType() == "list of string" ) { + ConfigEntryList< std::string >& entry = dynamic_cast< ConfigEntryList< std::string >& >( *entryBase ); + parameters.addList< std::string >( entry_name, entry.getDefaultValue() ); + continue; + } + else + throw std::runtime_error( "Function addDefaultValues encountered unsupported entry type: " + + entryBase->getUIEntryType() ); + } + } +} -std::vector< String > -parseObjectType( const String& objectType ); +/** + * \brief Prints configuration description with the \e program_name at the top. + * + * \param program_name Name of the program + */ +inline void +printUsage( const ConfigDescription& config, const char* program_name ) +{ + std::cout << "Usage of: " << program_name << std::endl << std::endl; + std::size_t max_name_length = 0; + std::size_t max_type_length = 0; -namespace Config { + for( const auto& entry : config ) { + if( ! entry->isDelimiter() ) { + max_name_length = std::max( max_name_length, entry->getName().length() ); + max_type_length = std::max( max_type_length, entry->getUIEntryType().length() ); + } + } + max_name_length += 2; // this is for "--" + + for( const auto& entry : config ) { + if( entry->isDelimiter() ) + { + std::cout << std::endl; + std::cout << entry->getDescription(); + std::cout << std::endl << std::endl; + } + else + { + std::cout << std::setw( max_name_length + 3 ) << "--" << entry->getName() + << std::setw( max_type_length + 5 ) << entry->getUIEntryType() + << " " << entry->getDescription(); + if( entry->isRequired() ) + std::cout << " *** REQUIRED ***"; + if( entry->hasEnumValues() ) + { + std::cout << std::endl + << std::setw( max_name_length + 3 ) << "" + << std::setw( max_type_length + 5 ) << "" + << " "; + entry->printEnumValues( std::cout ); + } + if( entry->hasDefaultValue() ) + { + std::cout << std::endl + << std::setw( max_name_length + 3 ) << "" + << std::setw( max_type_length + 5 ) << "" + << " "; + std::cout << "- Default value is: " << entry->printDefaultValue(); + } + std::cout << std::endl; + } + } + std::cout << std::endl; +} + +//! Check for all entries with the flag 'required'. +/*! Returns false if any parameter is missing. + */ +inline bool +checkMissingEntries( const ConfigDescription& config, + Config::ParameterContainer& parameters, + bool printUsage, + const char* programName ) +{ + std::vector< std::string > missingParameters; + for( const auto& entryBase : config ) { + const std::string entry_name = entryBase->getName(); + if( entryBase->isRequired() && ! parameters.checkParameter( entry_name ) ) + missingParameters.push_back( entry_name ); + } + if( missingParameters.size() > 0 ) { + std::cerr << "Some mandatory parameters are misssing. They are listed at the end." << std::endl; + if( printUsage ) + Config::printUsage( config, programName ); + std::cerr << "Add the following missing parameters to the command line:" << std::endl << " "; + for( int i = 0; i < (int) missingParameters.size(); i++ ) + std::cerr << "--" << missingParameters[ i ] << " ... "; + std::cerr << std::endl; + return false; + } + return true; +} + +template< typename EntryType, typename DefaultValueType > +void +checkEnumValues( const ConfigEntry< EntryType, DefaultValueType >& entry, const std::string& name, const EntryType& value ) +{ + if( entry.getEnumValues().size() > 0 ) { + for( auto enumValue : entry.getEnumValues() ) + if( value == enumValue ) + return; + std::stringstream str; + str << "The value " << value << " is not allowed for the config entry " << name << ".\n"; + entry.printEnumValues( str ); + throw Exceptions::ConfigError( str.str() ); + } +} + +template< typename EntryType, typename DefaultValueType > +void +checkEnumValues( const ConfigEntry< EntryType, DefaultValueType >& entry, const std::string& name, const std::vector< EntryType >& values ) +{ + if( entry.getEnumValues().size() > 0 ) { + for( auto value : values ) + checkEnumValues( entry, name, value ); + } +} + +template< typename T > +T +convertStringValue( const String& value, const String& param ) +{ + T v; + std::stringstream str; + str << value; + str >> v; + if( str.fail() ) + throw Exceptions::ConfigError( "Value '" + value + "' could not be converted to type " + TNL::getType<T>().getString() + + " as required for the parameter " + param + "." ); + return v; +} inline bool parseCommandLine( int argc, char* argv[], @@ -39,158 +233,138 @@ parseCommandLine( int argc, char* argv[], return true; }; - auto matob = [iequals]( const char* value ) -> int + auto matob = [iequals]( const std::string& value, const std::string& option ) -> int { if( iequals( value, "yes" ) || iequals( value, "true" ) ) return true; if( iequals( value, "no" ) || iequals( value, "false" ) ) return false; - return -1; + throw Exceptions::ConfigError( "Yes/true or no/false is required for the parameter " + option + "." ); }; int i; - bool parse_error( false ); - for( i = 1; i < argc; i++ ) - { - const char* _option = argv[ i ]; - if( _option[ 0 ] != '-' ) - { - std::cerr << "Unknown option " << _option << ". Options must have prefix '--' or '-'." << std::endl; - parse_error = true; - continue; - } - if( strcmp( _option, "--help" ) == 0 ) - { - config_description.printUsage( argv[ 0 ] ); - return true; - } - const char* option = _option + 2; - const ConfigEntryBase* entry; - if( ( entry = config_description.getEntry( option ) ) == NULL ) + try { + for( i = 1; i < argc; i++ ) { - std::cerr << "Unknown parameter " << _option << "." << std::endl; - parse_error = true; - } - else - { - const String& entryType = entry->getEntryType(); - const char* value = argv[ ++i ]; - if( ! value ) - { - std::cerr << "Missing value for the parameter " << option << "." << std::endl; + const std::string _option = argv[ i ]; + if( _option.length() < 3 || _option[ 0 ] != '-' || _option[ 1 ] != '-' ) + throw Exceptions::ConfigError( "Unknown option " + _option + ". Options must be prefixed with \"--\"." ); + if( _option == "--help" ) { + Config::printUsage( config_description, argv[ 0 ] ); + // FIXME: false here indicates that the program should terminate, but the exit code should indicate success instead of failure return false; } - std::vector< String > parsedEntryType = parseObjectType( entryType ); + const std::string option = _option.substr(2); + const ConfigEntryBase* entryBase = config_description.getEntry( option ); + if( entryBase == NULL ) + throw Exceptions::ConfigError( "Unknown parameter " + _option + "." ); + const String entryType = entryBase->getUIEntryType(); + if( i == argc - 1 ) + throw Exceptions::ConfigError( "Missing value for the parameter " + option + "." ); + const std::string value = argv[ ++i ]; + if( value.empty() ) + throw Exceptions::ConfigError( "Missing value for the parameter " + option + "." ); + const std::vector< String > parsedEntryType = entryType.split(); if( parsedEntryType.size() == 0 ) + throw Exceptions::ConfigError( "Internal error: Unknown config entry type " + entryType + "." ); + if( parsedEntryType[ 0 ] == "list" ) { - std::cerr << "Internal error: Unknown config entry type " << entryType << "." << std::endl; - return false; - } - if( parsedEntryType[ 0 ] == "ConfigEntryList" ) - { - std::vector< String > string_list; std::vector< bool > bool_list; - std::vector< int > integer_list; + std::vector< Integer > integer_list; + std::vector< UnsignedInteger > unsigned_integer_list; std::vector< double > real_list; + std::vector< std::string > string_list; - while( i < argc && ( ( argv[ i ] )[ 0 ] != '-' || ( atof( argv[ i ] ) < 0.0 && ( parsedEntryType[ 1 ] == "int" || parsedEntryType[ 1 ] == "double" ) ) ) ) + while( i < argc && std::string( argv[ i ] ).substr(0, 2) != "--" ) { - const char* value = argv[ i ++ ]; - if( parsedEntryType[ 1 ] == "TNL::String" ) - { - string_list.push_back( String( value ) ); + const std::string value = argv[ i++ ]; + if( entryType == "list of bool" ) { + const bool v = matob( value, option ); + bool_list.push_back( v ); + } + else if( entryType == "list of integer" ) { + const Integer v = convertStringValue< Integer >( value, option ); + const ConfigEntryList< Integer >& entry = dynamic_cast< const ConfigEntryList< Integer >& >( *entryBase ); + checkEnumValues( entry, option, v ); + integer_list.push_back( v ); } - else if( parsedEntryType[ 1 ] == "bool" ) - { - const int v = matob( value ); - if( v == -1 ) - { - std::cerr << "Yes/true or no/false is required for the parameter " << option << "." << std::endl; - parse_error = true; - } - else bool_list.push_back( v ); + else if( entryType == "list of unsigned integer" ) { + const UnsignedInteger v = convertStringValue< UnsignedInteger >( value, option ); + const ConfigEntryList< UnsignedInteger >& entry = dynamic_cast< const ConfigEntryList< UnsignedInteger >& >( *entryBase ); + checkEnumValues( entry, option, v ); + unsigned_integer_list.push_back( v ); } - else if( parsedEntryType[ 1 ] == "int" ) - { - integer_list.push_back( atoi( value ) ); + else if( entryType == "list of real" ) { + const double v = convertStringValue< double >( value, option ); + const ConfigEntryList< double >& entry = dynamic_cast< const ConfigEntryList< double >& >( *entryBase ); + checkEnumValues( entry, option, v ); + real_list.push_back( v ); } - else if( parsedEntryType[ 1 ] == "double" ) - { - real_list.push_back( atof( value ) ); + else if( entryType == "list of string" ) { + const ConfigEntryList< std::string >& entry = dynamic_cast< const ConfigEntryList< std::string >& >( *entryBase ); + checkEnumValues( entry, option, value ); + string_list.push_back( value ); } else - { // this will not happen if all entry types are handled above throw std::runtime_error( "Function parseCommandLine encountered unsupported entry type: " + entryType ); - } } - if( string_list.size() ) - parameters.addParameter< std::vector< String > >( option, string_list ); if( bool_list.size() ) parameters.addParameter< std::vector< bool > >( option, bool_list ); if( integer_list.size() ) - parameters.addParameter< std::vector< int > >( option, integer_list ); + parameters.addParameter< std::vector< Integer > >( option, integer_list ); + if( unsigned_integer_list.size() ) + parameters.addParameter< std::vector< UnsignedInteger > >( option, unsigned_integer_list ); if( real_list.size() ) parameters.addParameter< std::vector< double > >( option, real_list ); - if( i < argc ) i --; - continue; + if( string_list.size() ) + parameters.addParameter< std::vector< std::string > >( option, string_list ); } else { - if( parsedEntryType[ 0 ] == "TNL::String" ) - { - if( ! ( ( ConfigEntry< String >* ) entry )->checkValue( value ) ) - return false; - parameters.addParameter< String >( option, value ); - continue; + if( entryType == "bool" ) { + const bool v = matob( value, option ); + parameters.addParameter< bool >( option, v ); } - else if( parsedEntryType[ 0 ] == "bool" ) - { - const int v = matob( value ); - if( v == -1 ) - { - std::cerr << "Yes/true or no/false is required for the parameter " << option << "." << std::endl; - parse_error = true; - } - else parameters.addParameter< bool >( option, v ); - continue; + else if( entryType == "integer" ) { + const Integer v = convertStringValue< Integer >( value, option ); + const ConfigEntry< Integer >& entry = dynamic_cast< const ConfigEntry< Integer >& >( *entryBase ); + checkEnumValues( entry, option, v ); + parameters.addParameter< Integer >( option, v ); } - else if( parsedEntryType[ 0 ] == "int" ) - { - /*if( ! std::isdigit( value ) ) //TODO: Check for real number - { - std::cerr << "Integer constant is required for the parameter " << option << "." << std::endl; - parse_error = true; - continue; - }*/ - if( ! ( ( ConfigEntry< int >* ) entry )->checkValue( atoi( value ) ) ) - return false; - parameters.addParameter< int >( option, atoi( value ) ); + else if( entryType == "unsigned integer" ) { + const UnsignedInteger v = convertStringValue< UnsignedInteger >( value, option ); + const ConfigEntry< UnsignedInteger >& entry = dynamic_cast< const ConfigEntry< UnsignedInteger >& >( *entryBase ); + checkEnumValues( entry, option, v ); + parameters.addParameter< UnsignedInteger >( option, v ); } - else if( parsedEntryType[ 0 ] == "double" ) - { - /*if( ! std::isdigit( value ) ) //TODO: Check for real number - { - std::cerr << "Real constant is required for the parameter " << option << "." << std::endl; - parse_error = true; - continue; - }*/ - if( ! ( ( ConfigEntry< double >* ) entry )->checkValue( atof( value ) ) ) - return false; - parameters.addParameter< double >( option, atof( value ) ); + else if( entryType == "real" ) { + const double v = convertStringValue< double >( value, option ); + const ConfigEntry< double >& entry = dynamic_cast< const ConfigEntry< double >& >( *entryBase ); + checkEnumValues( entry, option, v ); + parameters.addParameter< double >( option, v ); + } + else if( entryType == "string" ) { + const ConfigEntry< std::string >& entry = dynamic_cast< const ConfigEntry< std::string >& >( *entryBase ); + checkEnumValues( entry, option, (std::string) value ); + parameters.addParameter< std::string >( option, value ); } else - { // this will not happen if all entry types are handled above throw std::runtime_error( "Function parseCommandLine encountered unsupported entry type: " + entryType ); - } } } } - config_description.addMissingEntries( parameters ); - if( ! config_description.checkMissingEntries( parameters, printUsage, argv[ 0 ] ) ) + catch ( const Exceptions::ConfigError& e ) { + std::cerr << argv[ 0 ] << ": failed to parse the command line due to the following error:\n" << e.what() << std::endl; + if( printUsage ) + Config::printUsage( config_description, argv[ 0 ] ); + return false; + } + addDefaultValues( config_description, parameters ); + if( ! checkMissingEntries( config_description, parameters, printUsage, argv[ 0 ] ) ) return false; - return ! parse_error; + return true; } } // namespace Config diff --git a/src/TNL/Config/parseINIConfigFile.h b/src/TNL/Config/parseINIConfigFile.h new file mode 100644 index 0000000000000000000000000000000000000000..f03e63f4f88918d68fc372853045b449578f88df --- /dev/null +++ b/src/TNL/Config/parseINIConfigFile.h @@ -0,0 +1,129 @@ +/*************************************************************************** + parseINIConfigFile.h - description + ------------------- + begin : Feb 1, 2020 + copyright : (C) 2020 by Tomas Oberhuber et al. + email : tomas.oberhuber@fjfi.cvut.cz + ***************************************************************************/ + +/* See Copyright Notice in tnl/Copyright */ + +// Implemented by: Jakub Klinkovský + +#pragma once + +#include <set> + +#include <TNL/Config/ConfigDescription.h> +#include <TNL/Config/ParameterContainer.h> +#include <TNL/Config/parseCommandLine.h> // for addDefaultValues and checkEnumValues + +#include "iniparser.hpp" + +namespace TNL { +namespace Config { + +ParameterContainer +parseINIConfigFile( const std::string& configPath, + const ConfigDescription& description ) +{ + ParameterContainer parameters; + + INI::File file; + if( ! file.Load( configPath ) ) + throw std::runtime_error( file.LastResult().GetErrorDesc() ); + + // aggregated sets + std::set< std::string > undefinedOptions; + + // iterate over all entries in the global section + const INI::Section* section = file.GetSection( "" ); + for( auto e = section->ValuesBegin(); e != section->ValuesEnd(); e++ ) { + const std::string name = e->first; + const auto* entryBase = description.getEntry( name ); + if( entryBase == nullptr ) { + undefinedOptions.insert( name ); + continue; + } + const std::string entryType = entryBase->getUIEntryType(); + const auto value = e->second; + if( value.AsString().empty() ) + throw std::runtime_error( "Missing value for the parameter " + name + "." ); + + if( entryType == "bool" ) { + parameters.addParameter< bool >( name, value.AsBool() ); + continue; + } + else if( entryType == "integer" ) { + const auto v = value.AsT< Integer >(); + const ConfigEntry< Integer >& entry = dynamic_cast< const ConfigEntry< Integer >& >( *entryBase ); + checkEnumValues( entry, name, v ); + parameters.addParameter< Integer >( name, v ); + } + else if( entryType == "unsigned integer" ) { + const auto v = value.AsT< UnsignedInteger >(); + const ConfigEntry< UnsignedInteger >& entry = dynamic_cast< const ConfigEntry< UnsignedInteger >& >( *entryBase ); + checkEnumValues( entry, name, v ); + parameters.addParameter< UnsignedInteger >( name, v ); + } + else if( entryType == "real" ) { + const auto v = value.AsDouble(); + const ConfigEntry< double >& entry = dynamic_cast< const ConfigEntry< double >& >( *entryBase ); + checkEnumValues( entry, name, v ); + parameters.addParameter< double >( name, v ); + } + else if( entryType == "string" ) { + const auto v = value.AsString(); + const ConfigEntry< std::string >& entry = dynamic_cast< const ConfigEntry< std::string >& >( *entryBase ); + checkEnumValues( entry, name, v ); + parameters.addParameter< std::string >( name, v ); + continue; + } + else if( entryType == "list of bool" ) { + const auto list = value.AsArray().ToVector< bool >(); + parameters.addList< bool >( name, list ); + } + else if( entryType == "list of integer" ) { + const auto list = value.AsArray().ToVector< Integer >(); + const ConfigEntry< Integer >& entry = dynamic_cast< const ConfigEntry< Integer >& >( *entryBase ); + checkEnumValues( entry, name, list ); + parameters.addList< Integer >( name, list ); + } + else if( entryType == "list of unsigned integer" ) { + const auto list = value.AsArray().ToVector< UnsignedInteger >(); + const ConfigEntry< UnsignedInteger >& entry = dynamic_cast< const ConfigEntry< UnsignedInteger >& >( *entryBase ); + checkEnumValues( entry, name, list ); + parameters.addList< UnsignedInteger >( name, list ); + } + else if( entryType == "list of real" ) { + const auto list = value.AsArray().ToVector< double >(); + const ConfigEntry< double >& entry = dynamic_cast< const ConfigEntry< double >& >( *entryBase ); + checkEnumValues( entry, name, list ); + parameters.addList< double >( name, list ); + } + else if( entryType == "list of string" ) { + const auto list = value.AsArray().ToVector< std::string >(); + const ConfigEntry< std::string >& entry = dynamic_cast< const ConfigEntry< std::string >& >( *entryBase ); + checkEnumValues( entry, name, list ); + parameters.addList< std::string >( name, list ); + } + else + // this will not happen if all entry types are handled above + throw std::runtime_error( "Function parseINIConfigFil encountered unsupported entry type: " + entryType ); + } + + if( ! undefinedOptions.empty() ) { + std::string msg = "The configuration file contains the following options which are not defined in the program:\n"; + for( auto option : undefinedOptions ) + msg += " - " + option + "\n"; + throw std::runtime_error( msg ); + } + + // add default values to the parameters + addDefaultValues( description, parameters ); + + return parameters; +} + +} // namespace Config +} // namespace TNL diff --git a/src/TNL/Containers/StaticVector.hpp b/src/TNL/Containers/StaticVector.hpp index 4a1b41b2198d114bfe31fed16b3d04f37cf3ad5d..bbcf8a09f5f88edc202438cb9e323bd227e6f813 100644 --- a/src/TNL/Containers/StaticVector.hpp +++ b/src/TNL/Containers/StaticVector.hpp @@ -42,12 +42,7 @@ StaticVector< Size, Real >::setup( const Config::ParameterContainer& parameters, const String& prefix ) { for( int i = 0; i < Size; i++ ) - { - double aux; - if( ! parameters.template getParameter< double >( prefix + convertToString( i ), aux ) ) - return false; - this->data[ i ] = aux; - } + this->data[ i ] = parameters.template getParameter< double >( prefix + convertToString( i ) ); return true; } diff --git a/src/TNL/Exceptions/ConfigError.h b/src/TNL/Exceptions/ConfigError.h new file mode 100644 index 0000000000000000000000000000000000000000..275d58cfc25eb517c9ed350ca47bb00c8812cf9d --- /dev/null +++ b/src/TNL/Exceptions/ConfigError.h @@ -0,0 +1,29 @@ +/*************************************************************************** + ConfigError.h - description + ------------------- + begin : Apr 12, 2019 + copyright : (C) 2019 by Tomas Oberhuber et al. + email : tomas.oberhuber@fjfi.cvut.cz + ***************************************************************************/ + +/* See Copyright Notice in tnl/Copyright */ + +// Implemented by: Jakub Klinkovsky + +#pragma once + +#include <stdexcept> + +namespace TNL { +namespace Exceptions { + +struct ConfigError + : public std::runtime_error +{ + ConfigError( std::string msg ) + : std::runtime_error( msg ) + {} +}; + +} // namespace Exceptions +} // namespace TNL diff --git a/src/TNL/Solvers/Solver_impl.h b/src/TNL/Solvers/Solver_impl.h index ef865e8b7b25b6ce426c1b0d3c2918187058918d..9182c620fe2ed589389ab5a64328917f392795c7 100644 --- a/src/TNL/Solvers/Solver_impl.h +++ b/src/TNL/Solvers/Solver_impl.h @@ -13,6 +13,7 @@ #include <TNL/Solvers/SolverInitiator.h> #include <TNL/Solvers/SolverStarter.h> #include <TNL/Solvers/SolverConfig.h> +#include <TNL/Config/parseCommandLine.h> #include <TNL/Devices/Cuda.h> #include <TNL/Communicators/MpiCommunicator.h> #include <TNL/Communicators/ScopedInitializer.h> diff --git a/src/TNL/variant.hpp b/src/TNL/variant.hpp new file mode 100644 index 0000000000000000000000000000000000000000..c6a6d34b5e15da76ee9f43b0ebef518ed09aec6e --- /dev/null +++ b/src/TNL/variant.hpp @@ -0,0 +1,2815 @@ +// MPark.Variant +// +// Copyright Michael Park, 2015-2017 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#ifndef MPARK_VARIANT_HPP +#define MPARK_VARIANT_HPP + +/* + variant synopsis + +namespace std { + + // 20.7.2, class template variant + template <class... Types> + class variant { + public: + + // 20.7.2.1, constructors + constexpr variant() noexcept(see below); + variant(const variant&); + variant(variant&&) noexcept(see below); + + template <class T> constexpr variant(T&&) noexcept(see below); + + template <class T, class... Args> + constexpr explicit variant(in_place_type_t<T>, Args&&...); + + template <class T, class U, class... Args> + constexpr explicit variant( + in_place_type_t<T>, initializer_list<U>, Args&&...); + + template <size_t I, class... Args> + constexpr explicit variant(in_place_index_t<I>, Args&&...); + + template <size_t I, class U, class... Args> + constexpr explicit variant( + in_place_index_t<I>, initializer_list<U>, Args&&...); + + // 20.7.2.2, destructor + ~variant(); + + // 20.7.2.3, assignment + variant& operator=(const variant&); + variant& operator=(variant&&) noexcept(see below); + + template <class T> variant& operator=(T&&) noexcept(see below); + + // 20.7.2.4, modifiers + template <class T, class... Args> + T& emplace(Args&&...); + + template <class T, class U, class... Args> + T& emplace(initializer_list<U>, Args&&...); + + template <size_t I, class... Args> + variant_alternative<I, variant>& emplace(Args&&...); + + template <size_t I, class U, class... Args> + variant_alternative<I, variant>& emplace(initializer_list<U>, Args&&...); + + // 20.7.2.5, value status + constexpr bool valueless_by_exception() const noexcept; + constexpr size_t index() const noexcept; + + // 20.7.2.6, swap + void swap(variant&) noexcept(see below); + }; + + // 20.7.3, variant helper classes + template <class T> struct variant_size; // undefined + + template <class T> + constexpr size_t variant_size_v = variant_size<T>::value; + + template <class T> struct variant_size<const T>; + template <class T> struct variant_size<volatile T>; + template <class T> struct variant_size<const volatile T>; + + template <class... Types> + struct variant_size<variant<Types...>>; + + template <size_t I, class T> struct variant_alternative; // undefined + + template <size_t I, class T> + using variant_alternative_t = typename variant_alternative<I, T>::type; + + template <size_t I, class T> struct variant_alternative<I, const T>; + template <size_t I, class T> struct variant_alternative<I, volatile T>; + template <size_t I, class T> struct variant_alternative<I, const volatile T>; + + template <size_t I, class... Types> + struct variant_alternative<I, variant<Types...>>; + + constexpr size_t variant_npos = -1; + + // 20.7.4, value access + template <class T, class... Types> + constexpr bool holds_alternative(const variant<Types...>&) noexcept; + + template <size_t I, class... Types> + constexpr variant_alternative_t<I, variant<Types...>>& + get(variant<Types...>&); + + template <size_t I, class... Types> + constexpr variant_alternative_t<I, variant<Types...>>&& + get(variant<Types...>&&); + + template <size_t I, class... Types> + constexpr variant_alternative_t<I, variant<Types...>> const& + get(const variant<Types...>&); + + template <size_t I, class... Types> + constexpr variant_alternative_t<I, variant<Types...>> const&& + get(const variant<Types...>&&); + + template <class T, class... Types> + constexpr T& get(variant<Types...>&); + + template <class T, class... Types> + constexpr T&& get(variant<Types...>&&); + + template <class T, class... Types> + constexpr const T& get(const variant<Types...>&); + + template <class T, class... Types> + constexpr const T&& get(const variant<Types...>&&); + + template <size_t I, class... Types> + constexpr add_pointer_t<variant_alternative_t<I, variant<Types...>>> + get_if(variant<Types...>*) noexcept; + + template <size_t I, class... Types> + constexpr add_pointer_t<const variant_alternative_t<I, variant<Types...>>> + get_if(const variant<Types...>*) noexcept; + + template <class T, class... Types> + constexpr add_pointer_t<T> + get_if(variant<Types...>*) noexcept; + + template <class T, class... Types> + constexpr add_pointer_t<const T> + get_if(const variant<Types...>*) noexcept; + + // 20.7.5, relational operators + template <class... Types> + constexpr bool operator==(const variant<Types...>&, const variant<Types...>&); + + template <class... Types> + constexpr bool operator!=(const variant<Types...>&, const variant<Types...>&); + + template <class... Types> + constexpr bool operator<(const variant<Types...>&, const variant<Types...>&); + + template <class... Types> + constexpr bool operator>(const variant<Types...>&, const variant<Types...>&); + + template <class... Types> + constexpr bool operator<=(const variant<Types...>&, const variant<Types...>&); + + template <class... Types> + constexpr bool operator>=(const variant<Types...>&, const variant<Types...>&); + + // 20.7.6, visitation + template <class Visitor, class... Variants> + constexpr see below visit(Visitor&&, Variants&&...); + + // 20.7.7, class monostate + struct monostate; + + // 20.7.8, monostate relational operators + constexpr bool operator<(monostate, monostate) noexcept; + constexpr bool operator>(monostate, monostate) noexcept; + constexpr bool operator<=(monostate, monostate) noexcept; + constexpr bool operator>=(monostate, monostate) noexcept; + constexpr bool operator==(monostate, monostate) noexcept; + constexpr bool operator!=(monostate, monostate) noexcept; + + // 20.7.9, specialized algorithms + template <class... Types> + void swap(variant<Types...>&, variant<Types...>&) noexcept(see below); + + // 20.7.10, class bad_variant_access + class bad_variant_access; + + // 20.7.11, hash support + template <class T> struct hash; + template <class... Types> struct hash<variant<Types...>>; + template <> struct hash<monostate>; + +} // namespace std + +*/ + +#include <cstddef> +#include <exception> +#include <functional> +#include <initializer_list> +#include <new> +#include <type_traits> +#include <utility> + +// MPark.Variant +// +// Copyright Michael Park, 2015-2017 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#ifndef MPARK_CONFIG_HPP +#define MPARK_CONFIG_HPP + +// MSVC 2015 Update 3. +#if __cplusplus < 201103L && (!defined(_MSC_VER) || _MSC_FULL_VER < 190024210) +#error "MPark.Variant requires C++11 support." +#endif + +#ifndef __has_attribute +#define __has_attribute(x) 0 +#endif + +#ifndef __has_builtin +#define __has_builtin(x) 0 +#endif + +#ifndef __has_include +#define __has_include(x) 0 +#endif + +#ifndef __has_feature +#define __has_feature(x) 0 +#endif + +#if __has_attribute(always_inline) || defined(__GNUC__) +#define MPARK_ALWAYS_INLINE __attribute__((__always_inline__)) inline +#elif defined(_MSC_VER) +#define MPARK_ALWAYS_INLINE __forceinline +#else +#define MPARK_ALWAYS_INLINE inline +#endif + +#if __has_builtin(__builtin_addressof) || \ + (defined(__GNUC__) && __GNUC__ >= 7) || defined(_MSC_VER) +#define MPARK_BUILTIN_ADDRESSOF +#endif + +#if __has_builtin(__builtin_unreachable) || defined(__GNUC__) +#define MPARK_BUILTIN_UNREACHABLE __builtin_unreachable() +#elif defined(_MSC_VER) +#define MPARK_BUILTIN_UNREACHABLE __assume(false) +#else +#define MPARK_BUILTIN_UNREACHABLE +#endif + +#if __has_builtin(__type_pack_element) +#define MPARK_TYPE_PACK_ELEMENT +#endif + +#if defined(__cpp_constexpr) && __cpp_constexpr >= 200704 && \ + !(defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 9) +#define MPARK_CPP11_CONSTEXPR +#endif + +#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304 +#define MPARK_CPP14_CONSTEXPR +#endif + +#if __has_feature(cxx_exceptions) || defined(__cpp_exceptions) || \ + (defined(_MSC_VER) && defined(_CPPUNWIND)) +#define MPARK_EXCEPTIONS +#endif + +#if defined(__cpp_generic_lambdas) || defined(_MSC_VER) +#define MPARK_GENERIC_LAMBDAS +#endif + +#if defined(__cpp_lib_integer_sequence) +#define MPARK_INTEGER_SEQUENCE +#endif + +#if defined(__cpp_return_type_deduction) || defined(_MSC_VER) +#define MPARK_RETURN_TYPE_DEDUCTION +#endif + +#if defined(__cpp_lib_transparent_operators) || defined(_MSC_VER) +#define MPARK_TRANSPARENT_OPERATORS +#endif + +#if defined(__cpp_variable_templates) || defined(_MSC_VER) +#define MPARK_VARIABLE_TEMPLATES +#endif + +#if !defined(__GLIBCXX__) || __has_include(<codecvt>) // >= libstdc++-5 +#define MPARK_TRIVIALITY_TYPE_TRAITS +#define MPARK_INCOMPLETE_TYPE_TRAITS +#endif + +#endif // MPARK_CONFIG_HPP + +// MPark.Variant +// +// Copyright Michael Park, 2015-2017 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#ifndef MPARK_IN_PLACE_HPP +#define MPARK_IN_PLACE_HPP + +#include <cstddef> + + +namespace mpark { + + struct in_place_t { explicit in_place_t() = default; }; + + template <std::size_t I> + struct in_place_index_t { explicit in_place_index_t() = default; }; + + template <typename T> + struct in_place_type_t { explicit in_place_type_t() = default; }; + +#ifdef MPARK_VARIABLE_TEMPLATES + constexpr in_place_t in_place{}; + + template <std::size_t I> constexpr in_place_index_t<I> in_place_index{}; + + template <typename T> constexpr in_place_type_t<T> in_place_type{}; +#endif + +} // namespace mpark + +#endif // MPARK_IN_PLACE_HPP + +// MPark.Variant +// +// Copyright Michael Park, 2015-2017 +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.md or copy at http://boost.org/LICENSE_1_0.txt) + +#ifndef MPARK_LIB_HPP +#define MPARK_LIB_HPP + +#include <memory> +#include <functional> +#include <type_traits> +#include <utility> + + +#define MPARK_RETURN(...) \ + noexcept(noexcept(__VA_ARGS__)) -> decltype(__VA_ARGS__) { return __VA_ARGS__; } + +namespace mpark { + namespace lib { + template <typename T> + struct identity { using type = T; }; + + inline namespace cpp14 { + template <typename T, std::size_t N> + struct array { + constexpr const T &operator[](std::size_t index) const { + return data[index]; + } + + T data[N == 0 ? 1 : N]; + }; + + template <typename T> + using add_pointer_t = typename std::add_pointer<T>::type; + + template <typename... Ts> + using common_type_t = typename std::common_type<Ts...>::type; + + template <typename T> + using decay_t = typename std::decay<T>::type; + + template <bool B, typename T = void> + using enable_if_t = typename std::enable_if<B, T>::type; + + template <typename T> + using remove_const_t = typename std::remove_const<T>::type; + + template <typename T> + using remove_reference_t = typename std::remove_reference<T>::type; + + template <typename T> + inline constexpr T &&forward(remove_reference_t<T> &t) noexcept { + return static_cast<T &&>(t); + } + + template <typename T> + inline constexpr T &&forward(remove_reference_t<T> &&t) noexcept { + static_assert(!std::is_lvalue_reference<T>::value, + "can not forward an rvalue as an lvalue"); + return static_cast<T &&>(t); + } + + template <typename T> + inline constexpr remove_reference_t<T> &&move(T &&t) noexcept { + return static_cast<remove_reference_t<T> &&>(t); + } + +#ifdef MPARK_INTEGER_SEQUENCE + using std::integer_sequence; + using std::index_sequence; + using std::make_index_sequence; + using std::index_sequence_for; +#else + template <typename T, T... Is> + struct integer_sequence { + using value_type = T; + static constexpr std::size_t size() noexcept { return sizeof...(Is); } + }; + + template <std::size_t... Is> + using index_sequence = integer_sequence<std::size_t, Is...>; + + template <typename Lhs, typename Rhs> + struct make_index_sequence_concat; + + template <std::size_t... Lhs, std::size_t... Rhs> + struct make_index_sequence_concat<index_sequence<Lhs...>, + index_sequence<Rhs...>> + : identity<index_sequence<Lhs..., (sizeof...(Lhs) + Rhs)...>> {}; + + template <std::size_t N> + struct make_index_sequence_impl; + + template <std::size_t N> + using make_index_sequence = typename make_index_sequence_impl<N>::type; + + template <std::size_t N> + struct make_index_sequence_impl + : make_index_sequence_concat<make_index_sequence<N / 2>, + make_index_sequence<N - (N / 2)>> {}; + + template <> + struct make_index_sequence_impl<0> : identity<index_sequence<>> {}; + + template <> + struct make_index_sequence_impl<1> : identity<index_sequence<0>> {}; + + template <typename... Ts> + using index_sequence_for = make_index_sequence<sizeof...(Ts)>; +#endif + + // <functional> +#ifdef MPARK_TRANSPARENT_OPERATORS + using equal_to = std::equal_to<>; +#else + struct equal_to { + template <typename Lhs, typename Rhs> + inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const + MPARK_RETURN(lib::forward<Lhs>(lhs) == lib::forward<Rhs>(rhs)) + }; +#endif + +#ifdef MPARK_TRANSPARENT_OPERATORS + using not_equal_to = std::not_equal_to<>; +#else + struct not_equal_to { + template <typename Lhs, typename Rhs> + inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const + MPARK_RETURN(lib::forward<Lhs>(lhs) != lib::forward<Rhs>(rhs)) + }; +#endif + +#ifdef MPARK_TRANSPARENT_OPERATORS + using less = std::less<>; +#else + struct less { + template <typename Lhs, typename Rhs> + inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const + MPARK_RETURN(lib::forward<Lhs>(lhs) < lib::forward<Rhs>(rhs)) + }; +#endif + +#ifdef MPARK_TRANSPARENT_OPERATORS + using greater = std::greater<>; +#else + struct greater { + template <typename Lhs, typename Rhs> + inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const + MPARK_RETURN(lib::forward<Lhs>(lhs) > lib::forward<Rhs>(rhs)) + }; +#endif + +#ifdef MPARK_TRANSPARENT_OPERATORS + using less_equal = std::less_equal<>; +#else + struct less_equal { + template <typename Lhs, typename Rhs> + inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const + MPARK_RETURN(lib::forward<Lhs>(lhs) <= lib::forward<Rhs>(rhs)) + }; +#endif + +#ifdef MPARK_TRANSPARENT_OPERATORS + using greater_equal = std::greater_equal<>; +#else + struct greater_equal { + template <typename Lhs, typename Rhs> + inline constexpr auto operator()(Lhs &&lhs, Rhs &&rhs) const + MPARK_RETURN(lib::forward<Lhs>(lhs) >= lib::forward<Rhs>(rhs)) + }; +#endif + } // namespace cpp14 + + inline namespace cpp17 { + + // <type_traits> + template <bool B> + using bool_constant = std::integral_constant<bool, B>; + + template <typename...> + struct voider : identity<void> {}; + + template <typename... Ts> + using void_t = typename voider<Ts...>::type; + + namespace detail { + namespace swappable { + + using std::swap; + + template <typename T> + struct is_swappable { + private: + template <typename U, + typename = decltype(swap(std::declval<U &>(), + std::declval<U &>()))> + inline static std::true_type test(int); + + template <typename U> + inline static std::false_type test(...); + + public: + static constexpr bool value = decltype(test<T>(0))::value; + }; + + template <bool IsSwappable, typename T> + struct is_nothrow_swappable { + static constexpr bool value = + noexcept(swap(std::declval<T &>(), std::declval<T &>())); + }; + + template <typename T> + struct is_nothrow_swappable<false, T> : std::false_type {}; + + } // namespace swappable + } // namespace detail + + using detail::swappable::is_swappable; + + template <typename T> + using is_nothrow_swappable = + detail::swappable::is_nothrow_swappable<is_swappable<T>::value, T>; + + // <functional> + namespace detail { + + template <typename T> + struct is_reference_wrapper : std::false_type {}; + + template <typename T> + struct is_reference_wrapper<std::reference_wrapper<T>> + : std::true_type {}; + + template <bool, int> + struct Invoke; + + template <> + struct Invoke<true /* pmf */, 0 /* is_base_of */> { + template <typename R, typename T, typename Arg, typename... Args> + inline static constexpr auto invoke(R T::*pmf, Arg &&arg, Args &&... args) + MPARK_RETURN((lib::forward<Arg>(arg).*pmf)(lib::forward<Args>(args)...)) + }; + + template <> + struct Invoke<true /* pmf */, 1 /* is_reference_wrapper */> { + template <typename R, typename T, typename Arg, typename... Args> + inline static constexpr auto invoke(R T::*pmf, Arg &&arg, Args &&... args) + MPARK_RETURN((lib::forward<Arg>(arg).get().*pmf)(lib::forward<Args>(args)...)) + }; + + template <> + struct Invoke<true /* pmf */, 2 /* otherwise */> { + template <typename R, typename T, typename Arg, typename... Args> + inline static constexpr auto invoke(R T::*pmf, Arg &&arg, Args &&... args) + MPARK_RETURN(((*lib::forward<Arg>(arg)).*pmf)(lib::forward<Args>(args)...)) + }; + + template <> + struct Invoke<false /* pmo */, 0 /* is_base_of */> { + template <typename R, typename T, typename Arg> + inline static constexpr auto invoke(R T::*pmo, Arg &&arg) + MPARK_RETURN(lib::forward<Arg>(arg).*pmo) + }; + + template <> + struct Invoke<false /* pmo */, 1 /* is_reference_wrapper */> { + template <typename R, typename T, typename Arg> + inline static constexpr auto invoke(R T::*pmo, Arg &&arg) + MPARK_RETURN(lib::forward<Arg>(arg).get().*pmo) + }; + + template <> + struct Invoke<false /* pmo */, 2 /* otherwise */> { + template <typename R, typename T, typename Arg> + inline static constexpr auto invoke(R T::*pmo, Arg &&arg) + MPARK_RETURN((*lib::forward<Arg>(arg)).*pmo) + }; + + template <typename R, typename T, typename Arg, typename... Args> + inline constexpr auto invoke(R T::*f, Arg &&arg, Args &&... args) + MPARK_RETURN( + Invoke<std::is_function<R>::value, + (std::is_base_of<T, lib::decay_t<Arg>>::value + ? 0 + : is_reference_wrapper<lib::decay_t<Arg>>::value + ? 1 + : 2)>::invoke(f, + lib::forward<Arg>(arg), + lib::forward<Args>(args)...)) + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4100) +#endif + template <typename F, typename... Args> + inline constexpr auto invoke(F &&f, Args &&... args) + MPARK_RETURN(lib::forward<F>(f)(lib::forward<Args>(args)...)) +#ifdef _MSC_VER +#pragma warning(pop) +#endif + } // namespace detail + + template <typename F, typename... Args> + inline constexpr auto invoke(F &&f, Args &&... args) + MPARK_RETURN(detail::invoke(lib::forward<F>(f), + lib::forward<Args>(args)...)) + + namespace detail { + + template <typename Void, typename, typename...> + struct invoke_result {}; + + template <typename F, typename... Args> + struct invoke_result<void_t<decltype(lib::invoke( + std::declval<F>(), std::declval<Args>()...))>, + F, + Args...> + : identity<decltype( + lib::invoke(std::declval<F>(), std::declval<Args>()...))> {}; + + } // namespace detail + + template <typename F, typename... Args> + using invoke_result = detail::invoke_result<void, F, Args...>; + + template <typename F, typename... Args> + using invoke_result_t = typename invoke_result<F, Args...>::type; + + namespace detail { + + template <typename Void, typename, typename...> + struct is_invocable : std::false_type {}; + + template <typename F, typename... Args> + struct is_invocable<void_t<invoke_result_t<F, Args...>>, F, Args...> + : std::true_type {}; + + template <typename Void, typename, typename, typename...> + struct is_invocable_r : std::false_type {}; + + template <typename R, typename F, typename... Args> + struct is_invocable_r<void_t<invoke_result_t<F, Args...>>, + R, + F, + Args...> + : std::is_convertible<invoke_result_t<F, Args...>, R> {}; + + } // namespace detail + + template <typename F, typename... Args> + using is_invocable = detail::is_invocable<void, F, Args...>; + + template <typename R, typename F, typename... Args> + using is_invocable_r = detail::is_invocable_r<void, R, F, Args...>; + + namespace detail { + + template <bool Invocable, typename F, typename... Args> + struct is_nothrow_invocable { + static constexpr bool value = + noexcept(lib::invoke(std::declval<F>(), std::declval<Args>()...)); + }; + + template <typename F, typename... Args> + struct is_nothrow_invocable<false, F, Args...> : std::false_type {}; + + template <bool Invocable, typename R, typename F, typename... Args> + struct is_nothrow_invocable_r { + private: + inline static R impl() { + return lib::invoke(std::declval<F>(), std::declval<Args>()...); + } + + public: + static constexpr bool value = noexcept(impl()); + }; + + template <typename R, typename F, typename... Args> + struct is_nothrow_invocable_r<false, R, F, Args...> : std::false_type {}; + + } // namespace detail + + template <typename F, typename... Args> + using is_nothrow_invocable = detail:: + is_nothrow_invocable<is_invocable<F, Args...>::value, F, Args...>; + + template <typename R, typename F, typename... Args> + using is_nothrow_invocable_r = + detail::is_nothrow_invocable_r<is_invocable_r<R, F, Args...>::value, + R, + F, + Args...>; + + // <memory> +#ifdef MPARK_BUILTIN_ADDRESSOF + template <typename T> + inline constexpr T *addressof(T &arg) noexcept { + return __builtin_addressof(arg); + } +#else + namespace detail { + + namespace has_addressof_impl { + + struct fail; + + template <typename T> + inline fail operator&(T &&); + + template <typename T> + inline static constexpr bool impl() { + return (std::is_class<T>::value || std::is_union<T>::value) && + !std::is_same<decltype(&std::declval<T &>()), fail>::value; + } + + } // namespace has_addressof_impl + + template <typename T> + using has_addressof = bool_constant<has_addressof_impl::impl<T>()>; + + template <typename T> + inline constexpr T *addressof(T &arg, std::true_type) noexcept { + return std::addressof(arg); + } + + template <typename T> + inline constexpr T *addressof(T &arg, std::false_type) noexcept { + return &arg; + } + + } // namespace detail + + template <typename T> + inline constexpr T *addressof(T &arg) noexcept { + return detail::addressof(arg, detail::has_addressof<T>{}); + } +#endif + + template <typename T> + inline constexpr T *addressof(const T &&) = delete; + + } // namespace cpp17 + + template <typename T> + struct remove_all_extents : identity<T> {}; + + template <typename T, std::size_t N> + struct remove_all_extents<array<T, N>> : remove_all_extents<T> {}; + + template <typename T> + using remove_all_extents_t = typename remove_all_extents<T>::type; + + template <std::size_t N> + using size_constant = std::integral_constant<std::size_t, N>; + + template <std::size_t I, typename T> + struct indexed_type : size_constant<I> { using type = T; }; + + template <bool... Bs> + using all = std::is_same<integer_sequence<bool, true, Bs...>, + integer_sequence<bool, Bs..., true>>; + +#ifdef MPARK_TYPE_PACK_ELEMENT + template <std::size_t I, typename... Ts> + using type_pack_element_t = __type_pack_element<I, Ts...>; +#else + template <std::size_t I, typename... Ts> + struct type_pack_element_impl { + private: + template <typename> + struct set; + + template <std::size_t... Is> + struct set<index_sequence<Is...>> : indexed_type<Is, Ts>... {}; + + template <typename T> + inline static std::enable_if<true, T> impl(indexed_type<I, T>); + + inline static std::enable_if<false> impl(...); + + public: + using type = decltype(impl(set<index_sequence_for<Ts...>>{})); + }; + + template <std::size_t I, typename... Ts> + using type_pack_element = typename type_pack_element_impl<I, Ts...>::type; + + template <std::size_t I, typename... Ts> + using type_pack_element_t = typename type_pack_element<I, Ts...>::type; +#endif + +#ifdef MPARK_TRIVIALITY_TYPE_TRAITS + using std::is_trivially_copy_constructible; + using std::is_trivially_move_constructible; + using std::is_trivially_copy_assignable; + using std::is_trivially_move_assignable; +#else + template <typename T> + struct is_trivially_copy_constructible + : bool_constant< + std::is_copy_constructible<T>::value && __has_trivial_copy(T)> {}; + + template <typename T> + struct is_trivially_move_constructible : bool_constant<__is_trivial(T)> {}; + + template <typename T> + struct is_trivially_copy_assignable + : bool_constant< + std::is_copy_assignable<T>::value && __has_trivial_assign(T)> {}; + + template <typename T> + struct is_trivially_move_assignable : bool_constant<__is_trivial(T)> {}; +#endif + + template <typename T, bool> + struct dependent_type : T {}; + + template <typename Is, std::size_t J> + struct push_back; + + template <typename Is, std::size_t J> + using push_back_t = typename push_back<Is, J>::type; + + template <std::size_t... Is, std::size_t J> + struct push_back<index_sequence<Is...>, J> { + using type = index_sequence<Is..., J>; + }; + + } // namespace lib +} // namespace mpark + +#undef MPARK_RETURN + +#endif // MPARK_LIB_HPP + + +namespace mpark { + +#ifdef MPARK_RETURN_TYPE_DEDUCTION + +#define AUTO auto +#define AUTO_RETURN(...) { return __VA_ARGS__; } + +#define AUTO_REFREF auto && +#define AUTO_REFREF_RETURN(...) { return __VA_ARGS__; } + +#define DECLTYPE_AUTO decltype(auto) +#define DECLTYPE_AUTO_RETURN(...) { return __VA_ARGS__; } + +#else + +#define AUTO auto +#define AUTO_RETURN(...) \ + -> lib::decay_t<decltype(__VA_ARGS__)> { return __VA_ARGS__; } + +#define AUTO_REFREF auto +#define AUTO_REFREF_RETURN(...) \ + -> decltype((__VA_ARGS__)) { \ + static_assert(std::is_reference<decltype((__VA_ARGS__))>::value, ""); \ + return __VA_ARGS__; \ + } + +#define DECLTYPE_AUTO auto +#define DECLTYPE_AUTO_RETURN(...) \ + -> decltype(__VA_ARGS__) { return __VA_ARGS__; } + +#endif + + class bad_variant_access : public std::exception { + public: + virtual const char *what() const noexcept override { return "bad_variant_access"; } + }; + + [[noreturn]] inline void throw_bad_variant_access() { +#ifdef MPARK_EXCEPTIONS + throw bad_variant_access{}; +#else + std::terminate(); + MPARK_BUILTIN_UNREACHABLE; +#endif + } + + template <typename... Ts> + class variant; + + template <typename T> + struct variant_size; + +#ifdef MPARK_VARIABLE_TEMPLATES + template <typename T> + constexpr std::size_t variant_size_v = variant_size<T>::value; +#endif + + template <typename T> + struct variant_size<const T> : variant_size<T> {}; + + template <typename T> + struct variant_size<volatile T> : variant_size<T> {}; + + template <typename T> + struct variant_size<const volatile T> : variant_size<T> {}; + + template <typename... Ts> + struct variant_size<variant<Ts...>> : lib::size_constant<sizeof...(Ts)> {}; + + template <std::size_t I, typename T> + struct variant_alternative; + + template <std::size_t I, typename T> + using variant_alternative_t = typename variant_alternative<I, T>::type; + + template <std::size_t I, typename T> + struct variant_alternative<I, const T> + : std::add_const<variant_alternative_t<I, T>> {}; + + template <std::size_t I, typename T> + struct variant_alternative<I, volatile T> + : std::add_volatile<variant_alternative_t<I, T>> {}; + + template <std::size_t I, typename T> + struct variant_alternative<I, const volatile T> + : std::add_cv<variant_alternative_t<I, T>> {}; + + template <std::size_t I, typename... Ts> + struct variant_alternative<I, variant<Ts...>> { + static_assert(I < sizeof...(Ts), + "index out of bounds in `std::variant_alternative<>`"); + using type = lib::type_pack_element_t<I, Ts...>; + }; + + constexpr std::size_t variant_npos = static_cast<std::size_t>(-1); + + namespace detail { + + constexpr std::size_t not_found = static_cast<std::size_t>(-1); + constexpr std::size_t ambiguous = static_cast<std::size_t>(-2); + +#ifdef MPARK_CPP14_CONSTEXPR + template <typename T, typename... Ts> + inline constexpr std::size_t find_index() { + constexpr lib::array<bool, sizeof...(Ts)> matches = { + {std::is_same<T, Ts>::value...} + }; + std::size_t result = not_found; + for (std::size_t i = 0; i < sizeof...(Ts); ++i) { + if (matches[i]) { + if (result != not_found) { + return ambiguous; + } + result = i; + } + } + return result; + } +#else + inline constexpr std::size_t find_index_impl(std::size_t result, + std::size_t) { + return result; + } + + template <typename... Bs> + inline constexpr std::size_t find_index_impl(std::size_t result, + std::size_t idx, + bool b, + Bs... bs) { + return b ? (result != not_found ? ambiguous + : find_index_impl(idx, idx + 1, bs...)) + : find_index_impl(result, idx + 1, bs...); + } + + template <typename T, typename... Ts> + inline constexpr std::size_t find_index() { + return find_index_impl(not_found, 0, std::is_same<T, Ts>::value...); + } +#endif + + template <std::size_t I> + using find_index_sfinae_impl = + lib::enable_if_t<I != not_found && I != ambiguous, + lib::size_constant<I>>; + + template <typename T, typename... Ts> + using find_index_sfinae = find_index_sfinae_impl<find_index<T, Ts...>()>; + + template <std::size_t I> + struct find_index_checked_impl : lib::size_constant<I> { + static_assert(I != not_found, "the specified type is not found."); + static_assert(I != ambiguous, "the specified type is ambiguous."); + }; + + template <typename T, typename... Ts> + using find_index_checked = find_index_checked_impl<find_index<T, Ts...>()>; + + struct valueless_t {}; + + enum class Trait { TriviallyAvailable, Available, Unavailable }; + + template <typename T, + template <typename> class IsTriviallyAvailable, + template <typename> class IsAvailable> + inline constexpr Trait trait() { + return IsTriviallyAvailable<T>::value + ? Trait::TriviallyAvailable + : IsAvailable<T>::value ? Trait::Available + : Trait::Unavailable; + } + +#ifdef MPARK_CPP14_CONSTEXPR + template <typename... Traits> + inline constexpr Trait common_trait(Traits... traits_) { + Trait result = Trait::TriviallyAvailable; + lib::array<Trait, sizeof...(Traits)> traits = {{traits_...}}; + for (std::size_t i = 0; i < sizeof...(Traits); ++i) { + Trait t = traits[i]; + if (static_cast<int>(t) > static_cast<int>(result)) { + result = t; + } + } + return result; + } +#else + inline constexpr Trait common_trait_impl(Trait result) { return result; } + + template <typename... Traits> + inline constexpr Trait common_trait_impl(Trait result, + Trait t, + Traits... ts) { + return static_cast<int>(t) > static_cast<int>(result) + ? common_trait_impl(t, ts...) + : common_trait_impl(result, ts...); + } + + template <typename... Traits> + inline constexpr Trait common_trait(Traits... ts) { + return common_trait_impl(Trait::TriviallyAvailable, ts...); + } +#endif + + template <typename... Ts> + struct traits { + static constexpr Trait copy_constructible_trait = + common_trait(trait<Ts, + lib::is_trivially_copy_constructible, + std::is_copy_constructible>()...); + + static constexpr Trait move_constructible_trait = + common_trait(trait<Ts, + lib::is_trivially_move_constructible, + std::is_move_constructible>()...); + + static constexpr Trait copy_assignable_trait = + common_trait(copy_constructible_trait, + trait<Ts, + lib::is_trivially_copy_assignable, + std::is_copy_assignable>()...); + + static constexpr Trait move_assignable_trait = + common_trait(move_constructible_trait, + trait<Ts, + lib::is_trivially_move_assignable, + std::is_move_assignable>()...); + + static constexpr Trait destructible_trait = + common_trait(trait<Ts, + std::is_trivially_destructible, + std::is_destructible>()...); + }; + + namespace access { + + struct recursive_union { +#ifdef MPARK_RETURN_TYPE_DEDUCTION + template <typename V> + inline static constexpr auto &&get_alt(V &&v, in_place_index_t<0>) { + return lib::forward<V>(v).head_; + } + + template <typename V, std::size_t I> + inline static constexpr auto &&get_alt(V &&v, in_place_index_t<I>) { + return get_alt(lib::forward<V>(v).tail_, in_place_index_t<I - 1>{}); + } +#else + template <std::size_t I, bool Dummy = true> + struct get_alt_impl { + template <typename V> + inline constexpr AUTO_REFREF operator()(V &&v) const + AUTO_REFREF_RETURN(get_alt_impl<I - 1>{}(lib::forward<V>(v).tail_)) + }; + + template <bool Dummy> + struct get_alt_impl<0, Dummy> { + template <typename V> + inline constexpr AUTO_REFREF operator()(V &&v) const + AUTO_REFREF_RETURN(lib::forward<V>(v).head_) + }; + + template <typename V, std::size_t I> + inline static constexpr AUTO_REFREF get_alt(V &&v, in_place_index_t<I>) + AUTO_REFREF_RETURN(get_alt_impl<I>{}(lib::forward<V>(v))) +#endif + }; + + struct base { + template <std::size_t I, typename V> + inline static constexpr AUTO_REFREF get_alt(V &&v) +#ifdef _MSC_VER + AUTO_REFREF_RETURN(recursive_union::get_alt( + lib::forward<V>(v).data_, in_place_index_t<I>{})) +#else + AUTO_REFREF_RETURN(recursive_union::get_alt( + data(lib::forward<V>(v)), in_place_index_t<I>{})) +#endif + }; + + struct variant { + template <std::size_t I, typename V> + inline static constexpr AUTO_REFREF get_alt(V &&v) + AUTO_REFREF_RETURN(base::get_alt<I>(lib::forward<V>(v).impl_)) + }; + + } // namespace access + + namespace visitation { + +#if defined(MPARK_CPP14_CONSTEXPR) && !defined(_MSC_VER) +#define MPARK_VARIANT_SWITCH_VISIT +#endif + + struct base { + template <typename Visitor, typename... Vs> + using dispatch_result_t = decltype( + lib::invoke(std::declval<Visitor>(), + access::base::get_alt<0>(std::declval<Vs>())...)); + + template <typename Expected> + struct expected { + template <typename Actual> + inline static constexpr bool but_got() { + return std::is_same<Expected, Actual>::value; + } + }; + + template <typename Expected, typename Actual> + struct visit_return_type_check { + static_assert( + expected<Expected>::template but_got<Actual>(), + "`visit` requires the visitor to have a single return type"); + + template <typename Visitor, typename... Alts> + inline static constexpr DECLTYPE_AUTO invoke(Visitor &&visitor, + Alts &&... alts) + DECLTYPE_AUTO_RETURN(lib::invoke(lib::forward<Visitor>(visitor), + lib::forward<Alts>(alts)...)) + }; + +#ifdef MPARK_VARIANT_SWITCH_VISIT + template <bool B, typename R, typename... ITs> + struct dispatcher; + + template <typename R, typename... ITs> + struct dispatcher<false, R, ITs...> { + template <std::size_t B, typename F, typename... Vs> + MPARK_ALWAYS_INLINE static constexpr R dispatch( + F &&, typename ITs::type &&..., Vs &&...) { + MPARK_BUILTIN_UNREACHABLE; + } + + template <std::size_t I, typename F, typename... Vs> + MPARK_ALWAYS_INLINE static constexpr R dispatch_case(F &&, Vs &&...) { + MPARK_BUILTIN_UNREACHABLE; + } + + template <std::size_t B, typename F, typename... Vs> + MPARK_ALWAYS_INLINE static constexpr R dispatch_at(std::size_t, + F &&, + Vs &&...) { + MPARK_BUILTIN_UNREACHABLE; + } + }; + + template <typename R, typename... ITs> + struct dispatcher<true, R, ITs...> { + template <std::size_t B, typename F> + MPARK_ALWAYS_INLINE static constexpr R dispatch( + F &&f, typename ITs::type &&... visited_vs) { + using Expected = R; + using Actual = decltype(lib::invoke( + lib::forward<F>(f), + access::base::get_alt<ITs::value>( + lib::forward<typename ITs::type>(visited_vs))...)); + return visit_return_type_check<Expected, Actual>::invoke( + lib::forward<F>(f), + access::base::get_alt<ITs::value>( + lib::forward<typename ITs::type>(visited_vs))...); + } + + template <std::size_t B, typename F, typename V, typename... Vs> + MPARK_ALWAYS_INLINE static constexpr R dispatch( + F &&f, typename ITs::type &&... visited_vs, V &&v, Vs &&... vs) { +#define MPARK_DISPATCH(I) \ + dispatcher<(I < lib::decay_t<V>::size()), \ + R, \ + ITs..., \ + lib::indexed_type<I, V>>:: \ + template dispatch<0>(lib::forward<F>(f), \ + lib::forward<typename ITs::type>(visited_vs)..., \ + lib::forward<V>(v), \ + lib::forward<Vs>(vs)...) + +#define MPARK_DEFAULT(I) \ + dispatcher<(I < lib::decay_t<V>::size()), R, ITs...>::template dispatch<I>( \ + lib::forward<F>(f), \ + lib::forward<typename ITs::type>(visited_vs)..., \ + lib::forward<V>(v), \ + lib::forward<Vs>(vs)...) + + switch (v.index()) { + case B + 0: return MPARK_DISPATCH(B + 0); + case B + 1: return MPARK_DISPATCH(B + 1); + case B + 2: return MPARK_DISPATCH(B + 2); + case B + 3: return MPARK_DISPATCH(B + 3); + case B + 4: return MPARK_DISPATCH(B + 4); + case B + 5: return MPARK_DISPATCH(B + 5); + case B + 6: return MPARK_DISPATCH(B + 6); + case B + 7: return MPARK_DISPATCH(B + 7); + case B + 8: return MPARK_DISPATCH(B + 8); + case B + 9: return MPARK_DISPATCH(B + 9); + case B + 10: return MPARK_DISPATCH(B + 10); + case B + 11: return MPARK_DISPATCH(B + 11); + case B + 12: return MPARK_DISPATCH(B + 12); + case B + 13: return MPARK_DISPATCH(B + 13); + case B + 14: return MPARK_DISPATCH(B + 14); + case B + 15: return MPARK_DISPATCH(B + 15); + case B + 16: return MPARK_DISPATCH(B + 16); + case B + 17: return MPARK_DISPATCH(B + 17); + case B + 18: return MPARK_DISPATCH(B + 18); + case B + 19: return MPARK_DISPATCH(B + 19); + case B + 20: return MPARK_DISPATCH(B + 20); + case B + 21: return MPARK_DISPATCH(B + 21); + case B + 22: return MPARK_DISPATCH(B + 22); + case B + 23: return MPARK_DISPATCH(B + 23); + case B + 24: return MPARK_DISPATCH(B + 24); + case B + 25: return MPARK_DISPATCH(B + 25); + case B + 26: return MPARK_DISPATCH(B + 26); + case B + 27: return MPARK_DISPATCH(B + 27); + case B + 28: return MPARK_DISPATCH(B + 28); + case B + 29: return MPARK_DISPATCH(B + 29); + case B + 30: return MPARK_DISPATCH(B + 30); + case B + 31: return MPARK_DISPATCH(B + 31); + default: return MPARK_DEFAULT(B + 32); + } + +#undef MPARK_DEFAULT +#undef MPARK_DISPATCH + } + + template <std::size_t I, typename F, typename... Vs> + MPARK_ALWAYS_INLINE static constexpr R dispatch_case(F &&f, + Vs &&... vs) { + using Expected = R; + using Actual = decltype( + lib::invoke(lib::forward<F>(f), + access::base::get_alt<I>(lib::forward<Vs>(vs))...)); + return visit_return_type_check<Expected, Actual>::invoke( + lib::forward<F>(f), + access::base::get_alt<I>(lib::forward<Vs>(vs))...); + } + + template <std::size_t B, typename F, typename V, typename... Vs> + MPARK_ALWAYS_INLINE static constexpr R dispatch_at(std::size_t index, + F &&f, + V &&v, + Vs &&... vs) { + static_assert(lib::all<(lib::decay_t<V>::size() == + lib::decay_t<Vs>::size())...>::value, + "all of the variants must be the same size."); +#define MPARK_DISPATCH_AT(I) \ + dispatcher<(I < lib::decay_t<V>::size()), R>::template dispatch_case<I>( \ + lib::forward<F>(f), lib::forward<V>(v), lib::forward<Vs>(vs)...) + +#define MPARK_DEFAULT(I) \ + dispatcher<(I < lib::decay_t<V>::size()), R>::template dispatch_at<I>( \ + index, lib::forward<F>(f), lib::forward<V>(v), lib::forward<Vs>(vs)...) + + switch (index) { + case B + 0: return MPARK_DISPATCH_AT(B + 0); + case B + 1: return MPARK_DISPATCH_AT(B + 1); + case B + 2: return MPARK_DISPATCH_AT(B + 2); + case B + 3: return MPARK_DISPATCH_AT(B + 3); + case B + 4: return MPARK_DISPATCH_AT(B + 4); + case B + 5: return MPARK_DISPATCH_AT(B + 5); + case B + 6: return MPARK_DISPATCH_AT(B + 6); + case B + 7: return MPARK_DISPATCH_AT(B + 7); + case B + 8: return MPARK_DISPATCH_AT(B + 8); + case B + 9: return MPARK_DISPATCH_AT(B + 9); + case B + 10: return MPARK_DISPATCH_AT(B + 10); + case B + 11: return MPARK_DISPATCH_AT(B + 11); + case B + 12: return MPARK_DISPATCH_AT(B + 12); + case B + 13: return MPARK_DISPATCH_AT(B + 13); + case B + 14: return MPARK_DISPATCH_AT(B + 14); + case B + 15: return MPARK_DISPATCH_AT(B + 15); + case B + 16: return MPARK_DISPATCH_AT(B + 16); + case B + 17: return MPARK_DISPATCH_AT(B + 17); + case B + 18: return MPARK_DISPATCH_AT(B + 18); + case B + 19: return MPARK_DISPATCH_AT(B + 19); + case B + 20: return MPARK_DISPATCH_AT(B + 20); + case B + 21: return MPARK_DISPATCH_AT(B + 21); + case B + 22: return MPARK_DISPATCH_AT(B + 22); + case B + 23: return MPARK_DISPATCH_AT(B + 23); + case B + 24: return MPARK_DISPATCH_AT(B + 24); + case B + 25: return MPARK_DISPATCH_AT(B + 25); + case B + 26: return MPARK_DISPATCH_AT(B + 26); + case B + 27: return MPARK_DISPATCH_AT(B + 27); + case B + 28: return MPARK_DISPATCH_AT(B + 28); + case B + 29: return MPARK_DISPATCH_AT(B + 29); + case B + 30: return MPARK_DISPATCH_AT(B + 30); + case B + 31: return MPARK_DISPATCH_AT(B + 31); + default: return MPARK_DEFAULT(B + 32); + } + +#undef MPARK_DEFAULT +#undef MPARK_DISPATCH_AT + } + }; +#else + template <typename T> + inline static constexpr const T &at(const T &elem) noexcept { + return elem; + } + + template <typename T, std::size_t N, typename... Is> + inline static constexpr const lib::remove_all_extents_t<T> &at( + const lib::array<T, N> &elems, std::size_t i, Is... is) noexcept { + return at(elems[i], is...); + } + + template <typename F, typename... Fs> + inline static constexpr lib::array<lib::decay_t<F>, sizeof...(Fs) + 1> + make_farray(F &&f, Fs &&... fs) { + return {{lib::forward<F>(f), lib::forward<Fs>(fs)...}}; + } + + template <typename F, typename... Vs> + struct make_fmatrix_impl { + + template <std::size_t... Is> + inline static constexpr dispatch_result_t<F, Vs...> dispatch( + F &&f, Vs &&... vs) { + using Expected = dispatch_result_t<F, Vs...>; + using Actual = decltype(lib::invoke( + lib::forward<F>(f), + access::base::get_alt<Is>(lib::forward<Vs>(vs))...)); + return visit_return_type_check<Expected, Actual>::invoke( + lib::forward<F>(f), + access::base::get_alt<Is>(lib::forward<Vs>(vs))...); + } + +#ifdef MPARK_RETURN_TYPE_DEDUCTION + template <std::size_t... Is> + inline static constexpr auto impl(lib::index_sequence<Is...>) { + return &dispatch<Is...>; + } + + template <typename Is, std::size_t... Js, typename... Ls> + inline static constexpr auto impl(Is, + lib::index_sequence<Js...>, + Ls... ls) { + return make_farray(impl(lib::push_back_t<Is, Js>{}, ls...)...); + } +#else + template <typename...> + struct impl; + + template <std::size_t... Is> + struct impl<lib::index_sequence<Is...>> { + inline constexpr AUTO operator()() const + AUTO_RETURN(&dispatch<Is...>) + }; + + template <typename Is, std::size_t... Js, typename... Ls> + struct impl<Is, lib::index_sequence<Js...>, Ls...> { + inline constexpr AUTO operator()() const + AUTO_RETURN( + make_farray(impl<lib::push_back_t<Is, Js>, Ls...>{}()...)) + }; +#endif + }; + +#ifdef MPARK_RETURN_TYPE_DEDUCTION + template <typename F, typename... Vs> + inline static constexpr auto make_fmatrix() { + return make_fmatrix_impl<F, Vs...>::impl( + lib::index_sequence<>{}, + lib::make_index_sequence<lib::decay_t<Vs>::size()>{}...); + } +#else + template <typename F, typename... Vs> + inline static constexpr AUTO make_fmatrix() + AUTO_RETURN( + typename make_fmatrix_impl<F, Vs...>::template impl< + lib::index_sequence<>, + lib::make_index_sequence<lib::decay_t<Vs>::size()>...>{}()) +#endif + + template <typename F, typename... Vs> + struct make_fdiagonal_impl { + template <std::size_t I> + inline static constexpr dispatch_result_t<F, Vs...> dispatch( + F &&f, Vs &&... vs) { + using Expected = dispatch_result_t<F, Vs...>; + using Actual = decltype( + lib::invoke(lib::forward<F>(f), + access::base::get_alt<I>(lib::forward<Vs>(vs))...)); + return visit_return_type_check<Expected, Actual>::invoke( + lib::forward<F>(f), + access::base::get_alt<I>(lib::forward<Vs>(vs))...); + } + + template <std::size_t... Is> + inline static constexpr AUTO impl(lib::index_sequence<Is...>) + AUTO_RETURN(make_farray(&dispatch<Is>...)) + }; + + template <typename F, typename V, typename... Vs> + inline static constexpr auto make_fdiagonal() + -> decltype(make_fdiagonal_impl<F, V, Vs...>::impl( + lib::make_index_sequence<lib::decay_t<V>::size()>{})) { + static_assert(lib::all<(lib::decay_t<V>::size() == + lib::decay_t<Vs>::size())...>::value, + "all of the variants must be the same size."); + return make_fdiagonal_impl<F, V, Vs...>::impl( + lib::make_index_sequence<lib::decay_t<V>::size()>{}); + } +#endif + }; + +#if !defined(MPARK_VARIANT_SWITCH_VISIT) && \ + (!defined(_MSC_VER) || _MSC_VER >= 1910) + template <typename F, typename... Vs> + using fmatrix_t = decltype(base::make_fmatrix<F, Vs...>()); + + template <typename F, typename... Vs> + struct fmatrix { + static constexpr fmatrix_t<F, Vs...> value = + base::make_fmatrix<F, Vs...>(); + }; + + template <typename F, typename... Vs> + constexpr fmatrix_t<F, Vs...> fmatrix<F, Vs...>::value; + + template <typename F, typename... Vs> + using fdiagonal_t = decltype(base::make_fdiagonal<F, Vs...>()); + + template <typename F, typename... Vs> + struct fdiagonal { + static constexpr fdiagonal_t<F, Vs...> value = + base::make_fdiagonal<F, Vs...>(); + }; + + template <typename F, typename... Vs> + constexpr fdiagonal_t<F, Vs...> fdiagonal<F, Vs...>::value; +#endif + + struct alt { + template <typename Visitor, typename... Vs> + inline static constexpr DECLTYPE_AUTO visit_alt(Visitor &&visitor, + Vs &&... vs) +#ifdef MPARK_VARIANT_SWITCH_VISIT + DECLTYPE_AUTO_RETURN( + base::dispatcher< + true, + base::dispatch_result_t<Visitor, + decltype(as_base( + lib::forward<Vs>(vs)))...>>:: + template dispatch<0>(lib::forward<Visitor>(visitor), + as_base(lib::forward<Vs>(vs))...)) +#elif !defined(_MSC_VER) || _MSC_VER >= 1910 + DECLTYPE_AUTO_RETURN(base::at( + fmatrix<Visitor &&, + decltype(as_base(lib::forward<Vs>(vs)))...>::value, + vs.index()...)(lib::forward<Visitor>(visitor), + as_base(lib::forward<Vs>(vs))...)) +#else + DECLTYPE_AUTO_RETURN(base::at( + base::make_fmatrix<Visitor &&, + decltype(as_base(lib::forward<Vs>(vs)))...>(), + vs.index()...)(lib::forward<Visitor>(visitor), + as_base(lib::forward<Vs>(vs))...)) +#endif + + template <typename Visitor, typename... Vs> + inline static constexpr DECLTYPE_AUTO visit_alt_at(std::size_t index, + Visitor &&visitor, + Vs &&... vs) +#ifdef MPARK_VARIANT_SWITCH_VISIT + DECLTYPE_AUTO_RETURN( + base::dispatcher< + true, + base::dispatch_result_t<Visitor, + decltype(as_base( + lib::forward<Vs>(vs)))...>>:: + template dispatch_at<0>(index, + lib::forward<Visitor>(visitor), + as_base(lib::forward<Vs>(vs))...)) +#elif !defined(_MSC_VER) || _MSC_VER >= 1910 + DECLTYPE_AUTO_RETURN(base::at( + fdiagonal<Visitor &&, + decltype(as_base(lib::forward<Vs>(vs)))...>::value, + index)(lib::forward<Visitor>(visitor), + as_base(lib::forward<Vs>(vs))...)) +#else + DECLTYPE_AUTO_RETURN(base::at( + base::make_fdiagonal<Visitor &&, + decltype(as_base(lib::forward<Vs>(vs)))...>(), + index)(lib::forward<Visitor>(visitor), + as_base(lib::forward<Vs>(vs))...)) +#endif + }; + + struct variant { + private: + template <typename Visitor> + struct visitor { + template <typename... Values> + inline static constexpr bool does_not_handle() { + return lib::is_invocable<Visitor, Values...>::value; + } + }; + + template <typename Visitor, typename... Values> + struct visit_exhaustiveness_check { + static_assert(visitor<Visitor>::template does_not_handle<Values...>(), + "`visit` requires the visitor to be exhaustive."); + + inline static constexpr DECLTYPE_AUTO invoke(Visitor &&visitor, + Values &&... values) + DECLTYPE_AUTO_RETURN(lib::invoke(lib::forward<Visitor>(visitor), + lib::forward<Values>(values)...)) + }; + + template <typename Visitor> + struct value_visitor { + Visitor &&visitor_; + + template <typename... Alts> + inline constexpr DECLTYPE_AUTO operator()(Alts &&... alts) const + DECLTYPE_AUTO_RETURN( + visit_exhaustiveness_check< + Visitor, + decltype((lib::forward<Alts>(alts).value))...>:: + invoke(lib::forward<Visitor>(visitor_), + lib::forward<Alts>(alts).value...)) + }; + + template <typename Visitor> + inline static constexpr AUTO make_value_visitor(Visitor &&visitor) + AUTO_RETURN(value_visitor<Visitor>{lib::forward<Visitor>(visitor)}) + + public: + template <typename Visitor, typename... Vs> + inline static constexpr DECLTYPE_AUTO visit_alt(Visitor &&visitor, + Vs &&... vs) + DECLTYPE_AUTO_RETURN(alt::visit_alt(lib::forward<Visitor>(visitor), + lib::forward<Vs>(vs).impl_...)) + + template <typename Visitor, typename... Vs> + inline static constexpr DECLTYPE_AUTO visit_alt_at(std::size_t index, + Visitor &&visitor, + Vs &&... vs) + DECLTYPE_AUTO_RETURN( + alt::visit_alt_at(index, + lib::forward<Visitor>(visitor), + lib::forward<Vs>(vs).impl_...)) + + template <typename Visitor, typename... Vs> + inline static constexpr DECLTYPE_AUTO visit_value(Visitor &&visitor, + Vs &&... vs) + DECLTYPE_AUTO_RETURN( + visit_alt(make_value_visitor(lib::forward<Visitor>(visitor)), + lib::forward<Vs>(vs)...)) + + template <typename Visitor, typename... Vs> + inline static constexpr DECLTYPE_AUTO visit_value_at(std::size_t index, + Visitor &&visitor, + Vs &&... vs) + DECLTYPE_AUTO_RETURN( + visit_alt_at(index, + make_value_visitor(lib::forward<Visitor>(visitor)), + lib::forward<Vs>(vs)...)) + }; + + } // namespace visitation + + template <std::size_t Index, typename T> + struct alt { + using value_type = T; + +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4244) +#endif + template <typename... Args> + inline explicit constexpr alt(in_place_t, Args &&... args) + : value(lib::forward<Args>(args)...) {} +#ifdef _MSC_VER +#pragma warning(pop) +#endif + + T value; + }; + + template <Trait DestructibleTrait, std::size_t Index, typename... Ts> + union recursive_union; + + template <Trait DestructibleTrait, std::size_t Index> + union recursive_union<DestructibleTrait, Index> {}; + +#define MPARK_VARIANT_RECURSIVE_UNION(destructible_trait, destructor) \ + template <std::size_t Index, typename T, typename... Ts> \ + union recursive_union<destructible_trait, Index, T, Ts...> { \ + public: \ + inline explicit constexpr recursive_union(valueless_t) noexcept \ + : dummy_{} {} \ + \ + template <typename... Args> \ + inline explicit constexpr recursive_union(in_place_index_t<0>, \ + Args &&... args) \ + : head_(in_place_t{}, lib::forward<Args>(args)...) {} \ + \ + template <std::size_t I, typename... Args> \ + inline explicit constexpr recursive_union(in_place_index_t<I>, \ + Args &&... args) \ + : tail_(in_place_index_t<I - 1>{}, lib::forward<Args>(args)...) {} \ + \ + recursive_union(const recursive_union &) = default; \ + recursive_union(recursive_union &&) = default; \ + \ + destructor \ + \ + recursive_union &operator=(const recursive_union &) = default; \ + recursive_union &operator=(recursive_union &&) = default; \ + \ + private: \ + char dummy_; \ + alt<Index, T> head_; \ + recursive_union<destructible_trait, Index + 1, Ts...> tail_; \ + \ + friend struct access::recursive_union; \ + } + + MPARK_VARIANT_RECURSIVE_UNION(Trait::TriviallyAvailable, + ~recursive_union() = default;); + MPARK_VARIANT_RECURSIVE_UNION(Trait::Available, + ~recursive_union() {}); + MPARK_VARIANT_RECURSIVE_UNION(Trait::Unavailable, + ~recursive_union() = delete;); + +#undef MPARK_VARIANT_RECURSIVE_UNION + + using index_t = unsigned int; + + template <Trait DestructibleTrait, typename... Ts> + class base { + public: + inline explicit constexpr base(valueless_t tag) noexcept + : data_(tag), index_(static_cast<index_t>(-1)) {} + + template <std::size_t I, typename... Args> + inline explicit constexpr base(in_place_index_t<I>, Args &&... args) + : data_(in_place_index_t<I>{}, lib::forward<Args>(args)...), + index_(I) {} + + inline constexpr bool valueless_by_exception() const noexcept { + return index_ == static_cast<index_t>(-1); + } + + inline constexpr std::size_t index() const noexcept { + return valueless_by_exception() ? variant_npos : index_; + } + + protected: + using data_t = recursive_union<DestructibleTrait, 0, Ts...>; + + friend inline constexpr base &as_base(base &b) { return b; } + friend inline constexpr const base &as_base(const base &b) { return b; } + friend inline constexpr base &&as_base(base &&b) { return lib::move(b); } + friend inline constexpr const base &&as_base(const base &&b) { return lib::move(b); } + + friend inline constexpr data_t &data(base &b) { return b.data_; } + friend inline constexpr const data_t &data(const base &b) { return b.data_; } + friend inline constexpr data_t &&data(base &&b) { return lib::move(b).data_; } + friend inline constexpr const data_t &&data(const base &&b) { return lib::move(b).data_; } + + inline static constexpr std::size_t size() { return sizeof...(Ts); } + + data_t data_; + index_t index_; + + friend struct access::base; + friend struct visitation::base; + }; + + struct dtor { +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4100) +#endif + template <typename Alt> + inline void operator()(Alt &alt) const noexcept { alt.~Alt(); } +#ifdef _MSC_VER +#pragma warning(pop) +#endif + }; + +#if !defined(_MSC_VER) || _MSC_VER >= 1910 +#define MPARK_INHERITING_CTOR(type, base) using base::base; +#else +#define MPARK_INHERITING_CTOR(type, base) \ + template <typename... Args> \ + inline explicit constexpr type(Args &&... args) \ + : base(lib::forward<Args>(args)...) {} +#endif + + template <typename Traits, Trait = Traits::destructible_trait> + class destructor; + +#define MPARK_VARIANT_DESTRUCTOR(destructible_trait, definition, destroy) \ + template <typename... Ts> \ + class destructor<traits<Ts...>, destructible_trait> \ + : public base<destructible_trait, Ts...> { \ + using super = base<destructible_trait, Ts...>; \ + \ + public: \ + MPARK_INHERITING_CTOR(destructor, super) \ + using super::operator=; \ + \ + destructor(const destructor &) = default; \ + destructor(destructor &&) = default; \ + definition \ + destructor &operator=(const destructor &) = default; \ + destructor &operator=(destructor &&) = default; \ + \ + protected: \ + destroy \ + } + + MPARK_VARIANT_DESTRUCTOR( + Trait::TriviallyAvailable, + ~destructor() = default;, + inline void destroy() noexcept { + this->index_ = static_cast<index_t>(-1); + }); + + MPARK_VARIANT_DESTRUCTOR( + Trait::Available, + ~destructor() { destroy(); }, + inline void destroy() noexcept { + if (!this->valueless_by_exception()) { + visitation::alt::visit_alt(dtor{}, *this); + } + this->index_ = static_cast<index_t>(-1); + }); + + MPARK_VARIANT_DESTRUCTOR( + Trait::Unavailable, + ~destructor() = delete;, + inline void destroy() noexcept = delete;); + +#undef MPARK_VARIANT_DESTRUCTOR + + template <typename Traits> + class constructor : public destructor<Traits> { + using super = destructor<Traits>; + + public: + MPARK_INHERITING_CTOR(constructor, super) + using super::operator=; + + protected: +#ifndef MPARK_GENERIC_LAMBDAS + struct ctor { + template <typename LhsAlt, typename RhsAlt> + inline void operator()(LhsAlt &lhs_alt, RhsAlt &&rhs_alt) const { + constructor::construct_alt(lhs_alt, + lib::forward<RhsAlt>(rhs_alt).value); + } + }; +#endif + + template <std::size_t I, typename T, typename... Args> + inline static T &construct_alt(alt<I, T> &a, Args &&... args) { + auto *result = ::new (static_cast<void *>(lib::addressof(a))) + alt<I, T>(in_place_t{}, lib::forward<Args>(args)...); + return result->value; + } + + template <typename Rhs> + inline static void generic_construct(constructor &lhs, Rhs &&rhs) { + lhs.destroy(); + if (!rhs.valueless_by_exception()) { + visitation::alt::visit_alt_at( + rhs.index(), +#ifdef MPARK_GENERIC_LAMBDAS + [](auto &lhs_alt, auto &&rhs_alt) { + constructor::construct_alt( + lhs_alt, lib::forward<decltype(rhs_alt)>(rhs_alt).value); + } +#else + ctor{} +#endif + , + lhs, + lib::forward<Rhs>(rhs)); + lhs.index_ = rhs.index_; + } + } + }; + + template <typename Traits, Trait = Traits::move_constructible_trait> + class move_constructor; + +#define MPARK_VARIANT_MOVE_CONSTRUCTOR(move_constructible_trait, definition) \ + template <typename... Ts> \ + class move_constructor<traits<Ts...>, move_constructible_trait> \ + : public constructor<traits<Ts...>> { \ + using super = constructor<traits<Ts...>>; \ + \ + public: \ + MPARK_INHERITING_CTOR(move_constructor, super) \ + using super::operator=; \ + \ + move_constructor(const move_constructor &) = default; \ + definition \ + ~move_constructor() = default; \ + move_constructor &operator=(const move_constructor &) = default; \ + move_constructor &operator=(move_constructor &&) = default; \ + } + + MPARK_VARIANT_MOVE_CONSTRUCTOR( + Trait::TriviallyAvailable, + move_constructor(move_constructor &&that) = default;); + + MPARK_VARIANT_MOVE_CONSTRUCTOR( + Trait::Available, + move_constructor(move_constructor &&that) noexcept( + lib::all<std::is_nothrow_move_constructible<Ts>::value...>::value) + : move_constructor(valueless_t{}) { + this->generic_construct(*this, lib::move(that)); + }); + + MPARK_VARIANT_MOVE_CONSTRUCTOR( + Trait::Unavailable, + move_constructor(move_constructor &&) = delete;); + +#undef MPARK_VARIANT_MOVE_CONSTRUCTOR + + template <typename Traits, Trait = Traits::copy_constructible_trait> + class copy_constructor; + +#define MPARK_VARIANT_COPY_CONSTRUCTOR(copy_constructible_trait, definition) \ + template <typename... Ts> \ + class copy_constructor<traits<Ts...>, copy_constructible_trait> \ + : public move_constructor<traits<Ts...>> { \ + using super = move_constructor<traits<Ts...>>; \ + \ + public: \ + MPARK_INHERITING_CTOR(copy_constructor, super) \ + using super::operator=; \ + \ + definition \ + copy_constructor(copy_constructor &&) = default; \ + ~copy_constructor() = default; \ + copy_constructor &operator=(const copy_constructor &) = default; \ + copy_constructor &operator=(copy_constructor &&) = default; \ + } + + MPARK_VARIANT_COPY_CONSTRUCTOR( + Trait::TriviallyAvailable, + copy_constructor(const copy_constructor &that) = default;); + + MPARK_VARIANT_COPY_CONSTRUCTOR( + Trait::Available, + copy_constructor(const copy_constructor &that) + : copy_constructor(valueless_t{}) { + this->generic_construct(*this, that); + }); + + MPARK_VARIANT_COPY_CONSTRUCTOR( + Trait::Unavailable, + copy_constructor(const copy_constructor &) = delete;); + +#undef MPARK_VARIANT_COPY_CONSTRUCTOR + + template <typename Traits> + class assignment : public copy_constructor<Traits> { + using super = copy_constructor<Traits>; + + public: + MPARK_INHERITING_CTOR(assignment, super) + using super::operator=; + + template <std::size_t I, typename... Args> + inline /* auto & */ auto emplace(Args &&... args) + -> decltype(this->construct_alt(access::base::get_alt<I>(*this), + lib::forward<Args>(args)...)) { + this->destroy(); + auto &result = this->construct_alt(access::base::get_alt<I>(*this), + lib::forward<Args>(args)...); + this->index_ = I; + return result; + } + + protected: +#ifndef MPARK_GENERIC_LAMBDAS + template <typename That> + struct assigner { + template <typename ThisAlt, typename ThatAlt> + inline void operator()(ThisAlt &this_alt, ThatAlt &&that_alt) const { + self->assign_alt(this_alt, lib::forward<ThatAlt>(that_alt).value); + } + assignment *self; + }; +#endif + + template <std::size_t I, typename T, typename Arg> + inline void assign_alt(alt<I, T> &a, Arg &&arg) { + if (this->index() == I) { +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4244) +#endif + a.value = lib::forward<Arg>(arg); +#ifdef _MSC_VER +#pragma warning(pop) +#endif + } else { + struct { + void operator()(std::true_type) const { + this_->emplace<I>(lib::forward<Arg>(arg_)); + } + void operator()(std::false_type) const { + this_->emplace<I>(T(lib::forward<Arg>(arg_))); + } + assignment *this_; + Arg &&arg_; + } impl{this, lib::forward<Arg>(arg)}; + impl(lib::bool_constant< + std::is_nothrow_constructible<T, Arg>::value || + !std::is_nothrow_move_constructible<T>::value>{}); + } + } + + template <typename That> + inline void generic_assign(That &&that) { + if (this->valueless_by_exception() && that.valueless_by_exception()) { + // do nothing. + } else if (that.valueless_by_exception()) { + this->destroy(); + } else { + visitation::alt::visit_alt_at( + that.index(), +#ifdef MPARK_GENERIC_LAMBDAS + [this](auto &this_alt, auto &&that_alt) { + this->assign_alt( + this_alt, lib::forward<decltype(that_alt)>(that_alt).value); + } +#else + assigner<That>{this} +#endif + , + *this, + lib::forward<That>(that)); + } + } + }; + + template <typename Traits, Trait = Traits::move_assignable_trait> + class move_assignment; + +#define MPARK_VARIANT_MOVE_ASSIGNMENT(move_assignable_trait, definition) \ + template <typename... Ts> \ + class move_assignment<traits<Ts...>, move_assignable_trait> \ + : public assignment<traits<Ts...>> { \ + using super = assignment<traits<Ts...>>; \ + \ + public: \ + MPARK_INHERITING_CTOR(move_assignment, super) \ + using super::operator=; \ + \ + move_assignment(const move_assignment &) = default; \ + move_assignment(move_assignment &&) = default; \ + ~move_assignment() = default; \ + move_assignment &operator=(const move_assignment &) = default; \ + definition \ + } + + MPARK_VARIANT_MOVE_ASSIGNMENT( + Trait::TriviallyAvailable, + move_assignment &operator=(move_assignment &&that) = default;); + + MPARK_VARIANT_MOVE_ASSIGNMENT( + Trait::Available, + move_assignment & + operator=(move_assignment &&that) noexcept( + lib::all<(std::is_nothrow_move_constructible<Ts>::value && + std::is_nothrow_move_assignable<Ts>::value)...>::value) { + this->generic_assign(lib::move(that)); + return *this; + }); + + MPARK_VARIANT_MOVE_ASSIGNMENT( + Trait::Unavailable, + move_assignment &operator=(move_assignment &&) = delete;); + +#undef MPARK_VARIANT_MOVE_ASSIGNMENT + + template <typename Traits, Trait = Traits::copy_assignable_trait> + class copy_assignment; + +#define MPARK_VARIANT_COPY_ASSIGNMENT(copy_assignable_trait, definition) \ + template <typename... Ts> \ + class copy_assignment<traits<Ts...>, copy_assignable_trait> \ + : public move_assignment<traits<Ts...>> { \ + using super = move_assignment<traits<Ts...>>; \ + \ + public: \ + MPARK_INHERITING_CTOR(copy_assignment, super) \ + using super::operator=; \ + \ + copy_assignment(const copy_assignment &) = default; \ + copy_assignment(copy_assignment &&) = default; \ + ~copy_assignment() = default; \ + definition \ + copy_assignment &operator=(copy_assignment &&) = default; \ + } + + MPARK_VARIANT_COPY_ASSIGNMENT( + Trait::TriviallyAvailable, + copy_assignment &operator=(const copy_assignment &that) = default;); + + MPARK_VARIANT_COPY_ASSIGNMENT( + Trait::Available, + copy_assignment &operator=(const copy_assignment &that) { + this->generic_assign(that); + return *this; + }); + + MPARK_VARIANT_COPY_ASSIGNMENT( + Trait::Unavailable, + copy_assignment &operator=(const copy_assignment &) = delete;); + +#undef MPARK_VARIANT_COPY_ASSIGNMENT + + template <typename... Ts> + class impl : public copy_assignment<traits<Ts...>> { + using super = copy_assignment<traits<Ts...>>; + + public: + MPARK_INHERITING_CTOR(impl, super) + using super::operator=; + + template <std::size_t I, typename Arg> + inline void assign(Arg &&arg) { + this->assign_alt(access::base::get_alt<I>(*this), + lib::forward<Arg>(arg)); + } + + inline void swap(impl &that) { + if (this->valueless_by_exception() && that.valueless_by_exception()) { + // do nothing. + } else if (this->index() == that.index()) { + visitation::alt::visit_alt_at(this->index(), +#ifdef MPARK_GENERIC_LAMBDAS + [](auto &this_alt, auto &that_alt) { + using std::swap; + swap(this_alt.value, + that_alt.value); + } +#else + swapper{} +#endif + , + *this, + that); + } else { + impl *lhs = this; + impl *rhs = lib::addressof(that); + if (lhs->move_nothrow() && !rhs->move_nothrow()) { + std::swap(lhs, rhs); + } + impl tmp(lib::move(*rhs)); +#ifdef MPARK_EXCEPTIONS + // EXTENSION: When the move construction of `lhs` into `rhs` throws + // and `tmp` is nothrow move constructible then we move `tmp` back + // into `rhs` and provide the strong exception safety guarantee. + try { + this->generic_construct(*rhs, lib::move(*lhs)); + } catch (...) { + if (tmp.move_nothrow()) { + this->generic_construct(*rhs, lib::move(tmp)); + } + throw; + } +#else + this->generic_construct(*rhs, lib::move(*lhs)); +#endif + this->generic_construct(*lhs, lib::move(tmp)); + } + } + + private: +#ifndef MPARK_GENERIC_LAMBDAS + struct swapper { + template <typename ThisAlt, typename ThatAlt> + inline void operator()(ThisAlt &this_alt, ThatAlt &that_alt) const { + using std::swap; + swap(this_alt.value, that_alt.value); + } + }; +#endif + + inline constexpr bool move_nothrow() const { + return this->valueless_by_exception() || + lib::array<bool, sizeof...(Ts)>{ + {std::is_nothrow_move_constructible<Ts>::value...} + }[this->index()]; + } + }; + +#undef MPARK_INHERITING_CTOR + + template <std::size_t I, typename T> + struct overload_leaf { + using F = lib::size_constant<I> (*)(T); + operator F() const { return nullptr; } + }; + + template <typename... Ts> + struct overload_impl { + private: + template <typename> + struct impl; + + template <std::size_t... Is> + struct impl<lib::index_sequence<Is...>> : overload_leaf<Is, Ts>... {}; + + public: + using type = impl<lib::index_sequence_for<Ts...>>; + }; + + template <typename... Ts> + using overload = typename overload_impl<Ts...>::type; + + template <typename T, typename... Ts> + using best_match = lib::invoke_result_t<overload<Ts...>, T &&>; + + template <typename T> + struct is_in_place_index : std::false_type {}; + + template <std::size_t I> + struct is_in_place_index<in_place_index_t<I>> : std::true_type {}; + + template <typename T> + struct is_in_place_type : std::false_type {}; + + template <typename T> + struct is_in_place_type<in_place_type_t<T>> : std::true_type {}; + + } // detail + + template <typename... Ts> + class variant { + static_assert(0 < sizeof...(Ts), + "variant must consist of at least one alternative."); + + static_assert(lib::all<!std::is_array<Ts>::value...>::value, + "variant can not have an array type as an alternative."); + + static_assert(lib::all<!std::is_reference<Ts>::value...>::value, + "variant can not have a reference type as an alternative."); + + static_assert(lib::all<!std::is_void<Ts>::value...>::value, + "variant can not have a void type as an alternative."); + + public: + template < + typename Front = lib::type_pack_element_t<0, Ts...>, + lib::enable_if_t<std::is_default_constructible<Front>::value, int> = 0> + inline constexpr variant() noexcept( + std::is_nothrow_default_constructible<Front>::value) + : impl_(in_place_index_t<0>{}) {} + + variant(const variant &) = default; + variant(variant &&) = default; + + template < + typename Arg, + typename Decayed = lib::decay_t<Arg>, + lib::enable_if_t<!std::is_same<Decayed, variant>::value, int> = 0, + lib::enable_if_t<!detail::is_in_place_index<Decayed>::value, int> = 0, + lib::enable_if_t<!detail::is_in_place_type<Decayed>::value, int> = 0, + std::size_t I = detail::best_match<Arg, Ts...>::value, + typename T = lib::type_pack_element_t<I, Ts...>, + lib::enable_if_t<std::is_constructible<T, Arg>::value, int> = 0> + inline constexpr variant(Arg &&arg) noexcept( + std::is_nothrow_constructible<T, Arg>::value) + : impl_(in_place_index_t<I>{}, lib::forward<Arg>(arg)) {} + + template < + std::size_t I, + typename... Args, + typename T = lib::type_pack_element_t<I, Ts...>, + lib::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0> + inline explicit constexpr variant( + in_place_index_t<I>, + Args &&... args) noexcept(std::is_nothrow_constructible<T, + Args...>::value) + : impl_(in_place_index_t<I>{}, lib::forward<Args>(args)...) {} + + template < + std::size_t I, + typename Up, + typename... Args, + typename T = lib::type_pack_element_t<I, Ts...>, + lib::enable_if_t<std::is_constructible<T, + std::initializer_list<Up> &, + Args...>::value, + int> = 0> + inline explicit constexpr variant( + in_place_index_t<I>, + std::initializer_list<Up> il, + Args &&... args) noexcept(std:: + is_nothrow_constructible< + T, + std::initializer_list<Up> &, + Args...>::value) + : impl_(in_place_index_t<I>{}, il, lib::forward<Args>(args)...) {} + + template < + typename T, + typename... Args, + std::size_t I = detail::find_index_sfinae<T, Ts...>::value, + lib::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0> + inline explicit constexpr variant( + in_place_type_t<T>, + Args &&... args) noexcept(std::is_nothrow_constructible<T, + Args...>::value) + : impl_(in_place_index_t<I>{}, lib::forward<Args>(args)...) {} + + template < + typename T, + typename Up, + typename... Args, + std::size_t I = detail::find_index_sfinae<T, Ts...>::value, + lib::enable_if_t<std::is_constructible<T, + std::initializer_list<Up> &, + Args...>::value, + int> = 0> + inline explicit constexpr variant( + in_place_type_t<T>, + std::initializer_list<Up> il, + Args &&... args) noexcept(std:: + is_nothrow_constructible< + T, + std::initializer_list<Up> &, + Args...>::value) + : impl_(in_place_index_t<I>{}, il, lib::forward<Args>(args)...) {} + + ~variant() = default; + + variant &operator=(const variant &) = default; + variant &operator=(variant &&) = default; + + template <typename Arg, + lib::enable_if_t<!std::is_same<lib::decay_t<Arg>, variant>::value, + int> = 0, + std::size_t I = detail::best_match<Arg, Ts...>::value, + typename T = lib::type_pack_element_t<I, Ts...>, + lib::enable_if_t<(std::is_assignable<T &, Arg>::value && + std::is_constructible<T, Arg>::value), + int> = 0> + inline variant &operator=(Arg &&arg) noexcept( + (std::is_nothrow_assignable<T &, Arg>::value && + std::is_nothrow_constructible<T, Arg>::value)) { + impl_.template assign<I>(lib::forward<Arg>(arg)); + return *this; + } + + template < + std::size_t I, + typename... Args, + typename T = lib::type_pack_element_t<I, Ts...>, + lib::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0> + inline T &emplace(Args &&... args) { + return impl_.template emplace<I>(lib::forward<Args>(args)...); + } + + template < + std::size_t I, + typename Up, + typename... Args, + typename T = lib::type_pack_element_t<I, Ts...>, + lib::enable_if_t<std::is_constructible<T, + std::initializer_list<Up> &, + Args...>::value, + int> = 0> + inline T &emplace(std::initializer_list<Up> il, Args &&... args) { + return impl_.template emplace<I>(il, lib::forward<Args>(args)...); + } + + template < + typename T, + typename... Args, + std::size_t I = detail::find_index_sfinae<T, Ts...>::value, + lib::enable_if_t<std::is_constructible<T, Args...>::value, int> = 0> + inline T &emplace(Args &&... args) { + return impl_.template emplace<I>(lib::forward<Args>(args)...); + } + + template < + typename T, + typename Up, + typename... Args, + std::size_t I = detail::find_index_sfinae<T, Ts...>::value, + lib::enable_if_t<std::is_constructible<T, + std::initializer_list<Up> &, + Args...>::value, + int> = 0> + inline T &emplace(std::initializer_list<Up> il, Args &&... args) { + return impl_.template emplace<I>(il, lib::forward<Args>(args)...); + } + + inline constexpr bool valueless_by_exception() const noexcept { + return impl_.valueless_by_exception(); + } + + inline constexpr std::size_t index() const noexcept { + return impl_.index(); + } + + template <bool Dummy = true, + lib::enable_if_t< + lib::all<Dummy, + (lib::dependent_type<std::is_move_constructible<Ts>, + Dummy>::value && + lib::dependent_type<lib::is_swappable<Ts>, + Dummy>::value)...>::value, + int> = 0> + inline void swap(variant &that) noexcept( + lib::all<(std::is_nothrow_move_constructible<Ts>::value && + lib::is_nothrow_swappable<Ts>::value)...>::value) { + impl_.swap(that.impl_); + } + + private: + detail::impl<Ts...> impl_; + + friend struct detail::access::variant; + friend struct detail::visitation::variant; + }; + + template <std::size_t I, typename... Ts> + inline constexpr bool holds_alternative(const variant<Ts...> &v) noexcept { + return v.index() == I; + } + + template <typename T, typename... Ts> + inline constexpr bool holds_alternative(const variant<Ts...> &v) noexcept { + return holds_alternative<detail::find_index_checked<T, Ts...>::value>(v); + } + + namespace detail { + template <std::size_t I, typename V> + struct generic_get_impl { + constexpr generic_get_impl(int) noexcept {} + + constexpr AUTO_REFREF operator()(V &&v) const + AUTO_REFREF_RETURN( + access::variant::get_alt<I>(lib::forward<V>(v)).value) + }; + + template <std::size_t I, typename V> + inline constexpr AUTO_REFREF generic_get(V &&v) + AUTO_REFREF_RETURN(generic_get_impl<I, V>( + holds_alternative<I>(v) ? 0 : (throw_bad_variant_access(), 0))( + lib::forward<V>(v))) + } // namespace detail + + template <std::size_t I, typename... Ts> + inline constexpr variant_alternative_t<I, variant<Ts...>> &get( + variant<Ts...> &v) { + return detail::generic_get<I>(v); + } + + template <std::size_t I, typename... Ts> + inline constexpr variant_alternative_t<I, variant<Ts...>> &&get( + variant<Ts...> &&v) { + return detail::generic_get<I>(lib::move(v)); + } + + template <std::size_t I, typename... Ts> + inline constexpr const variant_alternative_t<I, variant<Ts...>> &get( + const variant<Ts...> &v) { + return detail::generic_get<I>(v); + } + + template <std::size_t I, typename... Ts> + inline constexpr const variant_alternative_t<I, variant<Ts...>> &&get( + const variant<Ts...> &&v) { + return detail::generic_get<I>(lib::move(v)); + } + + template <typename T, typename... Ts> + inline constexpr T &get(variant<Ts...> &v) { + return get<detail::find_index_checked<T, Ts...>::value>(v); + } + + template <typename T, typename... Ts> + inline constexpr T &&get(variant<Ts...> &&v) { + return get<detail::find_index_checked<T, Ts...>::value>(lib::move(v)); + } + + template <typename T, typename... Ts> + inline constexpr const T &get(const variant<Ts...> &v) { + return get<detail::find_index_checked<T, Ts...>::value>(v); + } + + template <typename T, typename... Ts> + inline constexpr const T &&get(const variant<Ts...> &&v) { + return get<detail::find_index_checked<T, Ts...>::value>(lib::move(v)); + } + + namespace detail { + + template <std::size_t I, typename V> + inline constexpr /* auto * */ AUTO generic_get_if(V *v) noexcept + AUTO_RETURN(v && holds_alternative<I>(*v) + ? lib::addressof(access::variant::get_alt<I>(*v).value) + : nullptr) + + } // namespace detail + + template <std::size_t I, typename... Ts> + inline constexpr lib::add_pointer_t<variant_alternative_t<I, variant<Ts...>>> + get_if(variant<Ts...> *v) noexcept { + return detail::generic_get_if<I>(v); + } + + template <std::size_t I, typename... Ts> + inline constexpr lib::add_pointer_t< + const variant_alternative_t<I, variant<Ts...>>> + get_if(const variant<Ts...> *v) noexcept { + return detail::generic_get_if<I>(v); + } + + template <typename T, typename... Ts> + inline constexpr lib::add_pointer_t<T> + get_if(variant<Ts...> *v) noexcept { + return get_if<detail::find_index_checked<T, Ts...>::value>(v); + } + + template <typename T, typename... Ts> + inline constexpr lib::add_pointer_t<const T> + get_if(const variant<Ts...> *v) noexcept { + return get_if<detail::find_index_checked<T, Ts...>::value>(v); + } + + namespace detail { + template <typename RelOp> + struct convert_to_bool { + template <typename Lhs, typename Rhs> + inline constexpr bool operator()(Lhs &&lhs, Rhs &&rhs) const { + static_assert(std::is_convertible<lib::invoke_result_t<RelOp, Lhs, Rhs>, + bool>::value, + "relational operators must return a type" + " implicitly convertible to bool"); + return lib::invoke( + RelOp{}, lib::forward<Lhs>(lhs), lib::forward<Rhs>(rhs)); + } + }; + } // namespace detail + + template <typename... Ts> + inline constexpr bool operator==(const variant<Ts...> &lhs, + const variant<Ts...> &rhs) { + using detail::visitation::variant; + using equal_to = detail::convert_to_bool<lib::equal_to>; +#ifdef MPARK_CPP14_CONSTEXPR + if (lhs.index() != rhs.index()) return false; + if (lhs.valueless_by_exception()) return true; + return variant::visit_value_at(lhs.index(), equal_to{}, lhs, rhs); +#else + return lhs.index() == rhs.index() && + (lhs.valueless_by_exception() || + variant::visit_value_at(lhs.index(), equal_to{}, lhs, rhs)); +#endif + } + + template <typename... Ts> + inline constexpr bool operator!=(const variant<Ts...> &lhs, + const variant<Ts...> &rhs) { + using detail::visitation::variant; + using not_equal_to = detail::convert_to_bool<lib::not_equal_to>; +#ifdef MPARK_CPP14_CONSTEXPR + if (lhs.index() != rhs.index()) return true; + if (lhs.valueless_by_exception()) return false; + return variant::visit_value_at(lhs.index(), not_equal_to{}, lhs, rhs); +#else + return lhs.index() != rhs.index() || + (!lhs.valueless_by_exception() && + variant::visit_value_at(lhs.index(), not_equal_to{}, lhs, rhs)); +#endif + } + + template <typename... Ts> + inline constexpr bool operator<(const variant<Ts...> &lhs, + const variant<Ts...> &rhs) { + using detail::visitation::variant; + using less = detail::convert_to_bool<lib::less>; +#ifdef MPARK_CPP14_CONSTEXPR + if (rhs.valueless_by_exception()) return false; + if (lhs.valueless_by_exception()) return true; + if (lhs.index() < rhs.index()) return true; + if (lhs.index() > rhs.index()) return false; + return variant::visit_value_at(lhs.index(), less{}, lhs, rhs); +#else + return !rhs.valueless_by_exception() && + (lhs.valueless_by_exception() || lhs.index() < rhs.index() || + (lhs.index() == rhs.index() && + variant::visit_value_at(lhs.index(), less{}, lhs, rhs))); +#endif + } + + template <typename... Ts> + inline constexpr bool operator>(const variant<Ts...> &lhs, + const variant<Ts...> &rhs) { + using detail::visitation::variant; + using greater = detail::convert_to_bool<lib::greater>; +#ifdef MPARK_CPP14_CONSTEXPR + if (lhs.valueless_by_exception()) return false; + if (rhs.valueless_by_exception()) return true; + if (lhs.index() > rhs.index()) return true; + if (lhs.index() < rhs.index()) return false; + return variant::visit_value_at(lhs.index(), greater{}, lhs, rhs); +#else + return !lhs.valueless_by_exception() && + (rhs.valueless_by_exception() || lhs.index() > rhs.index() || + (lhs.index() == rhs.index() && + variant::visit_value_at(lhs.index(), greater{}, lhs, rhs))); +#endif + } + + template <typename... Ts> + inline constexpr bool operator<=(const variant<Ts...> &lhs, + const variant<Ts...> &rhs) { + using detail::visitation::variant; + using less_equal = detail::convert_to_bool<lib::less_equal>; +#ifdef MPARK_CPP14_CONSTEXPR + if (lhs.valueless_by_exception()) return true; + if (rhs.valueless_by_exception()) return false; + if (lhs.index() < rhs.index()) return true; + if (lhs.index() > rhs.index()) return false; + return variant::visit_value_at(lhs.index(), less_equal{}, lhs, rhs); +#else + return lhs.valueless_by_exception() || + (!rhs.valueless_by_exception() && + (lhs.index() < rhs.index() || + (lhs.index() == rhs.index() && + variant::visit_value_at(lhs.index(), less_equal{}, lhs, rhs)))); +#endif + } + + template <typename... Ts> + inline constexpr bool operator>=(const variant<Ts...> &lhs, + const variant<Ts...> &rhs) { + using detail::visitation::variant; + using greater_equal = detail::convert_to_bool<lib::greater_equal>; +#ifdef MPARK_CPP14_CONSTEXPR + if (rhs.valueless_by_exception()) return true; + if (lhs.valueless_by_exception()) return false; + if (lhs.index() > rhs.index()) return true; + if (lhs.index() < rhs.index()) return false; + return variant::visit_value_at(lhs.index(), greater_equal{}, lhs, rhs); +#else + return rhs.valueless_by_exception() || + (!lhs.valueless_by_exception() && + (lhs.index() > rhs.index() || + (lhs.index() == rhs.index() && + variant::visit_value_at( + lhs.index(), greater_equal{}, lhs, rhs)))); +#endif + } + + struct monostate {}; + + inline constexpr bool operator<(monostate, monostate) noexcept { + return false; + } + + inline constexpr bool operator>(monostate, monostate) noexcept { + return false; + } + + inline constexpr bool operator<=(monostate, monostate) noexcept { + return true; + } + + inline constexpr bool operator>=(monostate, monostate) noexcept { + return true; + } + + inline constexpr bool operator==(monostate, monostate) noexcept { + return true; + } + + inline constexpr bool operator!=(monostate, monostate) noexcept { + return false; + } + +#ifdef MPARK_CPP14_CONSTEXPR + namespace detail { + + inline constexpr bool all(std::initializer_list<bool> bs) { + for (bool b : bs) { + if (!b) { + return false; + } + } + return true; + } + + } // namespace detail + + template <typename Visitor, typename... Vs> + inline constexpr decltype(auto) visit(Visitor &&visitor, Vs &&... vs) { + // NOTE: fix for nvcc, see https://github.com/mpark/variant/issues/63 +// return (detail::all({!vs.valueless_by_exception()...}) + return (detail::all(std::initializer_list<bool>({!vs.valueless_by_exception()...})) + ? (void)0 + : throw_bad_variant_access()), + detail::visitation::variant::visit_value( + lib::forward<Visitor>(visitor), lib::forward<Vs>(vs)...); + } +#else + namespace detail { + + template <std::size_t N> + inline constexpr bool all_impl(const lib::array<bool, N> &bs, + std::size_t idx) { + return idx >= N || (bs[idx] && all_impl(bs, idx + 1)); + } + + template <std::size_t N> + inline constexpr bool all(const lib::array<bool, N> &bs) { + return all_impl(bs, 0); + } + + } // namespace detail + + template <typename Visitor, typename... Vs> + inline constexpr DECLTYPE_AUTO visit(Visitor &&visitor, Vs &&... vs) + DECLTYPE_AUTO_RETURN( + (detail::all( + lib::array<bool, sizeof...(Vs)>{{!vs.valueless_by_exception()...}}) + ? (void)0 + : throw_bad_variant_access()), + detail::visitation::variant::visit_value(lib::forward<Visitor>(visitor), + lib::forward<Vs>(vs)...)) +#endif + + template <typename... Ts> + inline auto swap(variant<Ts...> &lhs, + variant<Ts...> &rhs) noexcept(noexcept(lhs.swap(rhs))) + -> decltype(lhs.swap(rhs)) { + lhs.swap(rhs); + } + + namespace detail { + + template <typename T, typename...> + using enabled_type = T; + + namespace hash { + + template <typename H, typename K> + constexpr bool meets_requirements() noexcept { + return std::is_copy_constructible<H>::value && + std::is_move_constructible<H>::value && + lib::is_invocable_r<std::size_t, H, const K &>::value; + } + + template <typename K> + constexpr bool is_enabled() noexcept { + using H = std::hash<K>; + return meets_requirements<H, K>() && + std::is_default_constructible<H>::value && + std::is_copy_assignable<H>::value && + std::is_move_assignable<H>::value; + } + + } // namespace hash + + } // namespace detail + +#undef AUTO +#undef AUTO_RETURN + +#undef AUTO_REFREF +#undef AUTO_REFREF_RETURN + +#undef DECLTYPE_AUTO +#undef DECLTYPE_AUTO_RETURN + +} // namespace mpark + +namespace std { + + template <typename... Ts> + struct hash<mpark::detail::enabled_type< + mpark::variant<Ts...>, + mpark::lib::enable_if_t<mpark::lib::all<mpark::detail::hash::is_enabled< + mpark::lib::remove_const_t<Ts>>()...>::value>>> { + using argument_type = mpark::variant<Ts...>; + using result_type = std::size_t; + + inline result_type operator()(const argument_type &v) const { + using mpark::detail::visitation::variant; + std::size_t result = + v.valueless_by_exception() + ? 299792458 // Random value chosen by the universe upon creation + : variant::visit_alt( +#ifdef MPARK_GENERIC_LAMBDAS + [](const auto &alt) { + using alt_type = mpark::lib::decay_t<decltype(alt)>; + using value_type = mpark::lib::remove_const_t< + typename alt_type::value_type>; + return hash<value_type>{}(alt.value); + } +#else + hasher{} +#endif + , + v); + return hash_combine(result, hash<std::size_t>{}(v.index())); + } + + private: +#ifndef MPARK_GENERIC_LAMBDAS + struct hasher { + template <typename Alt> + inline std::size_t operator()(const Alt &alt) const { + using alt_type = mpark::lib::decay_t<Alt>; + using value_type = + mpark::lib::remove_const_t<typename alt_type::value_type>; + return hash<value_type>{}(alt.value); + } + }; +#endif + + static std::size_t hash_combine(std::size_t lhs, std::size_t rhs) { + return lhs ^= rhs + 0x9e3779b9 + (lhs << 6) + (lhs >> 2); + } + }; + + template <> + struct hash<mpark::monostate> { + using argument_type = mpark::monostate; + using result_type = std::size_t; + + inline result_type operator()(const argument_type &) const noexcept { + return 66740831; // return a fundamentally attractive random value. + } + }; + +} // namespace std + +#endif // MPARK_VARIANT_HPP diff --git a/src/Tools/tnl-dicom-reader.cpp b/src/Tools/tnl-dicom-reader.cpp index c0f770e497b95ba2758cb852a36a3c3ccf562069..52eb7f7786d1847eb7be452b21497210d94de2d7 100644 --- a/src/Tools/tnl-dicom-reader.cpp +++ b/src/Tools/tnl-dicom-reader.cpp @@ -8,9 +8,8 @@ /* See Copyright Notice in tnl/Copyright */ -#include <TNL/Config/ConfigDescription.h> -#include <TNL/Config/ParameterContainer.h> -#include <TNL/Images//DicomSeries.h> +#include <TNL/Config/parseCommandLine.h> +#include <TNL/Images/DicomSeries.h> #include <TNL/FileName.h> using namespace TNL; @@ -85,15 +84,12 @@ int main( int argc, char* argv[] ) Config::ConfigDescription configDescription; setupConfig( configDescription ); if( ! parseCommandLine( argc, argv, configDescription, parameters ) ) - { - configDescription.printUsage( argv[ 0 ] ); return EXIT_FAILURE; - } if( ! parameters.checkParameter( "dicom-files" ) && ! parameters.checkParameter( "dicom-series") ) { std::cerr << "Neither DICOM series nor DICOM files are given." << std::endl; - configDescription.printUsage( argv[ 0 ] ); + Config::printUsage( configDescription, argv[ 0 ] ); return EXIT_FAILURE; } #ifdef HAVE_DCMTK_H diff --git a/src/Tools/tnl-diff.cpp b/src/Tools/tnl-diff.cpp index 7e442c982fe777abc2d02259a881f28d945e682f..84d7a08096e8b89e3ecc8278f82bcb586f5cbfe6 100644 --- a/src/Tools/tnl-diff.cpp +++ b/src/Tools/tnl-diff.cpp @@ -9,6 +9,7 @@ /* See Copyright Notice in tnl/Copyright */ #include "tnl-diff.h" +#include <TNL/Config/parseCommandLine.h> #include <TNL/Meshes/DummyMesh.h> #include <TNL/Meshes/Grid.h> @@ -37,10 +38,7 @@ int main( int argc, char* argv[] ) Config::ConfigDescription conf_desc; setupConfig( conf_desc ); if( ! parseCommandLine( argc, argv, conf_desc, parameters ) ) - { - conf_desc.printUsage( argv[ 0 ] ); - return 1; - } + return EXIT_FAILURE; String meshFile = parameters.getParameter< String >( "mesh" ); /*if( meshFile == "" ) diff --git a/src/Tools/tnl-grid-setup.cpp b/src/Tools/tnl-grid-setup.cpp index 261f1cf716d6f7b453b27a7acb3f2bfd7d6daa9a..115f02065920e50507acef551b68128d5be90dd4 100644 --- a/src/Tools/tnl-grid-setup.cpp +++ b/src/Tools/tnl-grid-setup.cpp @@ -9,7 +9,7 @@ /* See Copyright Notice in tnl/Copyright */ #include "tnl-grid-setup.h" -#include <TNL/Config/ParameterContainer.h> +#include <TNL/Config/parseCommandLine.h> void configSetup( Config::ConfigDescription& config ) { diff --git a/src/Tools/tnl-image-converter.cpp b/src/Tools/tnl-image-converter.cpp index 493ff503c8fd035681cadb608cecd5161429d110..d1ef8fa92b4dfceac9a8d8426c66b823020cc87e 100644 --- a/src/Tools/tnl-image-converter.cpp +++ b/src/Tools/tnl-image-converter.cpp @@ -8,8 +8,7 @@ /* See Copyright Notice in tnl/Copyright */ -#include <TNL/Config/ConfigDescription.h> -#include <TNL/Config/ParameterContainer.h> +#include <TNL/Config/parseCommandLine.h> #include <TNL/FileName.h> #include <TNL/Meshes/Grid.h> #include <TNL/Pointers/SharedPointer.h> @@ -206,15 +205,12 @@ int main( int argc, char* argv[] ) Config::ConfigDescription configDescription; configSetup( configDescription ); if( ! parseCommandLine( argc, argv, configDescription, parameters ) ) - { - configDescription.printUsage( argv[ 0 ] ); return EXIT_FAILURE; - } if( ! parameters.checkParameter( "input-images" ) && ! parameters.checkParameter( "input-files") ) { std::cerr << "Neither input images nor input .tnl files are given." << std::endl; - configDescription.printUsage( argv[ 0 ] ); + Config::printUsage( configDescription, argv[ 0 ] ); return EXIT_FAILURE; } if( parameters.checkParameter( "input-images" ) ) diff --git a/src/Tools/tnl-init.cpp b/src/Tools/tnl-init.cpp index 9accb36342d2c37e4979ef24deb2d56ce67d6b7d..220874ebc9d549b5923078f33b9bd119d5a29af5 100644 --- a/src/Tools/tnl-init.cpp +++ b/src/Tools/tnl-init.cpp @@ -11,8 +11,7 @@ #include "tnl-init.h" #include <TNL/File.h> -#include <TNL/Config/ConfigDescription.h> -#include <TNL/Config/ParameterContainer.h> +#include <TNL/Config/parseCommandLine.h> #include <TNL/Functions/TestFunction.h> #include <TNL/Meshes/DummyMesh.h> #include <TNL/Meshes/Grid.h> diff --git a/src/Tools/tnl-lattice-init.cpp b/src/Tools/tnl-lattice-init.cpp index f9d746f89f20b66d89614df910aa8aae0b76cd75..a4aa1ba0cfdeb05dd97f168d62f0069edd9159a9 100644 --- a/src/Tools/tnl-lattice-init.cpp +++ b/src/Tools/tnl-lattice-init.cpp @@ -10,8 +10,7 @@ #include "tnl-lattice-init.h" -#include <TNL/Config/ConfigDescription.h> -#include <TNL/Config/ParameterContainer.h> +#include <TNL/Config/parseCommandLine.h> using namespace TNL; diff --git a/src/Tools/tnl-mesh-converter.cpp b/src/Tools/tnl-mesh-converter.cpp index cd9de1a597c266722092d1851ac41e2c8dfa7217..ac8f9921966ba96d915c479056111729fd9b2dad 100644 --- a/src/Tools/tnl-mesh-converter.cpp +++ b/src/Tools/tnl-mesh-converter.cpp @@ -8,7 +8,7 @@ /* See Copyright Notice in tnl/Copyright */ -#include <TNL/Config/ParameterContainer.h> +#include <TNL/Config/parseCommandLine.h> #include <TNL/Meshes/TypeResolver/TypeResolver.h> #include <TNL/Meshes/Writers/VTKWriter.h> #include <TNL/Meshes/Writers/NetgenWriter.h> @@ -124,9 +124,8 @@ int main( int argc, char* argv[] ) configSetup( conf_desc ); - if( ! parseCommandLine( argc, argv, conf_desc, parameters ) ) { + if( ! parseCommandLine( argc, argv, conf_desc, parameters ) ) return EXIT_FAILURE; - } const String inputFileName = parameters.getParameter< String >( "input-file" ); const String outputFileName = parameters.getParameter< String >( "output-file" ); diff --git a/src/Tools/tnl-view.cpp b/src/Tools/tnl-view.cpp index 32fac87d9645c066fe111eef1fb2c66961ae1c5c..a2774699166e84a8063daf9bc10a2f93480d8bc6 100644 --- a/src/Tools/tnl-view.cpp +++ b/src/Tools/tnl-view.cpp @@ -11,8 +11,7 @@ #include "tnl-view.h" #include <cstdlib> #include <TNL/File.h> -#include <TNL/Config/ConfigDescription.h> -#include <TNL/Config/ParameterContainer.h> +#include <TNL/Config/parseCommandLine.h> #include <TNL/Meshes/DummyMesh.h> #include <TNL/Meshes/Grid.h> #include <TNL/Meshes/TypeResolver/TypeResolver.h>