static_assert( __cplusplus > 2020'99 ); #pragma once #include #include #include #include #include #include #include #include #include namespace Alepha::Hydrogen::Utility ::detail:: StringMap_m { namespace C { const bool debug= false; const bool debugCompare= false or C::debug; const bool debugInsertion= false or C::debug; } inline namespace exports { template< typename Value > class StringMap; } using namespace Alepha::Algorithm::exports::string_distance_m; template< typename Value > class exports::StringMap { private: std::map< std::string, Value > storage; template< typename Self > Value & at_impl( Self &self, const std::string &key ) { if( C::debugInsertion ) error() << "Map has " << storage.size() << " entries" << std::endl; if( not storage.contains( key ) ) { const auto closest= std::min_element( begin( storage ), end( storage ), [&]( const auto &lhs, const auto &rhs ) { const auto l= optimalStringDistance( lhs.first, key ); const auto r= optimalStringDistance( rhs.first, key ); if( C::debugCompare ) error() << "Left value: " << l << " right value: " << r << std::endl; return l < r; } ); if( closest == end( storage ) ) throw std::out_of_range{ IOStreams::String() << "The key `" << key << "` could not be found." }; else if( optimalStringDistance( closest->first, key ) < std::sqrt( key.size() ) ) { throw std::out_of_range{ IOStreams::String() << "The key `" << key << "` could not be found. Did you mean `" << closest->first << "`?" }; } throw std::out_of_range{ IOStreams::String() << "The key `" << key << "` could not be found." }; } return storage.at( key ); } public: Value &at( const std::string & key ) { return at_impl( *this, key ); } const Value &at( const std::string &key ) const { return at_impl( *this, key ); } bool contains( const std::string &key ) const { return storage.contains( key ); } void insert( const std::string &key, Value v ) { if( not contains( key ) ) storage.emplace( key, std::move( v ) ); if( C::debugInsertion ) error() << "Map has " << storage.size() << " entries" << std::endl; } }; } namespace Alepha::Hydrogen::Utility::inline exports::inline StringMap_m { using namespace detail::StringMap_m::exports; }