diff --git a/include/daw/daw_bitset_helper.h b/include/daw/daw_bitset_helper.h new file mode 100644 index 000000000..23387b4f4 --- /dev/null +++ b/include/daw/daw_bitset_helper.h @@ -0,0 +1,68 @@ +// 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 "daw/daw_cpp_feature_check.h" +#include "daw/daw_ensure.h" +#include "daw/traits/daw_traits_integer_type.h" + +#include +#include + +namespace daw { + namespace create_bs_impl { + template + DAW_CPP23_CX_BITSET_FN auto + create_bitset_from_set_positions( auto const &r ) { + auto result = std::bitset{ }; + for( auto const &position : r ) { +#ifndef NDEBUG + using value_t = daw::traits::integral_type_t< + std::ranges::range_value_t>; + daw_ensure( ( std::is_unsigned_v or + static_cast( position ) >= 0 ) ); + daw_ensure( static_cast( position ) < N ); +#endif + result.set( static_cast( position ) ); + } + return result; + } + } // namespace create_bs_impl + + template + requires( std::ranges::range + and daw::traits::IntegerEnum> ) // + DAW_ATTRIB_FLATTEN DAW_CPP23_CX_BITSET_FN + auto create_bitset_from_set_positions( R const &r ) { + return create_bs_impl::create_bitset_from_set_positions( r ); + } + + template + DAW_ATTRIB_FLATTEN DAW_CPP23_CX_BITSET_FN auto + create_bitset_from_set_positions( std::initializer_list r ) { + return create_bs_impl::create_bitset_from_set_positions( r ); + } + + template + DAW_ATTRIB_FLATTEN DAW_CPP23_CX_BITSET_FN auto + create_bitset_from_set_positions( traits::IntegerEnum auto... positions ) { + auto result = std::bitset{ }; + ( result.set( [&]( auto position ) { +#ifndef NDEBUG + using value_t = daw::traits::integral_type_t; + daw_ensure( ( std::is_unsigned_v or + static_cast( position ) >= 0 ) ); + daw_ensure( static_cast( position ) < N ); +#endif + return static_cast( position ); + }( positions ) ), + ... ); + return result; + } +} // namespace daw diff --git a/include/daw/daw_concepts.h b/include/daw/daw_concepts.h index f12a24a0c..46bdf1568 100644 --- a/include/daw/daw_concepts.h +++ b/include/daw/daw_concepts.h @@ -26,13 +26,12 @@ namespace daw { /*** * @brief Given types From and To and an expression E whose type and value * category are the same as those of std::declval(), - * convertible_to requires E to be both implicitly and explicitly - * convertible to type To. The implicit and explicit conversions are required - * to produce equal results. + * explicitly_convertible_to requires E to be explicitly + * convertible to type To. */ template - concept convertible_to = std::is_convertible_v and requires { - { static_cast( std::declval( ) ) }; + concept explicitly_convertible_to = requires { + static_cast( std::declval( ) ); }; /*** @@ -44,6 +43,17 @@ namespace daw { template concept implicitly_convertible_to = std::is_convertible_v; + /*** + * @brief Given types From and To and an expression E whose type and value + * category are the same as those of std::declval(), + * convertible_to requires E to be both implicitly and explicitly + * convertible to type To. The implicit and explicit conversions are required + * to produce equal results. + */ + template + concept convertible_to = + implicitly_convertible_to and explicitly_convertible_to; + /*** * @brief Satisfied when Lhs and Rhs name the same type (taking into account * const/volatile qualifications) @@ -113,14 +123,14 @@ namespace daw { template concept ContiguousContainer = requires( T && container ) { - { std::data( container ) } -> Pointers; - { std::size( container ) } -> convertible_to; + { std::data( container ) }->Pointers; + { std::size( container ) }->convertible_to; }; template concept ContiguousContainerOf = ContiguousContainer and requires( T container ) { - { *std::data( container ) } -> convertible_to; + { *std::data( container ) }->convertible_to; }; template @@ -182,7 +192,7 @@ namespace daw { std::assignable_from; #else std::is_lvalue_reference_v and requires( LHS lhs, RHS &&rhs ) { - { lhs = DAW_FWD( rhs ) } -> std::same_as; + { lhs = DAW_FWD( rhs ) }->std::same_as; }; #endif @@ -238,7 +248,7 @@ namespace daw { movable and requires( I i ) { typename iter_difference_t; requires SignedStd>; - { ++i } -> same_as; + { ++i }->same_as; i++; }; #endif @@ -253,9 +263,7 @@ namespace daw { */ template concept invocable_result = requires( Func && f, Args &&...args ) { - { - std::invoke( DAW_FWD( f ), DAW_FWD( args )... ) - } -> convertible_to; + { std::invoke( DAW_FWD( f ), DAW_FWD( args )... ) }->convertible_to; }; template @@ -358,7 +366,7 @@ namespace daw { template concept boolean_testable = concept_details::boolean_testable_impl and requires( B && b ) { - { not DAW_FWD( b ) } -> concept_details::boolean_testable_impl; + { not DAW_FWD( b ) }->concept_details::boolean_testable_impl; }; namespace concept_details { @@ -366,10 +374,10 @@ namespace daw { concept weakly_equality_comparable_with = requires( std::remove_reference_t const &t, std::remove_reference_t const &u ) { - { t == u } -> boolean_testable; - { t != u } -> boolean_testable; - { u == t } -> boolean_testable; - { u != t } -> boolean_testable; + { t == u }->boolean_testable; + { t != u }->boolean_testable; + { u == t }->boolean_testable; + { u != t }->boolean_testable; }; } // namespace concept_details #endif @@ -439,7 +447,7 @@ namespace daw { template concept Callable_r = requires( Fn fn, Args... args ) { - { fn( args... ) } -> convertible_to; + { fn( args... ) }->convertible_to; }; template @@ -457,4 +465,4 @@ namespace daw { { fn( args... ) } noexcept; }; } // namespace daw -#endif \ No newline at end of file +#endif diff --git a/include/daw/daw_contiguous_view.h b/include/daw/daw_contiguous_view.h index e5e8e179a..24e374965 100644 --- a/include/daw/daw_contiguous_view.h +++ b/include/daw/daw_contiguous_view.h @@ -8,12 +8,13 @@ #pragma once -#include "daw_concepts.h" -#include "daw_consteval.h" -#include "daw_data_end.h" -#include "daw_utility.h" -#include "impl/daw_view_tags.h" -#include "wrap_iter.h" +#include "daw/daw_concepts.h" +#include "daw/daw_consteval.h" +#include "daw/daw_data_end.h" +#include "daw/daw_ensure.h" +#include "daw/daw_utility.h" +#include "daw/impl/daw_view_tags.h" +#include "daw/wrap_iter.h" #include #include @@ -27,7 +28,8 @@ namespace daw { struct contiguous_view; template - requires( not std::is_const_v ) struct contiguous_view { + requires( not std::is_const_v ) // + struct contiguous_view { using value_type = T; using reference = value_type &; using const_reference = value_type const &; @@ -45,7 +47,8 @@ namespace daw { pointer m_last = nullptr; public: - contiguous_view( ) = default; + explicit contiguous_view( ) = default; + constexpr contiguous_view( contiguous_view &other ) noexcept : m_first( other.m_first ) , m_last( other.m_last ) {} @@ -70,6 +73,15 @@ namespace daw { : m_first( std::data( c ) ) , m_last( daw::data_end( c ) ) {} + template Container> + requires( not_cvref_of ) explicit( + ExplicitConv ) constexpr contiguous_view( Container &&c, + std::size_t count ) noexcept + : m_first( std::data( c ) ) + , m_last( std::next( m_first, static_cast( count ) ) ) { + daw_ensure( count <= std::size( c ) ); + } + template Container> explicit constexpr operator Container( ) const noexcept { return Container{ data( ), size( ) }; @@ -226,7 +238,7 @@ namespace daw { } constexpr void remove_prefix( std::size_t count ) noexcept { - count = ( std::min )( count, size( ) ); + count = (std::min)( count, size( ) ); m_first += count; } @@ -241,7 +253,7 @@ namespace daw { } constexpr void remove_suffix( std::size_t count ) noexcept { - count = ( std::min )( count, size( ) ); + count = (std::min)( count, size( ) ); m_last -= count; } @@ -397,8 +409,8 @@ namespace daw { [[nodiscard]] friend constexpr bool operator<( contiguous_view const &x, contiguous_view const &y ) { - return std::lexicographical_compare( x.data( ), x.data_end( ), y.data( ), - y.data_end( ) ); + return std::lexicographical_compare( + x.data( ), x.data_end( ), y.data( ), y.data_end( ) ); } [[nodiscard]] friend constexpr bool operator>( contiguous_view const &x, @@ -418,8 +430,8 @@ namespace daw { }; template - requires( std::is_const_v ) struct contiguous_view { - + requires( std::is_const_v ) // + struct contiguous_view { using value_type = T; using reference = value_type &; using const_reference = value_type const &; @@ -458,6 +470,15 @@ namespace daw { : m_first( std::data( c ) ) , m_last( daw::data_end( c ) ) {} + template Container> + requires( not_cvref_of ) explicit( + ExplicitConv ) constexpr contiguous_view( Container &&c, + std::size_t count ) noexcept + : m_first( std::data( c ) ) + , m_last( std::next( m_first, static_cast( count ) ) ) { + daw_ensure( count <= std::size( c ) ); + } + template Container> explicit constexpr operator Container( ) const noexcept { return Container{ data( ), size( ) }; @@ -593,7 +614,7 @@ namespace daw { } constexpr void remove_prefix( std::size_t count ) noexcept { - count = ( std::min )( count, size( ) ); + count = (std::min)( count, size( ) ); m_first += count; } @@ -608,7 +629,7 @@ namespace daw { } constexpr void remove_suffix( std::size_t count ) noexcept { - count = ( std::min )( count, size( ) ); + count = (std::min)( count, size( ) ); m_last -= count; } @@ -764,8 +785,8 @@ namespace daw { [[nodiscard]] friend constexpr bool operator<( contiguous_view const &x, contiguous_view const &y ) { - return std::lexicographical_compare( x.data( ), x.data_end( ), y.data( ), - y.data_end( ) ); + return std::lexicographical_compare( + x.data( ), x.data_end( ), y.data( ), y.data_end( ) ); } [[nodiscard]] friend constexpr bool operator>( contiguous_view const &x, @@ -784,18 +805,26 @@ namespace daw { } }; - template - contiguous_view( T *, T * ) -> contiguous_view; + template + contiguous_view( P, P ) -> contiguous_view>; - template - contiguous_view( T *, std::size_t ) -> contiguous_view; + template + contiguous_view( P, SizeT ) -> contiguous_view>; template - contiguous_view( Container &&c ) - -> contiguous_view>; + contiguous_view( Container &&c ) -> contiguous_view>, + daw::range_value_t const, daw::range_value_t>>; + + template + contiguous_view( Container &&c, SizeT ) -> contiguous_view>, + daw::range_value_t const, daw::range_value_t>>; template contiguous_view( T ( & )[N] ) -> contiguous_view; + template + contiguous_view( T ( & )[N], std::size_t ) -> contiguous_view; } // namespace daw DAW_UNSAFE_BUFFER_FUNC_STOP diff --git a/include/daw/daw_cpp_feature_check.h b/include/daw/daw_cpp_feature_check.h index f9f382952..90c76dbcf 100644 --- a/include/daw/daw_cpp_feature_check.h +++ b/include/daw/daw_cpp_feature_check.h @@ -227,4 +227,22 @@ inline constexpr bool daw_has_cx_cmath = false; #if __cpp_lib_move_only_function >= 202110L #define DAW_HAS_CPP23_MOVE_ONLY_FUNCTION #endif +#endif + +#if defined( __cpp_lib_constexpr_bitset ) +#if __cpp_lib_constexpr_bitset >= 202202L +#define DAW_HAS_CPP23_CONSTEXPR_BITSET 1 +#endif +#endif + +#if defined( DAW_HAS_CPP23_CONSTEXPR_BITSET ) +#define DAW_CPP23_CX_BITSET_FN constexpr +#define DAW_CPP23_CX_BITSET constexpr +#else +#define DAW_CPP23_CX_BITSET_FN inline +#define DAW_CPP23_CX_BITSET +#endif + +#if __cpp_lib_optional >= 202506L +#define DAW_HAS_CPP26_OPTIONAL_REFS #endif \ No newline at end of file diff --git a/include/daw/daw_ensure.h b/include/daw/daw_ensure.h index e36c567d8..f19686c9f 100644 --- a/include/daw/daw_ensure.h +++ b/include/daw/daw_ensure.h @@ -44,3 +44,16 @@ namespace daw::ensure { ::daw::ensure::ensure_error( not( __VA_ARGS__ ) ); \ } \ } while( false ) + +#if not defined( NDEBUG ) +#define daw_dbg_ensure( ... ) \ + do { \ + if( not( __VA_ARGS__ ) ) { \ + ::daw::ensure::ensure_error( not( __VA_ARGS__ ) ); \ + } \ + } while( false ) +#else +#define daw_dbg_ensure( ... ) \ + do { \ + } while( false ) +#endif diff --git a/include/daw/daw_forward_like.h b/include/daw/daw_forward_like.h new file mode 100644 index 000000000..2b17b7a62 --- /dev/null +++ b/include/daw/daw_forward_like.h @@ -0,0 +1,45 @@ +// 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/ +// + +#pragma once + +#include +#include + +namespace daw { + template + constexpr auto &&forward_like( U &&x ) noexcept { + constexpr bool is_adding_const = + std::is_const_v>; + if constexpr( std::is_lvalue_reference_v ) { + if constexpr( is_adding_const ) { + return std::as_const( x ); + } else { + return static_cast( x ); + } + } else { + if constexpr( is_adding_const ) { + return std::move( std::as_const( x ) ); + } else { + return std::move( x ); + } + } + } + + template + using forward_like_t = std::conditional_t< + std::is_lvalue_reference_v, + std::conditional_t< + std::is_const_v>, + std::add_lvalue_reference_t>>, + std::add_lvalue_reference_t>>, + std::conditional_t< + std::is_const_v>, + std::add_rvalue_reference_t>>, + std::add_rvalue_reference_t>>>; +} // namespace daw diff --git a/include/daw/daw_forward_lvalue.h b/include/daw/daw_forward_lvalue.h new file mode 100644 index 000000000..7f118b8c2 --- /dev/null +++ b/include/daw/daw_forward_lvalue.h @@ -0,0 +1,22 @@ +// 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 + +namespace daw { + template + DAW_ATTRIB_INLINE constexpr decltype( auto ) forward_lvalue( T &&r ) { + if constexpr( std::is_lvalue_reference_v ) { + return std::forward( r ); + } else { + return static_cast>( r ); + } + } +} // namespace daw diff --git a/include/daw/daw_iterator_traits.h b/include/daw/daw_iterator_traits.h index ca702a5d2..1c1e022f9 100644 --- a/include/daw/daw_iterator_traits.h +++ b/include/daw/daw_iterator_traits.h @@ -19,12 +19,13 @@ namespace daw { template - using iter_value_t = - typename std::iterator_traits>::value_type; + using iter_reference_t = decltype( *std::declval( ) ); template - using iter_reference_t = - typename std::iterator_traits>::reference; + using iter_const_reference_t = decltype( *std::declval( ) ); + + template + using iter_value_t = std::remove_cvref_t>; template using iter_pointer_t = @@ -34,17 +35,13 @@ namespace daw { using iter_difference_t = typename std::iterator_traits>::difference_type; - template - using iter_const_reference_t = - std::common_reference_t const &&, iter_reference_t>; - template using iter_category_t = typename std::iterator_traits>::iterator_category; template concept Iterator = requires( It & it ) { - { ++it } -> std::same_as; + { ++it }->std::same_as; { it++ }; { *it }; }; @@ -170,10 +167,10 @@ namespace daw { }; template - using iterator_t = DAW_TYPEOF( std::begin( std::declval( ) ) ); + using iterator_t = DAW_TYPEOF( std::begin( std::declval( ) ) ); template - using iterator_end_t = DAW_TYPEOF( std::end( std::declval( ) ) ); + using iterator_end_t = DAW_TYPEOF( std::end( std::declval( ) ) ); template using const_iterator_t = diff --git a/include/daw/daw_maybe_unique_ptr.h b/include/daw/daw_maybe_unique_ptr.h new file mode 100644 index 000000000..a42ff11fe --- /dev/null +++ b/include/daw/daw_maybe_unique_ptr.h @@ -0,0 +1,312 @@ +// 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 "daw/daw_concepts.h" +#include "daw/daw_move.h" +#include "daw/daw_unique_ptr.h" + +namespace daw { + template> + struct maybe_unique_ptr : private Deleter { + using value_type = T; + using pointer = unique_ptr_del::pointer_type_t; + using reference = std::add_lvalue_reference_t; + using deleter_t = Deleter; + + private: + daw::unique_ptr m_ptr = nullptr; + bool m_owned = true; + + template + friend struct maybe_unique_ptr; + + public: + maybe_unique_ptr( ) = default; + + explicit constexpr maybe_unique_ptr( pointer ptr ) noexcept + : m_ptr( ptr ) {} + + template + requires( not std::is_pointer_v ) // + explicit constexpr maybe_unique_ptr( pointer ptr, B owned ) noexcept + : m_ptr( ptr ) + , m_owned( owned ) {} + + template D> + explicit constexpr maybe_unique_ptr( pointer ptr, D &&deleter ) noexcept + : m_ptr( ptr, DAW_FWD( deleter ) ) {} + + template D, typename B> + requires( not std::is_pointer_v ) // + explicit constexpr maybe_unique_ptr( pointer ptr, D &&deleter, + B owned ) noexcept + : m_ptr( ptr, DAW_FWD( deleter ) ) + , m_owned( owned ) {} + + template + requires( not std::is_same_v ) // + constexpr maybe_unique_ptr( U *p ) noexcept + : m_ptr( p ) { + static_assert( unique_ptr_details::is_safe_child_type_v, + "One cannot destruct U, if T does not have a virtual " + "destructor, and U being a child of T" ); + } + + template + requires( not std::is_same_v and not std::is_pointer_v ) // + constexpr maybe_unique_ptr( U *p, B owned ) noexcept + : m_ptr( p ) + , m_owned( owned ) { + static_assert( unique_ptr_details::is_safe_child_type_v, + "One cannot destruct U, if T does not have a virtual " + "destructor, and U being a child of T" ); + } + + constexpr maybe_unique_ptr( std::nullptr_t ) noexcept {} + + constexpr maybe_unique_ptr( maybe_unique_ptr &&other ) noexcept + : m_ptr( other.release( ) ) + , m_owned( std::exchange( other.m_owned, true ) ) {} + + template + requires( not std::is_same_v ) // + constexpr maybe_unique_ptr( maybe_unique_ptr &&other ) noexcept + : Deleter( static_cast( other ) ) + , m_ptr( other.release( ) ) + , m_owned( std::exchange( other.m_owned, true ) ) { + static_assert( unique_ptr_details::is_safe_child_type_v, + "One cannot destruct U, if T does not have a virtual " + "destructor, and U being a child of T" ); + } + + template + requires( not std::is_same_v ) // + constexpr maybe_unique_ptr( unique_ptr &&other ) noexcept + : Deleter( std::move( other ).get_deleter( ) ) + , m_ptr( other.release( ) ) { + static_assert( unique_ptr_details::is_safe_child_type_v, + "One cannot destruct U, if T does not have a virtual " + "destructor, and U being a child of T" ); + } + + constexpr maybe_unique_ptr &operator=( maybe_unique_ptr &&rhs ) noexcept { + if( this != &rhs ) { + reset( ); + m_ptr = rhs.release( ); + m_owned = std::exchange( rhs.m_owned, true ); + } + return *this; + } + + template + requires( not std::is_same_v ) // + constexpr maybe_unique_ptr & + operator=( maybe_unique_ptr &&rhs ) noexcept { + static_assert( unique_ptr_details::is_safe_child_type_v, + "One cannot destruct U, if T does not have a virtual " + "destructor, and U being a child of T" ); + m_ptr = std::move( rhs.m_ptr ); + m_owned = std::exchange( rhs.m_owned, true ); + return *this; + } + + template + requires( not std::is_same_v ) // + constexpr maybe_unique_ptr &operator=( unique_ptr &&rhs ) noexcept { + static_assert( unique_ptr_details::is_safe_child_type_v, + "One cannot destruct U, if T does not have a virtual " + "destructor, and U being a child of T" ); + m_ptr = std::move( rhs ); + m_owned = std::exchange( rhs.m_owned, true ); + return *this; + } + + constexpr maybe_unique_ptr( maybe_unique_ptr const & ) = delete; + constexpr maybe_unique_ptr &operator=( maybe_unique_ptr const & ) = delete; + + DAW_CPP20_CX_ALLOC ~maybe_unique_ptr( ) noexcept { + reset( ); + } + + constexpr pointer release( ) noexcept { + m_owned = true; + return m_ptr.release( ); + } + + constexpr deleter_t &get_deleter( ) & { + return m_ptr.get_deleter( ); + } + + constexpr deleter_t const &get_deleter( ) const & { + return m_ptr.get_deleter( ); + } + + constexpr deleter_t &&get_deleter( ) && { + return std::move( m_ptr.get_deleter( ) ); + } + + constexpr deleter_t const &&get_deleter( ) const && { + return std::move( m_ptr.get_deleter( ) ); + } + + constexpr void reset( ) noexcept { + if( m_owned ) { + m_ptr.reset( ); + } else { + (void)m_ptr.release( ); + m_owned = true; + } + } + + constexpr void reset( pointer p, bool owned = true ) noexcept { + if( m_owned ) { + m_ptr.reset( std::move( p ) ); + } else { + (void)m_ptr.release( ); + } + m_ptr.reset( std::move( p ) ); + m_owned = owned; + } + + constexpr pointer get( ) const { + return m_ptr.get( ); + } + + constexpr pointer *get_out( ) noexcept { + return m_ptr.get_out( ); + } + + constexpr pointer operator->( ) const { + return m_ptr.get( ); + } + + constexpr reference operator*( ) const noexcept { + return *m_ptr; + } + + explicit constexpr operator bool( ) const noexcept { + return static_cast( m_ptr ); + } + + constexpr void swap( maybe_unique_ptr &other ) noexcept { + using std::swap; + swap( m_ptr, other.m_ptr ); + swap( m_owned, other.m_owned ); + } + + constexpr decltype( auto ) operator[]( std::size_t index ) const noexcept + requires( requires { m_ptr[std::size_t{ }]; } ) { + return m_ptr[index]; + } + + template + constexpr auto and_then( F &&func ) && { + return monadic_ptr::and_then( std::move( *this ), DAW_FWD( func ) ); + } + + template + constexpr auto or_else( F &&func ) && { + return monadic_ptr::or_else( std::move( *this ), DAW_FWD( func ) ); + } + + template + constexpr auto transform( F &&func ) & { + return monadic_ptr::transform( *this, DAW_FWD( func ) ); + } + + template + constexpr auto transform( F &&func ) const & { + return monadic_ptr::transform( *this, DAW_FWD( func ) ); + } + + template + constexpr auto transform( F &&func ) && { + return monadic_ptr::transform( std::move( *this ), DAW_FWD( func ) ); + } + + template + constexpr auto transform( F &&func ) const && { + return monadic_ptr::transform( std::move( *this ), DAW_FWD( func ) ); + } + }; + + template + DAW_CPP20_CX_ALLOC auto make_maybe_unique( Args &&...args ) + -> std::enable_if_t, maybe_unique_ptr> { + if constexpr( std::is_aggregate_v ) { + return maybe_unique_ptr( new T{ DAW_FWD( args )... } ); + } else { + return maybe_unique_ptr( new T( DAW_FWD( args )... ) ); + } + } + + template + DAW_CPP20_CX_ALLOC auto make_maybe_unique_for_overwrite( ) + -> std::enable_if_t, maybe_unique_ptr> { + return maybe_unique_ptr( new T ); + } + + template + DAW_CPP20_CX_ALLOC auto make_maybe_unique( std::size_t count ) + -> std::enable_if_t, maybe_unique_ptr> { + using value_type = std::remove_extent_t; + static_assert( daw::is_unbounded_array_v, + "It is an error to specify a bound on the array type. e.g " + "T[3], use T[] instead" ); + return maybe_unique_ptr( new value_type[count]{ } ); + } + + template + DAW_CPP20_CX_ALLOC auto make_maybe_unique_array( Elements &&...elements ) + -> std::enable_if_t, maybe_unique_ptr> { + static_assert( daw::is_unbounded_array_v, + "It is an error to specify a bound on the array type. e.g " + "T[3], use T[] instead" ); + using value_type = std::remove_extent_t; + return maybe_unique_ptr( + new value_type[sizeof...( Elements )]{ DAW_FWD( elements )... } ); + } + + template + constexpr bool operator==( maybe_unique_ptr const &lhs, + maybe_unique_ptr const &rhs ) noexcept { + return lhs.get( ) == rhs.get( ); + } + + template + constexpr bool operator!=( maybe_unique_ptr const &lhs, + maybe_unique_ptr const &rhs ) noexcept { + return lhs.get( ) != rhs.get( ); + } + + template + constexpr bool operator<( maybe_unique_ptr const &lhs, + maybe_unique_ptr const &rhs ) noexcept { + return std::less{ }( lhs.get( ), rhs.get( ) ); + } + + template + constexpr bool operator<=( maybe_unique_ptr const &lhs, + maybe_unique_ptr const &rhs ) noexcept { + return not( lhs < rhs ); + } + + template + constexpr bool operator>( maybe_unique_ptr const &lhs, + maybe_unique_ptr const &rhs ) noexcept { + return rhs < lhs; + } + + template + constexpr bool operator>=( maybe_unique_ptr const &lhs, + maybe_unique_ptr const &rhs ) noexcept { + return not( lhs < rhs ); + } +} // namespace daw diff --git a/include/daw/daw_observer_ptr.h b/include/daw/daw_observer_ptr.h index 3087388b4..117b897a3 100644 --- a/include/daw/daw_observer_ptr.h +++ b/include/daw/daw_observer_ptr.h @@ -44,8 +44,10 @@ namespace daw { return *this; } - constexpr void release( ) { + constexpr pointer release( ) { + auto tmp = m_ptr; m_ptr = nullptr; + return tmp; } constexpr void reset( pointer p = nullptr ) { @@ -56,6 +58,10 @@ namespace daw { return m_ptr; } + constexpr pointer *get_out( ) { + return &m_ptr; + } + constexpr explicit operator bool( ) const { return static_cast( m_ptr ); } @@ -126,10 +132,10 @@ namespace daw { }; template - requires std::is_array_v - observer_ptr( A ) -> observer_ptr>; + requires std::is_array_v observer_ptr( A ) + -> observer_ptr>; template - requires std::is_pointer_v

