diff --git a/CMakeLists.txt b/CMakeLists.txt index 765e9eb02..a7030151a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,7 +9,7 @@ cmake_minimum_required( VERSION 3.14 ) project( "daw-header-libraries" - VERSION "2.133.0" + VERSION "2.134.0" DESCRIPTION "Various headers" HOMEPAGE_URL "https://github.com/beached/header_libraries" LANGUAGES C CXX diff --git a/include/daw/daw_attributes.h b/include/daw/daw_attributes.h index be83c4849..e995596c9 100644 --- a/include/daw/daw_attributes.h +++ b/include/daw/daw_attributes.h @@ -130,7 +130,7 @@ #define DAW_ATTRIB_RET_NONNULL #endif -#if defined( DAW_NO_LIFETIME_BOUND ) +#if not defined( DAW_NO_LIFETIME_BOUND ) #if not defined( __has_cpp_attribute ) #define DAW_LIFETIME_BOUND #elif __has_cpp_attribute( clang::lifetimebound ) diff --git a/include/daw/daw_enable_if.h b/include/daw/daw_enable_if.h index fe83ffe66..6518b54ec 100644 --- a/include/daw/daw_enable_if.h +++ b/include/daw/daw_enable_if.h @@ -8,8 +8,8 @@ #pragma once -#include "cpp_17.h" -#include "daw_cpp_feature_check.h" +#include "daw/cpp_17.h" +#include "daw/daw_cpp_feature_check.h" #include #include diff --git a/include/daw/daw_heap_value.h b/include/daw/daw_heap_value.h deleted file mode 100644 index 696d080d8..000000000 --- a/include/daw/daw_heap_value.h +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) Darrell Wright -// -// Distributed under the Boost Software License, Version 1.0. (See accompanying -// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) -// -// Official repository: https://github.com/beached/header_libraries -// - -#pragma once - -namespace daw { - -} - - diff --git a/include/daw/daw_ignored.h b/include/daw/daw_ignored.h index 8d47400a5..6e2f26b52 100644 --- a/include/daw/daw_ignored.h +++ b/include/daw/daw_ignored.h @@ -13,7 +13,7 @@ namespace daw { namespace { struct ignored_t { - ignored_t( ) = default; + explicit ignored_t( ) = default; template DAW_ATTRIB_INLINE constexpr ignored_t( T && ) noexcept {} diff --git a/include/daw/daw_mutable_function_ref.h b/include/daw/daw_mutable_function_ref.h new file mode 100644 index 000000000..cad4f5ace --- /dev/null +++ b/include/daw/daw_mutable_function_ref.h @@ -0,0 +1,279 @@ +// Copyright (c) Darrell Wright +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/beached/header_libraries +// + +#pragma once + +#include +#include +#include +#include +#include +#include + +#ifdef DAW_CPP26_CONSTEXPR +#undef DAW_CPP26_CONSTEXPR +#endif +#ifdef DAW_CPP26_CONSTEVAL +#undef DAW_CPP26_CONSTEVAL +#endif +#if __cpp_constexpr >= 202306L +#define DAW_CPP26_CONSTEXPR constexpr +#define DAW_CPP26_CONSTEVAL consteval +#else +#define DAW_CPP26_CONSTEXPR +#define DAW_CPP26_CONSTEVAL +#endif + +namespace daw { + namespace mutable_function_ref_details { + template + concept class_invocable_r = std::is_class_v> and + std::is_invocable_r_v; + + template + concept different_from = not std::same_as, U>; + } // namespace mutable_function_ref_details + + template + class mutable_function_ref; + + template + class mutable_function_ref { + union data_t { + void *obj_ptr; + void const *const_obj_ptr; + Result ( *func_ptr )( Params... ); + + constexpr data_t( void *ptr ) noexcept + : obj_ptr( ptr ) {} + + constexpr data_t( void const *ptr ) noexcept + : const_obj_ptr( ptr ) {} + + constexpr data_t( Result ( *ptr )( Params... ) ) noexcept + : func_ptr( ptr ) {} + }; + + data_t m_data; + Result ( *m_thunk )( data_t const &, Params... ); + + template + static DAW_CPP26_CONSTEXPR Result obj_thunk( data_t const &d, + Params... params ) { + auto &obj = *static_cast( d.obj_ptr ); + return obj( std::forward( params )... ); + } + + template + static DAW_CPP26_CONSTEXPR Result const_obj_thunk( data_t const &d, + Params... params ) { + auto const &obj = *static_cast( d.const_obj_ptr ); + return obj( std::forward( params )... ); + } + + static constexpr Result fp_thunk( data_t const &d, Params... params ) { + return d.func_ptr( params... ); + } + + struct empty_call { + explicit empty_call( ) = default; + [[noreturn]] Result operator( )( Params... ) const { + std::abort( ); + } + }; + + public: + constexpr mutable_function_ref( ) noexcept + : mutable_function_ref( empty_call{ } ) {} + + template + requires( mutable_function_ref_details::different_from< + Func, mutable_function_ref> and + not std::is_const_v and + mutable_function_ref_details::class_invocable_r ) // + constexpr mutable_function_ref( Func &func ) noexcept + : m_data( static_cast( std::addressof( func ) ) ) + , m_thunk( obj_thunk ) {} + + template + requires( + mutable_function_ref_details::different_from + and mutable_function_ref_details::class_invocable_r< + Result, Func const &, Params...> ) // + constexpr mutable_function_ref( Func const &func ) noexcept + : m_data( static_cast( std::addressof( func ) ) ) + , m_thunk( const_obj_thunk ) {} + + template + requires( not std::is_lvalue_reference_v and + mutable_function_ref_details::different_from< + Func, mutable_function_ref> and + not std::is_const_v and + mutable_function_ref_details::class_invocable_r ) // + constexpr mutable_function_ref( Func &&func ) noexcept + : m_data( static_cast( std::addressof( func ) ) ) + , m_thunk( obj_thunk ) {} + + template + requires( mutable_function_ref_details::different_from< + Func, mutable_function_ref> and + not std::is_const_v and + mutable_function_ref_details::class_invocable_r ) // + constexpr mutable_function_ref &operator=( Func &func ) noexcept { + m_data = static_cast( std::addressof( func ) ); + m_thunk = obj_thunk; + return *this; + } + + template + requires( + mutable_function_ref_details::different_from + and mutable_function_ref_details::class_invocable_r< + Result, Func const &, Params...> ) // + constexpr mutable_function_ref &operator=( Func const &func ) noexcept { + m_data = static_cast( std::addressof( func ) ); + m_thunk = const_obj_thunk; + return *this; + } + + constexpr mutable_function_ref( Result ( *ptr )( Params... ) ) noexcept + : m_data( ptr ) + , m_thunk( nullptr ) { + assert( ptr ); + } + + constexpr mutable_function_ref & + operator=( Result ( *ptr )( Params... ) ) noexcept { + m_data = ptr; + m_thunk = nullptr; + assert( ptr ); + return *this; + } + + constexpr Result operator( )( Params... params ) const { + if( not m_thunk ) { + return m_data.func_ptr( std::forward( params )... ); + } + return m_thunk( m_data, std::forward( params )... ); + } + }; + + template + class mutable_function_ref { + union data_t { + void *obj_ptr; + void const *const_obj_ptr; + void ( *func_ptr )( Params... ); + + constexpr data_t( void *ptr ) noexcept + : obj_ptr( ptr ) {} + + constexpr data_t( void const *ptr ) noexcept + : const_obj_ptr( ptr ) {} + + constexpr data_t( void ( *ptr )( Params... ) ) noexcept + : func_ptr( ptr ) {} + }; + + data_t m_data; + void ( *m_thunk )( data_t const &, Params... ); + + template + static DAW_CPP26_CONSTEXPR void obj_thunk( data_t const &d, + Params... params ) { + auto &obj = *static_cast( d.obj_ptr ); + (void)obj( std::forward( params )... ); + } + + template + static DAW_CPP26_CONSTEXPR void const_obj_thunk( data_t const &d, + Params... params ) { + auto const &obj = *static_cast( d.const_obj_ptr ); + (void)obj( std::forward( params )... ); + } + + static constexpr void fp_thunk( data_t const &d, Params... params ) { + d.func_ptr( params... ); + } + + public: + template + requires( mutable_function_ref_details::different_from< + Func, mutable_function_ref> and + not std::is_const_v and + mutable_function_ref_details::class_invocable_r ) // + constexpr mutable_function_ref( Func &func ) noexcept + : m_data( static_cast( std::addressof( func ) ) ) + , m_thunk( obj_thunk ) {} + + template + requires( + mutable_function_ref_details::different_from + and mutable_function_ref_details::class_invocable_r ) // + constexpr mutable_function_ref( Func const &func ) noexcept + : m_data( static_cast( std::addressof( func ) ) ) + , m_thunk( const_obj_thunk ) {} + + template + requires( not std::is_lvalue_reference_v and + mutable_function_ref_details::different_from< + Func, mutable_function_ref> and + not std::is_const_v and + mutable_function_ref_details::class_invocable_r ) // + constexpr mutable_function_ref( Func &&func ) noexcept + : m_data( static_cast( std::addressof( func ) ) ) + , m_thunk( obj_thunk ) {} + + template + requires( mutable_function_ref_details::different_from< + Func, mutable_function_ref> and + not std::is_const_v and + mutable_function_ref_details::class_invocable_r ) // + constexpr mutable_function_ref &operator=( Func &func ) noexcept { + m_data = static_cast( std::addressof( func ) ); + m_thunk = obj_thunk; + return *this; + } + + template + requires( + mutable_function_ref_details::different_from + and mutable_function_ref_details::class_invocable_r ) // + constexpr mutable_function_ref &operator=( Func const &func ) noexcept { + m_data = static_cast( std::addressof( func ) ); + m_thunk = const_obj_thunk; + return *this; + } + + constexpr mutable_function_ref( void ( *ptr )( Params... ) ) noexcept + : m_data( ptr ) + , m_thunk( fp_thunk ) { + assert( ptr ); + } + + constexpr mutable_function_ref & + operator=( void ( *ptr )( Params... ) ) noexcept { + m_data = ptr; + m_thunk = fp_thunk; + assert( ptr ); + return *this; + } + + constexpr void operator( )( Params... params ) const { + m_thunk( m_data, params... ); + } + }; +} // namespace daw diff --git a/include/daw/daw_poly_value.h b/include/daw/daw_poly_value.h index dc472a557..b02c55806 100644 --- a/include/daw/daw_poly_value.h +++ b/include/daw/daw_poly_value.h @@ -8,9 +8,8 @@ #pragma once -#include "ciso646.h" -#include "daw_enable_if.h" -#include "daw_traits.h" +#include "daw/ciso646.h" +#include "daw/daw_traits.h" #include #include diff --git a/include/daw/daw_poly_var.h b/include/daw/daw_poly_var.h index aa909d520..b0a99a6ba 100644 --- a/include/daw/daw_poly_var.h +++ b/include/daw/daw_poly_var.h @@ -8,9 +8,9 @@ #pragma once -#include "ciso646.h" -#include "daw_enable_if.h" -#include "daw_visit.h" +#include "daw/ciso646.h" +#include "daw/daw_enable_if.h" +#include "daw/daw_visit.h" #include #include diff --git a/include/daw/daw_read_file.h b/include/daw/daw_read_file.h index 2c3f73a4e..e5885746d 100644 --- a/include/daw/daw_read_file.h +++ b/include/daw/daw_read_file.h @@ -25,7 +25,7 @@ namespace daw { template DAW_ATTRIB_NOINLINE std::optional> read_file( std::string const &path ) { - auto ec = std::error_code{}; + auto ec = std::error_code{ }; auto const fsize = std::filesystem::file_size( path, ec ); if( ec ) { return std::nullopt; @@ -54,8 +54,10 @@ namespace daw { #endif auto num_read = fread( result.data( ), sizeof( CharT ), result.size( ), f ); if( num_read != ( result.size( ) / sizeof( CharT ) ) ) { + fclose( f ); return std::nullopt; } + fclose( f ); return result; } @@ -77,7 +79,7 @@ namespace daw { DAW_ATTRIB_NOINLINE inline std::optional read_wfile( std::wstring path ) { using CharT = wchar_t; - auto ec = std::error_code{}; + auto ec = std::error_code{ }; auto const fsize = std::filesystem::file_size( path, ec ); if( ec ) { return std::nullopt; diff --git a/include/daw/daw_string_view.h b/include/daw/daw_string_view.h index 36be0f1e3..fe4fea932 100644 --- a/include/daw/daw_string_view.h +++ b/include/daw/daw_string_view.h @@ -729,8 +729,7 @@ namespace daw { template DAW_REQ_CONTIG_CHAR_RANGE_REQ( StringView, CharT ) - DAW_ATTRIB_INLINE constexpr basic_string_view( - StringView &&sv DAW_LIFETIME_BOUND ) noexcept + DAW_ATTRIB_INLINE constexpr basic_string_view( StringView &&sv ) noexcept : m_first( std::data( sv ) ) , m_last( std::size( sv ) ) { if constexpr( is_zero_terminated_v> ) { @@ -749,8 +748,7 @@ namespace daw { CharT )> DAW_REQ_CONTIG_CHAR_RANGE_REQ( StringView, CharT ) DAW_ATTRIB_INLINE - constexpr basic_string_view( StringView &&sv DAW_LIFETIME_BOUND, - size_type count ) noexcept + constexpr basic_string_view( StringView &&sv, size_type count ) noexcept : m_first( std::data( sv ) ) , m_last( (std::min)( { std::size( sv ), count } ) ) { if constexpr( is_zero_terminated_v> ) { @@ -772,8 +770,7 @@ namespace daw { CharT )> DAW_REQ_CONTIG_CHAR_RANGE_REQ( StringView, CharT ) DAW_ATTRIB_INLINE - constexpr basic_string_view( StringView &&sv DAW_LIFETIME_BOUND, - size_type count, + constexpr basic_string_view( StringView &&sv, size_type count, dont_clip_to_bounds_t ) noexcept : m_first( std::data( sv ) ) , m_last( count ) { @@ -826,11 +823,14 @@ namespace daw { typename CharPtr2 DAW_REQ_CHAR_PTR( CharPtr1, CharT ) DAW_REQ_CHAR_PTR( CharPtr2, CharT )> DAW_REQ_CHAR_PTR_REQ2( CharPtr1, CharT, CharPtr2 ) - constexpr basic_string_view( CharPtr1 &&first DAW_LIFETIME_BOUND, - CharPtr2 &&last ) noexcept + constexpr basic_string_view( CharPtr1 first DAW_LIFETIME_BOUND, + CharPtr2 last ) noexcept : m_first( first ) , m_last( static_cast( std::distance( first, last ) ) ) {} + template + basic_string_view( CharT const ( & )[N], CharT const ( & )[M] ) = delete; + /// @brief Construct a zero-terminated string_view from a range formed /// by two character pointers /// @param first Start of character range @@ -842,14 +842,18 @@ namespace daw { typename CharPtr2 DAW_REQ_CHAR_PTR( CharPtr1, CharT ) DAW_REQ_CHAR_PTR( CharPtr2, CharT )> DAW_REQ_CHAR_PTR_REQ2( CharPtr1, CharT, CharPtr2 ) - constexpr basic_string_view( CharPtr1 &&first DAW_LIFETIME_BOUND, - CharPtr2 &&last, zero_terminated_t ) noexcept + constexpr basic_string_view( CharPtr1 first DAW_LIFETIME_BOUND, + CharPtr2 last, zero_terminated_t ) noexcept : m_first( first ) , m_last( static_cast( std::distance( first, last ) ) ) { m_last = set_zero_terminated( m_first, m_last ); } + template + basic_string_view( CharT const ( & )[N], CharT const ( & )[M], + zero_terminated_t ) = delete; + //****************************** // Conversions //****************************** @@ -859,8 +863,7 @@ namespace daw { template DAW_REQ_CONTIG_CHAR_RANGE_CTOR_REQ( T ) explicit constexpr operator T( ) const - noexcept( std::is_nothrow_constructible_v ) - DAW_LIFETIME_BOUND { + noexcept( std::is_nothrow_constructible_v ) { return T{ data( ), size( ) }; } @@ -870,14 +873,13 @@ namespace daw { /// @brief Returns an iterator to the first character of the view. /// @return const_iterator to the first character - [[nodiscard]] constexpr const_iterator begin( ) const DAW_LIFETIME_BOUND { + [[nodiscard]] constexpr const_iterator begin( ) const { return m_first; } /// @brief Returns an iterator to the first character of the view. /// @return const_iterator to the first character - [[nodiscard]] constexpr const_iterator - cbegin( ) const DAW_LIFETIME_BOUND { + [[nodiscard]] constexpr const_iterator cbegin( ) const { return m_first; } @@ -885,8 +887,7 @@ namespace daw { /// reversed view. It corresponds to the last character of the /// non-reversed view. /// @return const_reverse_iterator to the first character - [[nodiscard]] constexpr reverse_iterator - rbegin( ) const DAW_LIFETIME_BOUND { + [[nodiscard]] constexpr reverse_iterator rbegin( ) const { return const_reverse_iterator( end( ) ); } @@ -894,8 +895,7 @@ namespace daw { /// reversed view. It corresponds to the last character of the /// non-reversed view. /// @return const_reverse_iterator to the first character - [[nodiscard]] constexpr const_reverse_iterator - crbegin( ) const DAW_LIFETIME_BOUND { + [[nodiscard]] constexpr const_reverse_iterator crbegin( ) const { return const_reverse_iterator( cend( ) ); } @@ -904,7 +904,7 @@ namespace daw { /// attempting to access it results in undefined behavior /// @return const_iterator to the character following the last /// character. - [[nodiscard]] constexpr const_iterator end( ) const DAW_LIFETIME_BOUND { + [[nodiscard]] constexpr const_iterator end( ) const { return last_pointer( ); } @@ -913,7 +913,7 @@ namespace daw { /// attempting to access it results in undefined behavior /// @return const_iterator to the character following the last /// character. - [[nodiscard]] constexpr const_iterator cend( ) const DAW_LIFETIME_BOUND { + [[nodiscard]] constexpr const_iterator cend( ) const { return last_pointer( ); } @@ -924,8 +924,7 @@ namespace daw { /// undefined behavior. /// @return const_reverse_iterator to the character following the last /// character. - [[nodiscard]] constexpr reverse_iterator - rend( ) const DAW_LIFETIME_BOUND { + [[nodiscard]] constexpr reverse_iterator rend( ) const { return const_reverse_iterator( begin( ) ); } @@ -936,8 +935,7 @@ namespace daw { /// undefined behavior. /// @return const_reverse_iterator to the character following the last /// character. - [[nodiscard]] constexpr const_reverse_iterator - crend( ) const DAW_LIFETIME_BOUND { + [[nodiscard]] constexpr const_reverse_iterator crend( ) const { return const_reverse_iterator( cbegin( ) ); } @@ -993,7 +991,7 @@ namespace daw { /// @pre data( ) != nullptr /// @return data( )[pos] [[nodiscard]] DAW_ATTRIB_INLINE constexpr const_reference - operator[]( size_type pos ) const DAW_LIFETIME_BOUND { + operator[]( size_type pos ) const { DAW_STRING_VIEW_DBG_RNG_CHECK( pos < size( ), "Attempt to access basic_string_view past end" ); @@ -1004,8 +1002,7 @@ namespace daw { /// @param pos Position in range /// @throws std::out_of_range when pos >= size( ) /// @return data( )[pos] - [[nodiscard]] constexpr const_reference - at( size_type pos ) const DAW_LIFETIME_BOUND { + [[nodiscard]] constexpr const_reference at( size_type pos ) const { if( DAW_UNLIKELY( not( pos < size( ) ) ) ) { DAW_THROW_OR_TERMINATE( std::out_of_range, "Attempt to access basic_string_view past end" ); @@ -1145,8 +1142,7 @@ namespace daw { /// current data( ) pointer values. /// @param count number of characters to increment data( ) by /// @return a new string_view of size count. - [[nodiscard]] constexpr basic_string_view - pop_front( size_type count ) DAW_LIFETIME_BOUND { + [[nodiscard]] constexpr basic_string_view pop_front( size_type count ) { basic_string_view result = substr( 0, count ); remove_prefix( count ); return result; @@ -1158,7 +1154,7 @@ namespace daw { /// @param count number of characters to increment data( ) by /// @return a new string_view of size count. [[nodiscard]] constexpr basic_string_view - pop_front_unsafe( size_type count ) DAW_LIFETIME_BOUND { + pop_front_unsafe( size_type count ) { DAW_STRING_VIEW_DBG_RNG_CHECK( size( ) >= count, "Attempt to pop front too many elements basic_string_view" ); @@ -1175,8 +1171,7 @@ namespace daw { /// position up to the position of the leading character in where. If /// where is not found, a copy of the string_view is made [[nodiscard]] constexpr basic_string_view - pop_front_until( basic_string_view where, - nodiscard_t ) DAW_LIFETIME_BOUND { + pop_front_until( basic_string_view where, nodiscard_t ) { auto pos = find( where ); auto result = pop_front( pos ); return result; @@ -1186,8 +1181,8 @@ namespace daw { /// where, then pops off the substring /// @param where string to split on and remove from front /// @return substring from beginning to where string - [[nodiscard]] constexpr basic_string_view - pop_front_until( CharT where, nodiscard_t ) DAW_LIFETIME_BOUND { + [[nodiscard]] constexpr basic_string_view pop_front_until( CharT where, + nodiscard_t ) { auto pos = find( where ); auto result = pop_front( pos ); return result; @@ -1197,8 +1192,7 @@ namespace daw { /// between front and where not, then pops off the substring /// @param where The pattern to extract /// @return substring from beginning to first non-match of where string - [[nodiscard]] constexpr basic_string_view - pop_front_while( CharT where ) DAW_LIFETIME_BOUND { + [[nodiscard]] constexpr basic_string_view pop_front_while( CharT where ) { auto pos = find_first_not_of( where ); auto result = pop_front( pos ); return result; @@ -1209,7 +1203,7 @@ namespace daw { /// @param where The pattern to extract /// @return substring from beginning to first non-match of where string [[nodiscard]] constexpr basic_string_view - pop_front_while( basic_string_view where ) DAW_LIFETIME_BOUND { + pop_front_while( basic_string_view where ) { auto pos = find_first_not_of( where ); auto result = pop_front( pos ); return result; @@ -1220,7 +1214,7 @@ namespace daw { /// @param where string to split on and remove from front /// @return substring from beginning to where string [[nodiscard]] constexpr basic_string_view - pop_front_until( basic_string_view where ) DAW_LIFETIME_BOUND { + pop_front_until( basic_string_view where ) { auto pos = find( where ); auto result = pop_front( pos ); remove_prefix( where.size( ) ); @@ -1231,8 +1225,7 @@ namespace daw { /// where, then pops off the substring and the where string /// @param where string to split on and remove from front /// @return substring from beginning to where string - [[nodiscard]] constexpr basic_string_view - pop_front_until( CharT where ) DAW_LIFETIME_BOUND { + [[nodiscard]] constexpr basic_string_view pop_front_until( CharT where ) { auto pos = find( where ); auto result = pop_front( pos ); remove_prefix( ); @@ -1254,7 +1247,7 @@ namespace daw { CharT )> DAW_REQ_UNARY_PRED_REQ( UnaryPredicate, CharT ) [[nodiscard]] constexpr basic_string_view - pop_front_until( UnaryPredicate pred, nodiscard_t ) DAW_LIFETIME_BOUND { + pop_front_until( UnaryPredicate pred, nodiscard_t ) { auto pos = find_first_of_if( std::move( pred ) ); return pop_front( pos ); } @@ -1328,8 +1321,7 @@ namespace daw { /// them from end /// @param count number of characters to remove and return /// @return a substr of size count ending at end of string_view - [[nodiscard]] constexpr basic_string_view - pop_back( size_type count ) DAW_LIFETIME_BOUND { + [[nodiscard]] constexpr basic_string_view pop_back( size_type count ) { count = (std::min)( { count, size( ) } ); basic_string_view result = substr( size( ) - count, npos ); remove_suffix( count ); @@ -1356,8 +1348,7 @@ namespace daw { /// @param where string to split on and remove from back /// @return substring from end of where string to end of string [[nodiscard]] constexpr basic_string_view - pop_back_until( basic_string_view where, - nodiscard_t ) DAW_LIFETIME_BOUND { + pop_back_until( basic_string_view where, nodiscard_t ) { auto pos = rfind( where ); if( pos == npos ) { auto result{ *this }; @@ -1373,8 +1364,8 @@ namespace daw { /// where and end, then pops off the substring /// @param where string to split on and remove from back /// @return substring from end of where string to end of string - [[nodiscard]] constexpr basic_string_view - pop_back_until( CharT where, nodiscard_t ) DAW_LIFETIME_BOUND { + [[nodiscard]] constexpr basic_string_view pop_back_until( CharT where, + nodiscard_t ) { auto pos = rfind( where ); if( pos == npos ) { auto result{ *this }; @@ -1392,7 +1383,7 @@ namespace daw { /// @param where string to split on and remove from back /// @return substring from end of where string to end of string [[nodiscard]] constexpr basic_string_view - pop_back_until( basic_string_view where ) DAW_LIFETIME_BOUND { + pop_back_until( basic_string_view where ) { auto pos = rfind( where ); if( pos == npos ) { auto result{ *this }; @@ -1409,8 +1400,7 @@ namespace daw { /// string /// @param where CharT to split string on and remove from back /// @return substring from end of where string to end of string - [[nodiscard]] constexpr basic_string_view - pop_back_until( CharT where ) DAW_LIFETIME_BOUND { + [[nodiscard]] constexpr basic_string_view pop_back_until( CharT where ) { auto pos = rfind( where ); if( pos == npos ) { auto result{ *this }; @@ -1434,7 +1424,7 @@ namespace daw { CharT )> DAW_REQ_UNARY_PRED_REQ( UnaryPredicate, CharT ) [[nodiscard]] constexpr basic_string_view - pop_back_until( UnaryPredicate pred ) DAW_LIFETIME_BOUND { + pop_back_until( UnaryPredicate pred ) { auto pos = find_last_of_if( std::move( pred ) ); if( pos == npos ) { auto result = *this; @@ -1459,7 +1449,7 @@ namespace daw { CharT )> DAW_REQ_UNARY_PRED_REQ( UnaryPredicate, CharT ) [[nodiscard]] constexpr basic_string_view - pop_back_until( UnaryPredicate pred, nodiscard_t ) DAW_LIFETIME_BOUND { + pop_back_until( UnaryPredicate pred, nodiscard_t ) { auto pos = find_last_of_if( std::move( pred ) ); if( pos == npos ) { auto result = *this; @@ -1477,7 +1467,7 @@ namespace daw { /// @param where string to split on and remove from front /// @return substring from beginning to where string [[nodiscard]] constexpr basic_string_view - try_pop_front_until( basic_string_view where ) DAW_LIFETIME_BOUND { + try_pop_front_until( basic_string_view where ) { auto pos = find( where ); if( pos == npos ) { return basic_string_view( ); @@ -1496,8 +1486,7 @@ namespace daw { /// position up to the position of the leading character in where. If /// where is not found, a copy of the string_view is made [[nodiscard]] constexpr basic_string_view - try_pop_front_until( basic_string_view where, - nodiscard_t ) DAW_LIFETIME_BOUND { + try_pop_front_until( basic_string_view where, nodiscard_t ) { auto pos = find( where ); if( pos == npos ) { return basic_string_view( ); @@ -1512,7 +1501,7 @@ namespace daw { /// @param where string to split on and remove from front /// @return substring from beginning to where string [[nodiscard]] constexpr basic_string_view - try_pop_front_until( CharT where, nodiscard_t ) DAW_LIFETIME_BOUND { + try_pop_front_until( CharT where, nodiscard_t ) { auto pos = find( where ); if( pos == npos ) { return basic_string_view( ); @@ -1527,7 +1516,7 @@ namespace daw { /// @param where string to split on and remove from front /// @return substring from beginning to where string [[nodiscard]] constexpr basic_string_view - try_pop_front_until( CharT where ) DAW_LIFETIME_BOUND { + try_pop_front_until( CharT where ) { auto pos = find( where ); if( pos == npos ) { return basic_string_view( ); @@ -1553,8 +1542,7 @@ namespace daw { CharT )> DAW_REQ_UNARY_PRED_REQ( UnaryPredicate, CharT ) [[nodiscard]] constexpr basic_string_view - try_pop_front_until( UnaryPredicate pred, - nodiscard_t ) DAW_LIFETIME_BOUND { + try_pop_front_until( UnaryPredicate pred, nodiscard_t ) { auto pos = find_first_of_if( std::move( pred ) ); if( pos == npos ) { return basic_string_view( ); @@ -1578,7 +1566,7 @@ namespace daw { CharT )> DAW_REQ_UNARY_PRED_REQ( UnaryPredicate, CharT ) [[nodiscard]] constexpr basic_string_view - try_pop_front_until( UnaryPredicate pred ) DAW_LIFETIME_BOUND { + try_pop_front_until( UnaryPredicate pred ) { auto result = try_pop_front_until( pred, nodiscard ); remove_prefix( sv2_details::find_predicate_result_size( pred ) ); return result; @@ -1591,7 +1579,7 @@ namespace daw { /// @param where string to split on and remove from back /// @return substring from end of where string to end of string [[nodiscard]] constexpr basic_string_view - try_pop_back_until( basic_string_view where ) DAW_LIFETIME_BOUND { + try_pop_back_until( basic_string_view where ) { auto pos = rfind( where ); if( pos == npos ) { return basic_string_view( ); @@ -1607,8 +1595,7 @@ namespace daw { /// @param where string to split on and remove from back /// @return substring from end of where string to end of string [[nodiscard]] constexpr basic_string_view - try_pop_back_until( basic_string_view where, - nodiscard_t ) DAW_LIFETIME_BOUND { + try_pop_back_until( basic_string_view where, nodiscard_t ) { auto pos = rfind( where ); if( pos == npos ) { return basic_string_view( ); @@ -1624,7 +1611,7 @@ namespace daw { /// @param where string to split on and remove from back /// @return substring from end of where string to end of string [[nodiscard]] constexpr basic_string_view - try_pop_back_until( CharT where, nodiscard_t ) DAW_LIFETIME_BOUND { + try_pop_back_until( CharT where, nodiscard_t ) { auto pos = rfind( where ); if( pos == npos ) { return basic_string_view( ); @@ -1640,7 +1627,7 @@ namespace daw { /// @param where CharT to split string on and remove from back /// @return substring from end of where string to end of string [[nodiscard]] constexpr basic_string_view - try_pop_back_until( CharT where ) DAW_LIFETIME_BOUND { + try_pop_back_until( CharT where ) { auto pos = rfind( where ); if( pos == npos ) { return basic_string_view( ); @@ -1663,7 +1650,7 @@ namespace daw { CharT )> DAW_REQ_UNARY_PRED_REQ( UnaryPredicate, CharT ) [[nodiscard]] constexpr basic_string_view - try_pop_back_until( UnaryPredicate pred ) DAW_LIFETIME_BOUND { + try_pop_back_until( UnaryPredicate pred ) { auto pos = find_last_of_if( std::move( pred ) ); if( pos == npos ) { return basic_string_view( ); @@ -1685,8 +1672,7 @@ namespace daw { CharT )> DAW_REQ_UNARY_PRED_REQ( UnaryPredicate, CharT ) [[nodiscard]] constexpr basic_string_view - try_pop_back_until( UnaryPredicate pred, - nodiscard_t ) DAW_LIFETIME_BOUND { + try_pop_back_until( UnaryPredicate pred, nodiscard_t ) { auto pos = find_last_of_if( std::move( pred ) ); if( pos == npos ) { return basic_string_view( ); @@ -1821,12 +1807,12 @@ namespace daw { /// @pre pos <= size( ) /// @returns a new basic_string_view of the sub-range [[nodiscard]] constexpr basic_string_view - substr( size_type pos, size_type count ) const DAW_LIFETIME_BOUND { + substr( size_type pos, size_type count ) const { DAW_STRING_VIEW_DBG_RNG_CHECK( pos <= size( ), "Attempt to access basic_string_view past end" ); auto const rcount = static_cast( (std::min)( { count, size( ) - pos } ) ); - return basic_string_view( m_first + pos, m_first + pos + rcount ); + return basic_string_view( m_first + pos, rcount ); } /// @brief Create a new sub-range basic_string_view [data( ) + pos, @@ -1836,7 +1822,7 @@ namespace daw { /// @returns a new basic_string_view of the sub-range /// @pre pos + count <= size( ) [[nodiscard]] constexpr basic_string_view - substr_unsafe( size_type pos, size_type count ) const DAW_LIFETIME_BOUND { + substr_unsafe( size_type pos, size_type count ) const { DAW_STRING_VIEW_DBG_RNG_CHECK( pos + count <= size( ), "Attempt to access basic_string_view past end" ); @@ -1849,8 +1835,7 @@ namespace daw { } /// @brief Return a copy of the string_view - [[nodiscard]] constexpr basic_string_view - substr( ) const DAW_LIFETIME_BOUND { + [[nodiscard]] constexpr basic_string_view substr( ) const { return substr_unsafe( 0, size( ) ); } @@ -1860,8 +1845,7 @@ namespace daw { /// @param pos Starting position /// @returns a new basic_string_view of the sub-range /// @pre pos <= size( ) - [[nodiscard]] constexpr basic_string_view - substr( size_type pos ) const DAW_LIFETIME_BOUND { + [[nodiscard]] constexpr basic_string_view substr( size_type pos ) const { return substr( pos, npos ); } @@ -1872,7 +1856,7 @@ namespace daw { /// @returns a new basic_string_view of the sub-range /// @pre pos <= size( ) [[nodiscard]] constexpr basic_string_view - substr_unsafe( size_type pos ) const DAW_LIFETIME_BOUND { + substr_unsafe( size_type pos ) const { DAW_STRING_VIEW_DBG_RNG_CHECK( pos <= size( ), "Attempt to access basic_string_view past end" ); return substr_unsafe( pos, size( ) - pos ); @@ -2740,7 +2724,7 @@ namespace daw { } [[nodiscard]] constexpr basic_string_view - trim_prefix_copy( ) const noexcept DAW_LIFETIME_BOUND { + trim_prefix_copy( ) const noexcept { auto result = *this; result.remove_prefix_while( is_space{ } ); return result; @@ -2768,7 +2752,7 @@ namespace daw { } [[nodiscard]] constexpr basic_string_view - trim_suffix_copy( ) const noexcept DAW_LIFETIME_BOUND { + trim_suffix_copy( ) const noexcept { auto result = *this; result = remove_suffix_while( is_space{ } ); return result; @@ -2779,8 +2763,7 @@ namespace daw { return trim_suffix( ); } - [[nodiscard]] constexpr basic_string_view - trim_copy( ) const noexcept DAW_LIFETIME_BOUND { + [[nodiscard]] constexpr basic_string_view trim_copy( ) const noexcept { auto result = trim_prefix_copy( ); result.trim_suffix( ); return result; @@ -2962,4 +2945,4 @@ namespace std { #undef DAW_REQ_CONTIG_CHAR_RANGE_REQ #undef DAW_REQ_CONTIG_CHAR_RANGE_CTOR #undef DAW_REQ_CONTIG_CHAR_RANGE_CTOR_REQ -DAW_UNSAFE_BUFFER_FUNC_STOP \ No newline at end of file +DAW_UNSAFE_BUFFER_FUNC_STOP diff --git a/include/daw/iterator/daw_circular_iterator.h b/include/daw/iterator/daw_circular_iterator.h index f4152e583..98d8991b1 100644 --- a/include/daw/iterator/daw_circular_iterator.h +++ b/include/daw/iterator/daw_circular_iterator.h @@ -22,9 +22,8 @@ namespace daw { namespace impl { DAW_MAKE_REQ_TRAIT( has_size_member_v, std::declval( ).size( ) ); - template< - typename Container, - std::enable_if_t, std::nullptr_t> = nullptr> + template, + std::nullptr_t> = nullptr> constexpr std::size_t container_size( Container &c ) { return c.size( ); } @@ -42,10 +41,17 @@ namespace daw { struct circular_iterator { using iterator = decltype( std::begin( std::declval( ) ) ); using difference_type = std::ptrdiff_t; - using pointer = void; + using pointer = typename std::iterator_traits::pointer; + using const_pointer = + std::conditional_t, + std::remove_pointer_t const *, pointer>; using value_type = typename std::iterator_traits::value_type; using iterator_category = std::random_access_iterator_tag; using reference = typename std::iterator_traits::reference; + using const_reference = std::conditional_t< + std::is_reference_v, + daw::traits::copy_ref_t, reference>, + reference>; private: static_assert( @@ -77,7 +83,7 @@ namespace daw { } public: - constexpr circular_iterator( ) noexcept + explicit constexpr circular_iterator( ) noexcept : m_container{ nullptr } , m_position{ 0 } {} @@ -122,7 +128,7 @@ namespace daw { return *this; } - ~circular_iterator( ) noexcept = default; + ~circular_iterator( ) = default; constexpr circular_iterator &operator+=( difference_type n ) noexcept { m_position = get_offset( n ); @@ -134,14 +140,30 @@ namespace daw { return *this; } - constexpr decltype( auto ) operator*( ) { + constexpr reference operator*( ) { return *get_iterator( m_position ); } - constexpr decltype( auto ) operator->( ) noexcept { + constexpr const_reference operator*( ) const { return *get_iterator( m_position ); } + constexpr reference operator[]( std::size_t idx ) { + return *get_iterator( get_offset( idx ) ); + } + + constexpr const_reference operator[]( std::size_t idx ) const { + return *get_iterator( get_offset( idx ) ); + } + + constexpr pointer operator->( ) noexcept { + return std::addressof( *get_iterator( m_position ) ); + } + + constexpr const_pointer operator->( ) const noexcept { + return std::addressof( *get_iterator( m_position ) ); + } + constexpr circular_iterator &operator++( ) noexcept { m_position = get_offset( 1 ); return *this; @@ -164,16 +186,28 @@ namespace daw { return result; } - constexpr circular_iterator operator+( difference_type n ) noexcept { - circular_iterator tmp{ *this }; - tmp += n; - return tmp; + friend constexpr circular_iterator operator+( circular_iterator lhs, + difference_type n ) noexcept { + lhs += n; + return lhs; } - constexpr circular_iterator operator-( difference_type n ) noexcept { - circular_iterator tmp{ *this }; - tmp -= n; - return tmp; + friend constexpr circular_iterator + operator+( difference_type n, circular_iterator rhs ) noexcept { + rhs += n; + return rhs; + } + + friend constexpr circular_iterator operator-( circular_iterator lhs, + difference_type n ) noexcept { + lhs -= n; + return lhs; + } + + friend constexpr circular_iterator + operator-( difference_type n, circular_iterator rhs ) noexcept { + rhs -= n; + return rhs; } constexpr circular_iterator end( ) noexcept { @@ -182,6 +216,7 @@ namespace daw { static_cast( impl::container_size( *m_container ) ); return tmp; } + constexpr friend bool operator==( circular_iterator const &lhs, circular_iterator const &rhs ) noexcept { return lhs.m_position == rhs.m_position && diff --git a/include/daw/iterator/daw_random_iterator.h b/include/daw/iterator/daw_random_iterator.h index 088e587ce..fb56b4880 100644 --- a/include/daw/iterator/daw_random_iterator.h +++ b/include/daw/iterator/daw_random_iterator.h @@ -10,6 +10,7 @@ #include "daw/ciso646.h" +#include #include namespace daw { @@ -20,13 +21,12 @@ namespace daw { using pointer = value_type *; using iterator_category = std::random_access_iterator_tag; using reference = value_type &; - using const_reference = value_type const &; private: pointer m_pointer = nullptr; public: - RandomIterator( ) = default; + explicit RandomIterator( ) = default; explicit constexpr RandomIterator( T *ptr ) noexcept : m_pointer{ ptr } {} @@ -36,6 +36,10 @@ namespace daw { return *this; } + [[nodiscard]] constexpr pointer ptr( ) noexcept { + return m_pointer; + } + [[nodiscard]] constexpr pointer ptr( ) const noexcept { return m_pointer; } @@ -50,12 +54,12 @@ namespace daw { return *this; } - [[nodiscard]] constexpr reference operator*( ) { + [[nodiscard]] constexpr reference operator*( ) const { return *m_pointer; } - [[nodiscard]] constexpr const_reference operator*( ) const { - return *m_pointer; + [[nodiscard]] constexpr reference operator[]( std::size_t idx ) const { + return *std::next( m_pointer, static_cast( idx ) ); } [[nodiscard]] constexpr pointer operator->( ) const noexcept { @@ -84,20 +88,28 @@ namespace daw { return result; } - constexpr RandomIterator operator+( std::ptrdiff_t const &n ) noexcept { - auto old = this->m_pointer; - this->m_pointer += n; - auto temp{ *this }; - this->m_pointer = old; - return temp; + friend constexpr RandomIterator operator+( RandomIterator lhs, + std::ptrdiff_t n ) noexcept { + lhs += n; + return lhs; + } + + friend constexpr RandomIterator operator+( std::ptrdiff_t n, + RandomIterator rhs ) noexcept { + rhs += n; + return rhs; } - constexpr RandomIterator operator-( std::ptrdiff_t const &n ) noexcept { - auto old = this->m_pointer; - this->m_pointer -= n; - auto temp{ *this }; - this->m_pointer = old; - return temp; + friend constexpr RandomIterator operator-( RandomIterator lhs, + std::ptrdiff_t n ) noexcept { + lhs += n; + return lhs; + } + + friend constexpr RandomIterator operator-( std::ptrdiff_t n, + RandomIterator rhs ) noexcept { + rhs -= n; + return rhs; } constexpr friend bool operator==( RandomIterator const &lhs, @@ -137,12 +149,19 @@ namespace daw { }; // RandomIterator template - [[nodiscard]] constexpr auto make_random_iterator( T *const ptr ) noexcept { + [[nodiscard]] constexpr RandomIterator + make_random_iterator( T *ptr ) noexcept { return RandomIterator{ ptr }; } template - [[nodiscard]] constexpr auto + [[nodiscard]] constexpr RandomIterator + make_random_iterator( T const *ptr ) noexcept { + return RandomIterator{ ptr }; + } + + template + [[nodiscard]] constexpr RandomIterator make_const_random_iterator( T *const ptr ) noexcept { return RandomIterator{ ptr }; } diff --git a/include/daw/iterator/daw_repeat_n_char_iterator.h b/include/daw/iterator/daw_repeat_n_char_iterator.h index 95db6fd11..9e0c42605 100644 --- a/include/daw/iterator/daw_repeat_n_char_iterator.h +++ b/include/daw/iterator/daw_repeat_n_char_iterator.h @@ -9,6 +9,7 @@ #pragma once #include "daw/ciso646.h" +#include "daw/daw_ensure.h" #include #include @@ -71,33 +72,76 @@ namespace daw { return m_position == rhs.m_position; } - constexpr repeat_n_char_iterator const &operator+=( ptrdiff_t p ) noexcept { + constexpr repeat_n_char_iterator &operator+=( ptrdiff_t p ) noexcept { m_position += p; return *this; } - constexpr repeat_n_char_iterator const &operator-=( ptrdiff_t p ) noexcept { + constexpr repeat_n_char_iterator &operator-=( ptrdiff_t p ) noexcept { m_position -= p; return *this; } - constexpr repeat_n_char_iterator operator+( ptrdiff_t p ) const noexcept { - auto tmp = *this; - tmp += p; - return tmp; + friend constexpr repeat_n_char_iterator + operator+( repeat_n_char_iterator lhs, ptrdiff_t p ) noexcept { + lhs += p; + return lhs; } - constexpr repeat_n_char_iterator operator-( ptrdiff_t p ) const noexcept { - auto tmp = *this; - tmp -= p; - return tmp; + friend constexpr repeat_n_char_iterator + operator+( ptrdiff_t p, repeat_n_char_iterator rhs ) noexcept { + rhs += p; + return rhs; + } + + friend constexpr repeat_n_char_iterator + operator-( repeat_n_char_iterator lhs, ptrdiff_t p ) noexcept { + lhs -= p; + return lhs; + } + + friend constexpr repeat_n_char_iterator + operator-( ptrdiff_t p, repeat_n_char_iterator rhs ) noexcept { + rhs -= p; + return rhs; + } + + constexpr difference_type + operator-( repeat_n_char_iterator rhs ) const noexcept { + return m_position - rhs.m_position; + } + + constexpr bool + operator==( repeat_n_char_iterator const &rhs ) const noexcept { + return m_position == rhs.m_position; + } + + constexpr bool + operator!=( repeat_n_char_iterator const &rhs ) const noexcept { + return m_position != rhs.m_position; + } + + constexpr bool + operator<( repeat_n_char_iterator const &rhs ) const noexcept { + return m_position < rhs.m_position; } - constexpr ptrdiff_t - operator-( repeat_n_char_iterator const &rhs ) const noexcept { - return rhs.m_position - m_position; + constexpr bool + operator>( repeat_n_char_iterator const &rhs ) const noexcept { + return m_position > rhs.m_position; + } + + constexpr bool + operator<=( repeat_n_char_iterator const &rhs ) const noexcept { + return m_position <= rhs.m_position; + } + + constexpr bool + operator>=( repeat_n_char_iterator const &rhs ) const noexcept { + return m_position >= rhs.m_position; } }; + template repeat_n_char_iterator( size_t, CharT ) -> repeat_n_char_iterator; diff --git a/include/daw/pipelines/enumerate.h b/include/daw/pipelines/enumerate.h index 2279da1c3..c168cff20 100644 --- a/include/daw/pipelines/enumerate.h +++ b/include/daw/pipelines/enumerate.h @@ -23,7 +23,7 @@ namespace daw::pipelines::pimpl { template [[nodiscard]] DAW_CPP23_STATIC_CALL_OP constexpr auto operator( )( R &&r ) DAW_CPP23_STATIC_CALL_OP_CONST { - return zip_view, daw::remove_cvref_t>( + return zip_view, std::remove_reference_t>( iota_view( 0, max_value ), DAW_FWD( r ) ); } }; diff --git a/include/daw/pipelines/filter.h b/include/daw/pipelines/filter.h index f8ead4c12..4cf60c588 100644 --- a/include/daw/pipelines/filter.h +++ b/include/daw/pipelines/filter.h @@ -125,6 +125,13 @@ namespace daw::pipelines { operator!=( filter_view const &lhs, filter_view const &rhs ) { return lhs.m_first != rhs.m_first; } + + // clang-format off + [[nodiscard]] DAW_ATTRIB_INLINE constexpr friend auto + operator<=>( filter_view const &lhs, filter_view const &rhs ) { + return lhs.m_first <=> rhs.m_first; + } + // clang-format on }; template @@ -147,8 +154,8 @@ namespace daw::pipelines { static_assert( std::convertible_to, bool>, "Filter requires an invokable function that returns a bool" ); - return filter_view, Fn>( std::begin( r ), std::end( r ), - m_func, m_projection ); + return filter_view, Fn>( + std::begin( r ), std::end( r ), m_func, m_projection ); } template diff --git a/include/daw/pipelines/iota.h b/include/daw/pipelines/iota.h index 6183f0f62..627552839 100644 --- a/include/daw/pipelines/iota.h +++ b/include/daw/pipelines/iota.h @@ -24,8 +24,8 @@ namespace daw::pipelines { struct iota_iterator { using iterator_category = std::random_access_iterator_tag; using value_type = T; - using reference = value_type; - using const_reference = value_type; + using reference = value_type &; + using const_reference = value_type const &; using pointer = daw::arrow_proxy; using const_pointer = daw::arrow_proxy; using difference_type = std::ptrdiff_t; @@ -83,18 +83,28 @@ namespace daw::pipelines { return *this; } - [[nodiscard]] constexpr iota_iterator - operator+( difference_type n ) const noexcept { - iota_iterator result = *this; - result.value += n; - return result; + [[nodiscard]] constexpr friend iota_iterator + operator+( iota_iterator lhs, difference_type n ) noexcept { + lhs += n; + return lhs; } - [[nodiscard]] constexpr iota_iterator - operator-( difference_type n ) const noexcept { - iota_iterator result = *this; - result.value -= n; - return result; + [[nodiscard]] constexpr friend iota_iterator + operator+( difference_type n, iota_iterator rhs ) noexcept { + rhs += n; + return rhs; + } + + [[nodiscard]] constexpr friend iota_iterator + operator-( iota_iterator lhs, difference_type n ) noexcept { + lhs -= n; + return lhs; + } + + [[nodiscard]] constexpr friend iota_iterator + operator-( difference_type n, iota_iterator rhs ) noexcept { + rhs -= n; + return rhs; } [[nodiscard]] constexpr difference_type @@ -102,11 +112,7 @@ namespace daw::pipelines { return static_cast( value - i.value ); } - [[nodiscard]] constexpr reference operator[]( size_type n ) noexcept { - return *( value + static_cast( n ) ); - } - - [[nodiscard]] constexpr const_reference + [[nodiscard]] constexpr value_type operator[]( size_type n ) const noexcept { return *( value + static_cast( n ) ); } @@ -121,25 +127,12 @@ namespace daw::pipelines { return lhs.value != rhs.value; } - [[nodiscard]] friend constexpr bool operator<( iota_iterator const &lhs, - iota_iterator const &rhs ) { - return lhs.value < rhs.value; - } - - [[nodiscard]] friend constexpr bool operator<=( iota_iterator const &lhs, - iota_iterator const &rhs ) { - return lhs.value <= rhs.value; - } - - [[nodiscard]] friend constexpr bool operator>( iota_iterator const &lhs, - iota_iterator const &rhs ) { - return lhs.value > rhs.value; - } - - [[nodiscard]] friend constexpr bool operator>=( iota_iterator const &lhs, - iota_iterator const &rhs ) { - return lhs.value >= rhs.value; + // clang-format off + [[nodiscard]] friend constexpr auto operator<=> + ( iota_iterator const &lhs, iota_iterator const &rhs ) { + return lhs.value <=> rhs.value; } + // clang-format on }; template @@ -177,6 +170,6 @@ namespace daw::pipelines { iota_view( T, T ) -> iota_view; inline constexpr auto ToIota = []( I last ) { - return iota_view{ I{}, last }; + return iota_view{ I{ }, last }; }; } // namespace daw::pipelines diff --git a/include/daw/pipelines/map.h b/include/daw/pipelines/map.h index e46a6008b..614a3f378 100644 --- a/include/daw/pipelines/map.h +++ b/include/daw/pipelines/map.h @@ -10,6 +10,7 @@ #include "daw/daw_iterator_traits.h" #include "daw/daw_move.h" +#include "daw/daw_mutable_function_ref.h" #include "daw/daw_tuple_forward.h" #include "daw/daw_typeof.h" #include "daw/iterator/daw_arrow_proxy.h" @@ -19,36 +20,68 @@ #include #include #include +#include #include #include +namespace daw::pipelines::pimpl { + template + consteval bool is_const_fn_same_v( ) { + if constexpr( std::is_invocable_v ) { + using fn_result_t = std::remove_reference_t< + std::remove_const_t>>; + using fn_c_result_t = std::remove_reference_t< + std::remove_const_t>>; + return std::is_convertible_v; + } else { + return true; + } + } +} // namespace daw::pipelines::pimpl + namespace daw::pipelines { template struct map_iterator { using iterator_category = daw::iter_category_t; - using value_type = daw::remove_cvref_t>>>; - using reference = value_type; - using const_reference = value_type; + + private: + using iter_ref_t = + daw::remove_rvalue_ref_t>; + static_assert( + std::is_same_v> ); + using proj_result_t = + daw::remove_rvalue_ref_t>; + static_assert( pimpl::is_const_fn_same_v( ), + "Expect similar results for const/non-const Projection" ); + using func_result_t = + daw::remove_rvalue_ref_t>; + static_assert( pimpl::is_const_fn_same_v( ), + "Expect similar results for const/non-const Fn" ); + + public: + using reference = func_result_t; + using value_type = std::remove_cvref_t; + using const_reference = reference; using pointer = arrow_proxy; using difference_type = std::ptrdiff_t; using size_type = std::size_t; private: Iterator m_iter{ }; - DAW_NO_UNIQUE_ADDRESS Fn m_func = Fn{ }; - DAW_NO_UNIQUE_ADDRESS Projection m_projection = Projection{ }; + DAW_NO_UNIQUE_ADDRESS daw::remove_rvalue_ref_t m_func{ }; + DAW_NO_UNIQUE_ADDRESS daw::remove_rvalue_ref_t m_projection{ }; public: - explicit constexpr map_iterator( ) = default; + explicit map_iterator( ) = default; + explicit constexpr map_iterator( Iterator it, Fn f ) : m_iter( it ) - , m_func( f ) {} + , m_func( std::forward( f ) ) {} explicit constexpr map_iterator( Iterator it, Fn f, Projection projection ) : m_iter( it ) - , m_func( f ) - , m_projection( projection ) {} + , m_func( std::forward( f ) ) + , m_projection( std::forward( projection ) ) {} private: [[nodiscard]] DAW_ATTRIB_INLINE constexpr decltype( auto ) @@ -61,6 +94,26 @@ namespace daw::pipelines { return *( m_iter + static_cast( n ) ); } + [[nodiscard]] DAW_ATTRIB_INLINE constexpr decltype( auto ) + do_project( auto &&v ) { + return std::invoke( m_projection, DAW_FWD( v ) ); + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr decltype( auto ) + do_project( auto &&v ) const { + return std::invoke( m_projection, DAW_FWD( v ) ); + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr decltype( auto ) + do_func( auto &&v ) { + return std::invoke( m_func, do_project( DAW_FWD( v ) ) ); + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr decltype( auto ) + do_func( auto &&v ) const { + return std::invoke( m_func, do_project( DAW_FWD( v ) ) ); + } + public: [[nodiscard]] constexpr auto &base( ) { return m_iter; @@ -72,23 +125,23 @@ namespace daw::pipelines { [[nodiscard]] DAW_ATTRIB_INLINE constexpr value_type operator[]( size_type n ) const requires( RandomIterator ) { - return std::invoke( m_func, raw_get( n ) ); + return do_func( raw_get( n ) ); } [[nodiscard]] DAW_ATTRIB_INLINE constexpr value_type operator*( ) { - return std::invoke( m_func, *m_iter ); + return do_func( *m_iter ); } [[nodiscard]] DAW_ATTRIB_INLINE constexpr value_type operator*( ) const { - return std::invoke( m_func, *m_iter ); + return do_func( *m_iter ); } [[nodiscard]] DAW_ATTRIB_INLINE constexpr pointer operator->( ) { - return pointer( std::invoke( m_func, *m_iter ) ); + return do_func( *m_iter ); } [[nodiscard]] DAW_ATTRIB_INLINE constexpr pointer operator->( ) const { - return pointer( std::invoke( m_func, *m_iter ) ); + return do_func( *m_iter ); } DAW_ATTRIB_INLINE constexpr map_iterator &operator++( ) { @@ -127,24 +180,37 @@ namespace daw::pipelines { return *this; } - [[nodiscard]] DAW_ATTRIB_INLINE constexpr map_iterator - operator+( difference_type n ) const noexcept + [[nodiscard]] DAW_ATTRIB_INLINE friend constexpr map_iterator + operator+( map_iterator lhs, difference_type n ) noexcept requires( RandomIterator ) { - map_iterator result = *this; - m_iter += n; - return result; + lhs += n; + return lhs; } - [[nodiscard]] DAW_ATTRIB_INLINE constexpr map_iterator - operator-( difference_type n ) const noexcept + [[nodiscard]] DAW_ATTRIB_INLINE friend constexpr map_iterator + operator+( difference_type n, map_iterator rhs ) noexcept requires( RandomIterator ) { - map_iterator result = *this; - m_iter -= n; - return result; + rhs += n; + return rhs; + } + + [[nodiscard]] DAW_ATTRIB_INLINE friend constexpr map_iterator + operator-( map_iterator lhs, difference_type n ) noexcept + requires( RandomIterator ) { + lhs -= n; + return lhs; + } + + [[nodiscard]] DAW_ATTRIB_INLINE friend constexpr map_iterator + operator-( difference_type n, map_iterator rhs ) noexcept + requires( RandomIterator ) { + rhs -= n; + return rhs; } [[nodiscard]] DAW_ATTRIB_INLINE constexpr difference_type - operator-( map_iterator const &rhs ) requires( RandomIterator ) { + operator-( map_iterator const &rhs ) const + requires( RandomIterator ) { return m_iter - rhs.m_iter; } diff --git a/include/daw/pipelines/sized_iterator.h b/include/daw/pipelines/sized_iterator.h index 26fc3929d..09f693f7f 100644 --- a/include/daw/pipelines/sized_iterator.h +++ b/include/daw/pipelines/sized_iterator.h @@ -95,6 +95,13 @@ namespace daw::pipelines { return m_count != rhs.m_count; } + // clang-format off + [[nodiscard]] DAW_ATTRIB_INLINE constexpr auto + operator<=>( sized_iterator const &rhs ) const noexcept { + return m_count <=> rhs.m_count; + } + // clang-format on + // bidirectional iterator interface constexpr sized_iterator &operator--( ) requires( BidirectionalIteratorTag ) { @@ -134,47 +141,37 @@ namespace daw::pipelines { return *this; } - constexpr sized_iterator operator+( difference_type n ) const - requires( RandomIteratorTag ) { - auto result = *this; - result.advance( n ); - return result; - } - - constexpr sized_iterator operator-( difference_type n ) const - requires( RandomIteratorTag ) { - auto result = *this; - result.advance( -n ); - return result; - } - - constexpr difference_type operator-( sized_iterator const &rhs ) const + friend constexpr sized_iterator operator+( sized_iterator lhs, + difference_type n ) requires( RandomIteratorTag ) { - return rhs.m_count - m_count; + lhs += n; + return lhs; } - [[nodiscard]] DAW_ATTRIB_INLINE constexpr bool - operator<( sized_iterator const &rhs ) + friend constexpr sized_iterator operator+( difference_type n, + sized_iterator rhs ) requires( RandomIteratorTag ) { - return m_count > rhs.m_count; + rhs += n; + return rhs; } - [[nodiscard]] DAW_ATTRIB_INLINE constexpr bool - operator<=( sized_iterator const &rhs ) + friend constexpr sized_iterator operator-( sized_iterator lhs, + difference_type n ) requires( RandomIteratorTag ) { - return m_count >= rhs.m_count; + lhs -= n; + return lhs; } - [[nodiscard]] DAW_ATTRIB_INLINE constexpr bool - operator>( sized_iterator const &rhs ) + friend constexpr sized_iterator operator-( difference_type n, + sized_iterator rhs ) requires( RandomIteratorTag ) { - return m_count < rhs.m_count; + rhs -= n; + return rhs; } - [[nodiscard]] DAW_ATTRIB_INLINE constexpr bool - operator>=( sized_iterator const &rhs ) + constexpr difference_type operator-( sized_iterator const &rhs ) const requires( RandomIteratorTag ) { - return m_count <= rhs.m_count; + return rhs.m_count - m_count; } }; @@ -202,8 +199,7 @@ namespace daw::pipelines { public: explicit sized_iterator( ) = default; - explicit constexpr sized_iterator( Iterator first, - Iterator last, + explicit constexpr sized_iterator( Iterator first, Iterator last, std::size_t how_many ) : m_first( first ) , m_last( last ) diff --git a/include/daw/pipelines/zip.h b/include/daw/pipelines/zip.h index be2e09eb8..dc167a90d 100644 --- a/include/daw/pipelines/zip.h +++ b/include/daw/pipelines/zip.h @@ -145,6 +145,13 @@ namespace daw::pipelines { }( std::make_index_sequence{ } ); } + // clang-format off + [[nodiscard]] constexpr auto + operator<=>( zip_iterator const &rhs ) const noexcept { + return m_iters <=> rhs.m_iters; + } + // clang-format on + // bidirectional iterator interface constexpr zip_iterator &operator--( ) requires( BidirectionalIteratorTag ) { @@ -182,45 +189,40 @@ namespace daw::pipelines { return *this; } - constexpr zip_iterator operator+( difference_type n ) const + friend constexpr zip_iterator operator+( zip_iterator lhs, + difference_type n ) requires( RandomIteratorTag ) { - auto result = *this; - result.advance( n, zip_indices( ) ); - return result; + lhs += n; + return lhs; } - constexpr zip_iterator operator-( difference_type n ) const + friend constexpr zip_iterator operator+( difference_type n, + zip_iterator rhs ) requires( RandomIteratorTag ) { - auto result = *this; - result.advance( -n, zip_indices( ) ); - return result; - } - - constexpr difference_type operator-( zip_iterator const &rhs ) const - requires( RandomIteratorTag ) { - return std::get<0>( m_iters ) - std::get<0>( rhs.m_iters ); + rhs += n; + return rhs; } - [[nodiscard]] constexpr bool operator<( zip_iterator const &rhs ) + friend constexpr zip_iterator operator-( zip_iterator lhs, + difference_type n ) requires( RandomIteratorTag ) { - return m_iters < rhs.m_iters; + lhs -= n; + return lhs; } - [[nodiscard]] constexpr bool operator<=( zip_iterator const &rhs ) + friend constexpr zip_iterator operator-( difference_type n, + zip_iterator rhs ) requires( RandomIteratorTag ) { - return m_iters <= rhs.m_iters; + rhs -= n; + return rhs; } - [[nodiscard]] constexpr bool operator>( zip_iterator const &rhs ) - requires( RandomIteratorTag ) { - return m_iters > rhs.m_iters; - } - - [[nodiscard]] constexpr bool operator>=( zip_iterator const &rhs ) + constexpr difference_type operator-( zip_iterator const &rhs ) const requires( RandomIteratorTag ) { - return m_iters >= rhs.m_iters; + return std::get<0>( m_iters ) - std::get<0>( rhs.m_iters ); } }; + template zip_iterator( Iterators... ) -> zip_iterator; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 4e3954deb..02acd97aa 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -161,6 +161,7 @@ set( CPP20_TEST_SOURCES daw_formatters_test.cpp daw_from_string_test.cpp daw_iter_view_test.cpp + daw_mutable_function_ref_test.cpp daw_poly_value_test.cpp daw_maybe_unique_ptr_test.cpp daw_move_only_test.cpp diff --git a/tests/cmake/test_compiler_options.cmake b/tests/cmake/test_compiler_options.cmake index 933becae2..09df553d1 100644 --- a/tests/cmake/test_compiler_options.cmake +++ b/tests/cmake/test_compiler_options.cmake @@ -81,6 +81,11 @@ if( ${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang" OR ${CMAKE_CXX_COMPILER_ID} STREQU -Wno-c++26-extensions ) endif() + if( CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 21 ) + add_compile_options( + -Wno-nrvo + ) + endif() add_compile_options( -Wno-poison-system-directories ) if( DAW_WERROR ) add_compile_options( -Werror -pedantic-errors ) @@ -181,19 +186,19 @@ elseif( ${CMAKE_CXX_COMPILER_ID} STREQUAL "GNU" ) endif() message( STATUS "g++ ${CMAKE_CXX_COMPILER_VERSION} detected" ) add_compile_options( --param max-gcse-memory=260000000 - -Wall - -Wextra - -pedantic - -pedantic-errors - -Wpedantic - -Wconversion - -Wduplicated-cond - -Wlogical-op - -Wold-style-cast - -Wshadow - -Wzero-as-null-pointer-constant - -Wconversion - ) + -Wall + -Wextra + -pedantic + -pedantic-errors + -Wpedantic + -Wconversion + -Wduplicated-cond + -Wlogical-op + -Wold-style-cast + -Wshadow + -Wzero-as-null-pointer-constant + -Wconversion + ) #-Wno-deprecated-declarations if( DAW_WERROR ) add_compile_options( -Werror -pedantic-errors -ftrapv ) diff --git a/tests/daw_enumerate_tuple_test.cpp b/tests/daw_enumerate_tuple_test.cpp index 170c5e290..209a334ba 100644 --- a/tests/daw_enumerate_tuple_test.cpp +++ b/tests/daw_enumerate_tuple_test.cpp @@ -36,7 +36,7 @@ int main( ) { std::same_as, elem0_t> ); static_assert( std::tuple_size_v == 2 ); - auto const [index,element] = std::get<0>( enum_x2 ); + [[maybe_unused]] auto const [index,element] = std::get<0>( enum_x2 ); static_assert( std::same_as ); using namespace daw::literals; static_assert( enum_x2[0_c].value == "a"sv ); diff --git a/tests/daw_mutable_function_ref_test.cpp b/tests/daw_mutable_function_ref_test.cpp new file mode 100644 index 000000000..5554a8800 --- /dev/null +++ b/tests/daw_mutable_function_ref_test.cpp @@ -0,0 +1,116 @@ +// Copyright (c) Darrell Wright +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE or copy at http://www.boost.org/LICENSE_1_0.txt) +// +// Official repository: https://github.com/beached/header_libraries +// + +#include "daw/daw_mutable_function_ref.h" + +#include "daw/daw_ensure.h" + +#include +#include +#include + +int func( daw::mutable_function_ref f ) { + return f( 1, 2, 3 ) * f( 4, 5, 7 ); +} + +int test( ) { + return func( []( int a, int b, int c ) { + return a * b * c; + } ); +} + +inline constexpr int add( int a, int b, int c ) { + return a + b + c; +} + +int test2( ) { + return func( add ); +} + +int func2( daw::mutable_function_ref f ) { + f( 1.2, 3.4 ); + return 0; +} + +int test3( ) { + return func2( +[]( double, double ) { + puts( "Hello\n" ); + } ); +} + +int call_mutable( daw::mutable_function_ref f ) { + return f( ) + f( ); +} + +int call_mutable2( daw::mutable_function_ref const f ) { + return f( ) + f( ); +} + +void call_mutable_void( daw::mutable_function_ref f ) { + f( ); + f( ); +} + +struct mutable_callable { + int value = 0; + + int operator( )( ) { + return ++value; + } +}; + +static_assert( std::invocable ); +static_assert( not std::invocable ); + +int main( ) { + auto const const_lvalue = []( ) { + return 42; + }; + daw::mutable_function_ref const_view = const_lvalue; + daw_ensure( const_view( ) == 42 ); + + mutable_callable mutable_lvalue{ }; + daw_ensure( call_mutable( mutable_lvalue ) == 3 ); + daw_ensure( call_mutable( [n = 0]( ) mutable { + return ++n; + } ) == 3 ); + mutable_lvalue.value = 0; + daw_ensure( call_mutable2( mutable_lvalue ) == 3 ); + daw_ensure( call_mutable2( [n = 0]( ) mutable { + return ++n; + } ) == 3 ); + + int n = 0; + auto mutable_void = [&n]( ) mutable { + ++n; + }; + call_mutable_void( mutable_void ); + daw_ensure( n == 2 ); + + struct FooCall { + mutable int x = 0; + + constexpr void operator( )( ) { + x = 1; + } + + constexpr void operator( )( ) const { + x = 2; + } + }; + + { + auto fc = FooCall{ }; + daw::mutable_function_ref mfr_fc0 = fc; + mfr_fc0( ); + daw_ensure( fc.x == 1 ); + daw::mutable_function_ref mfr_fc1 = std::as_const( fc ); + mfr_fc1( ); + daw_ensure( fc.x == 2 ); + } +} diff --git a/tests/daw_pipelines_test.cpp b/tests/daw_pipelines_test.cpp index d6ec6226d..dc9cfcf85 100644 --- a/tests/daw_pipelines_test.cpp +++ b/tests/daw_pipelines_test.cpp @@ -194,9 +194,9 @@ namespace tests { Map( []( int x ) { return x * 2; } ) ); - constexpr auto x = p4( std::array{ 1, 2, 3 } ); - constexpr auto y = *std::next( x.begin( ) ); - static_assert( y == 2 ); + auto x = p4( std::array{ 1, 2, 3 } ); + auto y = *std::next( x.begin( ) ); + daw_ensure( y == 2 ); } DAW_ATTRIB_NOINLINE void test008( ) {