- observer_ptr( P ) -> observer_ptr>; + requires std::is_pointer_v

observer_ptr( P ) + -> observer_ptr>; } // namespace daw diff --git a/include/daw/daw_pipelines.h b/include/daw/daw_pipelines.h index ab0f42029..4f1fd339c 100644 --- a/include/daw/daw_pipelines.h +++ b/include/daw/daw_pipelines.h @@ -9,13 +9,17 @@ #pragma once #include "daw/pipelines/algorithm.h" +#include "daw/pipelines/cache_last_view.h" #include "daw/pipelines/chunk.h" #include "daw/pipelines/concat.h" +#include "daw/pipelines/copy.h" #include "daw/pipelines/drop.h" +#include "daw/pipelines/elements.h" #include "daw/pipelines/enumerate.h" #include "daw/pipelines/every.h" #include "daw/pipelines/filter.h" #include "daw/pipelines/find.h" +#include "daw/pipelines/first.h" #include "daw/pipelines/flatten.h" #include "daw/pipelines/foreach.h" #include "daw/pipelines/generate.h" diff --git a/include/daw/daw_print_ostream.h b/include/daw/daw_print_ostream.h index 74dcd4b36..7af1d6783 100644 --- a/include/daw/daw_print_ostream.h +++ b/include/daw/daw_print_ostream.h @@ -35,7 +35,17 @@ namespace daw { static_assert( ( has_std_formatter_specialization_v and ... ), "Print requires a std::formatter specialization for each " "Arg type" ); - return daw::print( os, "{}\n", - std::format( std::move( fmt ), DAW_FWD( args )... ) ); + return daw::print( + os, "{}\n", std::format( std::move( fmt ), DAW_FWD( args )... ) ); } + + template + std::ostream &print_log( std::format_string fmt, Args &&...args ) { + static_assert( ( has_std_formatter_specialization_v and ... ), + "print_log requires a std::formatter specialization for each " + "Arg type" ); + return daw::print( + std::clog, "{}\n", std::format( std::move( fmt ), DAW_FWD( args )... ) ); + } + } // namespace daw diff --git a/include/daw/daw_safe_pointer.h b/include/daw/daw_safe_pointer.h index 817b49b39..053f82737 100644 --- a/include/daw/daw_safe_pointer.h +++ b/include/daw/daw_safe_pointer.h @@ -16,6 +16,7 @@ #include #include #include +#include #include #if not defined( DAW_NO_SAFE_POINTER_CHECKS ) diff --git a/include/daw/daw_span_writer.h b/include/daw/daw_span_writer.h new file mode 100644 index 000000000..6a41afba8 --- /dev/null +++ b/include/daw/daw_span_writer.h @@ -0,0 +1,222 @@ +// 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 "daw/daw_concepts.h" +#include "daw/daw_cpp_feature_check.h" +#include "daw/daw_ensure.h" +#include "daw/daw_restrict.h" + +#include +#include +#include +#include +#include + +namespace daw { + + /// + /// @tparam T Destination type + /// @param out output span to write elements to + /// @param values parameters that are convertible to T to write to out + /// @return out.subspan( sizeof...( values ) ) + template + [[nodiscard]] constexpr std::span + write_to_span( std::span out, + daw::explicitly_convertible_to auto &&...values ) { + if constexpr( sizeof...( values ) == 0 ) { + return out; + } + daw_ensure( sizeof...( values ) <= out.size( ) ); + return [&]( std::index_sequence ) { + ( (void)( out[Is] = static_cast( values ) ), ... ); + return out.subspan( sizeof...( values ) ); + }( std::make_index_sequence{ } ); + } + + /// + /// @tparam T Destination type + /// @tparam R Range of elements convertible to T + /// @param out output span to write elements to + /// @param r input range values to copy write to out + /// @return out.subspan( std::ranges::size( r ) ) + /// The two ranges cannot overlap + template + requires( + std::ranges::contiguous_range + and daw::explicitly_convertible_to, T> ) + [[nodiscard]] constexpr std::span write_to_span( std::span out, + R const &r ) { + auto const sz = std::ranges::size( r ); + daw_ensure( sz <= out.size( ) ); + T *DAW_RESTRICT out_ptr = out.data( ); + auto *DAW_RESTRICT in_ptr = std::ranges::data( r ); + for( std::size_t n = 0; n < sz; ++n ) { + out_ptr[n] = static_cast( in_ptr[n] ); + } + return out.subspan( sz ); + } + + /// Write a string literal, minus trailing zero to span + /// @tparam T Destination type + /// @tparam N size, including trailing zero, of string literal + /// @param out output span to write elements to + /// @param str input string literal to write to out + /// @return out.subspan( N-1 ) + /// The two ranges cannot overlap and str must have a trailing 0 + template + requires( daw::explicitly_convertible_to ) + [[nodiscard]] constexpr std::span write_to_span_ntz( + std::span out, char const ( &str )[N] ) { + daw_ensure( str[N - 1] == '\0' ); + auto const sz = N - 1; + daw_ensure( sz <= out.size( ) ); + T *DAW_RESTRICT out_ptr = out.data( ); + auto *DAW_RESTRICT in_ptr = str; + for( std::size_t n = 0; n < sz; ++n ) { + out_ptr[n] = static_cast( in_ptr[n] ); + } + return out.subspan( sz ); + } + + template + requires( not std::is_const_v and not std::is_reference_v ) // + struct span_writer { + using pointer = T *; + using const_pointer = T const *; + using reference = T &; + using const_reference = T const &; + + private: + pointer m_first = nullptr; + std::size_t m_size = 0; + + constexpr void remove_prefix_unsafe( std::size_t n ) { + m_first += static_cast( n ); + m_size -= n; + } + + public: + span_writer( ) = default; + + constexpr span_writer( std::ranges::contiguous_range auto &r ) + : m_first( std::ranges::data( r ) ) + , m_size( std::ranges::size( r ) ) {} + + constexpr span_writer( std::ranges::contiguous_range auto &r, + std::size_t count ) + : m_first( std::ranges::data( r ) ) + , m_size( count ) { + daw_ensure( count <= std::ranges::size( r ) ); + } + + constexpr pointer data( ) { + return m_first; + } + + constexpr const_pointer data( ) const { + return m_first; + } + + constexpr pointer begin( ) { + return m_first; + } + + constexpr const_pointer begin( ) const { + return m_first; + } + + constexpr pointer end( ) { + return std::next( m_first, static_cast( m_size ) ); + } + + constexpr const_pointer end( ) const { + return std::next( m_first, static_cast( m_size ) ); + } + + constexpr std::size_t size( ) const { + return m_size; + } + + constexpr reference operator[]( std::size_t n ) { + daw_ensure( n < m_size ); + return m_first[n]; + } + + constexpr const_reference operator[]( std::size_t n ) const { + daw_ensure( n < m_size ); + return m_first[n]; + } + + constexpr span_writer subspan( std::size_t n ) const { + daw_ensure( n <= m_size ); + return span_writer{ .m_first = m_first + static_cast( n ), + .m_size = m_size - n }; + } + + constexpr span_writer &remove_prefix( std::size_t n ) { + daw_ensure( n <= m_size ); + m_first += static_cast( n ); + m_size -= n; + return *this; + } + + constexpr span_writer & + write( this auto &self, + daw::explicitly_convertible_to auto &&...values ) { + if constexpr( sizeof...( values ) == 0 ) { + return self; + } + daw_ensure( sizeof...( values ) <= self.m_size ); + [&]( std::index_sequence ) { + ( (void)( self.m_first[Is] = static_cast( values ) ), ... ); + }( std::make_index_sequence{ } ); + self.remove_prefix_unsafe( sizeof...( values ) ); + return self; + } + + template + requires( + std::ranges::contiguous_range and daw::explicitly_convertible_to< + std::ranges::range_reference_t, T> ) // + constexpr span_writer &write( this auto &self, R const &r ) { + auto const sz = std::ranges::size( r ); + daw_ensure( sz <= self.m_size ); + T *DAW_RESTRICT self_ptr = self.m_first; + auto *DAW_RESTRICT in_ptr = std::ranges::data( r ); + for( std::size_t n = 0; n < sz; ++n ) { + self_ptr[n] = static_cast( in_ptr[n] ); + } + self.remove_prefix_unsafe( sz ); + return self; + } + + template + requires( daw::explicitly_convertible_to ) // + constexpr span_writer &write_ntz( this auto &self, + char const ( &str )[N] ) { + daw_ensure( str[N - 1] == '\0' ); + auto const sz = N - 1; + daw_ensure( sz <= self.m_size ); + T *DAW_RESTRICT self_ptr = self.m_first; + auto *DAW_RESTRICT in_ptr = str; + for( std::size_t n = 0; n < sz; ++n ) { + self_ptr[n] = static_cast( in_ptr[n] ); + } + self.remove_prefix_unsafe( sz ); + return self; + } + }; + + template + span_writer( R ) -> span_writer>; + + template + span_writer( R, std::size_t ) -> span_writer>; +} // namespace daw diff --git a/include/daw/daw_string_view.h b/include/daw/daw_string_view.h index 04b4dd1a8..36be0f1e3 100644 --- a/include/daw/daw_string_view.h +++ b/include/daw/daw_string_view.h @@ -24,6 +24,7 @@ #include "daw/daw_cpp_feature_check.h" #include "daw/daw_data_end.h" #include "daw/daw_enable_requires.h" +#include "daw/daw_ensure.h" #include "daw/daw_fnv1a_hash.h" #include "daw/daw_is_constant_evaluated.h" #include "daw/daw_likely.h" @@ -461,6 +462,7 @@ namespace daw { struct zero_terminated_t { explicit zero_terminated_t( ) = default; }; + inline constexpr zero_terminated_t zero_terminated{ }; // tag type for non zero-terminated overloads @@ -491,10 +493,19 @@ namespace daw { DAW_CPP20_CX_ALLOC c_str_proxy( CharT const *str, std::size_t N, zero_terminated_t ) noexcept - : m_str{ buff_t{ str, N } } {} + : m_str{ buff_t{ str, N } } { +#if not defined( DAW_STRINGVIEW_NOZTERM_CHECK ) + daw_dbg_ensure( N == sv2_details::strlen( str ) ); +#endif + } DAW_CPP20_CX_ALLOC c_str_proxy( CharT const *str, std::size_t N ) noexcept - : m_str{ std::basic_string( str, N ) } {} + : m_str{ std::basic_string( str, N ) } { +#if not defined( DAW_STRINGVIEW_NOZTERM_CHECK ) + daw_dbg_ensure( N == sv2_details::strlen( + std::get<1>( m_str ).c_str( ) ) ); +#endif + } template static DAW_CPP20_CX_ALLOC std::basic_string diff --git a/include/daw/daw_traits.h b/include/daw/daw_traits.h index 761e71f6e..0280c4dbf 100644 --- a/include/daw/daw_traits.h +++ b/include/daw/daw_traits.h @@ -937,6 +937,9 @@ namespace daw { std::get<0>( std::declval( ) ); typename std::tuple_element_t<0, daw::remove_cvref_t>; }; + + template + concept TupleLike = is_tuple_like_v; #else template inline constexpr bool is_tuple_like_v = false; diff --git a/include/daw/daw_unique_ptr.h b/include/daw/daw_unique_ptr.h index 0d6e439ef..8cef9448b 100644 --- a/include/daw/daw_unique_ptr.h +++ b/include/daw/daw_unique_ptr.h @@ -176,14 +176,22 @@ namespace daw { m_ptr, unique_ptr_del::default_pointer_value_v ); } - constexpr deleter_t &get_deleter( ) { + constexpr deleter_t &get_deleter( ) & { return *static_cast( this ); } - constexpr deleter_t const &get_deleter( ) const { + constexpr deleter_t const &get_deleter( ) const & { return *static_cast( this ); } + constexpr deleter_t &&get_deleter( ) && { + return std::move( *static_cast( this ) ); + } + + constexpr deleter_t const &&get_deleter( ) const && { + return std::move( *static_cast( this ) ); + } + constexpr void reset( ) noexcept { if( unique_ptr_del::does_validity_check_v or m_ptr ) { get_deleter( )( daw::exchange( @@ -200,7 +208,7 @@ namespace daw { return m_ptr; } - constexpr pointer * get_out( ) noexcept { + constexpr pointer *get_out( ) noexcept { return std::addressof( m_ptr ); } diff --git a/include/daw/pipelines/algorithm.h b/include/daw/pipelines/algorithm.h index 35f620c79..73a1e877d 100644 --- a/include/daw/pipelines/algorithm.h +++ b/include/daw/pipelines/algorithm.h @@ -9,6 +9,7 @@ #pragma once #include "daw/daw_attributes.h" +#include "daw/daw_forward_lvalue.h" #include "daw/daw_iterator_traits.h" #include "daw/daw_move.h" #include "daw/pipelines/range.h" @@ -36,13 +37,14 @@ namespace daw::pipelines { [[nodiscard]] constexpr decltype( auto ) operator( )( Sortable auto &&r ) const { - std::sort( std::begin( r ), std::end( r ), + std::sort( std::begin( r ), + std::end( r ), [&]( auto const &lhs, auto const &rhs ) { return std::invoke( m_compare, std::invoke( m_projection, lhs ), std::invoke( m_projection, rhs ) ); } ); - return DAW_FWD( r ); + return daw::forward_lvalue( r ); } }; Sort_t( ) -> Sort_t, std::identity>; @@ -61,19 +63,22 @@ namespace daw::pipelines { template requires( not Range ) // - [[nodiscard]] DAW_CPP23_STATIC_CALL_OP constexpr auto - operator( )( C &&compare, P &&projection = Projection{ } ) + [[nodiscard]] DAW_CPP23_STATIC_CALL_OP + constexpr auto operator( )( C &&compare, + P &&projection = Projection{ } ) DAW_CPP23_STATIC_CALL_OP_CONST { return Max_t{ DAW_FWD( compare ), DAW_FWD( projection ) }; } [[nodiscard]] constexpr auto operator( )( Range auto &&r ) const { - return std::max_element( - std::begin( r ), std::end( r ), - [&]( auto const &lhs, auto const &rhs ) { - return std::invoke( m_compare, std::invoke( m_projection, lhs ), - std::invoke( m_projection, rhs ) ); - } ); + return std::max_element( std::begin( r ), + std::end( r ), + [&]( auto const &lhs, auto const &rhs ) { + return std::invoke( + m_compare, + std::invoke( m_projection, lhs ), + std::invoke( m_projection, rhs ) ); + } ); } }; Max_t( ) -> Max_t<>; @@ -92,19 +97,22 @@ namespace daw::pipelines { template requires( not Range ) // - [[nodiscard]] DAW_CPP23_STATIC_CALL_OP constexpr auto - operator( )( C &&compare, P &&projection = Projection{ } ) + [[nodiscard]] DAW_CPP23_STATIC_CALL_OP + constexpr auto operator( )( C &&compare, + P &&projection = Projection{ } ) DAW_CPP23_STATIC_CALL_OP_CONST { return Min_t{ DAW_FWD( compare ), DAW_FWD( projection ) }; } [[nodiscard]] constexpr auto operator( )( Range auto &&r ) const { - return std::min_element( - std::begin( r ), std::end( r ), - [&]( auto const &lhs, auto const &rhs ) { - return std::invoke( m_compare, std::invoke( m_projection, lhs ), - std::invoke( m_projection, rhs ) ); - } ); + return std::min_element( std::begin( r ), + std::end( r ), + [&]( auto const &lhs, auto const &rhs ) { + return std::invoke( + m_compare, + std::invoke( m_projection, lhs ), + std::invoke( m_projection, rhs ) ); + } ); } }; Min_t( ) -> Min_t<>; @@ -123,17 +131,20 @@ namespace daw::pipelines { template requires( not Range ) // - [[nodiscard]] DAW_CPP23_STATIC_CALL_OP constexpr auto - operator( )( C &&compare, P &&projection = Projection{ } ) + [[nodiscard]] DAW_CPP23_STATIC_CALL_OP + constexpr auto operator( )( C &&compare, + P &&projection = Projection{ } ) DAW_CPP23_STATIC_CALL_OP_CONST { return MinMax_t{ DAW_FWD( compare ), DAW_FWD( projection ) }; } [[nodiscard]] constexpr auto operator( )( Range auto &&r ) const { auto result = std::minmax_element( - std::begin( r ), std::end( r ), + std::begin( r ), + std::end( r ), [&]( auto const &lhs, auto const &rhs ) { - return std::invoke( m_compare, std::invoke( m_projection, lhs ), + return std::invoke( m_compare, + std::invoke( m_projection, lhs ), std::invoke( m_projection, rhs ) ); } ); return std::tuple{ result.first, result.second }; @@ -197,7 +208,8 @@ namespace daw::pipelines { [[nodiscard]] constexpr auto Contains( auto &&needle, auto &&compare, auto &&projection ) { return pimpl::Contains_t{ - DAW_FWD( needle ), DAW_FWD( compare ), + DAW_FWD( needle ), + DAW_FWD( compare ), DAW_FWD( projection ) }; // namespace daw::pipelines } } // namespace daw::pipelines \ No newline at end of file diff --git a/include/daw/pipelines/cache_last_view.h b/include/daw/pipelines/cache_last_view.h new file mode 100644 index 000000000..7250bc2fc --- /dev/null +++ b/include/daw/pipelines/cache_last_view.h @@ -0,0 +1,149 @@ +// 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 "daw/daw_iterator_traits.h" +#include "daw/iterator/daw_arrow_proxy.h" +#include "daw/pipelines/range.h" + +#include +#include +#include +#include + +namespace daw::pipelines { + template + struct cache_last_iterator { + using difference_type = daw::iter_difference_t; + using value_type = std::remove_reference_t>; + using reference = value_type &; + using pointer = daw::arrow_proxy; + using iterator_category = + daw::common_iterator_category_t, + std::bidirectional_iterator_tag>; + + private: + It m_iterator = It{ }; + std::optional m_cached = std::nullopt; + + public: + cache_last_iterator( ) = default; + + explicit constexpr cache_last_iterator( It i ) + : m_iterator( std::move( i ) ) {} + + constexpr reference value( ) { + if( not m_cached ) { + m_cached.emplace( *m_iterator ); + } + return *m_cached; + } + + constexpr reference operator*( ) { + return value( ); + } + + constexpr pointer operator->( ) { + return pointer{ value( ) }; + } + + constexpr cache_last_iterator &operator++( ) { + m_cached.reset( ); + ++m_iterator; + return *this; + } + + constexpr cache_last_iterator operator++( int ) { + auto result = *this; + operator++( ); + return result; + } + + constexpr cache_last_iterator &operator--( ) requires( + std::is_same_v ) { + + m_cached.reset( ); + --m_iterator; + return *this; + } + + constexpr cache_last_iterator operator--( int ) requires( + std::is_same_v ) { + + auto result = *this; + operator--( ); + return result; + } + constexpr bool operator==( cache_last_iterator const &rhs ) const { + return m_iterator == rhs.m_iterator; + } + + constexpr bool operator!=( cache_last_iterator const &rhs ) const { + return m_iterator != rhs.m_iterator; + } + + constexpr bool operator==( It const &rhs ) const { + return m_iterator == rhs; + } + + constexpr bool operator!=( It const &rhs ) const { + return m_iterator != rhs; + } + }; + + template + struct cache_last_view { + using iterator_first_t = cache_last_iterator>; + using iterator_last_t = cache_last_iterator>; + + private: + iterator_first_t m_first = iterator_first_t{ }; + iterator_last_t m_last = iterator_last_t{ }; + + public: + cache_last_view( ) = default; + + constexpr cache_last_view( std::convertible_to auto &&r ) + : m_first( std::begin( r ) ) + , m_last( std::end( r ) ) {} + + constexpr iterator_first_t begin( ) { + return m_first; + } + + constexpr iterator_first_t begin( ) const { + return m_first; + } + + constexpr iterator_last_t end( ) { + return m_last; + } + + constexpr iterator_last_t end( ) const { + return m_last; + } + }; + + template + cache_last_view( R ) -> cache_last_view; + + namespace pimpl { + struct CacheLast_t { + explicit CacheLast_t( ) = default; + + template + DAW_CPP23_STATIC_CALL_OP constexpr auto + operator( )( R &&r ) DAW_CPP23_STATIC_CALL_OP_CONST { + return cache_last_view{ DAW_FWD( r ) }; + } + }; + } // namespace pimpl + + inline constexpr auto CacheLast = pimpl::CacheLast_t{ }; +} // namespace daw::pipelines diff --git a/include/daw/pipelines/chunk.h b/include/daw/pipelines/chunk.h index d27a68ebe..246b438e0 100644 --- a/include/daw/pipelines/chunk.h +++ b/include/daw/pipelines/chunk.h @@ -8,6 +8,7 @@ #pragma once +#include "daw/cpp_17.h" #include "daw/daw_attributes.h" #include "daw/daw_iterator_traits.h" #include "daw/daw_move.h" @@ -54,7 +55,9 @@ namespace daw::pipelines::pimpl { public: explicit chunk_view( ) = default; - explicit chunk_view( Range auto &&r ) + template + requires( not std::same_as, chunk_view> ) // + explicit chunk_view( U &&r ) : m_range{ DAW_FWD( r ) } , m_iter{ std::begin( m_range ) } {} @@ -119,9 +122,9 @@ namespace daw::pipelines::pimpl { operator!=( chunk_view const &rhs ) const noexcept = default; }; template - chunk_view( R &&r ) -> chunk_view; + chunk_view( R &&r ) -> chunk_view>; template - chunk_view( R &&r, std::size_t ) -> chunk_view; + chunk_view( R &&r, std::size_t ) -> chunk_view>; struct Chunk_t { std::size_t chunk_size; diff --git a/include/daw/pipelines/concat.h b/include/daw/pipelines/concat.h index 448761310..09c867ee9 100644 --- a/include/daw/pipelines/concat.h +++ b/include/daw/pipelines/concat.h @@ -8,6 +8,7 @@ #pragma once +#include "daw/cpp_17.h" #include "daw/daw_iterator_traits.h" #include "daw/daw_move.h" #include "daw/daw_traits.h" @@ -115,7 +116,8 @@ namespace daw::pipelines { } }; template - concat_view( Ranges &&... ) -> concat_view; + concat_view( Ranges &&... ) + -> concat_view...>; namespace pimpl { struct Concat_t { diff --git a/include/daw/pipelines/copy.h b/include/daw/pipelines/copy.h new file mode 100644 index 000000000..da0e1f5a3 --- /dev/null +++ b/include/daw/pipelines/copy.h @@ -0,0 +1,32 @@ +// 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 "daw/daw_attributes.h" +#include "daw/daw_iterator_traits.h" +#include "daw/daw_move.h" +#include "daw/pipelines/range.h" + +namespace daw::pipelines::pimpl { + struct Copy_t { + explicit Copy_t( ) = default; + + template + DAW_CPP23_STATIC_CALL_OP constexpr auto + operator( )( T &&value ) DAW_CPP23_STATIC_CALL_OP_CONST { + return DAW_FWD( value ); + } + }; +} // namespace daw::pipelines::pimpl + +namespace daw::pipelines { + constexpr auto Copy( ) { + return pimpl::Copy_t{ }; + } +} // namespace daw::pipelines diff --git a/include/daw/pipelines/elements.h b/include/daw/pipelines/elements.h new file mode 100644 index 000000000..8ab449954 --- /dev/null +++ b/include/daw/pipelines/elements.h @@ -0,0 +1,410 @@ +// 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 "daw/cpp_17.h" +#include "daw/daw_iterator_traits.h" +#include "daw/daw_move.h" +#include "daw/iterator/daw_arrow_proxy.h" + +#include + +namespace daw::pipelines::pimpl { + template + struct element_iterator { + using iterator_category = daw::iter_category_t; + using value_type = + std::tuple_element_t>; + using reference = value_type; + using const_reference = + std::tuple_element_t>; + using pointer = arrow_proxy; + using const_pointer = arrow_proxy; + using difference_type = std::ptrdiff_t; + using size_type = std::size_t; + + private: + Iterator m_iter{ }; + + public: + explicit constexpr element_iterator( ) = default; + explicit constexpr element_iterator( Iterator it ) + : m_iter( std::move( it ) ) {} + + private: + template + [[nodiscard]] DAW_ATTRIB_INLINE static constexpr decltype( auto ) + raw_get( I &&iter ) { + return std::get( *DAW_FWD( iter ) ); + } + + public: + [[nodiscard]] constexpr auto &base( ) { + return m_iter; + } + + [[nodiscard]] constexpr auto const &base( ) const { + return m_iter; + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr reference + operator[]( size_type n ) requires( RandomIterator ) { + return raw_get( std::next( m_iter, static_cast( n ) ) ); + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr const_reference + operator[]( size_type n ) const requires( RandomIterator ) { + return raw_get( std::next( m_iter, static_cast( n ) ) ); + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr reference operator*( ) { + return raw_get( m_iter ); + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr const_reference + operator*( ) const { + return raw_get( m_iter ); + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr pointer operator->( ) { + return pointer( raw_get( m_iter ) ); + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr const_pointer + operator->( ) const { + return const_pointer( raw_get( m_iter ) ); + } + + DAW_ATTRIB_INLINE constexpr element_iterator &operator++( ) { + ++m_iter; + return *this; + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr element_iterator + operator++( int ) { + element_iterator result = *this; + ++m_iter; + return result; + } + + DAW_ATTRIB_INLINE constexpr element_iterator &operator--( ) + requires( BidirectionalIterator ) { + --m_iter; + return *this; + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr element_iterator operator--( int ) + requires( BidirectionalIterator ) { + element_iterator result = *this; + --m_iter; + return result; + } + + DAW_ATTRIB_INLINE constexpr element_iterator & + operator+=( difference_type n ) requires( RandomIterator ) { + m_iter += n; + return *this; + } + + DAW_ATTRIB_INLINE constexpr element_iterator & + operator-=( difference_type n ) requires( RandomIterator ) { + m_iter -= n; + return *this; + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr element_iterator + operator+( difference_type n ) const noexcept + requires( RandomIterator ) { + element_iterator result = *this; + m_iter += n; + return result; + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr element_iterator + operator-( difference_type n ) const noexcept + requires( RandomIterator ) { + element_iterator result = *this; + m_iter -= n; + return result; + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr difference_type + operator-( element_iterator const &rhs ) + requires( RandomIterator ) { + return m_iter - rhs.m_iter; + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr friend bool + operator==( element_iterator const &lhs, element_iterator const &rhs ) { + return lhs.m_iter == rhs.m_iter; + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr friend bool + operator!=( element_iterator const &lhs, element_iterator const &rhs ) { + return lhs.m_iter != rhs.m_iter; + } + + // clang-format off + [[nodiscard]] DAW_ATTRIB_INLINE constexpr friend auto + operator<=>( element_iterator const &lhs, element_iterator const &rhs ) + requires( RandomIterator ) { + return lhs.m_iter <=> rhs.m_iter; + } + // clang-format on + }; + + template + struct element_view + : range_base_t< + element_iterator>, Index>, + element_iterator>, + Index>> { + using range_t = std::remove_reference_t; + using daw_range_base_t = + range_base_t, Index>, + element_iterator, Index>>; + + using typename daw_range_base_t::iterator_first_t; + using typename daw_range_base_t::iterator_last_t; + + using value_type = daw::iter_value_t; + + iterator_first_t m_first = iterator_first_t{ }; + iterator_last_t m_last = iterator_last_t{ }; + + explicit element_view( ) = default; + + template + explicit constexpr element_view( U &&r ) + : m_first( std::begin( daw::forward_lvalue( r ) ) ) + , m_last( std::end( daw::forward_lvalue( r ) ) ) {} + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr iterator_first_t begin( ) const { + return m_first; + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr iterator_last_t end( ) const { + return m_last; + } + }; + + template + struct element_t { + explicit element_t( ) = default; + + template + DAW_CPP23_STATIC_CALL_OP constexpr auto + operator( )( R &&r ) DAW_CPP23_STATIC_CALL_OP_CONST { + return element_view, Index>{ + daw::forward_lvalue( r ) }; + } + }; + + template + struct elements_iterator { + using iterator_category = daw::iter_category_t; + using value_type = std::tuple< + std::tuple_element_t>...>; + using reference = value_type; + using const_reference = std::tuple< + std::tuple_element_t>...>; + using pointer = arrow_proxy; + using const_pointer = arrow_proxy; + using difference_type = std::ptrdiff_t; + using size_type = std::size_t; + + private: + Iterator m_iter{ }; + + public: + explicit constexpr elements_iterator( ) = default; + explicit constexpr elements_iterator( Iterator it ) + : m_iter( std::move( it ) ) {} + + private: + template + [[nodiscard]] DAW_ATTRIB_INLINE static constexpr auto raw_get( I &&iter ) { + using result_t = + std::tuple>...>; + auto &&r = *DAW_FWD( iter ); + return result_t{ std::get( r )... }; + } + + public: + [[nodiscard]] constexpr auto &base( ) { + return m_iter; + } + + [[nodiscard]] constexpr auto const &base( ) const { + return m_iter; + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr reference + operator[]( size_type n ) requires( RandomIterator ) { + return raw_get( std::next( m_iter, static_cast( n ) ) ); + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr const_reference + operator[]( size_type n ) const requires( RandomIterator ) { + return raw_get( std::next( m_iter, static_cast( n ) ) ); + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr reference operator*( ) { + return raw_get( m_iter ); + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr const_reference + operator*( ) const { + return raw_get( m_iter ); + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr pointer operator->( ) { + return pointer( raw_get( m_iter ) ); + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr const_pointer + operator->( ) const { + return const_pointer( raw_get( m_iter ) ); + } + + DAW_ATTRIB_INLINE constexpr elements_iterator &operator++( ) { + ++m_iter; + return *this; + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr elements_iterator + operator++( int ) { + elements_iterator result = *this; + ++m_iter; + return result; + } + + DAW_ATTRIB_INLINE constexpr elements_iterator &operator--( ) + requires( BidirectionalIterator ) { + --m_iter; + return *this; + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr elements_iterator + operator--( int ) requires( BidirectionalIterator ) { + elements_iterator result = *this; + --m_iter; + return result; + } + + DAW_ATTRIB_INLINE constexpr elements_iterator & + operator+=( difference_type n ) requires( RandomIterator ) { + m_iter += n; + return *this; + } + + DAW_ATTRIB_INLINE constexpr elements_iterator & + operator-=( difference_type n ) requires( RandomIterator ) { + m_iter -= n; + return *this; + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr elements_iterator + operator+( difference_type n ) const noexcept + requires( RandomIterator ) { + elements_iterator result = *this; + m_iter += n; + return result; + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr elements_iterator + operator-( difference_type n ) const noexcept + requires( RandomIterator ) { + elements_iterator result = *this; + m_iter -= n; + return result; + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr difference_type + operator-( elements_iterator const &rhs ) + requires( RandomIterator ) { + return m_iter - rhs.m_iter; + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr friend bool + operator==( elements_iterator const &lhs, elements_iterator const &rhs ) { + return lhs.m_iter == rhs.m_iter; + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr friend bool + operator!=( elements_iterator const &lhs, elements_iterator const &rhs ) { + return lhs.m_iter != rhs.m_iter; + } + + // clang-format off + [[nodiscard]] DAW_ATTRIB_INLINE constexpr friend auto + operator<=>( elements_iterator const &lhs, elements_iterator const &rhs ) + requires( RandomIterator ) { + return lhs.m_iter <=> rhs.m_iter; + } + // clang-format on + }; + + template + struct elements_view + : range_base_t< + elements_iterator>, + Indices...>, + elements_iterator>, + Indices...>> { + using range_t = std::remove_reference_t; + using daw_range_base_t = + range_base_t, Indices...>, + elements_iterator, Indices...>>; + + using typename daw_range_base_t::iterator_first_t; + using typename daw_range_base_t::iterator_last_t; + + using value_type = daw::iter_value_t; + + iterator_first_t m_first = iterator_first_t{ }; + iterator_last_t m_last = iterator_last_t{ }; + + explicit elements_view( ) = default; + + template + explicit constexpr elements_view( U &&r ) + : m_first( std::begin( daw::forward_lvalue( r ) ) ) + , m_last( std::end( daw::forward_lvalue( r ) ) ) {} + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr iterator_first_t begin( ) const { + return m_first; + } + + [[nodiscard]] DAW_ATTRIB_INLINE constexpr iterator_last_t end( ) const { + return m_last; + } + }; + + template + struct elements_t { + explicit elements_t( ) = default; + + template + DAW_CPP23_STATIC_CALL_OP constexpr auto + operator( )( R &&r ) DAW_CPP23_STATIC_CALL_OP_CONST { + return elements_view, Indices...>{ + daw::forward_lvalue( r ) }; + } + }; + +} // namespace daw::pipelines::pimpl + +namespace daw::pipelines { + template + inline constexpr auto Element = pimpl::element_t{ }; + + template + inline constexpr auto Elements = pimpl::elements_t{ }; +} // namespace daw::pipelines diff --git a/include/daw/pipelines/first.h b/include/daw/pipelines/first.h new file mode 100644 index 000000000..adac835e0 --- /dev/null +++ b/include/daw/pipelines/first.h @@ -0,0 +1,71 @@ +// 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 "daw/daw_cpp_feature_check.h" +#include "daw/daw_iterator_traits.h" + +#include +#include +#include +#include +#include + +namespace daw::pipelines::pimpl { + struct FirstRefFn { + explicit FirstRefFn( ) = default; + + DAW_CPP23_STATIC_CALL_OP constexpr auto + operator( )( Range auto &&r ) DAW_CPP23_STATIC_CALL_OP_CONST { + auto f = std::begin( r ); + auto l = std::end( r ); + using ref_t = daw::iter_reference_t; +#if defined( DAW_HAS_CPP26_OPTIONAL_REFS ) + using result_t = + std::conditional_t::value, + ref_t, + std::remove_cvref_t>; +#else + using result_t = std::conditional_t< + std::is_lvalue_reference::value, + std::reference_wrapper>, + std::remove_cvref_t>; +#endif + if( f == l ) { + return std::optional( ); + } + return std::optional( std::in_place, *f ); + } + }; + struct FirstFn { + explicit FirstFn( ) = default; + + DAW_CPP23_STATIC_CALL_OP constexpr auto + operator( )( Range auto &&r ) DAW_CPP23_STATIC_CALL_OP_CONST { + auto f = std::begin( r ); + auto l = std::end( r ); + using ref_t = daw::iter_reference_t; + using result_t = std::remove_cvref_t; + if( f == l ) { + return std::optional( ); + } + return std::optional( std::in_place, *f ); + } + }; +} // namespace daw::pipelines::pimpl + +namespace daw::pipelines { + constexpr pimpl::FirstRefFn FirstRef( ) { + return pimpl::FirstRefFn{ }; + } + + constexpr pimpl::FirstFn First( ) { + return pimpl::FirstFn{ }; + } +} // namespace daw::pipelines diff --git a/include/daw/pipelines/flatten.h b/include/daw/pipelines/flatten.h index d17d9f568..8fab762ec 100644 --- a/include/daw/pipelines/flatten.h +++ b/include/daw/pipelines/flatten.h @@ -25,7 +25,7 @@ namespace daw::pipelines::pimpl { template struct flatten_view_end_t { using iterator_t = daw::iterator_t; - using sub_iterator_t = daw::iterator_t>; + using sub_iterator_t = daw::iterator_t>; using iterator_category = std::forward_iterator_tag; using value_type = daw::iter_value_t; using reference = daw::iter_reference_t; @@ -50,7 +50,7 @@ namespace daw::pipelines::pimpl { using end_t = flatten_view_end_t; using m_range_t = daw::remove_cvrvref_t; - m_range_t m_range; + mutable m_range_t m_range; iterator_t m_range_first{ }; sub_iterator_t m_cur_first{ }; @@ -62,11 +62,11 @@ namespace daw::pipelines::pimpl { return std::begin( m_range ); } - [[nodiscard]] constexpr iterator_end_t raend( ) { + [[nodiscard]] constexpr auto raend( ) { return std::end( m_range ); } - [[nodiscard]] constexpr iterator_end_t raend( ) const { + [[nodiscard]] constexpr auto raend( ) const { return std::end( m_range ); } @@ -93,7 +93,10 @@ namespace daw::pipelines::pimpl { public: explicit flatten_view( ) = default; - explicit constexpr flatten_view( auto &&r ) + template + requires( not std::same_as, + flatten_view> ) // + explicit constexpr flatten_view( U &&r ) : m_range( DAW_FWD( r ) ) , m_range_first( rabegin( ) ) , m_cur_first( m_range_first == raend( ) @@ -152,7 +155,7 @@ namespace daw::pipelines::pimpl { } }; template - flatten_view( R && ) -> flatten_view; + flatten_view( R && ) -> flatten_view>; struct Flatten_t { [[nodiscard]] DAW_ATTRIB_INLINE DAW_CPP23_STATIC_CALL_OP constexpr auto diff --git a/include/daw/pipelines/map.h b/include/daw/pipelines/map.h index 7b5cb62cf..e46a6008b 100644 --- a/include/daw/pipelines/map.h +++ b/include/daw/pipelines/map.h @@ -27,7 +27,7 @@ namespace daw::pipelines { struct map_iterator { using iterator_category = daw::iter_category_t; using value_type = daw::remove_cvref_t>>>; + Fn, std::invoke_result_t>>>; using reference = value_type; using const_reference = value_type; using pointer = arrow_proxy; @@ -172,38 +172,37 @@ namespace daw::pipelines { template map_iterator( I, F, P ) -> map_iterator; - template - struct map_view : range_base_t> { - using daw_range_base_t = range_base_t>; + template + struct map_view + : range_base_t, Fn, Projection>, + map_iterator, Fn, Projection>> { + using daw_range_base_t = + range_base_t, Fn, Projection>, + map_iterator, Fn, Projection>>; + using typename daw_range_base_t::iterator_first_t; using typename daw_range_base_t::iterator_last_t; - using value_type = daw::iter_value_t>; + using value_type = daw::iter_value_t; - iterator_first_t m_first = iterator_first_t{ }; - iterator_last_t m_last = iterator_last_t{ }; + daw::remove_rvalue_ref_t m_range{ }; + iterator_first_t m_first{ }; + iterator_last_t m_last{ }; explicit map_view( ) = default; - explicit constexpr map_view( First first, Fn const &fn ) - requires( not Iterator ) - : m_first( first, fn ) {} - - explicit constexpr map_view( First first, Fn const &fn, - Projection const &projection ) - requires( not Iterator and not Iterator ) - : m_first( first, fn, projection ) {} - - explicit constexpr map_view( First first, First last, Fn const &fn ) + explicit constexpr map_view( Range auto &&r, Fn const &fn ) requires( not Iterator ) - : m_first( first, fn ) - , m_last( last, fn ) {} + : m_range( DAW_FWD( r ) ) + , m_first{ std::begin( m_range ), fn } + , m_last{ std::end( m_range ), fn } {} - explicit constexpr map_view( First first, First last, Fn const &fn, + explicit constexpr map_view( Range auto &&r, Fn const &fn, Projection const &projection ) requires( not Iterator and not Iterator ) - : m_first( first, fn, projection ) - , m_last( last, fn, projection ) {} + : m_range( DAW_FWD( r ) ) + , m_first{ std::begin( m_range ), fn, projection } + , m_last{ std::end( m_range ), fn, projection } {} [[nodiscard]] DAW_ATTRIB_INLINE constexpr iterator_first_t begin( ) const { return m_first; @@ -213,21 +212,13 @@ namespace daw::pipelines { return m_last; } }; - template - requires( not Iterator ) // - map_view( I, F ) -> map_view; - - template - requires( not Iterator and not Iterator

) // - map_view( I, F, P ) -> map_view; - - template + template requires( not Iterator ) // - map_view( I, I, F ) -> map_view; + map_view( R &&, F ) -> map_view, F>; - template + template requires( not Iterator and not Iterator

) // - map_view( I, I, F, P ) -> map_view; + map_view( R &&, F, P ) -> map_view, F, P>; namespace pimpl { template @@ -236,23 +227,27 @@ namespace daw::pipelines { DAW_NO_UNIQUE_ADDRESS Projection m_projection = Projection{ }; [[nodiscard]] constexpr auto operator( )( auto &&r ) const { - using R = DAW_TYPEOF( r ); - static_assert( - std::invocable>, - "Projection must be invocable with the range_value_t" ); - using projected_t = std::invoke_result_t>; - + using R = decltype( r ); if constexpr( Range ) { + static_assert( + std::invocable>, + "Projection must be invocable with the range_value_t" ); + using projected_t = + std::invoke_result_t>; + static_assert( std::invocable, "Map requires the function to be able to be called " "with invoke and the range_reference_t(e.g. invoke( " "MapFn, *it ) )" ); static_assert( traits::NoVoidResults, "Map requires the result to not be void" ); - return map_view, Fn, Projection>( - std::begin( DAW_FWD( r ) ), std::end( DAW_FWD( r ) ), m_func, - m_projection ); + return map_view( + DAW_FWD( r ), m_func, m_projection ); } else { + static_assert( std::invocable, + "Projection must be invocable with R" ); + using projected_t = std::invoke_result_t; + static_assert( std::invocable, "Map requires the function to be able to be called " "with invoke and passed value" ); @@ -273,15 +268,15 @@ namespace daw::pipelines { struct MapApply_t { DAW_NO_UNIQUE_ADDRESS Fn m_func; - [[nodiscard]] constexpr auto operator( )( auto &&r ) const { - using R = DAW_TYPEOF( r ); + template + [[nodiscard]] constexpr auto operator( )( R &&r ) const { static_assert( traits::is_applicable_v>, "MapApply requires the function to be able to be called " "with apply and the range_reference_t" ); auto func = m_func; - return map_view( std::begin( r ), std::end( r ), [=]( auto &&tp ) { - return std::apply( func, tp ); - } ); + return map_view{ DAW_FWD( r ), [=]( auto &&tp ) { + return std::apply( func, tp ); + } }; } }; template @@ -293,8 +288,8 @@ namespace daw::pipelines { T hi; DAW_NO_UNIQUE_ADDRESS Compare compare; - [[nodiscard]] constexpr auto operator( )( auto &&r ) const { - using R = DAW_TYPEOF( r ); + template + [[nodiscard]] constexpr auto operator( )( R &&r ) const { auto h = hi; auto l = lo; auto c = compare; @@ -303,10 +298,9 @@ namespace daw::pipelines { static_assert( std::convertible_to, "Clamp requires a lo/hi values convertible to the " "range value type" ); - return map_view( std::begin( r ), std::end( r ), - [=]( value_type const &v ) { - return std::clamp( v, l, h, c ); - } ); + return map_view{ DAW_FWD( r ), [=]( value_type const &v ) { + return std::clamp( v, l, h, c ); + } }; } else { static_assert( std::convertible_to>, diff --git a/include/daw/pipelines/pipeline.h b/include/daw/pipelines/pipeline.h index f3c4b5ae9..8d4419998 100644 --- a/include/daw/pipelines/pipeline.h +++ b/include/daw/pipelines/pipeline.h @@ -36,14 +36,14 @@ namespace daw::pipelines::pimpl { template [[nodiscard]] DAW_ATTRIB_FLATINLINE constexpr auto - pipeline( std::tuple const &tpfns, R &&r, Ranges &&...ranges ) { + pipeline( std::tuple const &functions, R &&r, Ranges &&...ranges ) { using std::get; if constexpr( Idx > 0 ) { - return std::invoke( - get( tpfns ), - pipeline( tpfns, DAW_FWD( r ), DAW_FWD( ranges )... ) ); + auto &¶m = + pipeline( functions, DAW_FWD( r ), DAW_FWD( ranges )... ); + return get( functions )( DAW_FWD( param ) ); } else { - return std::invoke( get<0>( tpfns ), DAW_FWD( r ), DAW_FWD( ranges )... ); + return get<0>( functions )( DAW_FWD( r ), DAW_FWD( ranges )... ); } } diff --git a/include/daw/pipelines/slide.h b/include/daw/pipelines/slide.h index 8be552291..c4bae70f7 100644 --- a/include/daw/pipelines/slide.h +++ b/include/daw/pipelines/slide.h @@ -21,11 +21,11 @@ namespace daw::pipelines::pimpl { template struct slide_view { using iterator = daw::iterator_t; - using const_iterator = daw::iterator_t>; + using const_iterator = daw::const_iterator_t; using iterator_category = daw::range_category_t; using value_type = range_t; using reference = range_t; - using const_reference = range_t; + using const_reference = range_t; using difference_type = std::ptrdiff_t; using i_am_a_daw_slide_view_iterator_class = void; @@ -55,7 +55,9 @@ namespace daw::pipelines::pimpl { public: explicit slide_view( ) = default; - explicit slide_view( Range auto &&r ) + template + requires( not std::same_as, slide_view> ) // + explicit slide_view( U &&r ) : m_range{ DAW_FWD( r ) } , m_iter{ std::begin( m_range ) } {} @@ -120,9 +122,9 @@ namespace daw::pipelines::pimpl { operator!=( slide_view const &rhs ) const noexcept = default; }; template - slide_view( R &&r ) -> slide_view; + slide_view( R &&r ) -> slide_view>; template - slide_view( R &&r, std::size_t ) -> slide_view; + slide_view( R &&r, std::size_t ) -> slide_view>; struct Slide_t { std::size_t slide_size = 1; diff --git a/include/daw/pipelines/swizzle.h b/include/daw/pipelines/swizzle.h index 62cdd1da4..986d33405 100644 --- a/include/daw/pipelines/swizzle.h +++ b/include/daw/pipelines/swizzle.h @@ -26,7 +26,7 @@ namespace daw::pipelines::pimpl { typename daw::remove_cvref_t< R>::i_am_a_daw_zip_iterator_class; } ) { - return map_view{ std::begin( r ), std::end( r ), []( auto &&tp ) { + return map_view{ DAW_FWD( r ), []( auto &&tp ) { return daw::forward_nonrvalue_as_tuple( get( DAW_FWD( tp ) )... ); } }; @@ -35,7 +35,7 @@ namespace daw::pipelines::pimpl { static_assert( std::max( { Indices... } ) < std::tuple_size_v>, "Swizzle - Index out of range of tuple type" ); - return map_view{ std::begin( r ), std::end( r ), []( auto &&v ) { + return map_view{ DAW_FWD( r ), []( auto &&v ) { return daw::forward_nonrvalue_as_tuple( get( DAW_FWD( v ) )... ); } }; diff --git a/include/daw/pipelines/to.h b/include/daw/pipelines/to.h index d981a5080..b42a4b29a 100644 --- a/include/daw/pipelines/to.h +++ b/include/daw/pipelines/to.h @@ -48,9 +48,7 @@ namespace daw::pipelines::pimpl { operator( )( R &&r ) DAW_CPP23_STATIC_CALL_OP_CONST { #if defined( __cpp_lib_containers_ranges ) #if __cpp_lib_containers_ranges >= 202202L - if constexpr( requires { - Container( std::from_range, DAW_FWD( r ) ); - } ) { + if constexpr( requires { Container( std::from_range, DAW_FWD( r ) ); } ) { return Container( std::from_range, DAW_FWD( r ) ); } else { #endif diff --git a/include/daw/pipelines/unique.h b/include/daw/pipelines/unique.h index b63c5c489..7483a0477 100644 --- a/include/daw/pipelines/unique.h +++ b/include/daw/pipelines/unique.h @@ -100,11 +100,58 @@ namespace daw::pipelines { template unique_view( I ) -> unique_view; + template + struct unique_range { + using value_type = daw::range_value_t; + static_assert( requires( value_type const &v ) { v == v; } ); + using iterator = unique_view>; + using const_iterator = unique_view>; + + private: + R m_range; + + public: + explicit constexpr unique_range( R const &r ) noexcept + : m_range{ r } {} + + explicit constexpr unique_range( R &&r ) noexcept + : m_range{ std::move( r ) } {} + + [[nodiscard]] constexpr iterator begin( ) { + return iterator{ std::begin( m_range ), std::end( m_range ) }; + } + + [[nodiscard]] constexpr const_iterator begin( ) const { + return const_iterator{ std::begin( m_range ), std::end( m_range ) }; + } + + [[nodiscard]] constexpr iterator end( ) { + return iterator{ std::end( m_range ), std::end( m_range ) }; + } + + [[nodiscard]] constexpr const_iterator end( ) const { + return const_iterator{ std::end( m_range ), std::end( m_range ) }; + } + + [[nodiscard]] constexpr friend bool + operator==( unique_range const &lhs, unique_range const &rhs ) = default; + + [[nodiscard]] constexpr friend bool + operator!=( unique_range const &lhs, unique_range const &rhs ) = default; + }; + + template + unique_range( R && ) -> unique_range>; + namespace pimpl { struct Unique_t { [[nodiscard]] DAW_CPP23_STATIC_CALL_OP constexpr auto operator( )( Range auto &&r ) DAW_CPP23_STATIC_CALL_OP_CONST { - return unique_view( std::begin( r ), std::end( r ) ); + if constexpr( std::is_rvalue_reference_v ) { + return unique_range{ DAW_FWD( r ) }; + } else { + return unique_view{ DAW_FWD( r ) }; + } } }; } // namespace pimpl diff --git a/include/daw/pipelines/zip.h b/include/daw/pipelines/zip.h index e2893c7cd..be2e09eb8 100644 --- a/include/daw/pipelines/zip.h +++ b/include/daw/pipelines/zip.h @@ -148,14 +148,14 @@ namespace daw::pipelines { // bidirectional iterator interface constexpr zip_iterator &operator--( ) requires( BidirectionalIteratorTag ) { - decrement( m_iters ); + decrement( zip_indices( ) ); return *this; } [[nodiscard]] constexpr zip_iterator operator--( int ) requires( BidirectionalIteratorTag ) { auto tmp = *this; - decrement( m_iters ); + decrement( zip_indices( ) ); return tmp; } diff --git a/include/daw/traits/daw_traits_integer_type.h b/include/daw/traits/daw_traits_integer_type.h new file mode 100644 index 000000000..d65d76343 --- /dev/null +++ b/include/daw/traits/daw_traits_integer_type.h @@ -0,0 +1,22 @@ +// 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 + +namespace daw::traits { + template + concept IntegerEnum = std::is_integral_v or std::is_enum_v; + // Get the underlying type or integral type passed + template + using integral_type_t = + typename std::conditional_t, std::underlying_type, + std::type_identity>::type; + +} // namespace daw::traits diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 91c796a27..f48a703e4 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -5,282 +5,285 @@ # #Official repository : https: // github.com/beached/header_libraries # -cmake_policy(SET CMP0065 NEW) +cmake_policy( SET CMP0065 NEW ) -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_EXTENSIONS OFF) +set( CMAKE_CXX_STANDARD_REQUIRED ON ) +set( CMAKE_CXX_EXTENSIONS OFF ) -if (CMAKE_BUILD_TYPE EQUAL "Debug") - add_compile_definitions(DEBUG=1) -endif () +if( CMAKE_BUILD_TYPE EQUAL "Debug" ) + add_compile_definitions( DEBUG=1 ) +endif() -set(TEST_SOURCES - InputIterator_test.cpp - cpp_17_test.cpp - daw_algorithm_test.cpp - daw_arith_traits_test.cpp - daw_array_compare_test.cpp - daw_array_test.cpp - daw_ascii_test.cpp - daw_assume_test.cpp - daw_attributes_test.cpp - daw_benchmark_test.cpp - daw_bounded_vector_test.cpp - daw_constant_test.cpp - daw_container_algorithm_test.cpp - daw_contract_test.cpp - daw_cx_offset_of_test.cpp - daw_cxmath_test.cpp - daw_endian_test.cpp - daw_exception_test.cpp - daw_expected_test.cpp - daw_fnv1a_hash_test.cpp - daw_function_ref_test.cpp - daw_function_table_test.cpp - daw_function_test.cpp - daw_function_view_test.cpp - daw_fwd_pack_apply_test.cpp - daw_generic_hash_test.cpp - daw_graph_algorithm_test.cpp - daw_graph_test.cpp - daw_hash_set_test.cpp - daw_is_any_of_test.cpp - daw_iterator_argument_iterator_test.cpp - daw_iterator_back_inserter_test.cpp - daw_iterator_checked_iterator_proxy_test.cpp - daw_iterator_chunk_iterator_test.cpp - daw_iterator_circular_iterator_test.cpp - daw_iterator_counting_iterators_test.cpp - daw_iterator_end_inserter_test.cpp - daw_iterator_find_iterator_test.cpp - daw_iterator_indexed_iterator_test.cpp - daw_iterator_inserter_test.cpp - daw_iterator_integer_iterator_test.cpp - daw_iterator_iota_iterator_test.cpp - daw_iterator_output_stream_iterator_test.cpp - daw_iterator_random_iterator_test.cpp - daw_iterator_repeat_n_char_iterator_test.cpp - daw_iterator_reverse_iterator_test.cpp - daw_iterator_sorted_insert_iterator_test.cpp - daw_iterator_zipiter_test.cpp - daw_keep_n_test.cpp - daw_lift_test.cpp - daw_logic_test.cpp - daw_math_test.cpp - daw_memory_mapped_file_test.cpp - daw_metro_hash_test.cpp - daw_natural_test.cpp - daw_not_null_test.cpp - daw_nth_pack_element_test.cpp - daw_optional_test.cpp - daw_ordered_map_test.cpp - daw_overload_test.cpp - daw_parse_args_test.cpp - daw_parse_to_test.cpp - daw_parser_helper_sv_test.cpp - daw_poly_var_test.cpp - daw_prop_const_ptr_test.cpp - daw_random_test.cpp - daw_read_file_test.cpp - daw_read_only_test.cpp - daw_ref_counted_pointer_test.cpp - daw_ring_adaptor_test.cpp - daw_rw_ref_test.cpp - daw_scope_guard_test.cpp - daw_simple_array_test.cpp - daw_sip_hash_test.cpp - daw_size_literals_test.cpp - daw_span_test.cpp - daw_stack_function_test.cpp - daw_string_concat_test.cpp - daw_string_view2_test.cpp - daw_take_test.cpp - daw_traits_test.cpp - daw_tuple_helper_test.cpp - daw_tuple_test.cpp - daw_uint_buffer_test.cpp - daw_uninitialized_storage_test.cpp - daw_union_pair_test.cpp - daw_unique_array_test.cpp - daw_unique_ptr_test.cpp - daw_utility_test.cpp - daw_validated_test.cpp - daw_value_ptr_test.cpp - daw_variant_cast_test.cpp - daw_view_test.cpp - daw_virtual_base_test.cpp - daw_visit_test.cpp - daw_visit_as_test.cpp - daw_zipcontainer_test.cpp - sbo_test.cpp - static_hash_table_test.cpp -) +set( TEST_SOURCES + InputIterator_test.cpp + cpp_17_test.cpp + daw_algorithm_test.cpp + daw_arith_traits_test.cpp + daw_array_compare_test.cpp + daw_array_test.cpp + daw_ascii_test.cpp + daw_assume_test.cpp + daw_attributes_test.cpp + daw_benchmark_test.cpp + daw_bounded_vector_test.cpp + daw_constant_test.cpp + daw_container_algorithm_test.cpp + daw_contract_test.cpp + daw_cx_offset_of_test.cpp + daw_cxmath_test.cpp + daw_endian_test.cpp + daw_exception_test.cpp + daw_expected_test.cpp + daw_fnv1a_hash_test.cpp + daw_function_ref_test.cpp + daw_function_table_test.cpp + daw_function_test.cpp + daw_function_view_test.cpp + daw_fwd_pack_apply_test.cpp + daw_generic_hash_test.cpp + daw_graph_algorithm_test.cpp + daw_graph_test.cpp + daw_hash_set_test.cpp + daw_is_any_of_test.cpp + daw_iterator_argument_iterator_test.cpp + daw_iterator_back_inserter_test.cpp + daw_iterator_checked_iterator_proxy_test.cpp + daw_iterator_chunk_iterator_test.cpp + daw_iterator_circular_iterator_test.cpp + daw_iterator_counting_iterators_test.cpp + daw_iterator_end_inserter_test.cpp + daw_iterator_find_iterator_test.cpp + daw_iterator_indexed_iterator_test.cpp + daw_iterator_inserter_test.cpp + daw_iterator_integer_iterator_test.cpp + daw_iterator_iota_iterator_test.cpp + daw_iterator_output_stream_iterator_test.cpp + daw_iterator_random_iterator_test.cpp + daw_iterator_repeat_n_char_iterator_test.cpp + daw_iterator_reverse_iterator_test.cpp + daw_iterator_sorted_insert_iterator_test.cpp + daw_iterator_zipiter_test.cpp + daw_keep_n_test.cpp + daw_lift_test.cpp + daw_logic_test.cpp + daw_math_test.cpp + daw_memory_mapped_file_test.cpp + daw_metro_hash_test.cpp + daw_natural_test.cpp + daw_not_null_test.cpp + daw_nth_pack_element_test.cpp + daw_optional_test.cpp + daw_ordered_map_test.cpp + daw_overload_test.cpp + daw_parse_args_test.cpp + daw_parse_to_test.cpp + daw_parser_helper_sv_test.cpp + daw_poly_var_test.cpp + daw_prop_const_ptr_test.cpp + daw_random_test.cpp + daw_read_file_test.cpp + daw_read_only_test.cpp + daw_ref_counted_pointer_test.cpp + daw_ring_adaptor_test.cpp + daw_rw_ref_test.cpp + daw_scope_guard_test.cpp + daw_simple_array_test.cpp + daw_sip_hash_test.cpp + daw_size_literals_test.cpp + daw_span_test.cpp + daw_stack_function_test.cpp + daw_string_concat_test.cpp + daw_string_view2_test.cpp + daw_take_test.cpp + daw_traits_test.cpp + daw_tuple_helper_test.cpp + daw_tuple_test.cpp + daw_uint_buffer_test.cpp + daw_uninitialized_storage_test.cpp + daw_union_pair_test.cpp + daw_unique_array_test.cpp + daw_unique_ptr_test.cpp + daw_utility_test.cpp + daw_validated_test.cpp + daw_value_ptr_test.cpp + daw_variant_cast_test.cpp + daw_view_test.cpp + daw_virtual_base_test.cpp + daw_visit_test.cpp + daw_visit_as_test.cpp + daw_zipcontainer_test.cpp + sbo_test.cpp + static_hash_table_test.cpp + ) -set(DEPRECATED_TEST_SOURCES - daw_cstring_test.cpp - daw_bounded_graph_test.cpp - daw_bounded_hash_map_test.cpp - daw_bounded_hash_set_test.cpp - daw_bounded_string_test.cpp - daw_carray_test.cpp - daw_checked_expected_test.cpp - daw_clumpy_sparsy_test.cpp - daw_copiable_unique_ptr_test.cpp - daw_fixed_array_test.cpp - daw_fixed_lookup_test.cpp - daw_heap_array_test.cpp - daw_heap_value_test.cpp - daw_optional_poly_test.cpp - daw_poly_vector_test.cpp - daw_range_collection_test.cpp - daw_range_test.cpp - daw_safe_string_test.cpp - daw_stack_quick_sort_test.cpp - daw_string_split_range_test.cpp - daw_string_test.cpp - daw_string_view1_test.cpp - daw_vector_test.cpp -) +set( DEPRECATED_TEST_SOURCES + daw_cstring_test.cpp + daw_bounded_graph_test.cpp + daw_bounded_hash_map_test.cpp + daw_bounded_hash_set_test.cpp + daw_bounded_string_test.cpp + daw_carray_test.cpp + daw_checked_expected_test.cpp + daw_clumpy_sparsy_test.cpp + daw_copiable_unique_ptr_test.cpp + daw_fixed_array_test.cpp + daw_fixed_lookup_test.cpp + daw_heap_array_test.cpp + daw_heap_value_test.cpp + daw_optional_poly_test.cpp + daw_poly_vector_test.cpp + daw_range_collection_test.cpp + daw_range_test.cpp + daw_safe_string_test.cpp + daw_stack_quick_sort_test.cpp + daw_string_split_range_test.cpp + daw_string_test.cpp + daw_string_view1_test.cpp + daw_vector_test.cpp + ) -set(CPP23_TEST_SOURCES - daw_enumerate_tuple_test.cpp -) +set( CPP23_TEST_SOURCES + daw_enumerate_tuple_test.cpp + daw_span_writer_test.cpp + ) -set(CPP20_TEST_SOURCES - daw_atomic_wait_test.cpp - daw_any_if_test.cpp - daw_concepts_test.cpp - daw_contiguous_view_test.cpp - daw_formatters_test.cpp - daw_from_string_test.cpp - daw_iter_view_test.cpp - daw_move_only_test.cpp - daw_named_params_test.cpp - daw_observer_ptr_test.cpp - daw_poly_value_test.cpp -) +set( CPP20_TEST_SOURCES + daw_atomic_wait_test.cpp + daw_any_if_test.cpp + daw_bitset_helper_test.cpp + daw_concepts_test.cpp + daw_contiguous_view_test.cpp + daw_formatters_test.cpp + daw_from_string_test.cpp + daw_iter_view_test.cpp + daw_poly_value_test.cpp + daw_maybe_unique_ptr_test.cpp + daw_move_only_test.cpp + daw_named_params_test.cpp + daw_observer_ptr_test.cpp + ) -set(CPP20_NOT_MSVC_TEST_SOURCES - daw_pipelines_test.cpp - vector_test.cpp -) +set( CPP20_NOT_MSVC_TEST_SOURCES + daw_pipelines_test.cpp + vector_test.cpp + ) #NOT COMPLETED daw_iterator_split_iterator_test.cpp #NOT COMPLETED daw_static_bitset_test.cpp #NOT COMPLETED daw_string_fmt_test.cpp -set(NOT_MSVC_TEST_SOURCES - daw_can_constant_evaluate_test.cpp - daw_parser_helper_test.cpp - daw_piecewise_factory_test.cpp - daw_tuple2_test.cpp -) +set( NOT_MSVC_TEST_SOURCES + daw_can_constant_evaluate_test.cpp + daw_parser_helper_test.cpp + daw_piecewise_factory_test.cpp + daw_tuple2_test.cpp + ) #not included in CI as they are not ready -set(DEV_TEST_SOURCES - daw_bind_args_at_test.cpp - daw_container_help_test.cpp - daw_bit_queues_test.cpp - daw_bit_test.cpp - daw_min_perfect_hash_test.cpp - daw_range_algorithm_test.cpp - daw_sort_n_test.cpp - daw_tracked_allocator_test.cpp -) +set( DEV_TEST_SOURCES + daw_bind_args_at_test.cpp + daw_container_help_test.cpp + daw_bit_queues_test.cpp + daw_bit_test.cpp + daw_min_perfect_hash_test.cpp + daw_range_algorithm_test.cpp + daw_sort_n_test.cpp + daw_tracked_allocator_test.cpp + ) -include(cmake/test_compiler_options.cmake) +include( cmake/test_compiler_options.cmake ) -find_package(Threads REQUIRED) +find_package( Threads REQUIRED ) #Allows building all in some IDE's -add_custom_target(${PROJECT_NAME}_full) +add_custom_target( ${PROJECT_NAME}_full ) -add_library(daw_test INTERFACE) -target_link_libraries(daw_test INTERFACE daw::header_libraries) -target_compile_options(daw_test INTERFACE $<$:/permissive->) +add_library( daw_test INTERFACE ) +target_link_libraries( daw_test INTERFACE daw::header_libraries ) +target_compile_options( daw_test INTERFACE $<$:/permissive-> ) -set(all_tests ${TEST_SOURCES}) +set( all_tests ${TEST_SOURCES} ) -if (NOT CMAKE_CXX_COMPILER_ID MATCHES "MSVC") - list(APPEND all_tests ${NOT_MSVC_TEST_SOURCES}) -endif () +if( NOT CMAKE_CXX_COMPILER_ID MATCHES "MSVC" ) + list( APPEND all_tests ${NOT_MSVC_TEST_SOURCES} ) +endif() -foreach (CUR_TEST IN LISTS all_tests) - string(REPLACE ".cpp" "" CUR_TEST_NAME ${CUR_TEST}) - add_executable("${CUR_TEST_NAME}" "${CUR_TEST}") - target_link_libraries(${CUR_TEST_NAME} PRIVATE daw_test) - add_test(${CUR_TEST_NAME}_test ${CUR_TEST_NAME}) - add_dependencies(${PROJECT_NAME}_full ${CUR_TEST_NAME}) -endforeach () +foreach( CUR_TEST IN LISTS all_tests ) + string( REPLACE ".cpp" "" CUR_TEST_NAME ${CUR_TEST} ) + add_executable( "${CUR_TEST_NAME}" "${CUR_TEST}" ) + target_link_libraries( ${CUR_TEST_NAME} PRIVATE daw_test ) + add_test( ${CUR_TEST_NAME}_test ${CUR_TEST_NAME} ) + add_dependencies( ${PROJECT_NAME}_full ${CUR_TEST_NAME} ) +endforeach() -option(DAW_ENABLE_DEPRECATED_TESTING "Build unit tests still for deprecated libraries" OFF) -foreach (CUR_TEST IN LISTS DEPRECATED_TEST_SOURCES) - string(REPLACE ".cpp" "" CUR_TEST_NAME ${CUR_TEST}) - if (DAW_ENABLE_DEPRECATED_TESTING) - add_executable("${CUR_TEST_NAME}" "deprecated/${CUR_TEST}") - add_test(${CUR_TEST_NAME}_test ${CUR_TEST_NAME}) - add_dependencies(${PROJECT_NAME}_full ${CUR_TEST_NAME}) - else () - add_executable("${CUR_TEST_NAME}" EXCLUDE_FROM_ALL "deprecated/${CUR_TEST}") - endif () - target_link_libraries(${CUR_TEST_NAME} PRIVATE daw_test) -endforeach () +option( DAW_ENABLE_DEPRECATED_TESTING "Build unit tests still for deprecated libraries" OFF ) +foreach( CUR_TEST IN LISTS DEPRECATED_TEST_SOURCES ) + string( REPLACE ".cpp" "" CUR_TEST_NAME ${CUR_TEST} ) + if( DAW_ENABLE_DEPRECATED_TESTING ) + add_executable( "${CUR_TEST_NAME}" "deprecated/${CUR_TEST}" ) + add_test( ${CUR_TEST_NAME}_test ${CUR_TEST_NAME} ) + add_dependencies( ${PROJECT_NAME}_full ${CUR_TEST_NAME} ) + else() + add_executable( "${CUR_TEST_NAME}" EXCLUDE_FROM_ALL "deprecated/${CUR_TEST}" ) + endif() + target_link_libraries( ${CUR_TEST_NAME} PRIVATE daw_test ) +endforeach() -if (CMAKE_CXX_STANDARD STRGREATER_EQUAL "20") - foreach (CUR_TEST IN LISTS CPP20_TEST_SOURCES) - string(REPLACE ".cpp" "" CUR_TEST_NAME ${CUR_TEST}) - add_executable("${CUR_TEST_NAME}" "${CUR_TEST}") - target_link_libraries(${CUR_TEST_NAME} PRIVATE daw_test) - target_compile_features(${CUR_TEST_NAME} PUBLIC cxx_std_20) - add_test(${CUR_TEST_NAME}_test ${CUR_TEST_NAME}) - add_dependencies(${PROJECT_NAME}_full ${CUR_TEST_NAME}) - endforeach () - if (NOT MSVC) - foreach (CUR_TEST IN LISTS CPP20_NOT_MSVC_TEST_SOURCES) - string(REPLACE ".cpp" "" CUR_TEST_NAME ${CUR_TEST}) - add_executable("${CUR_TEST_NAME}" "${CUR_TEST}") - target_link_libraries(${CUR_TEST_NAME} PRIVATE daw_test) - target_compile_features(${CUR_TEST_NAME} PUBLIC cxx_std_20) - add_test(${CUR_TEST_NAME}_test ${CUR_TEST_NAME}) - add_dependencies(${PROJECT_NAME}_full ${CUR_TEST_NAME}) - endforeach () - endif () -else () - message(STATUS "Disabling C++20 tests") -endif () +if( CMAKE_CXX_STANDARD STRGREATER_EQUAL "20" ) + foreach( CUR_TEST IN LISTS CPP20_TEST_SOURCES ) + string( REPLACE ".cpp" "" CUR_TEST_NAME ${CUR_TEST} ) + add_executable( "${CUR_TEST_NAME}" "${CUR_TEST}" ) + target_link_libraries( ${CUR_TEST_NAME} PRIVATE daw_test ) + target_compile_features( ${CUR_TEST_NAME} PUBLIC cxx_std_20 ) + add_test( ${CUR_TEST_NAME}_test ${CUR_TEST_NAME} ) + add_dependencies( ${PROJECT_NAME}_full ${CUR_TEST_NAME} ) + endforeach() + if( NOT MSVC ) + foreach( CUR_TEST IN LISTS CPP20_NOT_MSVC_TEST_SOURCES ) + string( REPLACE ".cpp" "" CUR_TEST_NAME ${CUR_TEST} ) + add_executable( "${CUR_TEST_NAME}" "${CUR_TEST}" ) + target_link_libraries( ${CUR_TEST_NAME} PRIVATE daw_test ) + target_compile_features( ${CUR_TEST_NAME} PUBLIC cxx_std_20 ) + add_test( ${CUR_TEST_NAME}_test ${CUR_TEST_NAME} ) + add_dependencies( ${PROJECT_NAME}_full ${CUR_TEST_NAME} ) + endforeach() + endif() +else() + message( STATUS "Disabling C++20 tests" ) +endif() -if (CMAKE_CXX_STANDARD STRGREATER_EQUAL "23") - foreach (CUR_TEST IN LISTS CPP23_TEST_SOURCES) - string(REPLACE ".cpp" "" CUR_TEST_NAME ${CUR_TEST}) - add_executable("${CUR_TEST_NAME}" "${CUR_TEST}") - target_link_libraries(${CUR_TEST_NAME} PRIVATE daw_test) - target_compile_features(${CUR_TEST_NAME} PUBLIC cxx_std_23) - add_test(${CUR_TEST_NAME}_test ${CUR_TEST_NAME}) - add_dependencies(${PROJECT_NAME}_full ${CUR_TEST_NAME}) - endforeach () - if (NOT MSVC) - foreach (CUR_TEST IN LISTS CPP23_NOT_MSVC_TEST_SOURCES) - string(REPLACE ".cpp" "" CUR_TEST_NAME ${CUR_TEST}) - add_executable("${CUR_TEST_NAME}" "${CUR_TEST}") - target_link_libraries(${CUR_TEST_NAME} PRIVATE daw_test) - target_compile_features(${CUR_TEST_NAME} PUBLIC cxx_std_23) - add_test(${CUR_TEST_NAME}_test ${CUR_TEST_NAME}) - add_dependencies(${PROJECT_NAME}_full ${CUR_TEST_NAME}) - endforeach () - endif () -else () - message(STATUS "Disabling C++23 tests") -endif () +if( CMAKE_CXX_STANDARD STRGREATER_EQUAL "23" ) + foreach( CUR_TEST IN LISTS CPP23_TEST_SOURCES ) + string( REPLACE ".cpp" "" CUR_TEST_NAME ${CUR_TEST} ) + add_executable( "${CUR_TEST_NAME}" "${CUR_TEST}" ) + target_link_libraries( ${CUR_TEST_NAME} PRIVATE daw_test ) + target_compile_features( ${CUR_TEST_NAME} PUBLIC cxx_std_23 ) + add_test( ${CUR_TEST_NAME}_test ${CUR_TEST_NAME} ) + add_dependencies( ${PROJECT_NAME}_full ${CUR_TEST_NAME} ) + endforeach() + if( NOT MSVC ) + foreach( CUR_TEST IN LISTS CPP23_NOT_MSVC_TEST_SOURCES ) + string( REPLACE ".cpp" "" CUR_TEST_NAME ${CUR_TEST} ) + add_executable( "${CUR_TEST_NAME}" "${CUR_TEST}" ) + target_link_libraries( ${CUR_TEST_NAME} PRIVATE daw_test ) + target_compile_features( ${CUR_TEST_NAME} PUBLIC cxx_std_23 ) + add_test( ${CUR_TEST_NAME}_test ${CUR_TEST_NAME} ) + add_dependencies( ${PROJECT_NAME}_full ${CUR_TEST_NAME} ) + endforeach() + endif() +else() + message( STATUS "Disabling C++23 tests" ) +endif() -option(DAW_ENABLE_DEV_TESTING "Build unit tests still in development" OFF) -foreach (CUR_TEST IN LISTS DEV_TEST_SOURCES) - string(REPLACE ".cpp" "" CUR_TEST_NAME ${CUR_TEST}) - if (DAW_ENABLE_DEV_TESTING) - add_executable(${CUR_TEST_NAME} ${CUR_TEST}) - add_dependencies(${PROJECT_NAME}_full ${CUR_TEST_NAME}) - else () - add_executable(${CUR_TEST_NAME} EXCLUDE_FROM_ALL ${CUR_TEST}) - endif () - target_link_libraries(${CUR_TEST_NAME} PRIVATE daw_test) -endforeach () +option( DAW_ENABLE_DEV_TESTING "Build unit tests still in development" OFF ) +foreach( CUR_TEST IN LISTS DEV_TEST_SOURCES ) + string( REPLACE ".cpp" "" CUR_TEST_NAME ${CUR_TEST} ) + if( DAW_ENABLE_DEV_TESTING ) + add_executable( ${CUR_TEST_NAME} ${CUR_TEST} ) + add_dependencies( ${PROJECT_NAME}_full ${CUR_TEST_NAME} ) + else() + add_executable( ${CUR_TEST_NAME} EXCLUDE_FROM_ALL ${CUR_TEST} ) + endif() + target_link_libraries( ${CUR_TEST_NAME} PRIVATE daw_test ) +endforeach() diff --git a/tests/daw_bitset_helper_test.cpp b/tests/daw_bitset_helper_test.cpp new file mode 100644 index 000000000..8801d0926 --- /dev/null +++ b/tests/daw_bitset_helper_test.cpp @@ -0,0 +1,51 @@ +// 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_bitset_helper.h" +#include "daw/daw_do_not_optimize.h" + +#include +#include + +#include + +int main( ) { + auto const bs0 = daw::create_bitset_from_set_positions<16>( { 1, 2, 5, 10 } ); + daw_ensure( bs0.count( ) == 4 ); + daw_ensure( bs0.test( 1 ) ); + daw_ensure( bs0.test( 2 ) ); + daw_ensure( bs0.test( 5 ) ); + daw_ensure( bs0.test( 10 ) ); + + enum class EPos { a, b, c, d, e, f }; + auto const bs1 = + daw::create_bitset_from_set_positions<4>( { EPos::a, EPos::d } ); + daw_ensure( bs1.count( ) == 2 ); + daw_ensure( bs1.test( static_cast( EPos::a ) ) ); + daw_ensure( bs1.test( static_cast( EPos::d ) ) ); +#if defined( DAW_HAS_CPP23_CONSTEXPR_BITSET ) + constexpr auto bs2 = + daw::create_bitset_from_set_positions<16>( { 1, 2, 5, 10 } ); + static_assert( bs2.count( ) == 4 ); + static_assert( bs2.test( 1 ) ); + static_assert( bs2.test( 2 ) ); + static_assert( bs2.test( 5 ) ); + static_assert( bs2.test( 10 ) ); + + constexpr auto bs3 = + daw::create_bitset_from_set_positions<4>( { EPos::a, EPos::d } ); + static_assert( bs3.count( ) == 2 ); + static_assert( bs3.test( static_cast( EPos::a ) ) ); + static_assert( bs3.test( static_cast( EPos::d ) ) ); +#endif + auto const bs4 = daw::create_bitset_from_set_positions<4>( EPos::a, EPos::d ); + daw::do_not_optimize( ( bs4 ) ); + daw_ensure( bs4.count( ) == 2 ); + daw_ensure( bs4.test( static_cast( EPos::a ) ) ); + daw_ensure( bs4.test( static_cast( EPos::d ) ) ); +} diff --git a/tests/daw_contiguous_view_test.cpp b/tests/daw_contiguous_view_test.cpp index 48104e02f..d54bf4f6d 100644 --- a/tests/daw_contiguous_view_test.cpp +++ b/tests/daw_contiguous_view_test.cpp @@ -6,15 +6,32 @@ // Official repository: https://github.com/beached/header_libraries // -#include +#include "daw/daw_contiguous_view.h" + +#include #include -DAW_CONSTEVAL int foo( daw::contiguous_view vals ) { +int foo( daw::contiguous_view vals ) { + return std::accumulate( vals.begin( ), vals.end( ), 0 ); +} + +int foo( daw::contiguous_view vals ) { return std::accumulate( vals.begin( ), vals.end( ), 0 ); } int main( ) { - constexpr int vals[] = { 1, 2, 3 }; - return foo( vals ) == 6 ? 0 : foo( vals ); + static constexpr int vals[] = { 1, 2, 3 }; + constexpr auto cv = daw::contiguous_view( vals ); + daw_ensure( foo( cv ) == 6 ); + constexpr auto vals2 = std::array{ 1, 2, 3 }; + static_assert( daw::contiguous_view( vals2 )[0] == 1 ); + static_assert( daw::contiguous_view( vals2, 1 )[0] == 1 ); + + int vals3[] = { 1, 2, 3 }; + auto cv3 = daw::contiguous_view( vals3 ); + daw_ensure( foo( cv3 ) == 6 ); + constexpr auto vals4 = std::array{ 1, 2, 3 }; + daw_ensure( daw::contiguous_view( vals4 )[0] == 1 ); + daw_ensure( daw::contiguous_view( vals4, 1 )[0] == 1 ); } \ No newline at end of file diff --git a/tests/daw_maybe_unique_ptr_test.cpp b/tests/daw_maybe_unique_ptr_test.cpp new file mode 100644 index 000000000..707fbb9be --- /dev/null +++ b/tests/daw_maybe_unique_ptr_test.cpp @@ -0,0 +1,89 @@ +// 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 +// +#ifdef NDEBUG +#undef NDEBUG +#endif + +#include + +#include +#include + +struct Base { + int x = 55; + Base( ) = default; + Base( int v ) + : x( v ) {} + virtual ~Base( ) = default; +}; + +struct Child : Base { + Child( ) = default; + Child( int v ) + : Base( v ) {} +}; + +int main( ) { + auto a1 = daw::make_maybe_unique( 5 ); + assert( a1 ); + assert( *a1 == 5 ); + auto a2 = daw::make_maybe_unique( 5 ); + assert( a2 ); + assert( *a2 == 5 ); + assert( a1 != a2 ); + auto b = daw::make_maybe_unique( 5 ); + assert( b ); + b[0] = 0; + b[1] = 1; + b[2] = 2; + b[3] = 3; + b[4] = 4; + assert( b[1] == 1 ); + auto c = daw::make_maybe_unique_array( 1, 2, 3, 4, 5 ); + assert( c ); + assert( c[1] == 2 ); + c.reset( ); + assert( not c ); + c = std::move( b ); + assert( c ); + assert( not b ); + assert( c[1] == 1 ); + auto d = std::move( a1 ); + assert( d ); + assert( not a1 ); + assert( *d == 5 ); + a2.reset( ); + assert( not a2 ); + + std::default_delete{ }; + daw::maybe_unique_ptr my_base = daw::make_maybe_unique( ); + int x = -1; + my_base = std::move( my_base ).and_then( [&]( auto p ) { + x = p->x; + return p; + } ); + assert( x == my_base->x ); + my_base = std::move( my_base ).and_then( []( auto p ) { + return daw::make_maybe_unique( p->x ); + } ); + daw::maybe_unique_ptr my_child2 = nullptr; + auto x2 = std::move( my_child2 ) + .or_else( []( ) { + return daw::make_maybe_unique( 55 ); + } ) + .and_then( []( daw::maybe_unique_ptr p ) { + return daw::make_maybe_unique( 42 + p->x ); + } ) + .or_else( []( ) { + return daw::make_maybe_unique( 23 ); + } ) + .transform( []( auto const &p ) { + return p->x; + } ); + assert( x2 == 97 ); +} diff --git a/tests/daw_pipelines_test.cpp b/tests/daw_pipelines_test.cpp index a8b182b42..d6ec6226d 100644 --- a/tests/daw_pipelines_test.cpp +++ b/tests/daw_pipelines_test.cpp @@ -20,6 +20,7 @@ #include #include #include +#include #include #include #include @@ -53,10 +54,10 @@ namespace tests { DAW_ATTRIB_NOINLINE void test001( ) { auto m1 = pipeline( zip_view( prices, costs ), To ); - daw_ensure( m1[prices[0]] == costs[0] ); - daw::println( - "\ntest001: pipeline( zip_view( prices, costs ), To )\n{}", - daw::fmt_range{ m1 } ); + daw_ensure( m1.size( ) == prices.size( ) ); + for( std::size_t n = 0; n < prices.size( ); ++n ) { + daw_ensure( m1[prices[n]] == costs[n] ); + } } struct ToLetter_t { @@ -67,7 +68,11 @@ namespace tests { } else if( i < 52 ) { return static_cast( 'A' + ( i - 26 ) ); } - throw std::out_of_range( "i is out of range" ); + daw::println( stderr, + "{}:{} is out of range", + static_cast( i ), + static_cast( i ) ); + std::terminate( ); } }; inline constexpr auto to_letter = ToLetter_t{ }; @@ -75,17 +80,16 @@ namespace tests { DAW_ATTRIB_NOINLINE void test002( ) { constexpr auto pm2 = pipeline( Map( to_letter ), Enumerate, To ); auto const m2 = pm2( iota_view( 0, 26 ) ); - daw::println( - "\ntest002: pipeline( Map( to_letter ), Enumerate, To )\n{}", - daw::fmt_range( m2 ) ); + for( auto const &[k, v] : m2 ) { + daw_ensure( v == static_cast( 'a' + k ) ); + } constexpr auto pm3 = pipeline( Map( to_letter ), EnumerateWith, To ); auto const m3 = pm3( iota_view( 0, 26 ) ); - daw::println( - "\ntest002: pipeline( Map( to_letter ), EnumerateWith, To " - ")\n{}", - daw::fmt_range( m3 ) ); + for( auto const &[k, v] : m3 ) { + daw_ensure( v == static_cast( 'a' + k ) ); + } for( auto vec = std::vector{ 1, 2, 3 }; auto [index, value] : EnumerateWith( vec ) ) { @@ -532,11 +536,11 @@ namespace tests { } DAW_ATTRIB_NOINLINE void test030( ) { - constexpr auto comma_splitter = + static constexpr auto comma_splitter = pipeline( Split( ',' ), Map( []( daw::Range auto r ) { return daw::string_view( r ).trim( ); } ) ); - constexpr auto values = "1a, 2b,3c, 4d ,5e"_sv; + static constexpr auto values = "1a, 2b,3c, 4d ,5e"_sv; constexpr auto parts = comma_splitter( values ); daw::println( @@ -605,6 +609,121 @@ namespace tests { constexpr auto s2 = daw::string_view{ std::data( p ), std::size( p ) }; daw_ensure( s2 == "Hello" ); } + + DAW_ATTRIB_NOINLINE void test034( ) { + constexpr daw::string_view s = " Hello "; + constexpr auto p = pipeline( s, + DropWhile( is_control_or_space ), + Reverse, + DropWhile( is_control_or_space ), + Reverse, + FirstRef ); + daw_ensure( p.has_value( ) and p.value( ) == 'H' ); + } + + DAW_ATTRIB_NOINLINE void test035( ) { + char buff[] = "Hello"; + auto p = pipeline( buff, FirstRef ); + daw_ensure( p.has_value( ) and p.value( ) == 'H' ); + buff[0] = 'h'; + daw_ensure( p.value( ) == 'h' ); + } + + DAW_ATTRIB_NOINLINE void test036( ) { + constexpr daw::string_view s = " Hello "; + constexpr auto p = pipeline( s, + DropWhile( is_control_or_space ), + Reverse, + DropWhile( is_control_or_space ), + Reverse, + First ); + daw_ensure( p.has_value( ) and p.value( ) == 'H' ); + } + + DAW_ATTRIB_NOINLINE DAW_CONSTEVAL void test037( ) { + char buff[] = "Hello"; + auto p = pipeline( buff, First ); + daw_ensure( p.has_value( ) and p.value( ) == 'H' ); + buff[0] = 'h'; + daw_ensure( p.value( ) == 'H' ); + } + + DAW_ATTRIB_NOINLINE void test038( ) { + constexpr auto values = std::array{ 1, 5, 5, 10, 32 }; + daw::do_not_optimize( values ); + auto const unique_values = + pipeline( values, Copy, Sort, Unique, To ); + daw_ensure( unique_values.size( ) == 4 ); + daw_ensure( unique_values == std::vector{ 1, 5, 10, 32 } ); + } + + DAW_ATTRIB_NOINLINE void test039( ) { + auto z0 = Zip( prices, costs ); + + auto e0 = Elements<1>( z0 ); + daw_ensure( static_cast( std::ranges::distance( e0 ) ) == + costs.size( ) ); + auto eb0 = std::begin( e0 ); + for( std::size_t n = 0; n < costs.size( ); ++n ) { + daw_ensure( std::get<0>( eb0[n] ) == costs[n] ); + } + auto e1 = Elements<0>( z0 ); + auto eb1 = std::begin( e1 ); + daw_ensure( static_cast( std::ranges::distance( e1 ) ) == + prices.size( ) ); + for( std::size_t n = 0; n < prices.size( ); ++n ) { + daw_ensure( std::get<0>( eb1[n] ) == prices[n] ); + } + } + + DAW_ATTRIB_NOINLINE void test040( ) { + auto z0 = Zip( prices, costs ); + + auto e0 = Element<1>( z0 ); + daw_ensure( static_cast( std::ranges::distance( e0 ) ) == + costs.size( ) ); + auto eb0 = std::begin( e0 ); + for( std::size_t n = 0; n < costs.size( ); ++n ) { + daw_ensure( eb0[n] == costs[n] ); + } + auto e1 = Element<0>( z0 ); + auto eb1 = std::begin( e1 ); + daw_ensure( static_cast( std::ranges::distance( e1 ) ) == + prices.size( ) ); + for( std::size_t n = 0; n < prices.size( ); ++n ) { + daw_ensure( eb1[n] == prices[n] ); + } + } + + DAW_ATTRIB_NOINLINE void test041( ) { + constexpr auto values = std::array{ 1, 5, 5, 10, 32 }; + auto cp = pipeline( values, + Map( []( int x ) { + static int map_count = 0; + ++map_count; + daw::println( "MapCount = {}", map_count ); + return x * x; + } ), + CacheLast ); + auto first = std::begin( cp ); + auto last = std::end( cp ); + while( first != last ) { + daw::println( "{}", *first ); + daw::println( "{}", *first ); + ++first; + } + } + + DAW_ATTRIB_NOINLINE void test042( ) { + auto v = std::vector{ "Hello", "World" }; + + auto mapper = Map( +[]( std::string &s ) -> char * { + return s.data( ); + } ); + auto m = mapper( v ); + auto v2 = std::vector( std::begin( m ), std::end( m ) ); + daw_ensure( v2.size( ) == v.size( ) ); + } } // namespace tests int main( ) { @@ -641,6 +760,14 @@ int main( ) { tests::test031( ); tests::test032( ); tests::test033( ); - + tests::test034( ); + tests::test035( ); + tests::test036( ); + tests::test037( ); + tests::test038( ); + tests::test039( ); + tests::test040( ); + tests::test041( ); + tests::test042( ); daw::println( "Done" ); } diff --git a/tests/daw_span_writer_test.cpp b/tests/daw_span_writer_test.cpp new file mode 100644 index 000000000..35e2042b4 --- /dev/null +++ b/tests/daw_span_writer_test.cpp @@ -0,0 +1,66 @@ +// 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_span_writer.h" + +#include +#include +#include + +#include +#include +#include + +DAW_ATTRIB_NOINLINE void test1_impl( std::array &buff, + std::size_t &out_size ) { + auto sp = daw::write_to_span_ntz( + buff, "Hello World.......Hello little letters:" ); + sp = daw::write_to_span( sp, 'a', 'b', 'c', 0 ); + constexpr auto const expected_sz = + 256 - + ( ( daw::string_view( "Hello World.......Hello little letters:" ).size( ) + + 4 /*second write_to_span*/ ) ); + daw_ensure( sp.size( ) == expected_sz ); + out_size = sp.size( ); +} + +void test1( ) { + auto buff = std::array( ); + std::size_t out_size = 0; + test1_impl( buff, out_size ); + daw::do_not_optimize( buff ); + daw::do_not_optimize( out_size ); +} + +DAW_ATTRIB_NOINLINE void test2_impl( std::array &buff, + std::size_t &out_size ) { + static_assert( std::ranges::contiguous_range> ); + auto sp = daw::span_writer( buff ); + std::span s = sp; + (void)s; + sp.write_ntz( "Hello World.......Hello little letters:" ); + sp.write( 'a', 'b', 'c', 0 ); + constexpr auto const expected_sz = + ( daw::string_view( "Hello World.......Hello little letters:" ).size( ) + + 4 /*second write_to_span*/ ); + daw_ensure( sp.size( ) == ( buff.size( ) - expected_sz ) ); + out_size = sp.size( ); +} + +void test2( ) { + auto buff = std::array( ); + std::size_t out_size = 0; + test2_impl( buff, out_size ); + daw::do_not_optimize( buff ); + daw::do_not_optimize( out_size ); +} + +int main( ) { + test1( ); + test2( ); +} \ No newline at end of file