diff --git a/CMakeLists.txt b/CMakeLists.txt index b11669de..1773f46e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -35,7 +35,7 @@ option( KIWAKU_BUILD_DOCS "Build docs for raberu" OFF ) if( KIWAKU_BUILD_TEST ) enable_testing() include(CTest) - add_custom_target(kwk-unit) + add_custom_target(unit) add_subdirectory(test) endif() diff --git a/appveyor.yml b/appveyor.yml index be30dffc..96e91dda 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -9,9 +9,7 @@ build_script: - mkdir build - cd build - cmake -G "Visual Studio 17 2022" -A x64 .. -DKIWAKU_BUILD_TEST=ON -- cmake --build . --target kwk-unit --verbose --config Release -- cmake --build . --target kwk-unit --verbose --config Debug +- cmake --build . --target unit --verbose --config Release test_script: - ctest -C Release -VV -- ctest -C Debug -VV diff --git a/cmake/make_unit.cmake b/cmake/make_unit.cmake index c131c724..dc1a3ba5 100644 --- a/cmake/make_unit.cmake +++ b/cmake/make_unit.cmake @@ -28,7 +28,7 @@ function(source_to_target root ext filename testname) string(REPLACE ".cpp" ".${ext}" base ${filename}) string(REPLACE "/" "." base ${base}) string(REPLACE "\\" "." base ${base}) - SET(${testname} "kwk-${root}.${base}" PARENT_SCOPE) + SET(${testname} "${root}.${base}" PARENT_SCOPE) endfunction() function(setup_location test location) @@ -50,7 +50,7 @@ function(make_unit root) add_executable(${test} ${file}) add_target_parent(${test}) - add_dependencies(kwk-unit ${test}) + add_dependencies(unit ${test}) setup_location( ${test} "unit") target_link_libraries(${test} PUBLIC kiwaku_test) diff --git a/include/kwk/algorithm.hpp b/include/kwk/algorithm.hpp index fbc6d596..ff0654f1 100644 --- a/include/kwk/algorithm.hpp +++ b/include/kwk/algorithm.hpp @@ -1,9 +1,9 @@ //================================================================================================== -/** +/* KIWAKU - Containers Well Made Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 -**/ +*/ //================================================================================================== #pragma once diff --git a/include/kwk/algorithm/for_each.hpp b/include/kwk/algorithm/for_each.hpp index 414627d3..16a655d8 100644 --- a/include/kwk/algorithm/for_each.hpp +++ b/include/kwk/algorithm/for_each.hpp @@ -7,45 +7,35 @@ //================================================================================================== #pragma once +#include +#include +#include #include #include namespace kwk { - namespace detail + //================================================================================================ + // Order N for_each algorithm + //================================================================================================ + template + constexpr auto for_each(Func&& f, Container&& c) { - //================================================================================================ - // n-Dimensional for_each algorithm - //================================================================================================ - template - constexpr void for_each(Func f, Container&& c, Dim d) - { - for(std::ptrdiff_t i=get<0>(d);i(d);++i) f(KWK_FWD(c), i); - } - - template - constexpr void for_each(Func f, Container&& c, Dim d0, Dims... ds) + return [&](std::index_sequence const&) { - detail::for_each( [f,d0](auto&& x, auto... is) - { - for(std::ptrdiff_t i=get<0>(d0);i(d0);++i) - f(KWK_FWD(x), i,is...); - } - , KWK_FWD(c) - , ds... - ); - } + return detail::for_each(KWK_FWD(f), KWK_FWD(c), c.shape() ); + }( std::make_index_sequence::static_order>{} ); } //================================================================================================ - // Order N for_each algorithm + // Order N for_each_index algorithm //================================================================================================ - template - constexpr void for_each(Func f, Container&& c) + template + constexpr auto for_each_index(Func&& f, Container&& c) { return [&](std::index_sequence const&) { - return detail::for_each(f, KWK_FWD(c), kumi::tuple{first(c),last(c)}... ); + return detail::for_each_index(KWK_FWD(f), KWK_FWD(c), c.shape() ); }( std::make_index_sequence::static_order>{} ); } } diff --git a/include/kwk/allocator/any_allocator.hpp b/include/kwk/allocator/any_allocator.hpp deleted file mode 100644 index 8c306e39..00000000 --- a/include/kwk/allocator/any_allocator.hpp +++ /dev/null @@ -1,128 +0,0 @@ -//================================================================================================== -/* - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -*/ -//================================================================================================== -#pragma once - -#include -#include -#include -#include -#include - -namespace kwk -{ - //================================================================================================ - /** - @ingroup memory - @brief Opaque allocator type - - Model of the kwk::concepts::allocator concept. kwk::any_allocator is a type-erased object able - to contains any allocator type modeling kwk::concepts::allocator. It is meant to be used as a - non-dependent type in containers or other functions one may want to be non-template - **/ - //================================================================================================ - struct any_allocator - { - private: - - struct api_t - { - virtual ~api_t() {} - virtual void* allocate(std::size_t) = 0; - virtual void deallocate(void* ) = 0; - virtual std::unique_ptr clone() const = 0; - }; - - template struct model_t final : api_t - { - using base_type = T; - - model_t() : object() {} - model_t(const base_type& t) : object(t) {} - model_t(base_type&& t) : object(std::move(t)) {} - - void* allocate(std::size_t n) override { return object.allocate(n); } - void deallocate(void* b) override { object.deallocate(b); } - std::unique_ptr clone() const override { return std::make_unique(object); } - - private: - T object; - }; - - public: - - /// Default constructor - any_allocator() = default; - - /// Move constructor - any_allocator(any_allocator&& a) = default; - - /// Move assignment operator - any_allocator& operator=(any_allocator&& other) = default; - - /// Copy constructor - any_allocator(any_allocator const& a) : object( a.object->clone() ) {} - - /// Copy assignment operator - any_allocator& operator=(any_allocator const& other) - { - any_allocator that(other); - swap(that); - return *this; - } - - /** - @brief Constructor from an arbitrary allocator type - - Initializes an kwk::any_allocator with an instance of an kwk::concepts::allocator. - - @param other Instance of allocator to store - **/ - template - any_allocator ( T&& other ) - : object(std::make_unique>>(KWK_FWD(other))) - {} - - /** - @brief Assign an arbitrary allocator type - - Assign an instance of an kwk::concepts::allocator to the current instance of kwk::any_allocator. - - @param other Instance of allocator to store - **/ - template any_allocator& operator=(T&& other) - { - any_allocator that(KWK_FWD(other)); - swap(that); - return *this; - } - - /// Swap the contents of two instance of kwk::heap_allocator - void swap(any_allocator& other) noexcept { object.swap(other.object); } - - /** - @brief Allocates data - @param n Number of bytes to allocate - @return A kwk::block wrapping the newly allocated memory and its size. If zero byte was - requested, the returned kwk::block is empty. - **/ - [[nodiscard]] auto allocate(std::size_t n) { return object->allocate(n); } - - /** - @brief Deallocates data - - Deallocate the memory from a kwk::block. If the deallocated memory was not allocated by the - same instance of kwk::any_allocator, the behavior is undefined. - - @param b kwk::block containing the memory to deallocate - **/ - void deallocate(void* b) { object->deallocate(b); } - - private: - std::unique_ptr object; - }; -} diff --git a/include/kwk/allocator/heap_allocator.hpp b/include/kwk/allocator/heap_allocator.hpp deleted file mode 100644 index 1171796e..00000000 --- a/include/kwk/allocator/heap_allocator.hpp +++ /dev/null @@ -1,50 +0,0 @@ -//================================================================================================== -/* - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -*/ -//================================================================================================== -#pragma once - -#include -#include - -namespace kwk -{ - //================================================================================================ - /** - @ingroup memory - @brief Malloc based allocator - - Model of the kwk::concepts::allocator concept. kwk::heap_allocator allocates and deallocates - memory block on the heap using `malloc` and `free`. - **/ - //================================================================================================ - struct heap_allocator - { - /** - @brief Allocates data on the heap - @param n Number of bytes to allocate - @return A pointer to the newly allocated memory. If zero byte was requested, the returned - pointer is equal to `nullptr`. - **/ - [[nodiscard]] void* allocate(std::ptrdiff_t n) noexcept - { - return (n!=0) ? malloc(n) : nullptr; - } - - /** - @brief Deallocates data on the heap - - Free the heap memory from a pointer. If the deallocated memory was not allocated by an - instance of kwk::heap_allocator, the behavior is undefined. - - @param b Pointer to the memory to deallocate - **/ - void deallocate(void* ptr) noexcept { if(ptr) free(ptr); } - - /// Swap the contents of two instance of kwk::heap_allocator - void swap(heap_allocator&) {} - }; -} diff --git a/include/kwk/concept/allocator.hpp b/include/kwk/concept/allocator.hpp deleted file mode 100644 index ddea83b5..00000000 --- a/include/kwk/concept/allocator.hpp +++ /dev/null @@ -1,48 +0,0 @@ -//================================================================================================== -/* - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -*/ -//================================================================================================== -#pragma once - -#include - -namespace kwk::concepts -{ - //================================================================================================ - /** - @brief Allocator concept - - A **KIWAKU** Allocator is a @semiregular, @swappable type which provides: - + a `allocate` member function that takes an integral value and allocates bytes - + a `deallocate` member function that takes a pointer to bytes as parameter - **/ - //================================================================================================ - template - concept allocator = std::semiregular - && std::swappable - && requires(A a, void* b, std::ptrdiff_t n) - { - { a.allocate(n) }; - { a.deallocate(b) }; - }; - - //================================================================================================ - /** - @brief Aligned Allocator concept - - A **KIWAKU** Aligned Allocator is a kwk::concepts::allocator that also provides: - + a `allocate_aligned` member function and allocates aligned memory on a given alignment - + a `deallocate_aligned` member function that deallocates aligned memory - **/ - //================================================================================================ - template - concept aligned_allocator = allocator - && requires(A a, void* b, std::ptrdiff_t n, std::ptrdiff_t al) - { - { a.allocate_aligned(n,al) }; - { a.deallocate_aligned(b) }; - }; -} diff --git a/include/kwk/concept/range.hpp b/include/kwk/concept/range.hpp deleted file mode 100644 index a955892b..00000000 --- a/include/kwk/concept/range.hpp +++ /dev/null @@ -1,75 +0,0 @@ -//================================================================================================== -/* - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -*/ -//================================================================================================== -#pragma once - -#include -#include -#include -#include - -namespace kwk::concepts -{ - //================================================================================================ - /** - @brief Range - - Types model kwk::concepts::range if they supports call to the range standard interface. - **/ - //================================================================================================ - template - concept range = requires(Range&& r) - { - { std::begin(r) }; - { std::end(r) }; - { std::size(r) }; - }; - - //================================================================================================ - /** - @brief Contiguous Range - - Types model kwk::concepts::contiguous_range if they supports call to `std::data` along with - other range standard interface. - **/ - //================================================================================================ - template - concept contiguous_range = range && requires(Range&& r) - { - { std::data(r) }; - }; - - //================================================================================================ - /** - @brief Pointer - - Types model kwk::concepts::pointer if their are an actual pointer type. - This concept is used to discriminate overload sets that contains both pointers and C-style - arrays. - **/ - //================================================================================================ - template - concept pointer = std::is_pointer_v>; - - //================================================================================================ - /** - @brief Static-size capability - - Types model kwk::concepts::has_static_size if they can provides a compile-time size. - **/ - //================================================================================================ - template - concept has_static_size = detail::static_size>::value; - - //================================================================================================ - /** - @brief Contiguous Static Range - **/ - //================================================================================================ - template - concept contiguous_static_range = contiguous_range && has_static_size; -} diff --git a/include/kwk/concept/slicer.hpp b/include/kwk/concept/slicer.hpp deleted file mode 100644 index 2fe42fe4..00000000 --- a/include/kwk/concept/slicer.hpp +++ /dev/null @@ -1,25 +0,0 @@ -//================================================================================================== -/** - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -**/ -//================================================================================================== -#pragma once - -#include - -namespace kwk::detail -{ - template struct is_unit_slicer; - template struct is_contiguous_slicer; -} - -namespace kwk::concepts -{ - template - concept contiguous_slicer = detail::is_contiguous_slicer,D>::value; - - template - concept unit_slicer = detail::is_unit_slicer>::value; -} diff --git a/include/kwk/concept.hpp b/include/kwk/concepts.hpp similarity index 64% rename from include/kwk/concept.hpp rename to include/kwk/concepts.hpp index 822524c9..2f773f62 100644 --- a/include/kwk/concept.hpp +++ b/include/kwk/concepts.hpp @@ -7,6 +7,8 @@ //================================================================================================== #pragma once -#include -#include -#include +#include +#include +#include +#include +// #include diff --git a/include/kwk/concepts/allocator.hpp b/include/kwk/concepts/allocator.hpp new file mode 100644 index 00000000..83ac6599 --- /dev/null +++ b/include/kwk/concepts/allocator.hpp @@ -0,0 +1,27 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include + +namespace kwk::concepts +{ + //================================================================================================ + //! @brief Allocator concept + //! + //! A **KIWAKU** Allocator is a type which instances can be passed to the following free functions: + //! + `allocate(Allocator& alloc, std::size_t size)` + //! + `deallocate(Allocator& alloc, void* ptr)` + //================================================================================================ + template + concept allocator = requires(Allocator& alloc, void* ptr, std::size_t size) + { + { allocate (alloc, size) }; + { deallocate(alloc, ptr ) }; + }; +} diff --git a/include/kwk/allocator.hpp b/include/kwk/concepts/category.hpp similarity index 65% rename from include/kwk/allocator.hpp rename to include/kwk/concepts/category.hpp index 3bdd21f4..de26eb9d 100644 --- a/include/kwk/allocator.hpp +++ b/include/kwk/concepts/category.hpp @@ -1,21 +1,24 @@ //================================================================================================== -/** +/* KIWAKU - Containers Well Made Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 -**/ +*/ //================================================================================================== #pragma once -namespace kwk +#include + +namespace kwk::concepts { //================================================================================================ - /** - @defgroup memory Memory Management - @brief Classes and functions related to low level memory management - **/ + //! @brief Category concept + //! + //! A **KIWAKU** Category is a type usable as a semantic setting. //================================================================================================ + template + concept category = requires(Type const&) + { + typename Type::kwk_container_category; + }; } - -#include -#include diff --git a/include/kwk/concepts/container.hpp b/include/kwk/concepts/container.hpp new file mode 100644 index 00000000..308a7f5e --- /dev/null +++ b/include/kwk/concepts/container.hpp @@ -0,0 +1,93 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace kwk::concepts +{ + //================================================================================================ + //! @brief Basic container concept + //! + //! A @ref kwk::concepts::basic_container is a type exhibiting the basic interface of a + //! nD container. + //================================================================================================ + template + concept basic_container = requires(T const& t) + { + typename std::remove_cvref_t::value_type; + typename std::remove_cvref_t::reference; + typename std::remove_cvref_t::const_reference; + typename std::remove_cvref_t::pointer; + typename std::remove_cvref_t::const_pointer; + + { t.order() }; + { t.kind() }; + { t.shape() }; + }; + + //================================================================================================ + // Check if two types are the same + // If your compiler gives you an error here, you tried to pass a container of a given value type T + // a value type of U was expected. + //================================================================================================ + template + concept same_value_type = std::same_as; + + //================================================================================================ + // Check if two shapes are similar + // If your compiler gives you an error here, you tried to pass a container of a given Shape type + // that can't be represented as the ExpectedShape + //================================================================================================ + template + concept same_shape = ExpectedShape.is_similar(Shape{}); + + //================================================================================================ + //! @brief Container concept + //! + //! A @ref kwk::concepts::container is a type exhibiting the basic interface of a + //! nD container and having a given set of settings. + //================================================================================================ + template + concept container = basic_container + && same_value_type < typename std::remove_cvref_t::value_type + , typename rbr::result::fetch_t + < type + | as::value_type> + , decltype(Os)... + >::type + > + && same_shape< typename std::remove_cvref_t::shape_type + , rbr::fetch( size | typename std::remove_cvref_t::shape_type{} + , Os... + ) + >; + + //================================================================================================ + //! @brief Table concept + //! + //! A @ref kwk::concepts::table is a @ref kwk::concepts::container type with the semantic of a + //! @ref kwk::table. + //================================================================================================ + template + concept table = container && (kwk::table_ == std::remove_cvref_t::kind()); + + //================================================================================================ + //! @brief View concept + //! + //! A @ref kwk::concepts::view is a @ref kwk::concepts::container type with the semantic of a + //! @ref kwk::view. + //================================================================================================ + template + concept view = container && (kwk::view_ == std::remove_cvref_t::kind()); +} diff --git a/include/kwk/concepts/extent.hpp b/include/kwk/concepts/extent.hpp new file mode 100644 index 00000000..5576742a --- /dev/null +++ b/include/kwk/concepts/extent.hpp @@ -0,0 +1,28 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include + +namespace kwk::concepts +{ + /// Concept for types acting as a joker value + template concept joker = is_joker_v; + + /// Concept for types usable as shape and stride extent values + template + concept extent = std::convertible_to || joker; + + /// Concept for shape and stride extent descriptor + template + concept descriptor = requires(T) + { + typename std::remove_cvref_t::contents_type; + }; +} diff --git a/include/kwk/concepts/range.hpp b/include/kwk/concepts/range.hpp new file mode 100644 index 00000000..1446a343 --- /dev/null +++ b/include/kwk/concepts/range.hpp @@ -0,0 +1,44 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include + +namespace kwk::concepts +{ + /// Concept for types supporting calls to standard begin/end/size interface. + template + concept range = requires(Range&& r) + { + { std::begin(r) }; + { std::end(r) }; + { std::size(r) }; + }; + + /// Concept for Range types providing access to a contiguous block of data + template + concept contiguous_range = range && requires(Range&& r) + { + { std::data(r) }; + }; + + /// Concept for types behaving as an actual pointer type. + template + concept pointer = std::is_pointer_v>; + + /// Concept for types exposing a compile-time size value + template + concept has_static_size = detail::array_traits>::value; + + /// Concept for Contiguous Range exposing a compile-time size value + template + concept contiguous_static_range = contiguous_range && has_static_size; +} diff --git a/include/kwk/container/options.hpp b/include/kwk/concepts/values.hpp similarity index 59% rename from include/kwk/container/options.hpp rename to include/kwk/concepts/values.hpp index 87e0ec35..e8ddc181 100644 --- a/include/kwk/container/options.hpp +++ b/include/kwk/concepts/values.hpp @@ -1,12 +1,23 @@ //================================================================================================== -/** +/* KIWAKU - Containers Well Made Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 -**/ +*/ //================================================================================================== #pragma once -#include -#include -#include +namespace kwk::concepts +{ + template + concept static_constant = requires(T) + { + { T::value }; + }; + + template + concept extremum = requires(T const& t, int n) + { + { t.size(n) }; + }; +}; \ No newline at end of file diff --git a/include/kwk/container.hpp b/include/kwk/container.hpp index 50685276..4458d8e4 100644 --- a/include/kwk/container.hpp +++ b/include/kwk/container.hpp @@ -1,26 +1,21 @@ //================================================================================================== -/** +/* KIWAKU - Containers Well Made Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 -**/ +*/ //================================================================================================== #pragma once namespace kwk { //================================================================================================ - /** - @defgroup containers Containers - @brief Types and functions for containers' handling - - Defines types and functions related to the creation, usage and manipulation of **KIWAKU**'s - containers. - **/ + //! @defgroup containers Miscellaneous helper + //! @brief Container-like types and related functions + //! + //! This module defines th emain **KIWAKU**'s classes for handlign data. //================================================================================================ } -#include -#include #include #include diff --git a/include/kwk/container/components/container.hpp b/include/kwk/container/components/container.hpp deleted file mode 100644 index ab1d0739..00000000 --- a/include/kwk/container/components/container.hpp +++ /dev/null @@ -1,130 +0,0 @@ -//================================================================================================== -/* - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -*/ -//================================================================================================== -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace kwk -{ - template - struct container : private detail::builder::metadata - , detail::builder::data_block - , detail::builder::accessor - { - using meta_t = typename detail::builder::metadata; - using span_t = typename detail::builder::data_block; - using access_t = typename detail::builder::accessor; - - static constexpr auto tag = Tag{}; - - using value_type = Type; - using reference = typename span_t::reference; - using const_reference = typename span_t::const_reference; - using pointer = typename span_t::pointer; - using const_pointer = typename span_t::const_pointer; - - static constexpr auto static_order = access_t::static_order; - static constexpr auto has_label = meta_t::has_label; - - constexpr container( rbr::concepts::option auto const&... params ) - : container{ rbr::settings(params...) } - {} - - constexpr container(rbr::concepts::settings auto const& params) - : meta_t { tag, params } - , span_t { tag, params } - , access_t { tag, params } - {} - - constexpr auto order() const noexcept { return this->shape().order(); } - constexpr auto empty() const noexcept { return this->size() == 0; } - - using meta_t::label; - - friend std::ostream& operator<<(std::ostream& os, container const& v) - { - auto spaces = has_label ? " " : ""; - auto lbl = [&]() { if constexpr(has_label) os << v.label() << ":\n"; }; - - lbl(); - if( v.empty() ) - { - return os << spaces << "[ ]"; - } - - if constexpr( container::static_order < 3) - { - for_each( [&](auto const& c, auto i0, auto... i) - { - if(i0 == first<0>(v)) os << spaces << "[ "; - os << c(i0,i...) << ' '; - if(i0 == last<0>(v)-1) os << "]\n"; - } - , v - ); - } - else - { - for_each( [&](auto const& c, auto i0, auto i1, auto i2, auto... i) - { - if(i0 == first<0>(v)) - { - if(i1 == first<1>(v) && i2 > first<2>(v)) os << '\n'; - os << spaces << "[ "; - } - os << c(i0,i1,i2,i...) << ' '; - if(i0 == last<0>(v)-1) os << "]\n"; - } - , v - ); - } - - return os; - } - - template - requires(sizeof...(Is) == static_order) const_reference operator()(Is... is) const noexcept - { - return span_t::data()[ access_t::index(is...) ]; - } - - template - requires(sizeof...(Is) == static_order) reference operator()(Is... is) noexcept - { - return span_t::data()[ access_t::index(is...) ]; - } - }; - - template - constexpr auto dim(container const& v) noexcept - { - if constexpr(I::static_order) return get(v.shape()); - else return 1; - } - - /// Retrieve the first valid index along the Ith dimension - template - constexpr auto first(container const& v) noexcept - { - auto bi = options::base_index(v.tag, rbr::settings{Os...}); - return get(bi.template as_position::static_order>()); - } - - /// Retrieve the last valid index along the Ith dimension - template - constexpr auto last(container const& v) noexcept - { - return first(v) + dim(v); - } -} - diff --git a/include/kwk/container/components/data_block.hpp b/include/kwk/container/components/data_block.hpp deleted file mode 100644 index 7009d78c..00000000 --- a/include/kwk/container/components/data_block.hpp +++ /dev/null @@ -1,72 +0,0 @@ -//================================================================================================== -/* - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -*/ -//================================================================================================== -#pragma once -#include -#include -#include - -namespace kwk::detail -{ - //================================================================================================ - /* - Data holder base class - - SCARY base class gathering all types and member functions pertaining to the upkeep, access and - update to the data part of a kwk container. - - Contrary to most standard view and container,kwk::data_block keep the potential const qualifier - of underlying type on purpose. - - @tparam Source Source object carrying informations about the underlying pointer - */ - //================================================================================================ - template struct data_block : Source - { - using pointer = typename Source::pointer; - - // Constructs a kwk::data_block from any source - constexpr data_block(auto const& tag, rbr::concepts::settings auto const& opts) - : Source{ options::block(tag,opts) } - {} - - constexpr Source& as_source() noexcept { return static_cast(*this); } - constexpr Source const& as_source() const noexcept { return static_cast(*this); } - - /* - Replaces the managed pointer. - - Given `current_ptr`, the pointer that was managed by `*this`, performs the following - actions, in this order: - - - Saves a copy of the current pointer `old_ptr = current_ptr` - - Overwrites the current pointer with the argument `current_ptr = ptr` - - Returns the copy of the previous current pointer - - This function does not participate in overload resolution if the bse data - Source is owning its data. - */ - constexpr pointer reset(pointer ptr) noexcept - requires requires(Source& s) { s.reset(ptr); } - { - return as_source().reset(ptr); - } - - /* - Swap contents of two kwk::data_block - - This function does not participate in overload resolution if the underlying source block - can't be properly swapped. - */ - template - constexpr void swap( data_block& other ) noexcept - requires requires(Source& a, OtherSource& b) { a.swap(b);} - { - as_source().swap(other.as_source()); - } - }; -} diff --git a/include/kwk/container/container.hpp b/include/kwk/container/container.hpp new file mode 100644 index 00000000..e1c729c3 --- /dev/null +++ b/include/kwk/container/container.hpp @@ -0,0 +1,149 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include +#include + +namespace kwk +{ + template + struct container : private MetaData, Data, Access + { + using value_type = typename Data::value_type; + using reference = typename Data::reference; + using const_reference = typename Data::const_reference; + using pointer = typename Data::pointer; + using const_pointer = typename Data::const_pointer; + using shape_type = typename Access::shape_type; + using container_kind = decltype(Tag); + + static constexpr auto static_order = Access::static_order; + static constexpr auto has_label = MetaData::has_label; + + constexpr container( container_kind ) noexcept + : MetaData{ } + , Data { } + , Access { } + {} + + constexpr container( rbr::concepts::option auto const&... params ) + : container{ rbr::merge(rbr::settings(params...), rbr::settings(Tag)) } + {} + + constexpr container(rbr::concepts::settings auto const& params) + : MetaData{ params } + , Data { params } + , Access { params } + {} + + static constexpr auto kind() noexcept { return Tag; } + constexpr auto order() const noexcept { return this->shape().order(); } + constexpr auto numel() const noexcept { return this->shape().numel(); } + constexpr auto empty() const noexcept { return this->size() == 0; } + + using MetaData::label; + + void swap(container& other) noexcept + { + MetaData::swap(other); + Data::swap(other); + Access::swap(other); + } + + friend void swap(container& a,container& b) noexcept { a.swap(b); } + + static constexpr auto archetype() noexcept + { + return rbr::settings(as, shape_type{}); + } + + static constexpr auto archetype(auto tag) noexcept + { + return rbr::settings(tag, as, shape_type{}); + } + + constexpr auto settings() const noexcept + { + return rbr::settings(source = pointer(get_data()), this->shape()); + } + + constexpr auto settings(auto tag) const noexcept + { + return rbr::settings(tag, source = pointer(get_data()), this->shape()); + } + + friend std::ostream& operator<<(std::ostream& os, container const& v) + { + auto spaces = has_label ? " " : ""; + auto lbl = [&]() { if constexpr(has_label) os << v.label() << ":\n"; }; + + lbl(); + if( v.empty() ) + { + return os << spaces << "[ ]"; + } + + auto shp = v.shape(); + if constexpr( container::static_order < 3) + { + for_each_index( [&](auto e, auto i0, auto...) + { + if(i0 == 0) os << spaces << "[ "; + os << e << ' '; + if(i0 == get<0>(shp)-1) os << "]\n"; + } + , v + ); + } + else + { + for_each_index( [&](auto e, auto i0, auto i1, auto i2, auto... ) + { + if(i0 == 0) + { + if(i1 == 0 && i2 > 0) os << '\n'; + os << spaces << "[ "; + } + os << e << ' '; + if(i0 == get<0>(shp)-1) os << "]\n"; + } + , v + ); + } + + return os; + } + + template + requires(sizeof...(Is) == static_order) const_reference operator()(Is... is) const noexcept + { + return data(static_cast(*this))[ Access::index(is...) ]; + } + + template + requires(sizeof...(Is) == static_order) reference operator()(Is... is) noexcept + { + return data(static_cast(*this))[ Access::index(is...) ]; + } + + constexpr auto get_data() const noexcept { return data(static_cast(*this)); } + constexpr auto get_data() noexcept { return data(static_cast(*this)); } + }; + + template + constexpr auto dim(container const& v) noexcept + { + if constexpr(I::static_order) return get(v.shape()); + else return 1; + } +} + diff --git a/include/kwk/container/options/common.hpp b/include/kwk/container/options/common.hpp deleted file mode 100644 index 7171c2ea..00000000 --- a/include/kwk/container/options/common.hpp +++ /dev/null @@ -1,59 +0,0 @@ -//================================================================================================== -/* - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -*/ -//================================================================================================== -#pragma once - -#include -#include -#include - -namespace kwk::options -{ - // For containers, we infer the block type from the source that must be present - template - struct data - { - using type = decltype( block(Tag{}, std::declval()) ); - }; - - // The data source is fetched or an empty ptr_source is returned - template - constexpr auto source(Tag const&, Settings const& p) noexcept - { - return p[kwk::source | ptr_source{}]; - } - - // The shape has retrieved from the options or error occurs - template - constexpr auto shape(Tag const& tag, Settings const& p) noexcept - { - return p[kwk::size | options::source(tag,p).default_shape()]; - } - - // Unless specified, the stride is computed from the shape - template - constexpr auto stride(Tag const& m, Settings const& p) noexcept - { - return p[kwk::strides | options::shape(m,p).as_stride() ]; - } - - // Unless retrieved from options, the base_index is index_<0> - template - constexpr auto base_index(Tag const&, Settings const& p) noexcept - { - return p[kwk::base_index | bases<0> ]; - } - - // Compute the offset from base_index and stride - template - constexpr auto offset(Tag const& m, Settings const& p) noexcept - { - auto st = stride(m,p); - auto bi = base_index(m,p).template as_position(); - return kumi::apply([&](auto... i) { return st.index(i...); }, bi); - } -} diff --git a/include/kwk/container/options/forward.hpp b/include/kwk/container/options/forward.hpp deleted file mode 100644 index a5480499..00000000 --- a/include/kwk/container/options/forward.hpp +++ /dev/null @@ -1,29 +0,0 @@ -//================================================================================================== -/* - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -*/ -//================================================================================================== -#pragma once - -#include -#include - -namespace kwk::options -{ - template struct data; - template struct element; - - template - constexpr auto shape(Tag const&, Settings const&) noexcept; - - template - constexpr auto source(Tag const&, Settings const&) noexcept; - - template - constexpr auto stride(Tag const&, Settings const&) noexcept; - - template - constexpr auto offset(Tag const&, Settings const&) noexcept; -} diff --git a/include/kwk/container/options/table.hpp b/include/kwk/container/options/table.hpp deleted file mode 100644 index cf787a4e..00000000 --- a/include/kwk/container/options/table.hpp +++ /dev/null @@ -1,87 +0,0 @@ -//================================================================================================== -/* - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -*/ -//================================================================================================== -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -namespace kwk::tag { struct table_ {}; } - -namespace kwk::detail -{ - template - struct select_type; - - template - struct select_type - { - using type= typename T1::span_type::base_type; - }; - - template - struct select_type - { - using type = typename T2::type; - }; -} - -namespace kwk::options -{ - // For table, we infer the type from : - template - struct element - { - // - type_ if present, type of the source if not - using has_source = rbr::result::fetch_t; - using has_type = rbr::result::fetch_t; - using base_type = detail::select_type; - using type = typename base_type::type; - - static_assert ( !std::same_as - , "[KWK] - Error: table must specify type" - ); - }; - - // For table, we compute the data_block from the shape and allocator - template - constexpr auto block(tag::table_ const& m, Settings const& p) noexcept - { - auto shp = options::shape(m, p); - using shp_t = decltype(shp); - using type = typename element::type; - - // Get the data block - auto data = [&]() - { - if constexpr( shp_t::is_fully_static ) - { - constexpr auto offset = options::offset(tag::table_{}, Settings{}); - return detail::stack_block{}; - } - else - { - return detail::heap_block { p[ kwk::allocator | heap_allocator{} ] - , shp.numel(), options::offset(tag::table_{}, p) - }; - } - }(); - - if constexpr( Settings::contains(kwk::source) ) - { - data.assign(options::source(tag::table_{}, p).as_block()); - } - - return data; - } - -} diff --git a/include/kwk/container/options/view.hpp b/include/kwk/container/options/view.hpp deleted file mode 100644 index 5adfbaed..00000000 --- a/include/kwk/container/options/view.hpp +++ /dev/null @@ -1,32 +0,0 @@ -//================================================================================================== -/* - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -*/ -//================================================================================================== -#pragma once - -#include -#include -#include - -namespace kwk::tag { struct view_ {}; } - -namespace kwk::options -{ - // For view, we compute the data_block from the source and base_index - template - constexpr auto block(tag::view_ const& m, Settings const& p) noexcept - { - auto src = source(m,p); - return src.as_block(offset(m,p)); - } - - // For view, we infer the type from the source that must be present - template - struct element - { - using type = typename data::type::base_type; - }; -} diff --git a/include/kwk/container/pick.hpp b/include/kwk/container/pick.hpp new file mode 100644 index 00000000..87d0499f --- /dev/null +++ b/include/kwk/container/pick.hpp @@ -0,0 +1,40 @@ +//================================================================================================== +/** + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +**/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace kwk +{ + /// Retrieve a value from a settings pack using semantic category specialization + template + KWK_FORCEINLINE constexpr auto pick(Keyword const& k, Settings const& opts) + requires( Settings::contains(category).value ) + { + return pick(opts[category], k, opts); + } + + namespace result + { + template + struct pick + { + using type = decltype( kwk::pick(Keyword, std::declval() )); + }; + + template + using pick_t = typename pick::type; + } +} diff --git a/include/kwk/container/relabel.hpp b/include/kwk/container/relabel.hpp new file mode 100644 index 00000000..a59cd09e --- /dev/null +++ b/include/kwk/container/relabel.hpp @@ -0,0 +1,22 @@ +//================================================================================================== +/** + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +**/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include + +namespace kwk +{ + constexpr auto relabel(concepts::container auto&& c, auto&& l) + requires requires { kwk::label = KWK_FWD(l); } + { + return view{ rbr::merge( rbr::settings(label = KWK_FWD(l)), KWK_FWD(c).settings()) }; + } +} diff --git a/include/kwk/container/reshape.hpp b/include/kwk/container/reshape.hpp new file mode 100644 index 00000000..bdd1260d --- /dev/null +++ b/include/kwk/container/reshape.hpp @@ -0,0 +1,22 @@ +//================================================================================================== +/** + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +**/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include + +namespace kwk +{ + constexpr auto reshape(concepts::container auto&& c, auto&& sz) + requires requires { kwk::size = KWK_FWD(sz); } + { + return view{ rbr::merge( rbr::settings(size = KWK_FWD(sz)), KWK_FWD(c).settings()) }; + } +} diff --git a/include/kwk/container/settings/allocator.hpp b/include/kwk/container/settings/allocator.hpp new file mode 100644 index 00000000..a5c30e18 --- /dev/null +++ b/include/kwk/container/settings/allocator.hpp @@ -0,0 +1,28 @@ +//================================================================================================== +/** + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +**/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include +#include + +namespace kwk +{ + // Table use heap_allocator by default + template + KWK_FORCEINLINE constexpr auto pick(detail::table_, detail::allocator_, Settings const& opts) + { + return opts[allocator | heap_allocator{}]; + } + + // View can't have allocator - hard error + template + KWK_FORCEINLINE constexpr auto pick(detail::view_, detail::allocator_, Settings const&) =delete; +} diff --git a/include/kwk/container/settings/category.hpp b/include/kwk/container/settings/category.hpp new file mode 100644 index 00000000..60733f72 --- /dev/null +++ b/include/kwk/container/settings/category.hpp @@ -0,0 +1,56 @@ +//================================================================================================== +/** + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +**/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include + +// Pre-made categories +namespace kwk::detail +{ + struct view_ + { + using stored_value_type = view_; + using keyword_type = category_; + using kwk_container_category = void; + KWK_FORCEINLINE constexpr auto operator()(keyword_type const&) const noexcept { return *this; } + friend std::ostream& operator<<(std::ostream& os, view_ const&) { return os << "View"; } + + template + friend constexpr bool operator==(view_ const&, T const& ) noexcept + { + return std::same_as; + } + }; + + struct table_ + { + using stored_value_type = table_; + using keyword_type = category_; + using kwk_container_category = void; + KWK_FORCEINLINE constexpr auto operator()(keyword_type const&) const noexcept { return *this; } + friend std::ostream& operator<<(std::ostream& os, table_ const&) { return os << "Table"; } + + template + friend constexpr bool operator==(table_ const&, T const& ) noexcept + { + return std::same_as; + } + }; +} + +namespace kwk +{ + /// kwk::view category setting + inline constexpr detail::view_ view_ = {}; + + /// kwk::table category setting + inline constexpr detail::table_ table_ = {}; +} diff --git a/include/kwk/container/settings/label.hpp b/include/kwk/container/settings/label.hpp new file mode 100644 index 00000000..93a2b82e --- /dev/null +++ b/include/kwk/container/settings/label.hpp @@ -0,0 +1,22 @@ +//================================================================================================== +/** + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +**/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include + +namespace kwk +{ + template + KWK_FORCEINLINE constexpr auto pick(Category, detail::label_, Settings const& opts) + { + return opts[label]; + } +} diff --git a/include/kwk/container/settings/size.hpp b/include/kwk/container/settings/size.hpp new file mode 100644 index 00000000..1c1e964a --- /dev/null +++ b/include/kwk/container/settings/size.hpp @@ -0,0 +1,24 @@ +//================================================================================================== +/** + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +**/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include +#include + +namespace kwk +{ + // The data size is fetched or a default shape is fetched from the source if any + template + KWK_FORCEINLINE constexpr auto pick(Category c, detail::size_, Settings const& opts) + { + return opts[size | default_shape(pick(c,source,opts))]; + } +} diff --git a/include/kwk/container/settings/source.hpp b/include/kwk/container/settings/source.hpp new file mode 100644 index 00000000..5f6a75a5 --- /dev/null +++ b/include/kwk/container/settings/source.hpp @@ -0,0 +1,31 @@ +//================================================================================================== +/** + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +**/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include +#include + +namespace kwk +{ + // The data source is fetched or a ptr_source is returned using the type information if any + template + KWK_FORCEINLINE constexpr auto pick(detail::view_, detail::source_, Settings const& opts) + { + return opts[source | ptr_source{}]; + } + + template + KWK_FORCEINLINE constexpr auto pick(detail::table_, detail::source_, Settings const& opts) + { + auto value = opts[type]; + return opts[source | ptr_source{}]; + } +} diff --git a/include/kwk/container/settings/strides.hpp b/include/kwk/container/settings/strides.hpp new file mode 100644 index 00000000..012ce6f9 --- /dev/null +++ b/include/kwk/container/settings/strides.hpp @@ -0,0 +1,28 @@ +//================================================================================================== +/** + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +**/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include +#include +#include + +namespace kwk +{ + // The strides are fetched or computed from the size + template + KWK_FORCEINLINE constexpr auto pick(Category c, detail::strides_, Settings const& opts) + { + using shape_type = rbr::result::fetch_t; + + if constexpr(!concepts::descriptor) + return opts[strides | as_stride(pick(c,size,opts))]; + } +} diff --git a/include/kwk/container/settings/type.hpp b/include/kwk/container/settings/type.hpp new file mode 100644 index 00000000..92c27bc9 --- /dev/null +++ b/include/kwk/container/settings/type.hpp @@ -0,0 +1,52 @@ +//================================================================================================== +/** + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +**/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include +#include + +namespace kwk +{ + // Views find their type from either their source or their type if present + // source >> type however has we can't just cast the data on the fly + // Views can't have BOTH source and type + template + KWK_FORCEINLINE constexpr auto pick(detail::view_ c, detail::type_, Settings const& opts) + { + static_assert ( Settings::contains(source) != Settings::contains(type) + , "[KWK] - Error: view can't specify both source and type" + ); + + if constexpr( Settings::contains(source) ) + { + return as::value_type>; + } + else + { + return opts[type]; + } + } + + // Tables find their type int he type option OR the source if no type is used + // Both options can coexist as table will just copy the source data in a block of type + template + KWK_FORCEINLINE constexpr auto pick(detail::table_ c, detail::type_, Settings const& opts) + { + if constexpr( Settings::contains(type) ) + { + return opts[type]; + } + else + { + return as::value_type>; + } + } +} diff --git a/include/kwk/container/slicers/axis.hpp b/include/kwk/container/slicers/axis.hpp deleted file mode 100644 index c50b06dd..00000000 --- a/include/kwk/container/slicers/axis.hpp +++ /dev/null @@ -1,39 +0,0 @@ -//================================================================================================== -/** - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -**/ -//================================================================================================== -#pragma once - -#include -#include -#include - -namespace kwk::detail -{ - template - constexpr auto reshape( axis const& i, std::ptrdiff_t, Shape const& s ) noexcept - { - return s[i.dims]; - } - - inline constexpr auto origin( axis const& ) noexcept - { - return 0; - } - - template - inline auto restride( axis const&, std::ptrdiff_t i, Stride const& s) noexcept - { - return s[i]; - } - - // Traits for concepts - template struct is_unit_slicer; - template struct is_contiguous_slicer; - - template<> struct is_unit_slicer : std::false_type {}; - template struct is_contiguous_slicer : std::false_type {}; -} diff --git a/include/kwk/container/slicers/full_slicer.hpp b/include/kwk/container/slicers/full_slicer.hpp deleted file mode 100644 index b09537e4..00000000 --- a/include/kwk/container/slicers/full_slicer.hpp +++ /dev/null @@ -1,65 +0,0 @@ -//================================================================================================== -/** - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -**/ -//================================================================================================== -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace kwk::detail -{ - struct full_slicer - { - friend std::ostream& operator<<(std::ostream& os, full_slicer const&) - { - return os << "_"; - } - - constexpr auto operator()(std::ptrdiff_t b, std::ptrdiff_t e) const noexcept - { - return unit_slicer{b,e}; - } - - constexpr auto operator()(std::ptrdiff_t b, std::ptrdiff_t s, std::ptrdiff_t e) const noexcept - { - return slicer{b,s,e}; - } - - constexpr auto operator[](std::size_t d) const noexcept - { - return axis{d,0}; - } - }; - - template - constexpr auto reshape( full_slicer const& i, std::ptrdiff_t, Shape const& s ) noexcept - { - return s[i]; - } - - inline constexpr auto origin( full_slicer const& ) noexcept - { - return 0; - } - - template - inline auto restride( full_slicer const&, std::ptrdiff_t i, Stride const& s) noexcept - { - return s[i]; - } - - // Traits for concepts - template struct is_unit_slicer; - template struct is_contiguous_slicer; - - template<> struct is_unit_slicer : std::true_type {}; - template struct is_contiguous_slicer : std::true_type {}; -} diff --git a/include/kwk/container/slicers/single_slice.hpp b/include/kwk/container/slicers/single_slice.hpp deleted file mode 100644 index 8b852d96..00000000 --- a/include/kwk/container/slicers/single_slice.hpp +++ /dev/null @@ -1,40 +0,0 @@ -//================================================================================================== -/** - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -**/ -//================================================================================================== -#pragma once - -#include -#include - -namespace kwk::detail -{ - template - constexpr auto reshape( std::ptrdiff_t const&, std::ptrdiff_t, Shape const& ) noexcept - { - return 1; - } - - inline constexpr auto origin( std::ptrdiff_t const& i ) noexcept - { - return i; - } - - template - inline auto restride( std::ptrdiff_t const& , std::ptrdiff_t i, Stride const& s) noexcept - { - return s[i]; - } - - // Traits for concepts - template struct is_unit_slicer; - template struct is_contiguous_slicer; - - template struct is_unit_slicer : std::is_integral {}; - - template - struct is_contiguous_slicer : std::bool_constant && (D>1)> {}; -} diff --git a/include/kwk/container/slicers/slicer.hpp b/include/kwk/container/slicers/slicer.hpp deleted file mode 100644 index c2588075..00000000 --- a/include/kwk/container/slicers/slicer.hpp +++ /dev/null @@ -1,40 +0,0 @@ -//================================================================================================== -/** - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -**/ -//================================================================================================== -#pragma once - -#include -#include - -namespace kwk::detail -{ - struct slicer { std::ptrdiff_t begin, step, end; }; - - template - constexpr auto reshape( slicer const& i, std::ptrdiff_t, Shape const&) noexcept - { - return (i.end - i.begin)/i.step + 1; - } - - inline constexpr auto origin( slicer const& i ) noexcept - { - return i.begin; - } - - template - inline auto restride( slicer const& id, std::ptrdiff_t i, Stride const& s) noexcept - { - return s[i]*id.step; - } - - // Traits for concepts - template struct is_unit_slicer; - template struct is_contiguous_slicer; - - template<> struct is_unit_slicer : std::false_type {}; - template struct is_contiguous_slicer : std::false_type {}; -} diff --git a/include/kwk/container/slicers/unit_slicer.hpp b/include/kwk/container/slicers/unit_slicer.hpp deleted file mode 100644 index 8c3520ec..00000000 --- a/include/kwk/container/slicers/unit_slicer.hpp +++ /dev/null @@ -1,43 +0,0 @@ -//================================================================================================== -/** - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -**/ -//================================================================================================== -#pragma once - -#include -#include - -namespace kwk::detail -{ - struct unit_slicer - { - std::ptrdiff_t begin, end; - }; - - template - constexpr auto reshape( unit_slicer const& i, std::ptrdiff_t, Shape const& ) noexcept - { - return (i.end - i.begin) + 1; - } - - inline constexpr auto origin( unit_slicer const& i ) noexcept - { - return i.begin; - } - - template - inline auto restride( unit_slicer const&, std::ptrdiff_t i, Stride const& s) noexcept - { - return s[i]; - } - - // Traits for concepts - template struct is_unit_slicer; - template struct is_contiguous_slicer; - - template<> struct is_unit_slicer : std::true_type {}; - template struct is_contiguous_slicer : std::false_type {}; -} diff --git a/include/kwk/container/stride.hpp b/include/kwk/container/stride.hpp deleted file mode 100644 index 16e70a11..00000000 --- a/include/kwk/container/stride.hpp +++ /dev/null @@ -1,266 +0,0 @@ -//================================================================================================== -/* - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -*/ -//================================================================================================== -#pragma once - -#include -#include -#include -#include -#include - -namespace kwk -{ - struct strides_; - template struct shape; - - //================================================================================================ - //! @ingroup containers - //! @brief Fixed order stride with automatic unit stride detection capability - //! - //!
- //! **Required header**: - //! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} - //! #include - //! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - //!
- //! - //! @tparam Strider An instance of a stride descriptor - //================================================================================================ - template - struct stride - { - //============================================================================================== - // Info dump - //============================================================================================== - using strider_type = decltype(Strider); - using stride_map = typename strider_type::map_type; - - /// Type of dimensions' size - using size_type = typename strider_type::size_type; - - using storage_t = detail::stride_storage; - - static constexpr auto is_unit = strider_type::is_unit; - static constexpr auto is_implicit = strider_type::is_implicit; - static constexpr auto static_size = strider_type::static_size; - - static constexpr auto size() noexcept { return static_size; } - - //============================================================================================== - // stride is its self option keyword - //============================================================================================== - using stored_value_type = stride; - using keyword_type = strides_; - - constexpr auto operator()(keyword_type const&) const noexcept { return *this; } - - //============================================================================================== - // Element access - //============================================================================================== - template constexpr auto get() const noexcept - { - constexpr auto i = std::min(I,static_size-1); - - if constexpr(stride_map::contains(i)) - return std::integral_constant{}; - else - return storage_[stride_map::template locate(i)]; - } - - //============================================================================================== - // Construct from some amount of integral values - //============================================================================================== - template... Values> - constexpr stride(Values... v) noexcept : storage_{} - { - // Filter out the non-dynamic stride values - auto ptr = storage_.data(); - detail::for_each_args( [&ptr](T sv) - { - if constexpr( !std::is_same_v ) *ptr++ = sv; - } - , v... - ); - - constexpr std::ptrdiff_t sz = sizeof...(Values); - // Repeat last stride for when the data are missing - if constexpr(sz < static_size-2) - { - detail::constexpr_for - ( - [&]( std::integral_constant const&) - { - storage_[I] = storage_[sz-1]; - } - ); - } - } - - //============================================================================================== - // Construct from a shape with same dimensions - // Only possible if stride is unit on the inner dimension - //============================================================================================== - template - constexpr explicit stride(Shaper const& shp) noexcept requires(is_unit) - { - if constexpr(static_size > 1) - { - storage_[0] = shp.template get<0>(); - detail::constexpr_for<1,static_size-1> - ( - [&]( std::integral_constant const&) - { - storage_[I] = storage_[I-1] * shp.template get(); - } - ); - } - } - - void swap( stride& other ) noexcept { storage_.swap( other.storage_ ); } - - //============================================================================================== - // indexing interface - //============================================================================================== - template... Is> - constexpr auto index(Is... is) const noexcept - requires( ( sizeof...(Is) <= Strider.static_size) ) - { - return detail::linearize(std::make_index_sequence(),*this,is...); - } - - //============================================================================================== - // I/O - //============================================================================================== - friend std::ostream& operator<<(std::ostream& os, stride const& s) - { - os << "[{ "; - - []( std::index_sequence const&, auto& stream, auto const& c) - { - ((stream << c.template get

() << " "),...); - }( std::make_index_sequence{}, os, s); - - os << "}]"; - return os; - } - - storage_t storage_; - }; - - //================================================================================================ - // Specialization for 1D unit stride - //================================================================================================ - template - requires( Strider.is_implicit && Strider.static_size == 1) - struct stride - { - //============================================================================================== - // Info dump - //============================================================================================== - using strider_type = decltype(Strider); - using stride_map = typename strider_type::map_type; - using size_type = typename strider_type::size_type; - using storage_t = detail::stride_storage; - - static constexpr auto is_unit = strider_type::is_unit; - static constexpr auto is_implicit = strider_type::is_implicit; - static constexpr auto static_size = strider_type::static_size; - - //============================================================================================== - // stride is its self option keyword - //============================================================================================== - static constexpr auto size() noexcept { return static_size; } - - using stored_value_type = stride; - using keyword_type = strides_; - - constexpr auto operator()(keyword_type const&) const noexcept { return *this; } - - //============================================================================================== - // Element access - //============================================================================================== - template constexpr detail::unit_type get() const noexcept - { - return {}; - } - - //============================================================================================== - // Construct from whatever - //============================================================================================== - template constexpr stride(Values&&...) noexcept {} - - //============================================================================================== - // indexing interface - //============================================================================================== - constexpr auto index(std::convertible_to auto is) const noexcept { return is; } - - void swap( stride& ) noexcept {} - - //============================================================================================== - // I/O - //============================================================================================== - friend std::ostream& operator<<(std::ostream& os, stride const&) - { - return os << "[{ 1 }]"; - } - }; - - //================================================================================================ - // Generator - //================================================================================================ - template constexpr auto with_stride(S... s) - { - return stride< detail::index_map{} >{s...}; - } - - template constexpr auto with_stride(S... s) - { - using type_t = std::common_type_t...>; - return with_stride(s...); - } - - //================================================================================================ - // Unit stride helpers - //================================================================================================ - template - using unit_stride = stride{}>; - - inline constexpr detail::unit_type const unit_ = {}; - - //================================================================================================ - // Structured binding supports - //================================================================================================ - template - constexpr auto get(stride const& s) noexcept - { - return s.template get(); - } -} - -//================================================================================================== -// Structured binding supports -//================================================================================================== -namespace std -{ - template - struct tuple_element> - { - using type = decltype(std::declval>().template get()); - }; - - template - struct tuple_size> - : std::integral_constant - {}; -} - -namespace kumi -{ - template - struct is_product_type> : std::true_type {}; -} diff --git a/include/kwk/container/table.hpp b/include/kwk/container/table.hpp index dd3f570e..599c38df 100644 --- a/include/kwk/container/table.hpp +++ b/include/kwk/container/table.hpp @@ -7,14 +7,10 @@ //================================================================================================== #pragma once -#include -#include -#include +#include #include -#include #include - namespace kwk { //================================================================================================ @@ -24,12 +20,10 @@ namespace kwk //! @tparam Type Type of the underlying data //! @tparam Os Variadic list of settings describing current's table behavior //================================================================================================ - template - struct table : container + template + struct table : container { - using parent = container; - - static constexpr auto tag = parent::tag; + using parent = container; /// Underlying value type using value_type = typename parent::value_type; @@ -46,6 +40,9 @@ namespace kwk /// Associated const pointer type using const_pointer = typename parent::const_pointer; + /// Associated @ref kwk::shape type + using shape_type = typename parent::shape_type; + /// Compile-time @ref glossary-order static constexpr auto static_order = parent::static_order; @@ -54,37 +51,41 @@ namespace kwk //! @{ //============================================================================================== - constexpr table() : parent{rbr::settings(Os...)} {} + /// Default constructor + constexpr table() : parent{kwk::table_} {} /// Construct a table from a list of options - constexpr table(rbr::concepts::option auto const&... opts) : parent{rbr::settings(opts...)} {} + constexpr table(rbr::concepts::option auto const&... opts) : table{rbr::settings{opts...}} {} /// Construct a table from a settings descriptor - constexpr table(rbr::concepts::settings auto const& params) : parent{ params } {} + constexpr table(rbr::concepts::settings auto const& opts) + : parent{ [](S const& p) + { return rbr::merge(rbr::settings{kwk::table_}, p); }(opts) + } + {} - //============================================================================================== - //! @} - //============================================================================================== + /// Move constructor + constexpr table(table&&) = default; + + /// Move assignment operator + constexpr table& operator=(table&&) = default; + + /// Copy constructor + constexpr table(concepts::container, shape_type{}> auto const& other) + : table(other.settings()) + {} - constexpr auto settings() const noexcept + /// Copy assignment operator + constexpr table& operator=(concepts::container, shape_type{}> auto const& other) { - auto const opts = rbr::settings(Os...); - - if constexpr(parent::has_label) - { - return rbr::merge ( rbr::settings ( size = parent::shape() - , label = parent::label() - ) - , opts - ); - } - else - { - return rbr::merge ( rbr::settings(size = parent::shape()) - , opts - ); - } + table local(other); + parent::swap(local); + return *this; } + + //============================================================================================== + //! @} + //============================================================================================== }; //================================================================================================ @@ -94,14 +95,40 @@ namespace kwk /// This deduction guide is provided for kwk::table to allow deduction from a list of options template - table(O const&...) -> table>::type,O{}...>; + table(O const&...) + -> table < typename detail::builder::memory + , typename detail::builder::accessor + , typename detail::builder::metadata + >; /// This deduction guide is provided for kwk::table to allow deduction from another table's settings template table(rbr::settings const&) - -> table>::type, O{}...>; + -> table < typename detail::builder::memory + , typename detail::builder::accessor + , typename detail::builder::metadata + >; + + /// This deduction guide is provided for kwk::table to allow deduction from another container + template + table(C const&) -> table < typename detail::builder::memory + , typename detail::builder::accessor + , typename detail::builder::metadata + >; //================================================================================================ //! @} //================================================================================================ + + /// Type helper + template struct make_table + { + using type = table< typename detail::builder::memory + , typename detail::builder::accessor + , typename detail::builder::metadata + >; + }; + + template + using make_table_t = typename make_table::type; } diff --git a/include/kwk/container/view.hpp b/include/kwk/container/view.hpp index c2e87e23..9b7e75fd 100644 --- a/include/kwk/container/view.hpp +++ b/include/kwk/container/view.hpp @@ -7,10 +7,8 @@ //================================================================================================== #pragma once -#include -#include +#include #include -#include #include namespace kwk @@ -19,15 +17,12 @@ namespace kwk //! @ingroup containers //! @brief Non-owning, contiguous multi-dimensional container //! - //! @tparam Type Type of the underlying data - //! @tparam Os Variadic list of settings describing current's view behavior + //! @tparam Os Variadic list of settings describing current's view behavior //================================================================================================ - template - struct view : container + template + struct view : container { - using parent = container; - - static constexpr auto tag = parent::tag; + using parent = container; /// Underlying value type using value_type = typename parent::value_type; @@ -44,6 +39,9 @@ namespace kwk /// Associated const pointer type using const_pointer = typename parent::const_pointer; + /// Associated @ref kwk::shape type + using shape_type = typename parent::shape_type; + /// Compile-time @ref glossary-order static constexpr auto static_order = parent::static_order; @@ -52,42 +50,35 @@ namespace kwk //! @{ //============================================================================================== + /// Default constructor + constexpr view() : parent{kwk::view_} {} + /// Construct a view from a list of options - constexpr view(rbr::concepts::option auto const&... opts) : parent{rbr::settings(opts...)} {} + constexpr view(rbr::concepts::option auto const&... opts) : view{rbr::settings{opts...}} {} /// Construct a view from a settings descriptor - constexpr view(rbr::concepts::settings auto const& params) : parent{ params } {} + constexpr view(rbr::concepts::settings auto const& opts) + : parent{ [](S const& p) + { return rbr::merge(rbr::settings{kwk::view_}, p); }(opts) + } + {} + + /// Shallow copy constructor + constexpr view(concepts::container, shape_type{}> auto const& other) + : view(other.settings()) + {} + + /// Shallow assignment operator + constexpr view& operator=(concepts::container, shape_type{}> auto const& other) + { + view local(other); + parent::swap(local); + return *this; + } //============================================================================================== //! @} //============================================================================================== - - constexpr auto settings() const noexcept - { - // Retrieve all basic options + correct shape value - auto const base = rbr::settings(Os...); - auto const opts = rbr::merge( rbr::settings(size = parent::shape()) - , base - ); - - // Retrieve potential offset to rebuild proper view target - auto const offset = options::offset(tag, opts); - - if constexpr(parent::has_label) - { - return rbr::merge ( rbr::settings ( source = parent::data() + offset - , label = parent::label() - ) - , opts - ); - } - else - { - return rbr::merge ( rbr::settings(source = parent::data() + offset) - , opts - ); - } - } }; //================================================================================================ @@ -97,14 +88,40 @@ namespace kwk /// This deduction guide is provided for kwk::view to allow deduction from a list of options template - view(O const&...) -> view>::type,O{}...>; + view(O const&...) + -> view< typename detail::builder::memory + , typename detail::builder::accessor + , typename detail::builder::metadata + >; /// This deduction guide is provided for kwk::view to allow deduction from another view's settings template view(rbr::settings const&) - -> view>::type, O{}...>; + -> view< typename detail::builder::memory + , typename detail::builder::accessor + , typename detail::builder::metadata + >; + + /// This deduction guide is provided for kwk::view to allow deduction from another container + template + view(C const&) -> view < typename detail::builder::memory + , typename detail::builder::accessor + , typename detail::builder::metadata + >; //================================================================================================ //! @} //================================================================================================ + + /// Type helper + template struct make_view + { + using type = view < typename detail::builder::memory + , typename detail::builder::accessor + , typename detail::builder::metadata + >; + }; + + template + using make_view_t = typename make_view::type; } diff --git a/include/kwk/detail/abi.hpp b/include/kwk/detail/abi.hpp new file mode 100644 index 00000000..e9ed60c1 --- /dev/null +++ b/include/kwk/detail/abi.hpp @@ -0,0 +1,24 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +// Faster than std::forward +#define KWK_FWD(...) static_cast(__VA_ARGS__) + +// Force a function to be inline +#if defined(KWK_NO_FORCEINLINE) +# define KWK_FORCEINLINE inline +#else +# if defined(_MSC_VER) +# define KWK_FORCEINLINE __forceinline +# elif defined(__GNUC__) && __GNUC__ > 3 +# define KWK_FORCEINLINE inline __attribute__((__always_inline__)) +# else +# define KWK_FORCEINLINE inline +# endif +#endif diff --git a/include/kwk/detail/algorithm/for_each.hpp b/include/kwk/detail/algorithm/for_each.hpp new file mode 100644 index 00000000..df5e4fdd --- /dev/null +++ b/include/kwk/detail/algorithm/for_each.hpp @@ -0,0 +1,66 @@ +//================================================================================================== +/** + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +**/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include + +namespace kwk +{ + namespace detail + { + //============================================================================================== + // n-Dimensional for_each generator + // Piles up single for() lambda across each dimension then run them + //============================================================================================== + template + constexpr auto for_each(Func&& f, Container&& c, Dims const&ds) + { + auto loops = kumi::fold_right ( [](auto acc, auto m) + { + return [=](auto... is) + { + for(decltype(m) i = 0;i + constexpr auto for_each_index(Func&& f, Container&& c, Dims const& ds) + { + auto loops = kumi::fold_right ( [](auto acc, auto m) + { + return [=](auto... is) + { + for(decltype(m) i = 0;i -#include -#include -#include -#include - -namespace kwk::detail -{ - template - struct builder - { - static constexpr Tag tag = {}; - static constexpr auto opts = rbr::settings(Options...); - - // Computes view_access type - static constexpr auto shape = options::shape(tag, opts); - static constexpr auto stride = options::stride(tag, opts); - using accessor = detail::accessor< shape, stride >; - - // Computes data_block type - using data_block = detail::data_block::type>; - - // Computes metadata type; - using metadata = detail::metadata>; - }; -} diff --git a/include/kwk/container/components/accessor.hpp b/include/kwk/detail/container/accessor.hpp similarity index 75% rename from include/kwk/container/components/accessor.hpp rename to include/kwk/detail/container/accessor.hpp index 3e830d06..97132fe1 100644 --- a/include/kwk/container/components/accessor.hpp +++ b/include/kwk/detail/container/accessor.hpp @@ -7,7 +7,7 @@ //================================================================================================== #pragma once #include -#include +#include #include #include @@ -20,24 +20,26 @@ namespace kwk::detail { using shape_type = std::remove_cvref_t; using stride_type = std::remove_cvref_t; - static constexpr auto static_order = shape_type::static_order; + static constexpr auto static_order = shape_type::static_size; constexpr auto size() const noexcept { return shape_.numel(); } constexpr auto shape() const noexcept { return shape_; } constexpr auto stride() const noexcept { return stride_; } - constexpr accessor(auto const& tag, rbr::concepts::settings auto const& opts) - : shape_ ( options::shape(tag,opts) ) - , stride_( options::stride(tag,opts) ) + constexpr accessor(): shape_ (), stride_() {} + + constexpr accessor(rbr::concepts::settings auto const& opts) + : shape_ ( pick(kwk::size ,opts) ) + , stride_( pick(kwk::strides,opts) ) {} - constexpr auto index(auto i0) const noexcept { return i0*get<0>(stride_); } - constexpr auto index(auto... is) const noexcept { return stride_.index(is...); } + constexpr auto index(auto i0) const noexcept { return i0*get<0>(stride_); } + constexpr auto index(auto... is) const noexcept { return stride_.linearize(is...); } constexpr void reshape( shape_type const& s ) noexcept { shape_ = s; - stride_ = s.as_stride(); + stride_ = as_stride(s); } constexpr void reshape( shape_type const& s, stride_type const& st ) noexcept @@ -65,21 +67,22 @@ namespace kwk::detail { using shape_type = std::remove_cvref_t; using stride_type = std::remove_cvref_t; - static constexpr auto static_order = shape_type::static_order; + static constexpr auto static_order = shape_type::static_size; constexpr auto size() const noexcept { return Shape.numel(); } constexpr auto shape() const noexcept { return Shape; } constexpr auto stride() const noexcept { return Stride; } - constexpr accessor(auto const&, rbr::concepts::settings auto const&) noexcept {} + constexpr accessor() {} + constexpr accessor(rbr::concepts::settings auto const&) noexcept {} constexpr void swap( accessor& ) noexcept {} template - constexpr auto index(Is... is) const noexcept { return Stride.index(is...); } + constexpr auto index(Is... is) const noexcept { return Stride.linearize(is...); } }; //================================================================================================ - // Optimization : runtime 1D shape + unit/implicit stride + // Optimization : runtime 1D shape + unit stride // Expected sizeof : sizeof(void*) + sizeof(shape[0]) //================================================================================================ template @@ -88,10 +91,11 @@ namespace kwk::detail { using shape_type = std::remove_cvref_t; using stride_type = std::remove_cvref_t; - static constexpr auto static_order = shape_type::static_order; + static constexpr auto static_order = shape_type::static_size; - constexpr accessor(auto const& tag, rbr::concepts::settings auto const& opts) - : shape_ ( options::shape(tag,opts) ) + constexpr accessor() : shape_{} {} + constexpr accessor(rbr::concepts::settings auto const& opts) + : shape_ ( pick(kwk::size,opts) ) {} constexpr auto size() const noexcept { return get<0>(shape_); } @@ -106,26 +110,26 @@ namespace kwk::detail }; //================================================================================================ - // Optimization : runtime 2D shape + unit & implicit stride + // Optimization : runtime 2D shape + unit stride // Expected sizeof : sizeof(void*) + sizeof(shape) //================================================================================================ template - requires( !Shape.is_fully_static && Shape.order() == 2 - && Stride.is_unit && Stride.is_implicit - ) + requires( !Shape.is_fully_static && Shape.order() == 2 && Stride.is_unit ) struct accessor { using shape_type = std::remove_cvref_t; using stride_type = std::remove_cvref_t; - static constexpr auto static_order = shape_type::static_order; + static constexpr auto static_order = shape_type::static_size; - constexpr accessor(auto const& tag, rbr::concepts::settings auto const& opts) - : shape_ ( options::shape(tag,opts) ) + constexpr accessor() : shape_{} {} + constexpr accessor(rbr::concepts::settings auto const& opts) + : shape_ ( pick(kwk::size,opts) ) {} - constexpr std::ptrdiff_t size() const noexcept { return shape_.numel(); } - constexpr auto shape() const noexcept { return shape_; } - constexpr auto stride() const noexcept { return stride_type{unit_,get<0>(shape_)}; } + constexpr std::ptrdiff_t size() const noexcept { return shape_.numel(); } + constexpr auto shape() const noexcept { return shape_; } + + constexpr auto stride() const noexcept { return stride_type{fixed<1>,get<0>(shape_)}; } constexpr void reshape( shape_type const& s ) { shape_ = s; } diff --git a/include/kwk/detail/container/builder.hpp b/include/kwk/detail/container/builder.hpp new file mode 100644 index 00000000..1af324a3 --- /dev/null +++ b/include/kwk/detail/container/builder.hpp @@ -0,0 +1,46 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include +#include + +namespace kwk::detail +{ + template + struct builder + { + static constexpr auto options = Options; + static constexpr auto kind = Options[category]; + using options_t = decltype(options); + using shape_t = result::pick_t; + + // Computes shape type + static constexpr auto shape = []() + { + if constexpr(!concepts::descriptor) return pick(size, options); + else return kwk::shape{}; + }(); + + // Computes stride type + static constexpr auto stride = []() + { + if constexpr(!concepts::descriptor) return pick(strides, options); + else return pick(strides, rbr::settings(kind,shape)); + }(); + + // Builds all elements of a container: accessor, metadata, memory block + using accessor = detail::accessor; + using metadata = detail::metadata>; + using value_type = typename result::pick_t::type; + using memory = block_t; + }; +} diff --git a/include/kwk/container/components/metadata.hpp b/include/kwk/detail/container/metadata.hpp similarity index 79% rename from include/kwk/container/components/metadata.hpp rename to include/kwk/detail/container/metadata.hpp index 3187f771..30df2005 100644 --- a/include/kwk/container/components/metadata.hpp +++ b/include/kwk/detail/container/metadata.hpp @@ -7,8 +7,8 @@ //================================================================================================== #pragma once +#include #include -#include namespace kwk::detail { @@ -20,8 +20,10 @@ namespace kwk::detail { static constexpr bool has_label = true; - constexpr metadata(auto const&, rbr::concepts::settings auto const& opts) - : label_(opts[kwk::label]) + constexpr metadata() {} + + constexpr metadata(rbr::concepts::settings auto const& opts) + : label_( pick(kwk::label, opts)) {} constexpr Label const& label() const noexcept { return label_; } @@ -35,7 +37,8 @@ namespace kwk::detail struct metadata { static constexpr bool has_label = false; - constexpr metadata(auto const&, rbr::concepts::settings auto const&) noexcept {} + constexpr metadata() {} + constexpr metadata(rbr::concepts::settings auto const&) noexcept {} constexpr auto label() const noexcept { return ""; } constexpr void swap( metadata& ) noexcept {} diff --git a/include/kwk/detail/ct_helpers.hpp b/include/kwk/detail/ct_helpers.hpp deleted file mode 100644 index 182624fc..00000000 --- a/include/kwk/detail/ct_helpers.hpp +++ /dev/null @@ -1,157 +0,0 @@ -//================================================================================================== -/* - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -*/ -//================================================================================================== -#pragma once - -#include -#include -#include -#include - -// Faster than std::forward -#define KWK_FWD(...) static_cast(__VA_ARGS__) - -// Force a function to be inline -#if defined(KWK_NO_FORCEINLINE) -# define KWK_FORCEINLINE inline -#else -# if defined(_MSC_VER) -# define KWK_FORCEINLINE __forceinline -# elif defined(__GNUC__) && __GNUC__ > 3 -# define KWK_FORCEINLINE inline __attribute__((__always_inline__)) -# else -# define KWK_FORCEINLINE inline -# endif -#endif - - -namespace kwk::detail -{ - //================================================================================================ - // Find the static_size of static array like types - //================================================================================================ - template struct static_size : std::false_type {}; - - template struct static_size> : std::true_type - { - static constexpr std::size_t size_value = N; - }; - - template struct static_size : std::true_type - { - static constexpr std::size_t size_value = N; - }; - - template - inline constexpr std::size_t static_size_v = static_size>::size_value; - - //================================================================================================ - // Find the value type of anything with a .data() - //================================================================================================ - template - using value_type_of = std::remove_reference_t()))>; - - //================================================================================================ - // for_each_args abstraction - //================================================================================================ - template - constexpr void for_each_args(Callable c, Args&&... args) noexcept - { - (c(KWK_FWD(args)),...); - } - - //================================================================================================ - // constexpr_for abstraction - //================================================================================================ - template - constexpr auto constexpr_for(Callable c) noexcept - { - return [] - (std::integer_sequence const&, Func f) - { - ((f( std::integral_constant{})),...); - return f; - }( std::make_integer_sequence(), c ); - } - - template - constexpr auto constexpr_for(Callable c) noexcept - { - return constexpr_for<0,Count>(c); - } - - //================================================================================================ - // List of integral constants - //================================================================================================ - template struct values {}; - - //================================================================================================ - // Augmented static integer list for mapping known unit values - //================================================================================================ - template struct index_list - { - // How many indexes ? - static constexpr std::size_t size = sizeof...(I); - - // is N in the set of known unit indexes ? - static constexpr bool contains(std::size_t N) noexcept - { - if constexpr(sizeof...(I) > 0) - { - bool found[] = { (I==N)... }; - for(auto f : found) if(f) return true; - return false; - } - else return false; - } - - // Aggregation of an index into an existing index_list - template using append = index_list; - - // Find the actual dynamic index of a non-unit index - template static constexpr auto locate(std::uint8_t const N) noexcept - { - // Count how far you need to go to find an unknown - auto const less_than_n_count{( 0 + ... + (I < N) )}; - return N - less_than_n_count; - } - }; - - //================================================================================================ - // Build a list of index in a type list where a target type is found - //================================================================================================ - template - struct type_map_impl; - - template - struct type_map_impl - { - using type = typename Current::template append; - }; - - template - struct type_map_impl - { - using type = Current; - }; - - template - struct type_map_impl - : type_map_impl - { - }; - - template - struct type_map_impl - : type_map_impl,Tail...> - { - }; - - template - struct type_map : type_map_impl, Vs...> - {}; -} diff --git a/include/kwk/detail/heap_block.hpp b/include/kwk/detail/heap_block.hpp deleted file mode 100644 index 7f42804f..00000000 --- a/include/kwk/detail/heap_block.hpp +++ /dev/null @@ -1,73 +0,0 @@ -//================================================================================================== -/** - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -**/ -//================================================================================================== -#pragma once -#include -#include -#include - -namespace kwk::detail -{ - template struct heap_block - { - using base_type = T; - using value_type = std::remove_const_t; - using reference = std::add_lvalue_reference_t; - using const_reference = std::add_lvalue_reference_t; - using pointer = std::add_pointer_t; - using const_pointer = std::add_pointer_t; - - struct deleter - { - any_allocator allocator_; - std::ptrdiff_t size_; - std::ptrdiff_t offset_; - - deleter() : size_(0), offset_(0) {} - template deleter(A a, auto s, auto o) : allocator_(a), size_(s), offset_(o) {} - - void operator()(void* p) { allocator_.deallocate((value_type*)(p) + offset_); } - }; - - std::unique_ptr data_; - - template - constexpr heap_block( Allocator a, auto size, auto offset) - : data_ ( (value_type*)(a.allocate(size*sizeof(T))) - offset - , deleter(a,size,offset) - ) - {} - - constexpr heap_block(heap_block&&) = default; - constexpr heap_block& operator=(heap_block&&) = default; - - constexpr heap_block(heap_block const& other) - { - auto del = other.data_.get_deleter(); - auto local = heap_block( del.allocator_, del.size_ , del.offset_); - this->swap(local); - } - - constexpr heap_block& operator=(heap_block const& other) - { - auto that(other); - this->swap(that); - return *this; - } - - constexpr void swap(heap_block& other) { data_.swap(other.data_); } - constexpr friend void swap(heap_block& a,heap_block& b) { a.swap(b); } - - constexpr auto data() noexcept { return data_.get(); } - constexpr auto data() const noexcept { return data_.get(); } - - constexpr void assign(auto const& src) - { - std::copy(src.data(), src.data() + data_.get_deleter().size_, data()); - } - }; -} diff --git a/include/kwk/detail/hybrid_sequence.hpp b/include/kwk/detail/hybrid_sequence.hpp deleted file mode 100644 index 85774b9c..00000000 --- a/include/kwk/detail/hybrid_sequence.hpp +++ /dev/null @@ -1,96 +0,0 @@ -//================================================================================================== -/* - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -*/ -//================================================================================================== -#pragma once - -#include -#include -#include -#include -#include - -namespace kwk::detail -{ - // Discriminating types for hybrid_sequence building - struct dyn_ { dyn_(auto) {} }; - struct fix_ {}; - - // A type remembering the sequence of operations it was made from - template struct hybrid_sequence - { - using size_type = SizeType; - using type = hybrid_sequence; - - static constexpr auto size_map() { return typename type_map::type{}; } - static constexpr std::ptrdiff_t size() { return sizeof...(Ops); } - static constexpr bool is_fully_static = size_map().size == sizeof...(Ops); - - constexpr hybrid_sequence() : data_{} {} - - constexpr auto at(std::size_t i) const { return data_[i]; } - - template constexpr auto append(X... x) const - { - return [&](std::index_sequence const&) - { - using that_t = std::array; - return that_t{{std::get(data_)..., x...}}; - }(std::index_sequence_for()); - } - - template - constexpr bool is_compatible(hybrid_sequence o) const noexcept - { - if constexpr(sizeof...(O2) != sizeof...(Ops)) return false; - else - { - return [&]( std::index_sequence) - { - return ((( std::same_as - || (std::same_as && std::same_as && data_[I] == o.data_[I]) - )) && ...); - }( std::make_index_sequence{}); - } - } - - template - constexpr hybrid_sequence(hybrid_sequence other, SizeType i) : data_(other.append(i)) - {} - - constexpr hybrid_sequence operator()() const { return {*this, 0}; } - constexpr hybrid_sequence operator[](SizeType i) const { return {*this, i}; } - - std::array data_; - }; - - // Special case for empty hybrid_sequence - template struct hybrid_sequence - { - using size_type = SizeType; - using type = hybrid_sequence; - - static constexpr auto size_map() { return index_list{}; } - static constexpr std::ptrdiff_t size() { return 0; } - static constexpr bool is_fully_static = true; - - constexpr hybrid_sequence() {} - - template constexpr auto append(X... x) const - { - using that_t = std::array; - return that_t{{x...}}; - } - - template - constexpr bool is_compatible(hybrid_sequence) const noexcept { return true; } - - constexpr hybrid_sequence operator()() const { return {*this, 0}; } - constexpr hybrid_sequence operator[](SizeType i) const { return {*this, i}; } - }; - - template struct to_dyn_ { using type = detail::dyn_; }; -} diff --git a/include/kwk/detail/joker.hpp b/include/kwk/detail/joker.hpp deleted file mode 100644 index 5543b44f..00000000 --- a/include/kwk/detail/joker.hpp +++ /dev/null @@ -1,38 +0,0 @@ -//================================================================================================== -/** - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -**/ -//================================================================================================== -#pragma once - -#include - -namespace kwk::detail -{ - struct axis - { - axis& operator=(std::size_t s) { size = s; return *this;} - std::size_t dims; - std::ptrdiff_t size; - }; - - struct value_joker - { - friend std::ostream& operator<<(std::ostream& os, value_joker const&) - { - return os << "_"; - } - - constexpr auto operator[](std::size_t d) const noexcept - { - return axis{d,0}; - } - }; -} - -namespace kwk -{ - inline constexpr detail::value_joker _ = {}; -} diff --git a/include/kwk/detail/kumi.hpp b/include/kwk/detail/kumi.hpp index 82298a09..86c1c0ea 100644 --- a/include/kwk/detail/kumi.hpp +++ b/include/kwk/detail/kumi.hpp @@ -7,75 +7,53 @@ //================================================================================================== #ifndef KUMI_TUPLE_HPP_INCLUDED #define KUMI_TUPLE_HPP_INCLUDED - -#include -#include -#include +#include #include - +namespace kumi::detail +{ + template struct leaf + { + T value; + }; + template constexpr T &get_leaf(leaf &arg) noexcept + { + return arg.value; + } + template constexpr T &&get_leaf(leaf &&arg) noexcept + { + return static_cast(arg.value); + } + template + constexpr T const &&get_leaf(leaf const &&arg) noexcept + { + return static_cast(arg.value); + } + template constexpr T const &get_leaf(leaf const &arg) noexcept + { + return arg.value; + } + template struct binder; + template + struct binder, Ts...> : leaf... + { + }; +} +namespace kumi +{ +} #if defined(__clang__) # pragma clang diagnostic ignored "-Wmissing-braces" #endif - #define KUMI_FWD(...) static_cast(__VA_ARGS__) - -//================================================================================================== -//! @namespace kumi -//! @brief Main KUMI namespace -//================================================================================================== +#include namespace kumi { - //================================================================================================ - //! @defgroup utility Helper types and function - //! @brief Tools for interacting with kumi::tuple - //! - //! @defgroup tuple Tuple types and function - //! @brief Definition for kumi::tuple class and functions - //! - //! @defgroup algorithm Tuple Algorithms - //! @brief Algorithms for manipulating kumi::tuple - //! - //! @ingroup algorithm - //! @{ - //! @defgroup transforms Tuple Transformations - //! @brief Algorithms applying transformation to tuple - //! - //! @defgroup queries Tuple Queries - //! @brief Algorithms querying properties from tuples - //! - //! @defgroup reductions Tuple Generalized Reductions - //! @brief Algorithms performing reductions over tuples - //! - //! @defgroup generators Tuple Generators - //! @brief Algorithms generating tuples - //! @} - //================================================================================================ - - //================================================================================================ - //! @ingroup utility - //! @brief Integral constant type - //! - //! Defines a integral constant wrapper used to carry compile-time constant through API - //================================================================================================ template struct index_t { - /// Value stored by the constant static constexpr auto value = N; - - /// Conversion operator to integer constexpr inline operator std::size_t() const noexcept { return N; } }; - - //================================================================================================ - //! @ingroup utility - //! @brief Inline integral constant value for kumi::index_t - //================================================================================================ template inline constexpr index_t const index = {}; - - //================================================================================================ - //! @namespace literals - //! @brief KUMI literals namespace - //================================================================================================ namespace literals { template constexpr auto b10() @@ -84,307 +62,124 @@ namespace kumi ((value = value * 10 + (c - '0')), ...); return value; } - - //============================================================================================== - //! @ingroup utility - //! @brief Forms a integral constant literal of the desired value. - //! @return An instance of kumi::index_t for the specified integral value - //! ## Example: - //! @include doc/index.cpp - //============================================================================================== template constexpr auto operator"" _c() noexcept { return index()>; } } - - namespace detail + template class Pred> [[nodiscard]] constexpr auto predicate() noexcept { - //============================================================================================== - // Helper concepts - //============================================================================================== - template struct is_piecewise_constructible; - template struct is_piecewise_convertible; - - template class Box, typename... From, typename... To> - struct is_piecewise_convertible, Box> - { - static constexpr bool value = (... && std::convertible_to); - }; - - template class Box, typename... From, typename... To> - struct is_piecewise_constructible, Box> - { - static constexpr bool value = (... && std::is_constructible_v); - }; - - template - concept piecewise_convertible = detail::is_piecewise_convertible::value; - - template - concept piecewise_constructible = detail::is_piecewise_constructible::value; - - template concept implicit_constructible = requires(Args... args) - { - T {args...}; - }; - - //============================================================================================== - // Tuple leaf binder tricks - //============================================================================================== - template struct leaf - { - T value; - }; - - template constexpr T &get_leaf(leaf &arg) noexcept - { - return arg.value; - } - - template constexpr T &&get_leaf(leaf &&arg) noexcept - { - return static_cast(arg.value); - } - - template - constexpr T const &&get_leaf(leaf const &&arg) noexcept - { - return static_cast(arg.value); - } - - template constexpr T const &get_leaf(leaf const &arg) noexcept - { - return arg.value; - } - - template struct binder; - - template - struct binder, Ts...> : leaf... - { - }; - - //============================================================================================== - // Fold helpers - //============================================================================================== - template struct foldable - { - F func; - T value; - - template - friend constexpr decltype(auto) operator>>(foldable &&x, foldable &&y) - { - return detail::foldable {x.func, x.func(y.value, x.value)}; - } - - template - friend constexpr decltype(auto) operator<<(foldable &&x, foldable &&y) - { - return detail::foldable {x.func, x.func(x.value, y.value)}; - } - }; - - template foldable(const F &, T &&) -> foldable; + return [](T const&) constexpr { return Pred::value; }; } - - //================================================================================================ - //! @ingroup tuple - //! @brief Opt-in traits for types behaving like a kumi::product_type - //! - //! To be treated like a tuple, an user defined type must supports structured bindings opt-in to - //! kumi::product_type Semantic. - //! - //! This can be done in two ways: - //! - exposing an internal `is_product_type` type that evaluates to `void` - //! - specializing the `kumi::is_product_type` traits so it exposes a static constant member - //! `value` that evaluates to `true` - //! - //! ## Example: - //! @include doc/adapt.cpp - //============================================================================================== +} +#include +#include +namespace kumi +{ template struct is_product_type : std::false_type {}; template struct is_product_type : std::true_type {}; - - //================================================================================================ - //! @ingroup tuple - //! @brief Computes the number of elements of a kumi::product_type - //! - //! @param T kumi::product_type to inspect - //! - //! ## Helper value - //! @code - //! template inline constexpr auto size_v = size::value; - //! @endcode - //================================================================================================ template struct size : std::tuple_size {}; template struct size : size {}; template struct size : size {}; template struct size : size {}; template struct size : size {}; template struct size : size {}; - template inline constexpr auto size_v = size::value; - - //================================================================================================ - //! @ingroup tuple - //! @brief Concept specifying a type is non-empty standard tuple-like type. - //================================================================================================ - template concept non_empty_tuple = requires( T const &t ) + template struct element : std::tuple_element {}; + template struct element : element {}; + template struct element : element {}; + template struct element : element {}; + template struct element : element {}; + template using element_t = typename element::type; + template struct member { - typename std::tuple_element<0,std::remove_cvref_t>::type; - typename std::tuple_size>::type; + using type = decltype( get(std::declval())); }; - - - //================================================================================================ - //! @ingroup tuple - //! @brief Concept specifying a type is an empty standard tuple-like type. - //================================================================================================ - template concept empty_tuple = (std::tuple_size>::value == 0); - - //================================================================================================ - //! @ingroup tuple - //! @brief Concept specifying a type is a standard tuple-like type. - //================================================================================================ - template concept std_tuple_compatible = empty_tuple || non_empty_tuple; - - //================================================================================================ - //! @ingroup tuple - //! @brief Concept specifying a type follows the Product Type semantic - //! - //! A type `T` models `kumi::product_type` if it opts in for the Product Type semantic and - //! provides supports for structured bindings. - //================================================================================================ - template - concept product_type = std_tuple_compatible && is_product_type>::value; - - //================================================================================================ - //! @ingroup tuple - //! @brief Concept specifying a type follows the Product Type semantic and has a known size - //! - //! A type `T` models `kumi::sized_product_type` if it models `kumi::product_type` and has - //! exactly `N` elements. - //================================================================================================ - template - concept sized_product_type = product_type && (size::value == N); - - //================================================================================================ - //! @ingroup tuple - //! @brief Concept specifying a type follows the Product Type semantic and has a size lower bound - //! - //! A type `T` models `kumi::sized_product_type` if it models `kumi::product_type` and has - //! at least `N` elements. - //================================================================================================ - template - concept sized_product_type_or_more = product_type && (size::value >= N); - + template using member_t = typename member::type; template struct tuple; } - -//================================================================================================== -// Structured binding adaptation -//================================================================================================== -namespace std +#if !defined(KUMI_DOXYGEN_INVOKED) +template +struct std::tuple_element> + : std::tuple_element> +{ +}; +template struct std::tuple_element const> +{ + using type = typename tuple_element>::type const; +}; +template struct std::tuple_element<0, kumi::tuple> { - template - struct tuple_element> : tuple_element> + using type = Head; +}; +template +struct std::tuple_size> : std::integral_constant +{ +}; +#endif +#include +#include +namespace kumi::detail +{ + template struct is_piecewise_constructible; + template struct is_piecewise_convertible; + template class Box, typename... From, typename... To> + struct is_piecewise_convertible, Box> { + static constexpr bool value = (... && std::convertible_to); }; - - template struct tuple_element const> + template class Box, typename... From, typename... To> + struct is_piecewise_constructible, Box> { - using type = typename tuple_element>::type const; + static constexpr bool value = (... && std::is_constructible_v); }; - - template struct tuple_element<0, kumi::tuple> + template + concept piecewise_convertible = detail::is_piecewise_convertible::value; + template + concept piecewise_constructible = detail::is_piecewise_constructible::value; + template concept implicit_constructible = requires(Args... args) { - using type = Head; + T {args...}; }; - - template - struct tuple_size> : std::integral_constant + template + concept applicable_i = std::is_invocable_v...>; + template struct is_applicable; + template + struct is_applicable, Tuples...> + : std::bool_constant<(applicable_i && ...)> + { + }; + template + concept applicable = detail:: + is_applicable::value, ...)>, Tuples...>::value; + template + concept comparable = requires(T t, U u) { + { t == u }; }; } - +#include +#include +#include +#include namespace kumi { - //================================================================================================ - //! @ingroup tuple - //! @brief Provides indexed access to the types of the elements of a kumi::product_type. - //! - //! @tparam I Index of the type to retrieve - //! @tparam T kumi::product_type to access - //! - //! ## Helper type - //! @code - //! namespace kumi - //! { - //! template using element_t = typename element::type; - //! } - //! @endcode - //================================================================================================ - template struct element : std::tuple_element {}; - template struct element : element {}; - template struct element : element {}; - template struct element : element {}; - template struct element : element {}; - - template using element_t = typename element::type; - - //================================================================================================ - //! @ingroup tuple - //! @brief Computes the return type of a call to kumi::get - //! - //! @tparam I Index of the type to retrieve - //! @tparam T kumi::product_type to access - //! - //! ## Helper type - //! @code - //! namespace kumi - //! { - //! template using member_t = typename member::type; - //! } - //! @endcode - //================================================================================================ - template struct member + template concept non_empty_tuple = requires( T const &t ) { - using type = decltype( get(std::declval())); + typename std::tuple_element<0,std::remove_cvref_t>::type; + typename std::tuple_size>::type; }; - - template using member_t = typename member::type; - - //================================================================================================ - // Concept machinery to make our algorithms SFINAE friendly - //================================================================================================ + template concept empty_tuple = (std::tuple_size>::value == 0); + template concept std_tuple_compatible = empty_tuple || non_empty_tuple; + template + concept product_type = std_tuple_compatible && is_product_type>::value; + template + concept sized_product_type = product_type && (size::value == N); + template + concept sized_product_type_or_more = product_type && (size::value >= N); namespace detail { - template - concept applicable_i = std::is_invocable_v...>; - - template struct is_applicable; - - template - struct is_applicable, Tuples...> - : std::bool_constant<(applicable_i && ...)> - { - }; - - template - concept applicable = detail:: - is_applicable::value, ...)>, Tuples...>::value; - - // Helper for checking if two tuples can == each others - template - concept comparable = requires(T t, U u) - { - { t == u }; - }; - template constexpr auto check_equality() { - return comparable; + return detail::comparable; } - template constexpr auto check_equality() { @@ -394,31 +189,11 @@ namespace kumi }(std::make_index_sequence::value>{}); } } - - //================================================================================================ - //! @ingroup transforms - //! @brief Invoke the Callable object f with a tuple of arguments. - //! - //! @param f Callable object to be invoked - //! @param t kumi::product_type whose elements to be used as arguments to f - //! @return The value returned by f. - //! - //! ## Helper type - //! @code - //! namespace kumi::result - //! { - //! template struct apply; - //! - //! template - //! using apply_t = typename apply::type; - //! } - //! @endcode - //! - //! Computes the return type of a call to kumi::apply - //! - //! ## Example - //! @include doc/apply.cpp - //================================================================================================ + template + concept equality_comparable = detail::check_equality(); +} +namespace kumi +{ template constexpr decltype(auto) apply(Function &&f, Tuple &&t) { @@ -432,7 +207,6 @@ namespace kumi (std::make_index_sequence::value>()); } } - namespace result { template @@ -440,27 +214,12 @@ namespace kumi { using type = decltype(kumi::apply(std::declval(), std::declval())); }; - template using apply_t = typename apply::type; } - - //================================================================================================ - //! @ingroup transforms - //! @brief Applies the Callable object f on each element of a kumi::product_type. - //! - //! @note This function does not take part in overload resolution if `f` can't be applied to the - //! elements of `t` and/or `ts`. - //! - //! @param f Callable object to be invoked - //! @param t kumi::product_type whose elements to be used as arguments to f - //! @param ts Other kumi::product_type whose elements to be used as arguments to f - //! - //! @see kumi::for_each_index - //! - //! ## Example - //! @include doc/for_each.cpp - //================================================================================================ +} +namespace kumi +{ template constexpr void for_each(Function f, Tuple&& t, Tuples&&... ts) requires detail::applicable @@ -470,36 +229,17 @@ namespace kumi { [&](std::index_sequence) { - // clang needs this for some reason using std::get; [[maybe_unused]] auto call = [&](M) { f ( get(KUMI_FWD(t)) , get(KUMI_FWD(ts))... ); }; - ( call(std::integral_constant{}), ... ); } (std::make_index_sequence::value>()); } } - - //================================================================================================ - //! @ingroup transforms - //! @brief Applies the Callable object f on each element of a kumi::product_type and its index. - //! - //! @note This function does not take part in overload resolution if `f` can't be applied to the - //! elements of `t` and/or `ts` and an integral constant. - //! - //! @param f Callable object to be invoked - //! @param t kumi::product_type whose elements to be used as arguments to f - //! @param ts Other kumi::product_type whose elements to be used as arguments to f - //! - //! @see kumi::for_each - //! - //! ## Example - //! @include doc/for_each_index.cpp - //================================================================================================ template constexpr void for_each_index(Function f, Tuple&& t, Tuples&&... ts) { @@ -508,7 +248,6 @@ namespace kumi { [&](std::index_sequence) { - // clang needs this for some reason using std::get; [[maybe_unused]] auto call = [&](M idx) { f ( idx @@ -516,169 +255,42 @@ namespace kumi , get(KUMI_FWD(ts))... ); }; - ( call(std::integral_constant{}), ... ); } (std::make_index_sequence::value>()); } } - - //================================================================================================ - //! @ingroup tuple - //! @class tuple - //! @brief Fixed-size collection of heterogeneous values. - //! - //! kumi::tuple provides an aggregate based implementation of a tuple. It provides algorithms and - //! functions designed to facilitate tuple's handling and transformations. - //! - //! kumi::tuple is also compatible with standard tuple operations and structured bindings. - //! - //! @tparam Ts Sequence of types stored inside kumi::tuple. - //================================================================================================ +} +#include +namespace kumi +{ template struct tuple { using is_product_type = void; detail::binder, Ts...> impl; - - //============================================================================================== - //! @name Accessors - //! @{ - //============================================================================================== - - //============================================================================================== - //! @brief Extracts the Ith element from a kumi::tuple - //! - //! @note Does not participate in overload resolution if `I` is not in [0, sizeof...(Ts)). - //! @param i Compile-time index of the element to access - //! @return A reference to the selected element of current tuple. - //! - //! ## Example: - //! @include doc/subscript.cpp - //============================================================================================== template - requires(I < sizeof...(Ts)) constexpr decltype(auto) operator[](index_t) &noexcept + requires(I < sizeof...(Ts)) + constexpr decltype(auto) operator[]([[maybe_unused]] index_t i) &noexcept { return detail::get_leaf(impl); } - - /// @overload template requires(I < sizeof...(Ts)) constexpr decltype(auto) operator[](index_t) &&noexcept { return detail::get_leaf(static_cast(impl)); } - - /// @overload template requires(I < sizeof...(Ts)) constexpr decltype(auto) operator[](index_t) const &&noexcept { return detail::get_leaf(static_cast(impl)); } - - /// @overload template requires(I < sizeof...(Ts)) constexpr decltype(auto) operator[](index_t) const &noexcept { return detail::get_leaf(impl); } - - //============================================================================================== - //! @brief Extracts a sub-tuple from a kumi::tuple - //! - //! @note Does not participate in overload resolution if `I0` and `I1` do not verify that - //! `0 <= I0 <= I1 <= sizeof...(Ts)`. - //! @param i0 Compile-time index of the first element to extract. - //! @param i1 Compile-time index past the last element to extract. By default, `i1` is equal to - //! `sizeof...(Ts)`. - //! @return A new kumi::tuple containing to the selected elements of current tuple. - //! - //! ## Example: - //! @include doc/extract.cpp - //============================================================================================== - template - requires((I1 - I0) <= sizeof...(Ts)) - [[nodiscard]] constexpr auto extract(index_t const &, index_t const &) const noexcept - { - return [&](std::index_sequence) - { - return tuple...> {(*this)[index]...}; - } - (std::make_index_sequence()); - } - - /// @overload - template - requires(I0 <= sizeof...(Ts)) - [[nodiscard]] constexpr auto extract(index_t const &) const noexcept - { - return [&](std::index_sequence) - { - return tuple...> {(*this)[index]...}; - } - (std::make_index_sequence()); - } - - //============================================================================================== - //! @brief Split a tuple into two - //! - //! Split a kumi::tuple in two kumi::tuple containing all the elements before and after - //! a given index. - //! - //! @note Does not participate in overload resolution if `I0` is not in `[0, sizeof...(Ts)[`. - //! - //! @param i0 Compile-time index of the first element to extract. - //! @return A new kumi::tuple containing the two sub-tuple cut at index I. - //! - //! - //! ## Helper type - //! @code - //! namespace kumi::result - //! { - //! template struct split; - //! - //! template - //! using split_t = typename split::type; - //! } - //! @endcode - //! - //! Computes the type returned by a call to split. - //! - //! ## Example: - //! @include doc/split.cpp - //============================================================================================== - template - requires(I0 <= sizeof...(Ts)) [[nodiscard]] constexpr auto split(index_t const&) const noexcept; - - //============================================================================================== - //! @} - //============================================================================================== - - //============================================================================================== - //! @name Properties - //! @{ - //============================================================================================== - /// Returns the number of elements in a kumi::tuple [[nodiscard]] static constexpr auto size() noexcept { return sizeof...(Ts); } - - /// Returns `true` if a kumi::tuple contains 0 elements [[nodiscard]] static constexpr bool empty() noexcept { return sizeof...(Ts) == 0; } - - //============================================================================================== - //! @} - //============================================================================================== - - //============================================================================================== - //! @name Conversions - //! @{ - //============================================================================================== - - //============================================================================================== - //! @brief Converts a tuple to a tuple. - //! @tparam Us Types composing the destination tuple - //! - //! ## Example: - //! @include doc/cast.cpp - //============================================================================================== template requires( detail::piecewise_convertible> && (sizeof...(Us) == sizeof...(Ts)) @@ -688,27 +300,14 @@ namespace kumi { return apply([](auto &&...elems) { return tuple {static_cast(elems)...}; }, *this); } - - //============================================================================================== - //! @} - //============================================================================================== - - //============================================================================================== - //! @brief Replaces the contents of the tuple with the contents of another tuple. - //! @param other kumi::tuple to copy or move from - //! @return `*this` - //============================================================================================== template requires(detail::piecewise_convertible>) constexpr tuple & operator=(tuple const &other) { [&](std::index_sequence) { ((get(*this) = get(other)), ...); } (std::make_index_sequence()); - return *this; } - - /// @overload template requires(detail::piecewise_convertible>) constexpr tuple & operator=(tuple &&other) @@ -718,21 +317,11 @@ namespace kumi ((get(*this) = get(KUMI_FWD(other))), ...); } (std::make_index_sequence()); - return *this; } - - //============================================================================================== - //! @name Comparison operators - //! @{ - //============================================================================================== - - /// @ingroup tuple - /// @related kumi::tuple - /// @brief Compares a tuple with an other kumi::product_type for equality template Other> friend constexpr auto operator==(tuple const &self, Other const &other) noexcept - requires( (sizeof...(Ts) != 0 ) && detail::check_equality() ) + requires( (sizeof...(Ts) != 0 ) && equality_comparable ) { return [&](std::index_sequence) { @@ -740,7 +329,6 @@ namespace kumi } (std::make_index_sequence()); } - #if !defined(KUMI_DOXYGEN_INVOKED) template Other> friend constexpr auto operator==(tuple const&, Other const &) noexcept @@ -748,17 +336,12 @@ namespace kumi return true; } #endif - - /// @ingroup tuple - /// @related kumi::tuple - /// @brief Compares a tuple with an other kumi::product_type for inequality template Other> friend constexpr auto operator!=(tuple const &self, Other const &other) noexcept - requires( (sizeof...(Ts) != 0 ) && detail::check_equality() ) + requires( (sizeof...(Ts) != 0 ) && equality_comparable ) { return !(self == other); } - #if !defined(KUMI_DOXYGEN_INVOKED) template Other> friend constexpr auto operator!=(tuple const&, Other const &) noexcept @@ -766,75 +349,41 @@ namespace kumi return false; } #endif - - /// @ingroup tuple - /// @related kumi::tuple - /// @brief Compares tuple and product type value for lexicographical is less relation template Other> friend constexpr auto operator<(tuple const &lhs, Other const &rhs) noexcept { - // lexicographical order is defined as - // (v0 < w0) || ... andnot(wi < vi, vi+1 < wi+1) ... || andnot(wn-1 < vn-1, vn < wn); auto res = get<0>(lhs) < get<0>(rhs); - auto const order = [&](Index i) { auto y_less_x_prev = rhs[i] < lhs[i]; auto x_less_y = lhs[index_t{}] < rhs[index_t{}]; res = res || (x_less_y && !y_less_x_prev); }; - [&](std::index_sequence) { (order(index_t{}),...); } (std::make_index_sequence()); - return res; } - - /// @ingroup tuple - /// @related kumi::tuple - /// @brief Compares tuple and product type value for lexicographical is less or equal relation template friend constexpr auto operator<=(tuple const &lhs, Other const &rhs) noexcept { return !(rhs < lhs); } - - /// @ingroup tuple - /// @related kumi::tuple - /// @brief Compares tuple and product type value for lexicographical is greater relation template friend constexpr auto operator>(tuple const &lhs, Other const &rhs) noexcept { return rhs < lhs; } - - /// @ingroup tuple - /// @related kumi::tuple - /// @brief Compares tuple and product type value for lexicographical is greater relation relation template friend constexpr auto operator>=(tuple const &lhs, Other const &rhs) noexcept { return !(lhs < rhs); } - - //============================================================================================== - //! @} - //============================================================================================== - - //============================================================================================== - //! @brief Invoke the Callable object f on each element of the current tuple. - //! - //! @param f Callable object to be invoked - //! @return The value returned by f. - //! - //============================================================================================== template constexpr decltype(auto) operator()(Function &&f) const& noexcept(noexcept(kumi::apply(KUMI_FWD(f), *this))) { return kumi::apply(KUMI_FWD(f), *this); } - #if !defined(KUMI_DOXYGEN_INVOKED) template constexpr decltype(auto) operator()(Function &&f) & @@ -842,14 +391,12 @@ namespace kumi { return kumi::apply(KUMI_FWD(f), *this); } - template constexpr decltype(auto) operator()(Function &&f) const &&noexcept( noexcept(kumi::apply(KUMI_FWD(f), static_cast(*this)))) { return kumi::apply(KUMI_FWD(f), static_cast(*this)); } - template constexpr decltype(auto) operator()(Function &&f) &&noexcept( noexcept(kumi::apply(KUMI_FWD(f), static_cast(*this)))) @@ -857,12 +404,6 @@ namespace kumi return kumi::apply(KUMI_FWD(f), static_cast(*this)); } #endif - - //============================================================================================== - /// @ingroup tuple - //! @related kumi::tuple - //! @brief Inserts a kumi::tuple in an output stream - //============================================================================================== template friend std::basic_ostream &operator<<(std::basic_ostream &os, tuple const &t) noexcept @@ -870,503 +411,140 @@ namespace kumi os << "( "; kumi::for_each([&os](auto const &e) { os << e << " "; }, t); os << ")"; - return os; } }; - - //================================================================================================ - //! @name Tuple construction - //! @{ - //================================================================================================ - - //================================================================================================ - //! @ingroup tuple - //! @related kumi::tuple - //! @brief kumi::tuple deduction guide - //! @tparam Ts Type lists to build the tuple with. - //================================================================================================ template tuple(Ts &&...) -> tuple...>; - - //================================================================================================ - //! @ingroup tuple - //! @related kumi::tuple - //! @brief Creates a kumi::tuple of lvalue references to its arguments. - //! @param ts Zero or more lvalue arguments to construct the tuple from. - //! @return A kumi::tuple object containing lvalue references. - //! ## Example: - //! @include doc/tie.cpp - //================================================================================================ template [[nodiscard]] constexpr tuple tie(Ts &...ts) { return {ts...}; } - - //================================================================================================ - //! @ingroup tuple - //! @related kumi::tuple - //! @brief Creates a kumi::tuple of forwarding references to its arguments. - //! - //! Constructs a tuple of references to the arguments in args suitable for forwarding as an - //! argument to a function. The tuple has rvalue reference data members when rvalues are used as - //! arguments, and otherwise has lvalue reference data members. - //! - //! @note If the arguments are temporaries, `forward_as_tuple` does not extend their lifetime; - //! they have to be used before the end of the full expression. - //! - //! @param ts Zero or more lvalue arguments to construct the tuple from. - //! @return A kumi::tuple constructed as `kumi::tuple(std::forward(args)...)` - //! ## Example: - //! @include doc/forward_as_tuple.cpp - //================================================================================================ template [[nodiscard]] constexpr tuple forward_as_tuple(Ts &&...ts) { return {KUMI_FWD(ts)...}; } - - //================================================================================================ - //! @ingroup tuple - //! @related kumi::tuple - //! @brief Creates a tuple object, deducing the target type from the types of arguments. - //! - //! @param ts Zero or more lvalue arguments to construct the tuple from. - //! @return A kumi::tuple constructed from the ts or their inner references when ts is an instance - //! of `std::reference_wrapper`. - //! ## Example: - //! @include doc/make_tuple.cpp - //================================================================================================ template [[nodiscard]] constexpr tuple...> make_tuple(Ts &&...ts) { return {KUMI_FWD(ts)...}; } - - //================================================================================================ - //! @ingroup tuple - //! @related kumi::tuple - //! @brief Creates a kumi::tuple of references given a reference to a kumi::product_type. - //! - //! @param t Compile-time index of the element to access - //! @return A tuple equivalent to the result of `kumi::apply([](T&&... e) - //! { return kumi::forward_as_tuple(std::forward(e)...); }, t)` - //! - //! ## Example: - //! @include doc/to_ref.cpp - //================================================================================================ - template [[nodiscard]] constexpr auto to_ref(Type&& that) + template [[nodiscard]] constexpr auto to_ref(Type&& t) { return apply( [](auto&&... elems) { return kumi::forward_as_tuple(KUMI_FWD(elems)...); } - , KUMI_FWD(that) + , KUMI_FWD(t) ); } - - //================================================================================================ - //! @} - //================================================================================================ - - //================================================================================================ - //! @name Conversions - //! @{ - //================================================================================================ - - //================================================================================================ - //! @brief Converts a kumi::tuple to an instance of an arbitrary type - //! - //! Constructs an instance of `Type` by passing elements of `t` to the appropriate constructor. - //! - //! @tparam Type Type to generate - //! @param t kumi::tuple to convert - //! @return An instance of `Type` constructed from each element of `t` in order. - //! - //! ## Example - //! @include doc/from_tuple.cpp - //================================================================================================ - template - requires(!product_type && detail::implicit_constructible) - [[nodiscard]] constexpr auto from_tuple(tuple const &t) - { - return [&](std::index_sequence) { return Type {get(t)...}; } - (std::make_index_sequence()); - } - - //================================================================================================ - //! @brief Converts a kumi::product_type to an instance kumi::tuple - //! - //! Constructs an instance kumi::tuple from the elements of the kumi::product_type parameters - //! - //! @param t kumi::product_type to convert - //! @return An instance of kumi::tuple constructed from each elements of `t` in order. - //! - //! ## Example - //! @include doc/to_tuple.cpp - //================================================================================================ - template - [[nodiscard]] inline constexpr auto to_tuple(Type&& t) - { - return apply([](auto &&...elems) { return tuple{elems...}; }, KUMI_FWD(t)); - } - - //================================================================================================ - //! @} - //================================================================================================ - - template - template - requires(I0 <= sizeof...(Ts)) - [[nodiscard]] constexpr auto tuple::split(index_t const &) const noexcept - { - return kumi::make_tuple(extract(index<0>, index), extract(index)); - } - - namespace result - { - template struct split - { - using type = decltype ( std::declval().split(kumi::index_t{}) ); - }; - - template using split_t = typename split::type; - } - - //================================================================================================ - //! @name Accessors - //! @{ - //================================================================================================ - - //================================================================================================ - //! @ingroup tuple - //! @brief Extracts the Ith element from a kumi::tuple - //! - //! @note Does not participate in overload resolution if `I` is not in [0, sizeof...(Ts)). - //! @tparam I Compile-time index of the element to access - //! @param t Compile-time index of the element to access - //! @return A reference to the selected element of t. - //! @related kumi::tuple - //! - //! ## Example: - //! @include doc/get.cpp - //================================================================================================ template - requires(I < sizeof...(Ts)) [[nodiscard]] constexpr decltype(auto) get(tuple &arg) noexcept + requires(I < sizeof...(Ts)) [[nodiscard]] constexpr decltype(auto) get(tuple &t) noexcept { - return arg[index]; + return t[index]; } - - /// @overload template requires(I < sizeof...(Ts)) [[nodiscard]] constexpr decltype(auto) get(tuple &&arg) noexcept { return static_cast &&>(arg)[index]; } - - /// @overload template requires(I < sizeof...(Ts)) [[nodiscard]] constexpr decltype(auto) get(tuple const &arg) noexcept { return arg[index]; } - - /// @overload template requires(I < sizeof...(Ts)) [[nodiscard]] constexpr decltype(auto) get(tuple const &&arg) noexcept { return static_cast const &&>(arg)[index]; } - - //================================================================================================ - //! @} - //================================================================================================ - - //================================================================================================ - //! @ingroup transforms - //! @brief Apply the Callable object f on each tuples' elements - //! - //! Applies the given function to all the tuples passed as arguments and stores the result in - //! another tuple, keeping the original elements order. - //! - //! @note Does not participate in overload resolution if tuples' size are not equal or if `f` - //! can't be called on each tuple's elements. - //! - //! @param f Callable function to apply - //! @param t0 Tuple to operate on - //! @param others Tuples to operate on - //! @return The tuple of `f` calls results. - //! - //! ## Helper type - //! @code - //! namespace kumi::result - //! { - //! template struct map; - //! - //! template - //! using map_t = typename map::type; - //! } - //! @endcode - //! - //! Computes the return type of a call to kumi::map - //! - //! ## Example - //! @include doc/map.cpp - //================================================================================================ - template::value>... Tuples> - constexpr auto - map(Function f, - Tuple &&t0, - Tuples &&...others) requires detail::applicable +} +namespace kumi +{ +} +namespace kumi +{ + template + [[nodiscard]] constexpr decltype(auto) front(Tuple&& t) requires( size_v != 0) { - if constexpr(sized_product_type) return std::remove_cvref_t{}; - else - { - auto const call = [&](index_t, Ts &&... args) - { - return f(get(args)...); - }; - - return [&](std::index_sequence) - { - return kumi::make_tuple(call(index, KUMI_FWD(t0), KUMI_FWD(others)...)...); - }(std::make_index_sequence::value>()); - } + return get<0>(KUMI_FWD(t)); + } + template + [[nodiscard]] constexpr decltype(auto) back(Tuple&& t) requires( size_v != 0) + { + return get-1>(KUMI_FWD(t)); } - namespace result { - template::value>... Ts> - struct map - { - using type = decltype ( kumi::map ( std::declval() - , std::declval() - , std::declval()... - ) - ); - }; - - template::value>... Ts> - using map_t = typename map::type; + template struct front : member<0,Tuple> {}; + template struct back : member-1,Tuple> {}; + template using front_t = typename front::type; + template using back_t = typename back::type; } - - //================================================================================================ - //! @ingroup transforms - //! @brief Apply the Callable object f on each tuples' elements and their indexes - //! - //! Applies the given function to all the tuples passed as arguments along with their indexes and - //! stores the result in another tuple, keeping the original elements order. - //! - //! @note Does not participate in overload resolution if tuples' size are not equal or if `f` - //! can't be called on each tuple's elements and their indexes. - //! - //! @param f Callable function to apply - //! @param t0 Tuple to operate on - //! @param others Tuples to operate on - //! @return The tuple of `f` calls results. - //! - //! ## Helper type - //! @code - //! namespace kumi::result - //! { - //! template struct map_index; - //! - //! template - //! using map_index_t = typename map_index::type; - //! } - //! @endcode - //! - //! Computes the return type of a call to kumi::map_index - //! - //! ## Example - //! @include doc/map_index.cpp - //================================================================================================ - template::value>... Tuples> - constexpr auto map_index(Function f,Tuple &&t0,Tuples &&...others) +} +namespace kumi +{ + namespace detail { - if constexpr(sized_product_type) return std::remove_cvref_t{}; - else + template constexpr auto digits(std::size_t v) noexcept { - auto const call = [&](index_t idx, Ts &&... args) - { - return f(idx, get(args)...); - }; - - return [&](std::index_sequence) + struct { std::size_t data[N]; } digits = {}; + std::size_t shp[] = {S...}; + std::size_t i = 0; + while(v != 0) { - return kumi::make_tuple(call(index, KUMI_FWD(t0), KUMI_FWD(others)...)...); - }(std::make_index_sequence::value>()); + digits.data[i] = v % shp[i]; + v /= shp[i++]; + } + return digits; } } - - namespace result +#if !defined(KUMI_DOXYGEN_INVOKED) + [[nodiscard]] constexpr auto cartesian_product() { return kumi::tuple<>{}; } +#endif + template + [[nodiscard]] constexpr auto cartesian_product(Ts&&... ts) { - template::value>... Ts> - struct map_index + auto maps = [&](auto k, std::index_sequence) { - using type = decltype ( kumi::map_index ( std::declval() - , std::declval() - , std::declval()... - ) - ); + constexpr auto dg = detail::digits...>(k); + using tuple_t = kumi::tuple>...>; + return tuple_t{kumi::get(std::forward(ts))...}; }; - - template::value>... Ts> - using map_index_t = typename map_index::type; + return [&](std::index_sequence) + { + return kumi::make_tuple(maps( kumi::index, std::make_index_sequence{})...); + }(std::make_index_sequence<(kumi::size_v * ...)>{}); } - - //================================================================================================ - //! @ingroup reductions - //! @brief Computes the generalized sum of all elements using a tail recursive tail. - //! - //! @param f Binary callable function to apply - //! @param t Tuple to operate on - //! @param init Initial value of the sum - //! @return The value of `f( f( f(init, get<0>(t)), ...), get(t))` - //! - //! ## Helper type - //! @code - //! namespace kumi::result - //! { - //! template struct fold_left; - //! - //! template - //! using fold_left_t = typename fold_left_t::type; - //! } - //! @endcode - //! - //! Computes the return type of a call to kumi::fold_left - //! - //! ## Example - //! @include doc/fold_left.cpp - //================================================================================================ - template - [[nodiscard]] constexpr auto fold_left(Function f, Tuple&& t, Value init) + namespace result { - if constexpr(sized_product_type) return init; - else + template struct cartesian_product { - return [&](std::index_sequence) - { - return (detail::foldable {f, get(KUMI_FWD(t))} >> ... >> detail::foldable {f, init}).value; - } - (std::make_index_sequence::value>()); - } - } - - //================================================================================================ - //! @ingroup reductions - //! @brief Computes the generalized sum of all elements using a non-tail recursive tail. - //! - //! @param f Binary callable function to apply - //! @param t Tuple to operate on - //! @param init Initial value of the sum - //! @return The value of `f(get<0>(t), f(... , f(get(t), init))` - //! - //! ## Helper type - //! @code - //! namespace kumi::result - //! { - //! template struct fold_right; - //! - //! template - //! using fold_right_t = typename fold_right_t::type; - //! } - //! @endcode - //! - //! Computes the return type of a call to kumi::fold_right - //! - //! ## Example - //! @include doc/fold_right.cpp - //================================================================================================ - template - [[nodiscard]] constexpr auto fold_right(Function f, Tuple&& t, Value init) - { - if constexpr(size::value ==0) return init; - else - { - return [&](std::index_sequence) - { - return (detail::foldable {f, init} << ... << detail::foldable {f, get(KUMI_FWD(t))}).value; - } - (std::make_index_sequence::value>()); - } - } - - namespace result - { - template - struct fold_right - { - using type = decltype ( kumi::fold_right( std::declval() - , std::declval() - , std::declval() - ) - ); - }; - - template - struct fold_left - { - using type = decltype ( kumi::fold_left ( std::declval() - , std::declval() - , std::declval() - ) - ); + using type = decltype( kumi::cartesian_product( std::declval()... ) ); }; - - template - using fold_right_t = typename fold_right::type; - - template - using fold_left_t = typename fold_left::type; + template using cartesian_product_t = typename cartesian_product::type; } - - //================================================================================================ - //! @ingroup generators - //! @brief Concatenates tuples in a single one - //! - //! @param ts Tuples to concatenate - //! @return A tuple made of all element of all input tuples in order - //! - //! ## Helper type - //! @code - //! namespace kumi::result - //! { - //! template struct cat; - //! - //! template - //! using cat_t = typename cat::type; - //! } - //! @endcode - //! - //! Computes the return type of a call to kumi::cat - //! - //! ## Example - //! @include doc/cat.cpp - //================================================================================================ +} +namespace kumi +{ template [[nodiscard]] constexpr auto cat(Tuples&&... ts) { if constexpr(sizeof...(Tuples) == 0) return tuple{}; else { - // count is at least 1 so MSVC don't cry when we use a 0-sized array constexpr auto count = (1ULL + ... + kumi::size::value); constexpr auto pos = [&]() { struct { std::size_t t[count],e[count]; } that{}; std::size_t k = 0, offset = 0; - auto locate = [&](std::index_sequence) { (((that.t[I+offset] = k),(that.e[I+offset] = I)),...); offset += sizeof...(I); k++; }; - (locate(std::make_index_sequence::value>{}),...); - return that; }(); - return [&](auto&& tuples, std::index_sequence) { using ts = std::remove_cvref_t; @@ -1379,203 +557,135 @@ namespace kumi }(kumi::forward_as_tuple(KUMI_FWD(ts)...), std::make_index_sequence{}); } } - namespace result { template struct cat { using type = decltype( kumi::cat( std::declval()... ) ); }; - template using cat_t = typename cat::type; } - - //================================================================================================ - //! @ingroup generators - //! @brief Constructs a tuple by adding a value v at the beginning of t - //! - //! @param t Base tuple - //! @param v Value to insert in front of t - //! @return A tuple composed of v followed by all elements of t in order. - //! - //! ## Helper type - //! @code - //! namespace kumi::result - //! { - //! template struct push_front; - //! - //! template - //! using push_front_t = typename push_front::type; - //! } - //! @endcode - //! - //! Computes the return type of a call to kumi::push_front - //! - //! ## Example - //! @include doc/push_front.cpp - //================================================================================================ - template - [[nodiscard]] constexpr auto push_front(Tuple const& t, T&& v) +} +namespace kumi +{ + namespace detail { - return [&](std::index_sequence) + template< product_type Tuple + , typename IndexSequence + , template class Meta = std::type_identity + > + struct as_tuple; + template< product_type Tuple + , std::size_t... I + > + struct as_tuple> { - return make_tuple(KUMI_FWD(v), get(KUMI_FWD(t))...); - } - (std::make_index_sequence()); + using type = kumi::tuple< element_t... >; + }; + template< product_type Tuple + , std::size_t... I + , template class Meta + > + struct as_tuple, Meta> + { + using type = kumi::tuple< typename Meta>::type... >; + }; } - - //================================================================================================ - //! @ingroup generators - //! @brief Remove the first (if any) element of a kumi::product_type. - //! - //! @param t Base tuple - //! @return A tuple composed of all elements of t except its first. Has no effect on empty t. - //! - //! ## Helper type - //! @code - //! namespace kumi::result - //! { - //! template struct pop_front; - //! - //! template - //! using pop_front_t = typename pop_front::type; - //! } - //! @endcode - //! - //! Computes the return type of a call to kumi::pop_front - //! - //! ## Example - //! @include doc/pop_front.cpp - //================================================================================================ - template - [[nodiscard]] constexpr auto pop_front(Tuple const& t) + template + requires(!product_type && detail::implicit_constructible) + [[nodiscard]] constexpr auto from_tuple(tuple const &t) { - if constexpr(Tuple::size()>0) return t.extract(index<1>); - else return tuple<>{}; + return [&](std::index_sequence) { return Type {get(t)...}; } + (std::make_index_sequence()); } - - //================================================================================================ - //! @ingroup generators - //! @brief Constructs a tuple by adding a value v at the end of t - //! - //! @param t Base tuple - //! @param v Value to insert in front of t - //! @return A tuple composed of all elements of t in order followed by v. - //! - //! ## Helper type - //! @code - //! namespace kumi::result - //! { - //! template struct push_back; - //! - //! template - //! using push_back_t = typename push_back::type; - //! } - //! @endcode - //! - //! Computes the return type of a call to kumi::push_back - //! - //! ## Example - //! @include doc/push_back.cpp - //================================================================================================ - template - [[nodiscard]] constexpr auto push_back(Tuple const& t, T&& v) + template + [[nodiscard]] inline constexpr auto to_tuple(Type&& t) { - return [&](std::index_sequence) + return apply([](auto &&...elems) { return tuple{elems...}; }, KUMI_FWD(t)); + } + template class Meta = std::type_identity> + struct as_tuple : detail::as_tuple< Tuple + , std::make_index_sequence::value> + , Meta + > + {}; + template class Meta = std::type_identity> + using as_tuple_t = typename as_tuple::type; +} +namespace kumi +{ + template + requires( (I0 <= size_v) && (I1 <= size_v) ) + [[nodiscard]] constexpr + auto extract( Tuple const& t + , [[maybe_unused]] index_t const& i0 + , [[maybe_unused]] index_t const& i1 + ) noexcept + { + return [&](std::index_sequence) { - return make_tuple(get(KUMI_FWD(t))..., KUMI_FWD(v)); + return kumi::tuple...> {get(t)...}; } - (std::make_index_sequence()); + (std::make_index_sequence()); } - - //================================================================================================ - //! @ingroup generators - //! @brief Remove the last (if any) element of a kumi::product_type. - //! - //! @param t Base tuple - //! @return A tuple composed of all elements of t except its last. Has no effect on empty t. - //! - //! ## Helper type - //! @code - //! namespace kumi::result - //! { - //! template struct pop_back; - //! - //! template - //! using pop_back_t = typename pop_back::type; - //! } - //! @endcode - //! - //! Computes the return type of a call to kumi::pop_back - //! - //! ## Example - //! @include doc/pop_back.cpp - //================================================================================================ - template - [[nodiscard]] constexpr auto pop_back(Tuple const& t) + template + requires(I0<= size_v) + [[nodiscard]] constexpr + auto extract(Tuple const& t, index_t const& i0) noexcept { - if constexpr(Tuple::size()>1) return t.extract(index<0>, index); - else return tuple<>{}; + return extract(t,i0, index>); + } + template + requires(I0 <= size_v) + [[nodiscard]] constexpr auto split( Tuple const& t + , [[maybe_unused]] index_t const& i0 + ) noexcept + { + return kumi::make_tuple(extract(t,index<0>, index), extract(t,index)); } - namespace result { - template struct push_front + template + struct extract { - using type = decltype( kumi::push_front( std::declval(), std::declval() ) ); + using type = decltype ( kumi::extract ( std::declval() + , kumi::index_t{},kumi::index_t{} + ) + ); }; - - template struct pop_front + template + struct extract { - using type = decltype( kumi::pop_front( std::declval() ) ); + using type = decltype(kumi::extract(std::declval(),kumi::index_t{}) ); }; - - template struct push_back + template + struct split { - using type = decltype( kumi::push_back( std::declval(), std::declval() ) ); + using type = decltype(kumi::split(std::declval(),kumi::index_t{}) ); }; - - template struct pop_back + template + using extract_t = typename extract::type; + template + using split_t = typename split::type; + } +} +namespace kumi +{ + template + [[nodiscard]] constexpr auto locate( tuple const& t, Pred p ) noexcept + { + auto locator = [&](auto const&... m) { - using type = decltype( kumi::pop_back( std::declval() ) ); + bool checks[] = { p(m)... }; + for(std::size_t i=0;i - using push_front_t = typename push_front::type; - - template - using pop_front_t = typename pop_front::type; - - template - using push_back_t = typename push_back::type; - - template - using pop_back_t = typename pop_back::type; + return kumi::apply(locator, t); } - - //================================================================================================ - //! @ingroup generators - //! @brief Converts a tuple of tuples into a tuple of all elements. - //! - //! @param ts Tuple to flatten - //! @return A tuple composed of all elements of t flattened non-recursively - //! - //! ## Helper type - //! @code - //! namespace kumi::result - //! { - //! template struct flatten; - //! - //! template - //! using flatten_t = typename flatten::type; - //! } - //! @endcode - //! - //! Computes the return type of a call to kumi::flatten - //! - //! ## Example - //! @include doc/flatten.cpp - //================================================================================================ +} +namespace kumi +{ template [[nodiscard]] constexpr auto flatten(Tuple const &ts) { if constexpr(sized_product_type) return ts; @@ -1588,323 +698,91 @@ namespace kumi if constexpr(product_type) return KUMI_FWD(v); else return kumi::tuple{KUMI_FWD(v)}; }; - return cat( v_or_t(KUMI_FWD(m))... ); } , ts ); } } - - //================================================================================================ - //! @ingroup generators - //! @brief Recursively converts a tuple of tuples into a tuple of all elements. - //! - //! Recursively converts a tuple of tuples `t` into a tuple of all elements of said tuples. - //! If the Callable object f is provided, non-tuple elements are processed by `f` before being - //! inserted. - //! - //! @param ts Tuple to flatten - //! @param f Optional Callable object to apply when a sub-tuple is flattened - //! @return A tuple composed of all elements of t flattened recursively - //! - //! ## Helper type - //! @code - //! namespace kumi::result - //! { - //! template struct flatten_all; - //! - //! template - //! using flatten_all_t = typename flatten_all::type; - //! } - //! @endcode - //! - //! Computes the return type of a call to kumi::flatten_all - //! - //! ## Example - //! @include doc/flatten_all.cpp - //================================================================================================ - template [[nodiscard]] constexpr auto flatten_all(Tuple&& ts) + template + [[nodiscard]] constexpr auto flatten_all(Tuple&& ts, Func&& f) { - if constexpr(sized_product_type) return ts; + if constexpr(sized_product_type) return KUMI_FWD(ts); else { - return kumi::apply( [](auto&&... m) + return kumi::apply( [&](auto&&... m) { - auto v_or_t = [](V&& v) + auto v_or_t = [&](V&& v) { - if constexpr(product_type) return flatten_all(KUMI_FWD(v)); - else return kumi::tuple{KUMI_FWD(v)}; + if constexpr(product_type) + return flatten_all(KUMI_FWD(v),KUMI_FWD(f)); + else + return kumi::tuple{KUMI_FWD(f)(KUMI_FWD(v))}; }; - return cat( v_or_t(KUMI_FWD(m))... ); } , ts ); } } - - /// @overload - template - [[nodiscard]] constexpr auto flatten_all(Tuple&& ts, Func&& f) + template [[nodiscard]] constexpr auto flatten_all(Tuple&& ts) { - if constexpr(sized_product_type) return KUMI_FWD(ts); + if constexpr(sized_product_type) return ts; else { - return kumi::apply( [&](auto&&... m) + return kumi::apply( [](auto&&... m) { - auto v_or_t = [&](V&& v) + auto v_or_t = [](V&& v) { - if constexpr(product_type) - return flatten_all(KUMI_FWD(v),KUMI_FWD(f)); - else - return kumi::tuple{KUMI_FWD(f)(KUMI_FWD(v))}; + if constexpr(product_type) return flatten_all(KUMI_FWD(v)); + else return kumi::tuple{KUMI_FWD(v)}; }; - return cat( v_or_t(KUMI_FWD(m))... ); } , ts ); } } - namespace result { template struct flatten { using type = decltype( kumi::flatten( std::declval() ) ); }; - template struct flatten_all { using type = decltype( kumi::flatten_all( std::declval(), std::declval() ) ); }; - template struct flatten_all { using type = decltype( kumi::flatten_all( std::declval() ) ); }; - template using flatten_t = typename flatten::type; - template using flatten_all_t = typename flatten_all::type; } - - //================================================================================================ - //! @ingroup generators - //! @brief Convert a kumi::product_type to a flat tuple of pointers to each its components. - //! - //! @param ts Tuple to convert - //! @return A flat tuple composed of pointers to each elements of t. - //! - //! ## Helper type - //! @code - //! namespace kumi::result - //! { - //! template struct as_flat_ptr; - //! - //! template - //! using as_flat_ptr_t = typename as_flat_ptr::type; - //! } - //! @endcode - //! - //! Computes the return type of a call to kumi::as_flat_ptr - //! - //! ## Example - //! @include doc/as_flat_ptr.cpp - //================================================================================================ template - [[nodiscard]] auto as_flat_ptr(Tuple&& t) noexcept + [[nodiscard]] auto as_flat_ptr(Tuple&& ts) noexcept { - return kumi::flatten_all(KUMI_FWD(t), [](auto& m) { return &m; }); + return kumi::flatten_all(KUMI_FWD(ts), [](auto& m) { return &m; }); } - namespace result { template struct as_flat_ptr { using type = decltype( kumi::as_flat_ptr( std::declval() ) ); }; - template using as_flat_ptr_t = typename as_flat_ptr::type; } - - //================================================================================================ - //! @ingroup generators - //! @brief Constructs a tuple where the ith element is the tuple of all ith elements of ts... - //! - //! @param t0 Tuple to convert - //! @param ts Tuples to convert - //! @return The tuple of all combination of elements from t0, ts... - //! - //! ## Helper type - //! @code - //! namespace kumi::result - //! { - //! template struct zip; - //! - //! template - //! using zip_t = typename zip::type; - //! } - //! @endcode - //! - //! Computes the return type of a call to kumi::zip - //! - //! ## Example - //! @include doc/zip.cpp - //================================================================================================ - template>... Ts> - [[nodiscard]] constexpr auto zip(T0 const &t0, Ts const &...tuples) - { - return kumi::map([](auto const &m0, auto const &...ms) { return kumi::make_tuple(m0, ms...); }, - t0, - tuples...); - } - - namespace result - { - template - struct zip - { - using type = decltype( kumi::zip( std::declval(), std::declval()... ) ); - }; - - template - using zip_t = typename zip::type; - } - - - //================================================================================================ - //! @ingroup generators - //! @brief Transpose a tuple of tuples by shifting elements in their transposed position - //! - //! @param t Tuple to transpose - //! @return A tuple containing the transposed elements of t. - //! - //! ## Helper type - //! @code - //! namespace kumi::result - //! { - //! template struct transpose; - //! - //! template - //! using transpose_t = typename transpose::type; - //! } - //! @endcode - //! - //! Computes the return type of a call to kumi::transpose - //! - //! ## Example - //! @include doc/transpose.cpp - //================================================================================================ - template [[nodiscard]] constexpr auto transpose(Tuple const &t) - { - if constexpr(sized_product_type) return t; - else - { - return [&](std::index_sequence) - { - constexpr auto uz = [](N const &, auto const &u) { - return apply([](auto const &...m) { return kumi::make_tuple(get(m)...); }, u); - }; - - return kumi::make_tuple(uz(index_t {}, t)...); - } - (std::make_index_sequence>::value>()); - } - } - - namespace result - { - template struct transpose - { - using type = decltype( kumi::transpose( std::declval() ) ); - }; - - template - using transpose_t = typename transpose::type; - } - -//================================================================================================ - //! @ingroup generators - //! @brief Reorder elements of a kumi::product_type - //! - //! This function does not participate in overload resolution if any IDx is outside [0, size_v[. - //! - //! @note Nothing prevent the number of reordered index to be lesser or greater than t size or - //! the fact they can appear multiple times. - //! - //! @tparam Idx Reordered index of elements - //! @param t kumi::product_type to reorder - //! @return A tuple equivalent to kumi::make_tuple(t[index]...); - //! - //! ## Helper type - //! @code - //! namespace kumi::result - //! { - //! template struct reorder; - //! - //! template - //! using reorder_t = typename reorder::type; - //! } - //! @endcode - //! - //! Computes the return type of a call to kumi::reorder - //! - //! ## Example - //! @include doc/reorder.cpp - //================================================================================================ - template - requires((Idx < size::value) && ...) [[nodiscard]] constexpr auto reorder(Tuple &&t) - { - return kumi::make_tuple(KUMI_FWD(t)[index]...); - } - - namespace result - { - template - struct reorder - { - using type = decltype( kumi::reorder( std::declval() ) ); - }; - - template - using reorder_t = typename reorder::type; - } - - //================================================================================================ +} +namespace kumi +{ namespace detail { template constexpr auto const& eval(T const& v) noexcept { return v; } } - - //================================================================================================ - //! @ingroup generators - //! @brief Creates a kumi::tuple containing `N` copies of `v`. - //! - //! @tparam N Number of replications - //! @param v Value to replicate - //! @return A tuple containing `N` copy of `v` - //! - //! ## Helper type - //! @code - //! namespace kumi::result - //! { - //! template struct generate; - //! - //! template - //! using generate_t = typename generate::type; - //! } - //! @endcode - //! - //! Computes the return type of a call to kumi::generate - //! - //! ## Example - //! @include doc/generate.cpp - //================================================================================================ template [[nodiscard]] constexpr auto generate(T const& v) noexcept { return [&](std::index_sequence) @@ -1912,32 +790,6 @@ namespace kumi return kumi::tuple{detail::eval(v)...}; }(std::make_index_sequence{}); } - - - //================================================================================================ - //! @ingroup generators - //! @brief Creates a kumi::tuple containing an increasing ramp of values. - //! - //! @tparam N Number of replications - //! @param v Seed value - //! @return A tuple containing `{v, v + 1, ..., v + N-1}` - //! - //! ## Helper type - //! @code - //! namespace kumi::result - //! { - //! template struct iota; - //! - //! template - //! using iota_t = typename iota::type; - //! } - //! @endcode - //! - //! Computes the return type of a call to kumi::iota - //! - //! ## Example - //! @include doc/iota.cpp - //================================================================================================ template [[nodiscard]] constexpr auto iota(T v) noexcept { return [&](std::index_sequence) @@ -1945,139 +797,323 @@ namespace kumi return kumi::tuple{T(v+I)...}; }(std::make_index_sequence{}); } - namespace result { template struct generate { using type = decltype( kumi::generate( std::declval() ) ); }; - template struct iota { using type = decltype( kumi::iota( std::declval() ) ); }; - template using generate_t = typename generate::type; - template using iota_t = typename iota::type; } - - //================================================================================================ - //! @ingroup reductions - //! @brief Computes the maximum value of applications of f to all elements of t. - //! @param t Tuple to inspect - //! @param f Unary Callable object - //! @return The maximum value of f over all elements of t - //! - //! ## Helper type - //! @code - //! namespace kumi - //! { - //! template struct max; - //! - //! template - //! using max_t = typename max::type; - //! } - //! @endcode - //! - //! Computes the type returned by a call to kumi::max. - //! - //! ## Example: - //! @include doc/max.cpp - //================================================================================================ - template - [[nodiscard]] constexpr auto max(T const& t, F f) noexcept +} +namespace kumi +{ + namespace detail { - if constexpr ( !kumi::product_type ) return f(t); - else if constexpr( T::size() == 1 ) return f( get<0>(t) ); - else + template struct foldable { - auto base = f( get<0>(t) ); - return kumi::fold_left( [f](auto cur, U const& u) - { - return cur > f(u) ? cur : f(u); - } - , t, base - ); - } + F func; + T value; + template + friend constexpr decltype(auto) operator>>(foldable &&x, foldable &&y) + { + return detail::foldable {x.func, x.func(y.value, x.value)}; + } + template + friend constexpr decltype(auto) operator<<(foldable &&x, foldable &&y) + { + return detail::foldable {x.func, x.func(x.value, y.value)}; + } + }; + template foldable(const F &, T &&) -> foldable; } - - //================================================================================================ - //! @ingroup reductions - //! @brief Computes the maximum value of applications of f to all elements of kumi::flatten_all(t). - //! @param t Tuple to inspect - //! @param f Unary Callable object - //! @return The maximum value of f over all elements of a flattened version of t - //! - //! ## Helper type - //! @code - //! namespace kumi - //! { - //! template struct max_flat; - //! - //! template - //! using max_flat_t = typename max_flat::type; - //! } - //! @endcode - //! - //! Computes the type returned by a call to kumi::max_flat. - //! - //! ## Example: - //! @include doc/max_flat.cpp - //================================================================================================ - template - [[nodiscard]] constexpr auto max_flat(T const& t, F f) noexcept + template< product_type S1, sized_product_type S2, typename T + , typename Sum, typename Prod + > + [[nodiscard]] constexpr auto inner_product( S1 const& s1, S2 const& s2, T init + , Sum sum, Prod prod + ) noexcept { - if constexpr ( !kumi::product_type ) return f(t); + if constexpr(sized_product_type) return init; else { - auto flat_t = kumi::flatten_all(t); - return max(flat_t, f); + return [&](std::index_sequence) + { + return ( detail::foldable {sum, prod(get(KUMI_FWD(s1)),get(KUMI_FWD(s2)))} + >> ... + >> detail::foldable {sum, init} + ).value; + } + (std::make_index_sequence::value>()); + } + } + template S2, typename T> + [[nodiscard]] constexpr auto inner_product(S1 const& s1, S2 const& s2, T init) noexcept + { + if constexpr(sized_product_type) return init; + else + { + return [&](std::index_sequence) + { + return (init + ... + (get(s1) * get(s2))); + }(std::make_index_sequence::value>()); + } + } + namespace result + { + template< product_type S1, sized_product_type S2, typename T + , typename Sum, typename Prod + > + struct inner_product + { + using type = decltype ( kumi::inner_product ( std::declval(), std::declval() + , std::declval() + , std::declval(), std::declval() + ) + ); + }; + template< product_type S1, sized_product_type S2, typename T> + struct inner_product + { + using type = decltype ( kumi::inner_product ( std::declval(), std::declval() + , std::declval() + ) + ); + }; + template< product_type S1, sized_product_type S2, typename T + , typename Sum = void, typename Prod = void + > + using inner_product_t = typename inner_product::type; + } +} +namespace kumi +{ + template::value>... Tuples> + constexpr auto + map(Function f, + Tuple &&t0, + Tuples &&...others) requires detail::applicable + { + if constexpr(sized_product_type) return std::remove_cvref_t{}; + else + { + auto const call = [&](index_t, Ts &&... args) + { + return f(get(args)...); + }; + return [&](std::index_sequence) + { + return kumi::make_tuple(call(index, KUMI_FWD(t0), KUMI_FWD(others)...)...); + }(std::make_index_sequence::value>()); + } + } + namespace result + { + template::value>... Ts> + struct map + { + using type = decltype ( kumi::map ( std::declval() + , std::declval() + , std::declval()... + ) + ); + }; + template::value>... Ts> + using map_t = typename map::type; + } + template::value>... Tuples> + constexpr auto map_index(Function f,Tuple &&t0,Tuples &&...others) + { + if constexpr(sized_product_type) return std::remove_cvref_t{}; + else + { + auto const call = [&](index_t idx, Ts &&... args) + { + return f(idx, get(args)...); + }; + return [&](std::index_sequence) + { + return kumi::make_tuple(call(index, KUMI_FWD(t0), KUMI_FWD(others)...)...); + }(std::make_index_sequence::value>()); + } + } + namespace result + { + template::value>... Ts> + struct map_index + { + using type = decltype ( kumi::map_index ( std::declval() + , std::declval() + , std::declval()... + ) + ); + }; + template::value>... Ts> + using map_index_t = typename map_index::type; + } +} +namespace kumi +{ + template + [[nodiscard]] constexpr auto push_front(Tuple const& t, T&& v) + { + return [&](std::index_sequence) + { + return kumi::make_tuple(KUMI_FWD(v), get(KUMI_FWD(t))...); + } + (std::make_index_sequence()); + } + template + [[nodiscard]] constexpr auto pop_front(Tuple const& t) + { + if constexpr(Tuple::size()>0) return extract(t, index<1>); + else return tuple<>{}; + } + template + [[nodiscard]] constexpr auto push_back(Tuple const& t, T&& v) + { + return [&](std::index_sequence) + { + return kumi::make_tuple(get(KUMI_FWD(t))..., KUMI_FWD(v)); + } + (std::make_index_sequence()); + } + template + [[nodiscard]] constexpr auto pop_back(Tuple const& t) + { + if constexpr(Tuple::size()>1) return extract(t,index<0>, index); + else return tuple<>{}; + } + namespace result + { + template struct push_front + { + using type = decltype( kumi::push_front( std::declval(), std::declval() ) ); + }; + template struct pop_front + { + using type = decltype( kumi::pop_front( std::declval() ) ); + }; + template struct push_back + { + using type = decltype( kumi::push_back( std::declval(), std::declval() ) ); + }; + template struct pop_back + { + using type = decltype( kumi::pop_back( std::declval() ) ); + }; + template + using push_front_t = typename push_front::type; + template + using pop_front_t = typename pop_front::type; + template + using push_back_t = typename push_back::type; + template + using pop_back_t = typename pop_back::type; + } +} +namespace kumi +{ + template + [[nodiscard]] constexpr auto fold_left(Function f, Tuple&& t, Value init) + { + if constexpr(sized_product_type) return init; + else + { + return [&](std::index_sequence) + { + return (detail::foldable {f, get(KUMI_FWD(t))} >> ... >> detail::foldable {f, init}).value; + } + (std::make_index_sequence::value>()); + } + } + template + [[nodiscard]] constexpr auto fold_right(Function f, Tuple&& t, Value init) + { + if constexpr(size::value ==0) return init; + else + { + return [&](std::index_sequence) + { + return (detail::foldable {f, init} << ... << detail::foldable {f, get(KUMI_FWD(t))}).value; + } + (std::make_index_sequence::value>()); + } + } + namespace result + { + template + struct fold_right + { + using type = decltype ( kumi::fold_right( std::declval() + , std::declval() + , std::declval() + ) + ); + }; + template + struct fold_left + { + using type = decltype ( kumi::fold_left ( std::declval() + , std::declval() + , std::declval() + ) + ); + }; + template + using fold_right_t = typename fold_right::type; + template + using fold_left_t = typename fold_left::type; + } +} +namespace kumi +{ + template + [[nodiscard]] constexpr auto max(T const& t, F f) noexcept + { + if constexpr ( !kumi::product_type ) return f(t); + else if constexpr( T::size() == 1 ) return f( get<0>(t) ); + else + { + auto base = f( get<0>(t) ); + return kumi::fold_left( [f](auto cur, U const& u) + { + return cur > f(u) ? cur : f(u); + } + , t, base + ); + } + } + template + [[nodiscard]] constexpr auto max_flat(T const& t, F f) noexcept + { + if constexpr ( !kumi::product_type ) return f(t); + else + { + auto flat_t = kumi::flatten_all(t); + return max(flat_t, f); } } - namespace result { template struct max { using type = decltype( kumi::max( std::declval(), std::declval() ) ); }; - template struct max_flat { using type = decltype( kumi::max_flat( std::declval(), std::declval() ) ); }; - template using max_t = typename max::type; template using max_flat_t = typename max_flat::type; } - - //================================================================================================ - //! @ingroup reductions - //! @brief Computes the minimum value of applications of f to all elements of t. - //! @param t Tuple to inspect - //! @param f Unary Callable object - //! @return The minimum value of f over all elements of t - //! - //! ## Helper type - //! @code - //! namespace kumi - //! { - //! template struct min; - //! - //! template - //! using min_t = typename min::type; - //! } - //! @endcode - //! - //! Computes the type returned by a call to kumi::min. - //! - //! ## Example: - //! @include doc/min.cpp - //================================================================================================ template [[nodiscard]] constexpr auto min(T const& t, F f) noexcept { @@ -2094,30 +1130,6 @@ namespace kumi ); } } - - //================================================================================================ - //! @ingroup reductions - //! @brief Computes the minimum value of applications of f to all elements of kumi::flatten_all(t). - //! @param t Tuple to inspect - //! @param f Unary Callable object - //! @return The minimum value of f over all elements of a flattened version of t - //! - //! ## Helper type - //! @code - //! namespace kumi - //! { - //! template struct min_flat; - //! - //! template - //! using min_flat_t = typename min_flat::type; - //! } - //! @endcode - //! - //! Computes the type returned by a call to kumi::min_flat. - //! - //! ## Example: - //! @include doc/min_flat.cpp - //================================================================================================ template [[nodiscard]] constexpr auto min_flat(T const& t, F f) noexcept { @@ -2128,265 +1140,138 @@ namespace kumi return min(flat_t, f); } } - namespace result { template struct min { using type = decltype( kumi::min( std::declval(), std::declval() ) ); }; - template struct min_flat { using type = decltype( kumi::min_flat( std::declval(), std::declval() ) ); }; - template using min_t = typename min::type; template using min_flat_t = typename min_flat::type; } - - //================================================================================================ - //! @ingroup utility - //! @brief Convert a unary template meta-program in a running predicate - //! @tparam Pred Unary template meta-program to convert. - //! @return A Callable Object applying Pred to the type of its arguments - //================================================================================================ - template class Pred> [[nodiscard]] constexpr auto predicate() noexcept +} +namespace kumi +{ + template + [[nodiscard]] constexpr bool all_of( Tuple const& ts, Pred p) noexcept { - return [](T const&) constexpr { return Pred::value; }; + return kumi::apply( [&](auto const&... m) { return (p(m) && ... && true); }, ts ); } - - //================================================================================================ - //! @ingroup queries - //! @brief Checks if unary predicate p returns true for all elements in the tuple t. - //! @param t Tuple to process - //! @param p Unary predicate. p must return a value convertible to `bool` for every element of t. - //! @return `true` if all elements of t satisfy p. - //! ## Example: - //! @include doc/all_of.cpp - //================================================================================================ - template - [[nodiscard]] constexpr bool all_of( Tuple const& t, Pred p) noexcept - { - return kumi::apply( [&](auto const&... m) { return (p(m) && ... && true); }, t ); - } - - //================================================================================================ - //! @ingroup queries - //! @brief Checks if unary predicate p returns true for at least one element in the tuple t. - //! @param t Tuple to process - //! @param p Unary predicate. p must return a value convertible to `bool` for every element of t. - //! @return `true` if at least one of elements of t satisfy p. - //! ## Example: - //! @include doc/any_of.cpp - //================================================================================================ template [[nodiscard]] constexpr bool any_of( Tuple const& ts, Pred p) noexcept { return kumi::apply( [&](auto const&... m) { return (p(m) || ... || false); }, ts ); } - - //================================================================================================ - //! @ingroup queries - //! @brief Checks if unary predicate p returns true for at no elements in the tuple t. - //! @param t Tuple to process - //! @param p Unary predicate. p must return a value convertible to `bool` for every element of t. - //! @return `true` if at no elements of t satisfy p. - //! ## Example: - //! @include doc/none_of.cpp - //================================================================================================ template [[nodiscard]] constexpr bool none_of( Tuple const& ts, Pred p) noexcept { return !any_of(ts,p); } - - //================================================================================================ - //! @ingroup queries - //! @brief Counts the number of elements of t satisfying predicates p. - //! @param t Tuple to process - //! @param p Unary predicate. p must return a value convertible to `bool` for every element of t. - //! @return Number of elements satisfying the condition. - //! ## Example: - //! @include doc/count_if.cpp - //================================================================================================ template [[nodiscard]] constexpr std::size_t count_if( Tuple const& ts, Pred p) noexcept { return kumi::apply( [&](auto const&... m) { return ( (p(m)? 1 : 0)+ ... + 0); }, ts ); } - - //================================================================================================ - //! @ingroup queries - //! @brief Counts the number of elements of t not equivalent to false. - //! @param t Tuple to process - //! @return Number of elements not equivalent to `false`. - //! ## Example: - //! @include doc/count.cpp - //================================================================================================ template [[nodiscard]] constexpr std::size_t count( Tuple const& ts ) noexcept { return count_if(ts, [](auto const& m) { return static_cast(m); } ); } - - //================================================================================================ - //! @ingroup queries - //! @brief Return the index of a value which type satisfies a given predicate - //! @param t Tuple to process - //! @param p Unary predicate. p must return a value convertible to `bool` for every element of t. - //! @return Integral index of the element inside the tuple if present, kumi::size>::value - //! otherwise. - //! ## Example: - //! @include doc/locate.cpp - //================================================================================================ - template - [[nodiscard]] constexpr auto locate( tuple const& t, Pred p ) noexcept +} +namespace kumi +{ + template + requires((Idx < size_v) && ...) [[nodiscard]] constexpr auto reorder(Tuple &&t) { - auto locator = [&](auto const&... m) + return kumi::make_tuple( get(KUMI_FWD(t))...); + } + namespace result + { + template + struct reorder { - bool checks[] = { p(m)... }; - for(std::size_t i=0;i( std::declval() ) ); }; - - return kumi::apply(locator, t); + template + using reorder_t = typename reorder::type; } - - //================================================================================================ - namespace detail +} +namespace kumi +{ + template + [[nodiscard]] constexpr auto reverse(Tuple &&t) { - template constexpr auto digits(std::size_t v) noexcept + if constexpr(sized_product_type) return kumi::tuple<>{}; + else { - struct { std::size_t data[N]; } digits = {}; - std::size_t shp[] = {S...}; - std::size_t i = 0; - - while(v != 0) + return [&](std::index_sequence) { - digits.data[i] = v % shp[i]; - v /= shp[i++]; + return kumi::make_tuple(get<(size_v - 1 - I)>(KUMI_FWD(t))...); } - - return digits; + (std::make_index_sequence::value>()); } } - - // MSVC chokes on the other code for empty calls -#if !defined(KUMI_DOXYGEN_INVOKED) - [[nodiscard]] constexpr auto cartesian_product() { return kumi::tuple<>{}; } -#endif - - //================================================================================================ - //! @ingroup generators - //! @brief Return the Cartesian Product of all elements of its arguments product types - //! @param ts Tuples to process - //! @return a tuple containing all the tuple build from all combination of all ts' elements - //! - //! ## Helper type - //! @code - //! namespace kumi - //! { - //! template struct cartesian_product; - //! - //! template - //! using cartesian_product_t = typename cartesian_product::type; - //! } - //! @endcode - //! - //! Computes the type returned by a call to kumi::cartesian_product. - //! - //! ## Example: - //! @include doc/cartesian_product.cpp - //================================================================================================ - template - [[nodiscard]] constexpr auto cartesian_product(Ts&&... ts) + namespace result { - auto maps = [&](auto k, std::index_sequence) + template + struct reverse { - constexpr auto dg = detail::digits...>(k); - using tuple_t = kumi::tuple>...>; - return tuple_t{kumi::get(std::forward(ts))...}; + using type = decltype( kumi::reverse( std::declval() ) ); }; - - return [&](std::index_sequence) + template + using reverse_t = typename reverse::type; + } +} +namespace kumi +{ + template [[nodiscard]] constexpr auto transpose(Tuple const &t) + { + if constexpr(sized_product_type) return t; + else { - return kumi::make_tuple(maps( kumi::index, std::make_index_sequence{})...); - }(std::make_index_sequence<(kumi::size_v * ...)>{}); + return [&](std::index_sequence) + { + constexpr auto uz = [](N const &, auto const &u) { + return apply([](auto const &...m) { return kumi::make_tuple(get(m)...); }, u); + }; + return kumi::make_tuple(uz(index_t {}, t)...); + } + (std::make_index_sequence>::value>()); + } } - namespace result { - template struct cartesian_product + template struct transpose { - using type = decltype( kumi::cartesian_product( std::declval()... ) ); + using type = decltype( kumi::transpose( std::declval() ) ); }; - - template using cartesian_product_t = typename cartesian_product::type; + template + using transpose_t = typename transpose::type; } - - //================================================================================================ - namespace detail +} +namespace kumi +{ + template>... Ts> + [[nodiscard]] constexpr auto zip(T0 const &t0, Ts const &...ts) { - template< product_type Tuple - , typename IndexSequence - , template class Meta = std::type_identity - > - struct as_tuple; - - template< product_type Tuple - , std::size_t... I - > - struct as_tuple> - { - using type = kumi::tuple< element_t... >; - }; - - template< product_type Tuple - , std::size_t... I - , template class Meta - > - struct as_tuple, Meta> + return kumi::map( [](auto const &m0, auto const &...ms) { return kumi::make_tuple(m0, ms...); } + , t0,ts... + ); + } + namespace result + { + template + struct zip { - using type = kumi::tuple< typename Meta>::type... >; + using type = decltype( kumi::zip( std::declval(), std::declval()... ) ); }; + template + using zip_t = typename zip::type; } - - //================================================================================================ - //! @ingroup utility - //! @brief Generate a kumi::tuple type from a kumi::product_type - //! - //! Compute the exact kumi::tuple type containing the same element as `Tuple`, an arbitrary type - //! modeling kumi::product_type. A template meta-function can be optionally passed to be applied - //! to each of those types when types are computed. - //! - //! @tparam Tuple kumi::product_type to tranform - //! @tparam Meta Unary template meta-function to apply to each types. - //! Defaults to `std::type_identity` - //! - //! ## Helper type - //! @code - //! namespace kumi - //! { - //! template class Meta = std::type_identity> - //! using as_tuple_t = typename as_tuple::type; - //! } - //! @endcode - //! - //! ## Example: - //! @include doc/as_tuple.cpp - //================================================================================================ - template class Meta = std::type_identity> - struct as_tuple : detail::as_tuple< Tuple - , std::make_index_sequence::value> - , Meta - > - {}; - - template class Meta = std::type_identity> - using as_tuple_t = typename as_tuple::type; } - #undef KUMI_FWD #endif diff --git a/include/kwk/detail/memory/block.hpp b/include/kwk/detail/memory/block.hpp new file mode 100644 index 00000000..d2949d84 --- /dev/null +++ b/include/kwk/detail/memory/block.hpp @@ -0,0 +1,40 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include + +namespace kwk::detail +{ + template + struct block_type; + + template + struct block_type + { + using type = shallow_block; + }; + + template + struct block_type + { + static constexpr auto find() noexcept + { + if constexpr( Shape.is_fully_static ) return stack_block{}; + else return heap_block{}; + } + + using type = decltype( find() ); + }; + + template + using block_t = typename block_type::type; +} diff --git a/include/kwk/detail/memory/heap_block.hpp b/include/kwk/detail/memory/heap_block.hpp new file mode 100644 index 00000000..4ac4f27b --- /dev/null +++ b/include/kwk/detail/memory/heap_block.hpp @@ -0,0 +1,70 @@ +//================================================================================================== +/** + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +**/ +//================================================================================================== +#pragma once +#include +#include +#include +#include + +namespace kwk::detail +{ + template struct heap_block + { + using base_type = T; + using value_type = std::remove_const_t; + using reference = std::add_lvalue_reference_t; + using const_reference = std::add_lvalue_reference_t; + using pointer = std::add_pointer_t; + using const_pointer = std::add_pointer_t; + + struct deleter + { + any_allocator allocator_; + + deleter() {} + template deleter(A a) : allocator_(a) {} + void operator()(void* p) { deallocate(allocator_,(value_type*)(p)); } + }; + + using ptr_t = std::unique_ptr; + ptr_t data_; + + constexpr heap_block() : data_(nullptr, deleter{heap_allocator{}}) {} + + template + constexpr heap_block(Settings const& p) + : data_ ( [&]() + { + auto a = pick(kwk::allocator,p); + auto s = pick(kwk::size,p); + return ptr_t{(value_type*)(allocate(a,s.numel()*sizeof(T))), deleter(a)}; + }() + ) + { + if constexpr( Settings::contains(kwk::source) ) + assign( storage(pick(kwk::source, p)), pick(kwk::size,p).numel() ); + } + + constexpr void swap(heap_block& other) noexcept { data_.swap(other.data_); } + constexpr friend void swap(heap_block& a,heap_block& b) noexcept { a.swap(b); } + + constexpr auto get_data() noexcept { return data_.get(); } + constexpr auto get_data() const noexcept { return data_.get(); } + + constexpr void assign(auto const& src, auto sz) + { + std::copy(src, src + sz, get_data()); + } + }; + + template + constexpr auto data(heap_block const& src) noexcept { return src.get_data(); } + + template + constexpr auto data(heap_block& src) noexcept { return src.get_data(); } +} diff --git a/include/kwk/detail/memory/shallow_block.hpp b/include/kwk/detail/memory/shallow_block.hpp new file mode 100644 index 00000000..4a57c0a8 --- /dev/null +++ b/include/kwk/detail/memory/shallow_block.hpp @@ -0,0 +1,45 @@ +//================================================================================================== +/** + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +**/ +//================================================================================================== +#pragma once +#include + +namespace kwk::detail +{ + template struct shallow_block + { + using base_type = T; + using value_type = std::remove_const_t; + using reference = std::add_lvalue_reference_t; + using const_reference = std::add_lvalue_reference_t; + using pointer = std::add_pointer_t; + using const_pointer = std::add_pointer_t; + + pointer data_; + + constexpr shallow_block() : data_{nullptr} {} + + template + constexpr shallow_block(Settings const& p) : data_(storage(pick(kwk::source,p))) + {} + + constexpr void swap(shallow_block& o) noexcept { std::swap(data_, o.data_); } + constexpr friend void swap(shallow_block& a,shallow_block& b) noexcept { a.swap(b); } + + constexpr auto get_data() noexcept { return data_; } + constexpr auto get_data() const noexcept { return data_; } + }; + + template shallow_block( T* p) -> shallow_block; + + template + constexpr auto data(shallow_block const& src) noexcept { return src.get_data(); } + + template + constexpr auto data(shallow_block& src) noexcept { return src.get_data(); } + +} diff --git a/include/kwk/detail/stack_block.hpp b/include/kwk/detail/memory/stack_block.hpp similarity index 55% rename from include/kwk/detail/stack_block.hpp rename to include/kwk/detail/memory/stack_block.hpp index 6df0a630..6f9c2e4c 100644 --- a/include/kwk/detail/stack_block.hpp +++ b/include/kwk/detail/memory/stack_block.hpp @@ -12,7 +12,7 @@ namespace kwk::detail { - template + template struct stack_block { using base_type = T; @@ -24,12 +24,21 @@ namespace kwk::detail value_type data_[Size]; - constexpr auto data() noexcept { return &data_[0] - Offset; } - constexpr auto data() const noexcept { return &data_[0] - Offset; } + constexpr stack_block() {} - constexpr void assign(auto const& src) + template + constexpr stack_block(Settings const& p) { - std::copy(src.data(), src.data() + Size, data()); + if constexpr( Settings::contains(kwk::source) ) + assign( storage(pick(kwk::source, p)), pick(kwk::size,p).numel() ); + } + + constexpr auto get_data() noexcept { return &data_[0]; } + constexpr auto get_data() const noexcept { return &data_[0]; } + + constexpr void assign(auto const& src, auto) + { + std::copy(src, src + Size, get_data()); } constexpr void swap(stack_block& other) noexcept @@ -38,4 +47,10 @@ namespace kwk::detail std::swap(data_[i], other.data_[i]); } }; + + template + constexpr auto data(stack_block const& src) noexcept { return src.get_data(); } + + template + constexpr auto data(stack_block& src) noexcept { return src.get_data(); } } diff --git a/include/kwk/detail/prefilled_array.hpp b/include/kwk/detail/prefilled_array.hpp deleted file mode 100644 index a744d679..00000000 --- a/include/kwk/detail/prefilled_array.hpp +++ /dev/null @@ -1,128 +0,0 @@ -//================================================================================================== -/* - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -*/ -//================================================================================================== -#pragma once - -#include -#include -#include -#include -#include -#include -#include - -namespace kwk::detail -{ - // Compute the prefilled_array base class for prefilled storage - template struct array_storage - { - using size_map = decltype(Desc.size_map()); - static constexpr std::ptrdiff_t static_size = Desc.size(); - using size_type = typename decltype(Desc)::size_type; - - struct empty_storage {}; - static constexpr std::ptrdiff_t storage_size = static_size - size_map::size; - using type = std::conditional_t< (storage_size!=0) - , std::array - , empty_storage - >; - }; - - // prefilled_array is an array containing data or compile-time data - template - struct prefilled_array : detail::array_storage::type - { - using parent = detail::array_storage; - using size_map = typename parent::size_map; - using size_type = typename parent::size_type; - using storage_t = typename parent::type; - using is_product_type = void; - - static constexpr std::ptrdiff_t static_size = Desc.size(); - static constexpr std::ptrdiff_t storage_size = parent::storage_size; - static constexpr bool is_dynamic = storage_size >= 1; - static constexpr bool is_fully_dynamic = storage_size == static_size; - - constexpr prefilled_array() noexcept {} - - static constexpr auto size() noexcept { return static_size; } - - template - requires( Desc2.size() < static_size || Desc.is_compatible(Desc2) ) - constexpr prefilled_array& operator=( prefilled_array const& p ) noexcept - { - prefilled_array that(p); - swap(that); - return *this; - } - - template - requires(I>=0 && I(I)]; - } - - template - requires(I>=0 && I(I)]; - } - - constexpr auto operator[](std::size_t i) const noexcept - { - if constexpr(static_size == 0) return 1; else return as_array()[i]; - } - - constexpr auto& operator[](std::size_t i) noexcept requires( is_dynamic && static_size>0) - { - return storage()[size_map::template locate(i)]; - } - - // Swap prefilled_array's contents - void swap( prefilled_array& other ) noexcept { storage().swap( other.storage() ); } - friend void swap( prefilled_array& x,prefilled_array& y ) noexcept { x.swap(y); } - - // Conversion to std::array - constexpr decltype(auto) as_array() const noexcept - { - if constexpr(is_fully_dynamic) return storage(); - else - { - return kumi::apply( [](auto... m) { return std::array{m...}; } - , *this - ); - } - } - - constexpr storage_t& storage() noexcept { return static_cast(*this); } - constexpr storage_t const& storage() const noexcept { return static_cast(*this); } - }; -} - -// prefilled_array supports structured bindings. -namespace kwk::detail -{ - template - constexpr auto get(prefilled_array const& s) noexcept { return s.template get(); } - - template - constexpr decltype(auto) get(prefilled_array& s) noexcept { return s.template get(); } -} - -template -struct std::tuple_element> -{ - using type = typename kwk::detail::prefilled_array::size_type; -}; - -template -struct std::tuple_size> - : std::integral_constant::static_size> -{ -}; diff --git a/include/kwk/detail/raberu.hpp b/include/kwk/detail/raberu.hpp index a24a926c..ca8dc7e9 100644 --- a/include/kwk/detail/raberu.hpp +++ b/include/kwk/detail/raberu.hpp @@ -581,7 +581,10 @@ namespace rbr } /// Type indicating that a [Keyword](@ref rbr::concepts::keyword) is not available - struct unknown_key {}; + struct unknown_key + { + using type = unknown_key; + }; // Option calls aggregator template struct aggregator : Ts... diff --git a/include/kwk/detail/range.hpp b/include/kwk/detail/range.hpp new file mode 100644 index 00000000..3d9656fc --- /dev/null +++ b/include/kwk/detail/range.hpp @@ -0,0 +1,44 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include +#include + +namespace kwk::detail +{ + //================================================================================================ + // Find the static_size of static array like types + //================================================================================================ + template + struct array_traits : std::false_type + { + using value_type = T; + static constexpr auto sizes = kumi::tuple{}; + static constexpr auto data(auto&& a) noexcept { return &KWK_FWD(a); } + }; + + template + struct array_traits> : std::true_type + { + using value_type = typename array_traits::value_type; + static constexpr auto sizes = kumi::push_back(array_traits::sizes,fixed); + static constexpr auto data(auto&& a) noexcept { return array_traits::data(KWK_FWD(a)[0]); } + }; + + template + struct array_traits : std::true_type + { + using value_type = typename array_traits::value_type; + static constexpr auto sizes = kumi::push_back(array_traits::sizes,fixed); + static constexpr auto data(auto&& a) noexcept { return array_traits::data(KWK_FWD(a)[0]); } + }; +} diff --git a/include/kwk/detail/round.hpp b/include/kwk/detail/round.hpp deleted file mode 100644 index 038dead1..00000000 --- a/include/kwk/detail/round.hpp +++ /dev/null @@ -1,23 +0,0 @@ -//================================================================================================== -/* - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -*/ -//================================================================================================== -#pragma once - -#include - -namespace kwk::detail -{ - inline constexpr auto round_to(std::ptrdiff_t value, std::ptrdiff_t alg) noexcept - { - return std::ptrdiff_t{(value + alg - 1) & ~(alg - 1)}; - } - - inline constexpr bool is_rounded(std::ptrdiff_t value, std::ptrdiff_t alg) noexcept - { - return (value & (alg - 1)) == 0; - } -} diff --git a/include/kwk/detail/sequence/combo.hpp b/include/kwk/detail/sequence/combo.hpp new file mode 100644 index 00000000..d4e45d5d --- /dev/null +++ b/include/kwk/detail/sequence/combo.hpp @@ -0,0 +1,187 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include +#include + +namespace kwk::detail +{ + struct size_; + + // combo sequence allow for constructing sequence of static value and placeholders + template struct combo + { + using is_product_type = void; + using base_type = T; + using contents_type = kumi::tuple; + + // shape is its self option keyword + using stored_value_type = combo; + using keyword_type = detail::size_; + + static constexpr std::size_t static_size = sizeof...(Elems); + + KWK_FORCEINLINE constexpr auto operator()(keyword_type const&) const noexcept { return *this; } + + static constexpr auto size() noexcept { return sizeof...(Elems); } + + friend std::ostream& operator<<(std::ostream& os, combo c) { return os << c.data; } + + constexpr auto operator()() const + { + return combo{kumi::push_back(data,_)}; + } + + constexpr auto operator[](auto i) const + { + return combo{kumi::push_back(data,static_cast(i))}; + } + + template + friend constexpr decltype(auto) get(combo& s) noexcept { return get(s.data); } + + template + friend constexpr decltype(auto) get(combo const& s) noexcept { return get(s.data); } + + // combo sequences are compatible if they have the same size + // and don't contain conflicting static values + template< typename T0, typename... E0> + constexpr bool is_compatible(combo const& other) const noexcept + { + if constexpr(sizeof...(Elems) != sizeof...(E0)) return false; + else + { + return kumi::fold_left( [](bool acc, auto const& t) + { + auto[e,f] = t; + // _ _ or _ k is OK by design + if constexpr(is_joker_v) return acc; + // k _ is OK but checks later + else if constexpr ( !is_joker_v + && is_joker_v + ) return acc; + // k1 k2 requires e == f + else return acc && (e == f); + } + , kumi::zip(*this,other) + , true + ); + } + } + + template< typename T0, typename... E0> + constexpr bool is_similar(combo const& other) const noexcept + { + if constexpr(sizeof...(Elems) != sizeof...(E0)) return false; + else + { + return kumi::fold_left( [](bool acc, auto const& t) + { + auto[e,f] = t; + + // _ _ or _ k is OK by design + if constexpr(is_joker_v) return acc; + // k _ is KO + else if constexpr ( !is_joker_v + && is_joker_v + ) return false; + // k1 k2 requires e == f + else return acc && (e == f); + } + , kumi::zip(*this,other) + , true + ); + } + } + + template + constexpr bool is_similar( S2 const& ) const noexcept + { + return is_similar(S2::descriptor); + } + + kumi::tuple data; + }; + + template + constexpr auto to_combo(kumi::tuple const& es) noexcept + { + return combo{es}; + } + + template + constexpr auto combo_cast(combo const& es) noexcept + { + return to_combo( kumi::map ( [](M m) + { + if constexpr(is_joker_v) return m; + else return static_cast(m); + } + , es.data + ) + ); + } + + // Compress combo at a given size, projecting remaining elements + template + constexpr auto compress(combo s) noexcept + { + auto tail = kumi::extract(s.data,kumi::index); + + // We add a _ to the end of the first part + // - if there is at least one _ in the tail + // - if there is a _ in the last element of the head + if constexpr( kumi::any_of(decltype(tail){},kumi::predicate()) + || is_joker_v::contents_type>> + ) + { + // eg: [1][2][3]()() compress 2 -> [1]() + auto head = kumi::extract(s.data, kumi::index<0>, kumi::index); + return to_combo(kumi::push_back(head,kwk::_)); + } + else + { + // if there is no joker, we compute the product of all remaining elements and try + // to insert it in the last part eg: [1][4][5] compress 2 -> [1][20] + auto value = kumi::fold_left( [](auto acc, auto v) { return acc*v; } + , tail + , get(s.data) + ); + return to_combo ( kumi::push_back ( kumi::extract ( s.data + , kumi::index<0> + , kumi::index + ) + , value + ) + ); + } + } + + // Special case for empty combo so to not instantiate kumi::tuple<> + template struct combo + { + using base_type = T; + constexpr auto operator()() const { return combo{_}; } + constexpr auto operator[](auto i) const { return combo{static_cast(i)}; } + }; +} + +// Tuple interface adaptation +template +struct std::tuple_size> + : std::integral_constant +{}; + +template +struct std::tuple_element> : + std::tuple_element> +{}; diff --git a/include/kwk/detail/sequence/extent_builder.hpp b/include/kwk/detail/sequence/extent_builder.hpp new file mode 100644 index 00000000..6e26bede --- /dev/null +++ b/include/kwk/detail/sequence/extent_builder.hpp @@ -0,0 +1,43 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include + +namespace kwk::detail +{ + // Convert a sequence of values to a proper extent type + template + constexpr auto as_extent(Ds... ds) noexcept + { + return kumi::fold_right( [](auto a, T) + { + if constexpr( requires{ T::value; } ) return a[T::value]; + else return a(); + } + , kumi::tie(ds...) + , detail::combo{} + ); + } + + template< template class Wrapper + , typename SizeType + , concepts::extent... Ds + > + constexpr auto make_extent(Ds... ds) noexcept + { + return kumi::apply( [](auto... v) + { + return Wrapper(Ds{}...)>(v...); + } + , kumi::tuple{ds...} + ); + } +} diff --git a/include/kwk/detail/sequence/prefilled.hpp b/include/kwk/detail/sequence/prefilled.hpp new file mode 100644 index 00000000..b5d441b2 --- /dev/null +++ b/include/kwk/detail/sequence/prefilled.hpp @@ -0,0 +1,212 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace kwk::detail +{ + // Compute the prefilled_array base class for prefilled storage + template())> + struct array_storage + { + using descriptor_t = decltype(Desc); + using value_type = typename descriptor_t::base_type; + static constexpr std::size_t storage_size = Size; + using storage_type = std::array; + }; + + template struct array_storage + { + using descriptor_t = decltype(Desc); + using value_type = typename descriptor_t::base_type; + static constexpr std::size_t storage_size = 0ULL; + + struct storage_type {}; + }; + + template struct prefilled : array_storage::storage_type + { + using descriptor_t = decltype(Desc); + using value_type = typename descriptor_t::base_type; + using storage_t = typename array_storage::storage_type; + using is_product_type = void; + + static constexpr auto descriptor = Desc; + static constexpr std::size_t static_size = Desc.static_size; + static constexpr std::size_t dynamic_size = kumi::count_if(Desc,kumi::predicate()); + static constexpr bool is_fully_static = (dynamic_size == 0); + static constexpr bool is_dynamic = !is_fully_static; + + static constexpr + auto index = kumi::map ( [k=0](V) mutable + { + if constexpr(kwk::is_joker_v) return k++; + else return -1; + } + , Desc + ); + + static constexpr + auto location = kumi::apply ( [](auto... m) + { + return std::array < std::ptrdiff_t + , static_size + >{static_cast(m)...}; + } + , index + ); + + // Do we have runtime storage for a given index ? + static bool constexpr contains(std::size_t i) { return location[i] != -1; } + + // Default constructor + constexpr prefilled() : storage_t{} {} + + // Construct using a higher-level filling strategy + template + constexpr prefilled(Filler f) + { + kumi::for_each_index( [&](auto i, V const&, auto m) + { + if constexpr(kwk::is_joker_v) storage()[m] = f(i,m); + } + , Desc, index + ); + } + + // Fill with a sequence of value/joker + constexpr void fill(concepts::extent auto... vals) noexcept + requires( sizeof...(vals) <= static_size ) + { + auto& v = storage(); + + // Fill storage data with provided size + kumi::for_each_index( [&](N, S vs) + { + constexpr auto i = N::value; + if constexpr( std::is_convertible_v ) + { + if constexpr(contains(i)) v[location[i]] = vs; + else KIWAKU_ASSERT ( vs == get(descriptor) + , "[KWK] - Runtime/Compile-time mismatch in constructor" + ); + } + else + { + if constexpr(contains(i)) v[location[i]] = i != 0; + } + } + , kumi::tie(vals...) + ); + } + + template + KWK_FORCEINLINE constexpr auto extent() const noexcept + { + if constexpr(is_dynamic_extent_v) return storage()[location[N]]; + else return fixed(Desc)>; + } + + // Static access + template + friend KWK_FORCEINLINE constexpr auto get(prefilled const& s) noexcept + requires(N>=0 && N) return s.storage()[location[N]]; + else return get(Desc); + } + + template + friend KWK_FORCEINLINE constexpr auto& get(prefilled& s) noexcept + requires(N>=0 && N) return s.storage()[location[N]]; + else return get(Desc); + } + + // Dynamic access + KWK_FORCEINLINE constexpr auto operator[](std::size_t i) const noexcept + { + KIWAKU_ASSERT(i0) + { + KIWAKU_ASSERT ( i{static_cast(m)...}; + } + , *this + ); + } + + // Swap prefilled_array's contents + void swap( prefilled& other ) noexcept { storage().swap( other.storage() ); } + friend void swap( prefilled& x, prefilled& y ) noexcept { x.swap(y); } + + // Internal storage access for algorithms + constexpr storage_t& storage() noexcept + { + return static_cast(*this); + } + + constexpr storage_t const& storage() const noexcept + { + return static_cast(*this); + } + }; + + // Project elements in a N dimension prefilled instance + template + constexpr auto compress(prefilled const& s) noexcept + { + using t_t = prefilled(Desc)>; + t_t t; + + kumi::for_each_index + ( [&](auto i, auto m) { if constexpr(i < N && t_t::contains(i)) t[i] = m; }, s); + + kumi::for_each_index + ( [&](auto i, auto m) { if constexpr(i >= N && t_t::contains(N-1)) t[N-1] *= m; }, s); + + return t; + } +} + +// Tuple interface adaptation +template +struct std::tuple_size> + : std::integral_constant::static_size> +{}; + +template +struct std::tuple_element> +{ + using type = typename kwk::detail::prefilled::value_type; +}; diff --git a/include/kwk/detail/strider.hpp b/include/kwk/detail/strider.hpp deleted file mode 100644 index 3790a34d..00000000 --- a/include/kwk/detail/strider.hpp +++ /dev/null @@ -1,63 +0,0 @@ -//================================================================================================== -/** - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -**/ -//================================================================================================== -#pragma once - -#include -#include -#include -#include -#include -#include - -namespace kwk::detail -{ - //============================================================================================== - // Build the static storage of a stride depending on # of dimensions and unit dimensions - //============================================================================================== - template - using stride_storage = std::array; - - //============================================================================================== - // Type representing a unit stride - //============================================================================================== - using unit_type = std::integral_constant; - - //============================================================================================== - // Compute an index_list from a pack of stride value types - //============================================================================================== - template struct index_map - { - using size_type = T; - using map_type = typename type_map::type; - static constexpr std::ptrdiff_t size = map_type::size; - static constexpr std::ptrdiff_t static_size = sizeof...(Vs)+1; - static constexpr bool is_implicit = false; - static constexpr bool is_unit = map_type::contains(0); - }; - - template struct implicit_index_map - { - using size_type = T; - using map_type = detail::index_list<0>; - static constexpr std::ptrdiff_t size = map_type::size; - static constexpr std::ptrdiff_t static_size = Dims; - static constexpr bool is_implicit = true; - static constexpr bool is_unit = true; - }; - - //============================================================================================== - // Convert indexes to linear position - //============================================================================================== - template - constexpr auto linearize( std::index_sequence const&, Data const& d, Is... is ) noexcept - { - using std::get; - if constexpr(sizeof...(Idx) > 0) return ((is * get(d)) + ...); - else return 0; - } -} diff --git a/include/kwk/kwk.hpp b/include/kwk/kwk.hpp index 19f30359..67a430d8 100644 --- a/include/kwk/kwk.hpp +++ b/include/kwk/kwk.hpp @@ -7,8 +7,11 @@ //================================================================================================== #pragma once -#include -#include +/// @brief Main **KIWAKU** namespace +namespace kwk {} + +#include +#include #include -#include -#include +// #include +#include diff --git a/include/kwk/options/base_index.hpp b/include/kwk/options/base_index.hpp deleted file mode 100644 index e379c0d2..00000000 --- a/include/kwk/options/base_index.hpp +++ /dev/null @@ -1,58 +0,0 @@ -//================================================================================================== -/** - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -**/ -//================================================================================================== -#pragma once - -#include -#include -#include -#include - -namespace kwk -{ -#if !defined(KWK_USE_DOXYGEN) - struct base_index_; - - template struct bases_ - { - using stored_value_type = bases_; - using keyword_type = base_index_; - - constexpr auto operator()(keyword_type const&) const noexcept { return *this; } - - template constexpr auto as_position() const noexcept - { - return kumi::generate(Base); - } - }; - - struct base_index_ : rbr::as_keyword - { - template - constexpr auto operator=(bases_ const& s) const noexcept { return s; } - - // Display - template - std::ostream& show(std::ostream& os, bases_ const&) const - { - return os << "Base Index: " << N; - } - }; -#endif - - /** - @ingroup options - @brief Keyword for accessing base index options - **/ - inline constexpr auto base_index = base_index_{}; - - /** - @ingroup options - @brief Settings describing the base index for all dimensions of a container - **/ - template inline constexpr auto bases = bases_{}; -} diff --git a/include/kwk/options/fixed.hpp b/include/kwk/options/fixed.hpp deleted file mode 100644 index e02e6e48..00000000 --- a/include/kwk/options/fixed.hpp +++ /dev/null @@ -1,82 +0,0 @@ -//================================================================================================== -/** - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -**/ -//================================================================================================== -#pragma once -#include -#include -#include - -namespace kwk -{ - namespace detail - { - struct value_joker; - - template struct to_int { using type = T; }; - template<> struct to_int { using type = char; }; - template struct to_int> { using type = T; }; - template using to_int_t = typename to_int::type; - - template struct largest_type; - template struct largest_type { using type = T; }; - - template - struct largest_type : std::conditional - {}; - - template - struct largest_type : largest_type< typename largest_type::type, T2...> - {}; - - template constexpr auto clamp() - { - if constexpr(Value >= 0) - { - if constexpr (Value<0x100 ) return static_cast(Value); - else if constexpr (Value<0x10000 ) return static_cast(Value); - else if constexpr (Value<0x100000000) return static_cast(Value); - else return Value; - } - else - { - if constexpr (-Value<0x7F ) return static_cast(Value); - else if constexpr (-Value<0x7FFF ) return static_cast(Value); - else if constexpr (-Value<0x7FFFFFFF) return static_cast(Value); - else return Value; - } - } - } - - /** - @ingroup utility - @brief Provides a short-cut to define a `std::integral_constant` instance from a literal integer - - The underlying type is computed from the actual value to be the smallest fitting type. - This means, for example, that kwk::fixed<123> is an instance of - `std::integral_constant`. When negative values are used, signed integral - types are selected, i.e kwk::fixed<-999> is an instance of - `std::integral_constant`. - **/ - template - inline constexpr auto fixed = std::integral_constant()),detail::clamp()>{}; - - namespace literals - { - template constexpr auto b10() - { - auto value = 0LL; - ((value = value * 10 + (c - '0')), ...); - return value; - } - - /** - @ingroup utility - @brief User-defined literal suffix for compile-time constant - **/ - template constexpr auto operator"" _c() noexcept { return fixed()>; } - } -} diff --git a/include/kwk/options/source/array_source.hpp b/include/kwk/options/source/array_source.hpp deleted file mode 100644 index 29610f52..00000000 --- a/include/kwk/options/source/array_source.hpp +++ /dev/null @@ -1,47 +0,0 @@ -//================================================================================================== -/** - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -**/ -//================================================================================================== -#pragma once -#include - -namespace kwk -{ - struct data_source; - - template struct array_source - { - using base_type = T; - using stored_value_type = array_source; - using keyword_type = data_source; - using span_type = array_source; - - using value_type = std::remove_const_t; - using reference = std::add_lvalue_reference_t; - using const_reference = std::add_lvalue_reference_t; - using pointer = std::add_pointer_t; - using const_pointer = std::add_pointer_t; - - constexpr array_source(T* p = nullptr) : data_(p) {} - - constexpr auto operator()(keyword_type const&) const noexcept { return *this; } - - constexpr auto as_block(std::ptrdiff_t offset = 0) const noexcept - { - return array_source{data_ - offset}; - } - - constexpr pointer reset(pointer ptr) noexcept - { - return std::exchange(data_, ptr); - } - - constexpr auto data() const noexcept { return data_; } - constexpr auto default_shape() const noexcept { return of_size(fixed); } - - T* data_; - }; -} diff --git a/include/kwk/options/source/ptr_source.hpp b/include/kwk/options/source/ptr_source.hpp deleted file mode 100644 index 6619462e..00000000 --- a/include/kwk/options/source/ptr_source.hpp +++ /dev/null @@ -1,46 +0,0 @@ -//================================================================================================== -/** - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -**/ -//================================================================================================== -#pragma once -#include - -namespace kwk -{ - struct data_source; - - template struct ptr_source - { - using base_type = T; - using span_type = ptr_source; - using stored_value_type = ptr_source; - using keyword_type = data_source; - - using value_type = std::remove_const_t; - using reference = std::add_lvalue_reference_t; - using const_reference = std::add_lvalue_reference_t; - using pointer = std::add_pointer_t; - using const_pointer = std::add_pointer_t; - - constexpr ptr_source(T* p = nullptr) : data_(p) {} - - constexpr auto operator()(keyword_type const&) const noexcept { return *this; } - - constexpr auto as_block(std::ptrdiff_t offset = 0) const noexcept - { - return ptr_source{data_ - offset}; - } - - constexpr pointer reset(pointer ptr) noexcept - { - return std::exchange(data_, ptr); - } - - constexpr auto data() const noexcept { return data_; } - constexpr auto default_shape() const noexcept { return shape<_1D>{0}; } - T* data_; - }; -} diff --git a/include/kwk/options/source/range_source.hpp b/include/kwk/options/source/range_source.hpp deleted file mode 100644 index a335aa0b..00000000 --- a/include/kwk/options/source/range_source.hpp +++ /dev/null @@ -1,54 +0,0 @@ -//================================================================================================== -/** - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -**/ -//================================================================================================== -#pragma once -#include - -namespace kwk -{ - struct data_source; - - template struct range_source - { - using stored_value_type = range_source; - using keyword_type = data_source; - - constexpr range_source(T* p = nullptr, Size s = 0) : data_(p), size_(s) {} - - constexpr auto operator()(keyword_type const&) const noexcept { return *this; } - - struct range_span - { - using base_type = T; - using value_type = std::remove_const_t; - using reference = std::add_lvalue_reference_t; - using const_reference = std::add_lvalue_reference_t; - using pointer = std::add_pointer_t; - using const_pointer = std::add_pointer_t; - - T* data_; - constexpr auto data() const noexcept { return data_; } - - constexpr pointer reset(pointer ptr) noexcept - { - return std::exchange(data_, ptr); - } - }; - - using span_type = range_span; - - constexpr auto as_block(std::ptrdiff_t offset = 0) const noexcept - { - return range_span{data_ - offset}; - } - - constexpr auto default_shape() const noexcept { return of_size(size_); } - - T* data_; - Size size_; - }; -} diff --git a/include/kwk/options/type.hpp b/include/kwk/options/type.hpp deleted file mode 100644 index 33e36f4d..00000000 --- a/include/kwk/options/type.hpp +++ /dev/null @@ -1,54 +0,0 @@ -//================================================================================================== -/** - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -**/ -//================================================================================================== -#pragma once - -#include -#include - -namespace kwk -{ -#if !defined(KWK_USE_DOXYGEN) - struct type_ : rbr::as_keyword - { - template - struct info - { - using stored_value_type = info; - using keyword_type = type_; - using type = T; - - constexpr auto operator()(keyword_type const&) const noexcept { return *this; } - }; - - // Extent from of_size(...) - template constexpr auto operator=(info const& s) const noexcept - { - return s; - } - - // Display - template std::ostream& display(std::ostream& os, info const&) const - { - return os << "Type: " << rbr::detail::type_name(); - } - }; -#endif - - template constexpr inline type_::info type{}; - - constexpr inline type_::info single_{}; - constexpr inline type_::info double_{}; - constexpr inline type_::info int8_ {}; - constexpr inline type_::info int16_ {}; - constexpr inline type_::info int32_ {}; - constexpr inline type_::info int64_ {}; - constexpr inline type_::info uint8_ {}; - constexpr inline type_::info uint16_{}; - constexpr inline type_::info uint32_{}; - constexpr inline type_::info uint64_{}; -} diff --git a/include/kwk/settings.hpp b/include/kwk/settings.hpp new file mode 100644 index 00000000..18e77366 --- /dev/null +++ b/include/kwk/settings.hpp @@ -0,0 +1,26 @@ +//================================================================================================== +/** + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +**/ +//================================================================================================== +#pragma once + +namespace kwk +{ + //================================================================================================ + //! @ingroup utility + //! @defgroup settings Container settings + //! @brief Classes and functions related to table and views constructions + //================================================================================================ +} + +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/include/kwk/options/allocator.hpp b/include/kwk/settings/allocator.hpp similarity index 65% rename from include/kwk/options/allocator.hpp rename to include/kwk/settings/allocator.hpp index af195cbf..0e68d67b 100644 --- a/include/kwk/options/allocator.hpp +++ b/include/kwk/settings/allocator.hpp @@ -1,18 +1,17 @@ //================================================================================================== -/** +/* KIWAKU - Containers Well Made Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 -**/ +*/ //================================================================================================== #pragma once #include -#include +#include -namespace kwk +namespace kwk::detail { -#if !defined(KWK_USE_DOXYGEN) struct allocator_ : rbr::as_keyword { template @@ -25,11 +24,13 @@ namespace kwk return os << "Allocation via: " << rbr::detail::type_name(); } }; -#endif +} - /** - @ingroup options - @brief Allocator setting for kwk::table - **/ - inline constexpr allocator_ allocator = {}; +namespace kwk +{ + //================================================================================================ + //! @ingroup settings + //! @brief Allocator setting for kwk::table + //================================================================================================ + inline constexpr detail::allocator_ allocator = {}; } diff --git a/include/kwk/settings/category.hpp b/include/kwk/settings/category.hpp new file mode 100644 index 00000000..178b4b9b --- /dev/null +++ b/include/kwk/settings/category.hpp @@ -0,0 +1,35 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include + +namespace kwk::detail +{ + struct category_ : rbr::as_keyword + { + constexpr auto operator=(concepts::category auto const& s) const noexcept { return s; } + + template + std::ostream& display(std::ostream& os, Category const& s) const + { + return os << "Category: " << s; + } + }; +} + +namespace kwk +{ + //================================================================================================ + //! @ingroup settings + //! @brief Category setting discriminating **KIWAKU** containers + //================================================================================================ + inline constexpr detail::category_ category = {}; +} diff --git a/include/kwk/options/extent.hpp b/include/kwk/settings/extent.hpp similarity index 72% rename from include/kwk/options/extent.hpp rename to include/kwk/settings/extent.hpp index d554129f..dd689fe9 100644 --- a/include/kwk/options/extent.hpp +++ b/include/kwk/settings/extent.hpp @@ -7,25 +7,27 @@ //================================================================================================== #pragma once -#include +#include #include +#include #include namespace kwk { //================================================================================================ + //! @ingroup settings //! @var extent - //! @brief kwk::shape descriptor helper + //! @brief Constexpr generator for extent lists //! //!


//! **Required header**: //! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} - //! #include + //! #include //! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //!
//! - //! kwk::extent is used to define the layout of a kwk::shape in terms of order and potential - //! compile-time sizes. + //! kwk::extent is used to define the layout of a kwk::shape or kwk::stride in terms of order and + //! potential compile-time sizes. //! //! kwk::extent supports two member functions: //! - `operator()()` that specifies that a given dimension is known at runtime @@ -33,11 +35,12 @@ namespace kwk //! //! Both of these operators can be chained as needed to describe a given shape. //! - //! The actual integer type storing the size of each dimensions can be specified by using - //! kwk::extent_of. + //! The actual integer type storing the size or stride of each dimensions can be specified by + //! using kwk::extent_of. //! - //! Usage of kwk::extent is advised when one wants to properly type a given shape. - //! Other usage of shape descriptors are usually abstracted away via kwk::of_size. + //! Usage of @ref kwk::extent is advised when one wants to properly type a given shape or stride. + //! Other usage of @ref kwk::shape descriptors are usually abstracted away via @ref kwk::of_size + //! or @ref kwk::stride. //! //! @groupheader{Associated variables} //! @@ -73,21 +76,21 @@ namespace kwk //! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //! //================================================================================================ - inline constexpr detail::hybrid_sequence extent = {}; + inline constexpr detail::combo extent = {}; template - inline constexpr detail::hybrid_sequence extent_of = {}; + inline constexpr detail::combo extent_of = {}; - inline constexpr auto _1D = extent(); - inline constexpr auto _2D = _1D(); - inline constexpr auto _3D = _2D(); - inline constexpr auto _4D = _3D(); + inline constexpr auto _1D = extent(); + inline constexpr auto _2D = _1D(); + inline constexpr auto _3D = _2D(); + inline constexpr auto _4D = _3D(); template inline constexpr auto _nD = [](std::index_sequence const&) constexpr { - return detail::hybrid_sequence< std::ptrdiff_t - , typename detail::to_dyn_::type... - >{}; + return detail::combo< std::ptrdiff_t + , std::remove_cv_t... + >{}; }(std::make_index_sequence{}); } diff --git a/include/kwk/options/label.hpp b/include/kwk/settings/label.hpp similarity index 58% rename from include/kwk/options/label.hpp rename to include/kwk/settings/label.hpp index 444e77b7..0cacdbf3 100644 --- a/include/kwk/options/label.hpp +++ b/include/kwk/settings/label.hpp @@ -1,19 +1,17 @@ //================================================================================================== -/** +/* KIWAKU - Containers Well Made Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 -**/ +*/ //================================================================================================== #pragma once -#include #include #include -namespace kwk +namespace kwk::detail { -#if !defined(KWK_USE_DOXYGEN) struct label_ : rbr::as_keyword { template T> auto operator=(T s) const noexcept @@ -23,16 +21,18 @@ namespace kwk template std::ostream& show(std::ostream& os, Label const& l) const { - os << "Label: "; - if constexpr( std::same_as ) return os << "None"; - else return os << '\'' << l << '\''; + if constexpr( !std::same_as ) + return os << "Label: '" << l << '\''; + else return os; } }; -#endif +} - /** - @ingroup options - @brief Keyword for specifying label - **/ - inline constexpr label_ label = {}; +namespace kwk +{ + //================================================================================================ + //! @ingroup settings + //! @brief Label setting for kwk::table and kwk::view + //================================================================================================ + inline constexpr detail::label_ label = {}; } diff --git a/include/kwk/options/size.hpp b/include/kwk/settings/size.hpp similarity index 65% rename from include/kwk/options/size.hpp rename to include/kwk/settings/size.hpp index 6312a147..9e7f02eb 100644 --- a/include/kwk/options/size.hpp +++ b/include/kwk/settings/size.hpp @@ -1,19 +1,18 @@ //================================================================================================== -/** +/* KIWAKU - Containers Well Made Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 -**/ +*/ //================================================================================================== #pragma once -#include +#include #include #include -namespace kwk +namespace kwk::detail { -#if !defined(KWK_USE_DOXYGEN) struct size_ : rbr::as_keyword { // Single integral -> 1D shape @@ -25,9 +24,9 @@ namespace kwk // Extent -> shape{} template - constexpr auto operator=(detail::hybrid_sequence const&) const noexcept + constexpr auto operator=(detail::combo const&) const noexcept { - return shape{}>{}; + return shape{}>{}; } // Extent from of_size(...) @@ -43,11 +42,13 @@ namespace kwk return os << "Shape: " << s; } }; -#endif +} - /** - @ingroup options - @brief Keyword for specifying shape options - **/ - inline constexpr size_ size = {}; +namespace kwk +{ + //================================================================================================ + //! @ingroup settings + //! @brief Size setting for kwk::table and kwk::view + //================================================================================================ + inline constexpr detail::size_ size = {}; } diff --git a/include/kwk/options/source.hpp b/include/kwk/settings/source.hpp similarity index 50% rename from include/kwk/options/source.hpp rename to include/kwk/settings/source.hpp index 471b0c35..860ce147 100644 --- a/include/kwk/options/source.hpp +++ b/include/kwk/settings/source.hpp @@ -1,34 +1,34 @@ //================================================================================================== -/** +/* KIWAKU - Containers Well Made Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 -**/ +*/ //================================================================================================== #pragma once +#include #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include -namespace kwk +namespace kwk::detail { -#if !defined(KWK_USE_DOXYGEN) - struct data_source : rbr::as_keyword + struct source_ : rbr::as_keyword { // Options passthrough constexpr auto operator=(rbr::concepts::option auto const& o) const noexcept { return o; } - template + template constexpr auto operator=( Array&& a) const noexcept { using a_t = std::remove_reference_t; - return array_source < detail::value_type_of - , detail::static_size_v - >{std::data(KWK_FWD(a))}; + return array_source < typename detail::array_traits::value_type + , detail::array_traits::sizes + >{detail::array_traits::data(KWK_FWD(a))}; } // ContiguousRange with .data() @@ -46,16 +46,17 @@ namespace kwk // Display template std::ostream& display(std::ostream& os, Src src) const { - return os << "Source: " << src.as_block().data() - << " (" << rbr::detail::type_name() << ") " - << " - shape: " << src.default_shape(); + auto ptr = storage(src); + return os << "Source: " << ptr << " (" << rbr::detail::type_name() << ") "; } }; -#endif +} - /** - @ingroup options - @brief Data source setting for kwk::view - **/ - inline constexpr data_source source = {}; +namespace kwk +{ + //================================================================================================ + //! @ingroup settings + //! @brief Data source setting for kwk::table and kwk::view + //================================================================================================ + inline constexpr detail::source_ source = {}; } diff --git a/include/kwk/settings/source/array_source.hpp b/include/kwk/settings/source/array_source.hpp new file mode 100644 index 00000000..40c4d844 --- /dev/null +++ b/include/kwk/settings/source/array_source.hpp @@ -0,0 +1,44 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once +#include + +namespace kwk::detail { struct source_; } + +namespace kwk +{ + template struct array_source + { + using stored_value_type = array_source; + using keyword_type = detail::source_; + + using value_type = std::remove_const_t; + using reference = std::add_lvalue_reference_t; + using const_reference = std::add_lvalue_reference_t; + using pointer = std::add_pointer_t; + using const_pointer = std::add_pointer_t; + + constexpr array_source(T* p = nullptr) : data_(p) {} + + constexpr auto operator()(keyword_type const&) const noexcept { return *this; } + + T* data_; + }; + + template + constexpr auto storage(array_source const& src) noexcept { return src.data_; } + + template + constexpr auto default_shape(array_source const&) noexcept { return of_size( Szs ); } + + template struct source_traits; + template struct source_traits> + { + using value_type = T; + }; +} diff --git a/include/kwk/settings/source/ptr_source.hpp b/include/kwk/settings/source/ptr_source.hpp new file mode 100644 index 00000000..7d62a872 --- /dev/null +++ b/include/kwk/settings/source/ptr_source.hpp @@ -0,0 +1,50 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once +#include + +namespace kwk::detail { struct source_; } + +namespace kwk +{ + template struct ptr_source + { + using stored_value_type = ptr_source; + using keyword_type = detail::source_; + + using value_type = std::remove_const_t; + using reference = std::add_lvalue_reference_t; + using const_reference = std::add_lvalue_reference_t; + using pointer = std::add_pointer_t; + using const_pointer = std::add_pointer_t; + + constexpr ptr_source(T* p = nullptr) : data_(p) {} + + template + constexpr ptr_source(OtherSource p = {}) : data_(data(p)) {} + + constexpr auto operator()(keyword_type const&) const noexcept { return *this; } + + T* data_; + }; + + template + constexpr auto storage(ptr_source src) noexcept + { + return src.data_; + } + + template + constexpr auto default_shape(ptr_source const&) noexcept { return shape<_1D>{0}; } + + template struct source_traits; + template struct source_traits> + { + using value_type = T; + }; +} diff --git a/include/kwk/settings/source/range_source.hpp b/include/kwk/settings/source/range_source.hpp new file mode 100644 index 00000000..7341e92c --- /dev/null +++ b/include/kwk/settings/source/range_source.hpp @@ -0,0 +1,44 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once +#include + +namespace kwk::detail { struct source_; } + +namespace kwk +{ + template struct range_source + { + using stored_value_type = range_source; + using keyword_type = detail::source_; + + constexpr range_source(T* p = nullptr, std::size_t s = 0) : data_(p), size_(s) {} + constexpr auto operator()(keyword_type const&) const noexcept { return *this; } + + T* data_; + std::size_t size_; + }; + + template + constexpr auto storage(range_source src) noexcept + { + return src.data_; + } + + template + constexpr auto default_shape(range_source const& src) noexcept + { + return of_size(src.size_); + } + + template struct source_traits; + template struct source_traits> + { + using value_type = T; + }; +} diff --git a/include/kwk/options/strides.hpp b/include/kwk/settings/strides.hpp similarity index 63% rename from include/kwk/options/strides.hpp rename to include/kwk/settings/strides.hpp index 9e8e371b..311f795a 100644 --- a/include/kwk/options/strides.hpp +++ b/include/kwk/settings/strides.hpp @@ -1,22 +1,20 @@ //================================================================================================== -/** +/* KIWAKU - Containers Well Made Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 -**/ +*/ //================================================================================================== #pragma once -#include +#include #include #include -namespace kwk +namespace kwk::detail { -#if !defined(KWK_USE_DOXYGEN) struct strides_ : rbr::as_keyword { - // Extent from of_size(...) template auto operator=(stride const& s) const noexcept { return s; @@ -28,11 +26,13 @@ namespace kwk return os << "Strides: " << s; } }; -#endif +} - /** - @ingroup options - @brief Keyword for specifying strides options - **/ - inline constexpr strides_ strides = {}; +namespace kwk +{ + //================================================================================================ + //! @ingroup settings + //! @brief Stride setting for kwk::table and kwk::view + //================================================================================================ + inline constexpr detail::strides_ strides = {}; } diff --git a/include/kwk/settings/type.hpp b/include/kwk/settings/type.hpp new file mode 100644 index 00000000..4d51eebe --- /dev/null +++ b/include/kwk/settings/type.hpp @@ -0,0 +1,83 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include + +namespace kwk::detail +{ + struct type_ : rbr::as_keyword + { + template + struct info + { + using stored_value_type = info; + using keyword_type = type_; + using type = T; + + constexpr auto operator()(keyword_type const&) const noexcept { return *this; } + friend std::ostream& operator<<(std::ostream& os, info const&) + { + return os << rbr::detail::type_name(); + } + }; + + template constexpr auto operator=(info const& s) const noexcept + { + return s; + } + + // Display + template std::ostream& display(std::ostream& os, info const& s) const + { + return os << "Type: " << s; + } + }; +} + +namespace kwk +{ + constexpr inline detail::type_ type{}; + + //================================================================================================ + //! @ingroup settings + //! @brief Type setting for kwk::table + //================================================================================================ + template constexpr inline detail::type_::info as{}; + + /// Pre-defined type settings for float + constexpr inline auto single_ = as; + + /// Pre-defined type settings for double + constexpr inline auto double_ = as; + + /// Pre-defined type settings for std::int8_t + constexpr inline auto int8_ = as; + + /// Pre-defined type settings for std::int16_t + constexpr inline auto int16_ = as; + + /// Pre-defined type settings for std::int32_t + constexpr inline auto int32_ = as; + + /// Pre-defined type settings for std::int64_t + constexpr inline auto int64_ = as; + + /// Pre-defined type settings for std::uint8_t + constexpr inline auto uint8_ = as; + + /// Pre-defined type settings for std::uint16_t + constexpr inline auto uint16_ = as; + + /// Pre-defined type settings for std::uint32_t + constexpr inline auto uint32_ = as; + + /// Pre-defined type settings for std::uint64_t + constexpr inline auto uint64_ = as; +} diff --git a/include/kwk/options.hpp b/include/kwk/utility.hpp similarity index 51% rename from include/kwk/options.hpp rename to include/kwk/utility.hpp index ec42766a..8dc62488 100644 --- a/include/kwk/options.hpp +++ b/include/kwk/utility.hpp @@ -10,30 +10,25 @@ namespace kwk { //================================================================================================ - /** - @defgroup utility Miscellaneous helper - @brief Quality of Life helpers - - This module defines various functions, types and variables for improving Quality of Life when - using **KIWAKU** in user's code. - **/ + //! @defgroup utility Miscellaneous helper + //! @brief Quality of Life helpers + //! + //! This module defines various functions, types and variables for improving Quality of Life when + //! using **KIWAKU** in user's code. //================================================================================================ //================================================================================================ - /** - @defgroup options Options - @brief Containers properties settings - - This module defines the keywords usable to specify a container's list of properties. - **/ + //! @ingroup utility + //! @defgroup traits Type Traits + //! @brief Constants and meta-functions providing information on **KIWAKU** components //================================================================================================ } -#include -#include -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/include/kwk/container/shape.hpp b/include/kwk/utility/container/shape.hpp similarity index 51% rename from include/kwk/container/shape.hpp rename to include/kwk/utility/container/shape.hpp index 3e2b109b..32e555bf 100644 --- a/include/kwk/container/shape.hpp +++ b/include/kwk/utility/container/shape.hpp @@ -1,30 +1,30 @@ //================================================================================================== /* KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors + Copyright : EVE Project Contributors SPDX-License-Identifier: BSL-1.0 */ //================================================================================================== #pragma once -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include +#include "kwk/detail/kumi.hpp" +#include +#include +#include +#include +#include +#include +#include #include -#include -#include + +namespace kwk::detail { struct size_; } namespace kwk { - struct size_; + template struct shape; + + template + constexpr auto compress(shape const& s) noexcept; //================================================================================================ //! @ingroup containers @@ -33,7 +33,7 @@ namespace kwk //!
//! **Required header**: //! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} - //! #include + //! #include //! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ //!
//! @@ -67,41 +67,40 @@ namespace kwk //! //! @tparam Shaper An instance of a [shape descriptor](@ref eve::extent) //================================================================================================ - template - struct shape : detail::prefilled_array + template + struct shape : kwk::detail::prefilled { - using parent = detail::prefilled_array; + using parent = kwk::detail::prefilled; + + /// Compile-time shape descriptor + static constexpr auto descriptor = Shape; /// Compile-time value for @ref glossary-order static constexpr std::ptrdiff_t static_order = parent::static_size; + static constexpr std::ptrdiff_t static_size = parent::static_size; /// Type of dimensions' size - using size_type = typename parent::size_type; - - /// Associated kwk::stride type - using stride_type = unit_stride; + using size_type = typename parent::value_type; /// Indicates that the shape has at least one dimension specified at runtime - static constexpr bool is_dynamic = parent::storage_size >= 1; + static constexpr bool is_dynamic = parent::is_dynamic; /// Indicates that the shape's dimensions are all specified at runtime - static constexpr bool is_fully_dynamic = parent::storage_size == static_order; + static constexpr bool is_fully_dynamic = parent::dynamic_size == static_order; /// Indicates that the shape's dimensions are all specified compile-time - static constexpr bool is_fully_static = parent::storage_size == 0; + static constexpr bool is_fully_static = parent::is_fully_static; // shape is its self option keyword - using stored_value_type = shape; - using keyword_type = size_; + using stored_value_type = shape; + using keyword_type = detail::size_; KWK_FORCEINLINE constexpr auto operator()(keyword_type const&) const noexcept { return *this; } - /// @brief Constructs a default kwk::shape equals to [0 1 ... 1] - KWK_FORCEINLINE constexpr shape() noexcept - { - if constexpr(parent::storage_size > 1ULL) for(auto& e : storage()) e = 1; - if constexpr(parent::storage_size > 0ULL) storage()[0] = 0; - } + //============================================================================================== + //! @brief Constructs a default @ref kwk::shape equals to [0 1 ... 1] + //============================================================================================== + constexpr shape() : parent([](auto i, auto) -> size_type { return i > 0;}) {} //============================================================================================== //! @brief Constructor from set of dimensions @@ -121,63 +120,18 @@ namespace kwk //! //! @param s Variadic list of dimensions' values //============================================================================================== - template - constexpr shape(T... s) noexcept - requires( (sizeof...(T) <= static_order) - && ((std::same_as || std::is_convertible_v) && ...) - ) + constexpr shape(concepts::extent auto... vals) noexcept + requires( sizeof...(vals) <= static_order ) + : shape{} { - auto& st = storage(); - - // Fill storage data with provided size - [&](std::index_sequence const&) - { - [[maybe_unused]] auto proc = [&](X const& sz, N idx) - { - if constexpr( std::is_convertible_v ) - { - if constexpr(!parent::size_map::contains(N::value)) - { - st[parent::size_map::template locate(idx)] = sz; - } - else - KIWAKU_ASSERT ( sz == this->template get() - , "[kwk::shape] - Runtime/Compile-time mismatch in constructor" - ); - } - else - { - if constexpr(!parent::size_map::contains(N::value)) - { - if constexpr(!N::value) st[parent::size_map::template locate(idx)] = 0; - else st[parent::size_map::template locate(idx)] = 1; - } - } - }; - (proc(s, kumi::index),...); - }(std::index_sequence_for{}); - - // Complete the rest with 0/1 if needed - [&](std::index_sequence const&) - { - [[maybe_unused]] auto proc = [&](N) - { - constexpr auto M = sizeof...(T) + N::value; - if constexpr(!parent::size_map::contains(M)) - { - if constexpr(M==0) st[parent::size_map::template locate(M)] = 0; - else st[parent::size_map::template locate(M)] = 1; - } - }; - (proc(kumi::index),...); - }(std::make_index_sequence{}); + parent::fill(vals...); } //============================================================================================== //! @brief Construct from a subset of runtime dimension values //! //! This constructor takes a variadic list of arguments specifying the size specified for a - //! given runtime dimension. Those sizes are passed by using the `kwk::_` dimension specifier. + //! given runtime dimension. Those sizes are passed by using `kwk::_[i]` as a dimension value. //! //! Passing a dimension specifier to overwrite one of the compile-time dimensions is undefined //! behavior. @@ -189,35 +143,23 @@ namespace kwk //! //! @param s Variadic list of dimension/size association //============================================================================================== - template... Extent> - constexpr shape(Extent... s) noexcept - requires( (sizeof...(Extent) <= static_order) && !is_fully_static ) + constexpr shape(std::same_as auto... dims) noexcept + requires( (sizeof...(dims) <= static_order) && !is_fully_static ) + : shape{} { - auto& st = storage(); - - // Default fillings - detail::constexpr_for - ( [&](std::integral_constant const&) - { - if constexpr(!parent::size_map::contains(I)) - { - constexpr auto ii = parent::size_map::template locate(I); - if constexpr(I==0) st[ii] = 0; else st[ii] = 1; - } - } - ); + auto& st = parent::storage(); // Fill the proper axis value with the corresponding size - auto const fill = [&](auto e) - { - KIWAKU_ASSERT ( !parent::size_map::contains(e.dims) - , "[kwk::shape] Semi-dynamic construction overwrite static shape" - ); - - auto ii = parent::size_map::template locate(e.dims); - st[ii] = static_cast(e.size); - }; - (fill(s),...); + kumi::for_each( [&](auto e) + { + KIWAKU_ASSERT ( parent::contains(e.dims) + , "[KWK] - Semi-dynamic construction overwrite static shape" + ); + + st[parent::location[e.dims]] = static_cast(e.size); + } + , kumi::tie(dims...) + ); } //============================================================================================== @@ -227,8 +169,9 @@ namespace kwk //! size_type. //! //! Two kwk::shapes have compatible layout if they have the same @ref glossary-order and if each - //! dimension of the constructed kwk::shape can hold its equivalent from the source shape, i.e - //! it's runtime specified or, if it's compile-time specified, has the same value than its source. + //! dimension of the constructed @ref kwk::shape can hold its equivalent from the source shape, + //! i.e it's runtime specified or, if it's compile-time specified, has the same value than its + //! source. //! //! This constructor doesn not participate in overload resolution if shape's orders are not equal. //! @@ -237,17 +180,24 @@ namespace kwk //! //! @param other Source kwk::shape to copy //============================================================================================== - template - constexpr shape( shape const& other ) noexcept - requires( OtherShaper.size() == Shaper.size() && Shaper.is_compatible(OtherShaper)) + template + constexpr shape( shape const& other ) noexcept + requires(shape::static_size == static_order && Shape.is_compatible(OtherShape)) { - detail::constexpr_for - ( [&](std::integral_constant const&) - { - constexpr auto ii = parent::size_map::template locate(I); - if constexpr( ii < parent::storage_size ) storage()[ii] = other.template get(); - } - ); + auto& v = parent::storage(); + kumi::for_each_index( [&](I, auto const& m) + { + constexpr auto i = I::value; + if constexpr(parent::contains(i)) v[parent::location[i]] = m; + else + { + KIWAKU_ASSERT( m == get(Shape) + , "[KWK] - Static/Dynamic mismatch in constructor" + ); + } + } + , other + ); } //============================================================================================== @@ -264,26 +214,21 @@ namespace kwk //! @param other Shape to copy //============================================================================================== template - constexpr shape( shape const& other ) noexcept - requires( OtherShaper.size() < static_order && is_fully_dynamic) + constexpr explicit shape( shape const& other ) noexcept + requires( shape::static_order < static_order && is_fully_dynamic) { - constexpr auto dz = std::min(OtherShaper.size(),static_order); - - detail::constexpr_for - ( [&](std::integral_constant const&) - { - storage()[I] = other.template get(); - } - ); - - for(std::size_t i = dz; i < static_order;++i) storage()[i] = 1; + constexpr auto dz = std::min(shape::static_order,static_order); + for(std::size_t i = 0; i < dz;++i) parent::storage()[i] = other[i]; + for(std::size_t i = dz; i < static_order;++i) parent::storage()[i] = 1; } //============================================================================================== //! @brief Constructs from a shape with a higher order //! - //! Constructs a kwk::shape from a shape with higher orders, compacting the extra-dimensions into - //! the last. + //! Constructs a kwk::shape from a shape with higher orders, compacting the extra-dimensions + //! into the last. + //! + //! If you require compile-time shape descriptor to be updated, consider using @ref compress. //! //! This constructor does not participate in overload resolution of the shape is not fully //! specified at runtime. @@ -293,77 +238,80 @@ namespace kwk //! //! @param other Shape to copy //============================================================================================== - template - constexpr explicit shape( shape const& o ) noexcept - requires( OtherShaper.size() > static_order && is_fully_dynamic) - { - constexpr auto dz = std::min(OtherShaper.size(),static_order); - constexpr auto oz = shape::static_order - dz; - detail::constexpr_for ( [&](I) - { storage()[I{}] = o.template get(); } - ); - detail::constexpr_for ( [&](I) - { storage().back() *= o.template get(); } - ); - } - - /// Number of dimensions - static constexpr auto order() noexcept { return static_order; } + template + constexpr explicit shape( shape const& o ) noexcept + requires( shape::static_order > static_order && is_fully_dynamic) + : shape( compress(o) ) + {} + //============================================================================================== /// Assignment operator - template - requires( OtherShaper.size() < static_order || Shaper.is_compatible(OtherShaper) ) - constexpr shape& operator=( shape const& other ) noexcept + //============================================================================================== + template + requires( shape::static_order < static_order || Shape.is_compatible(Other) ) + constexpr shape& operator=( shape const& other ) noexcept { shape that(other); swap(that); return *this; } - // Elements access - using parent::get; + /// Swap shapes' contents + friend void swap( shape& x, shape& y ) noexcept { x.swap(y); } + using parent::swap; - constexpr auto operator[](std::size_t i) const noexcept + /// Equality comparison operator + template + constexpr bool operator==( shape const& other) const noexcept { - KIWAKU_ASSERT ( (i>=0 && i0) + /// Inequality comparison operator + template + constexpr bool operator!=( shape const& other) const noexcept { - KIWAKU_ASSERT ( (i>=0 && i constexpr auto operator()(Slices... slices) const noexcept + //============================================================================================== + //! @brief Check if current shape contains the volume of another one + //! + //! Check if a given shape's extents are all less or equal than current shape. + //! + //! @param other Shape to compare with + //! @return `true` if all extent of other fits inside current shape. `false` otherwise. + //! + //============================================================================================== + template + constexpr bool contains( shape const& other) const noexcept { - using that_t = shape; - auto rs = [&](std::index_sequence const&, auto const& s) - { - return that_t{ detail::reshape(slices,I,s) ... }; - }; - - that_t that{*this}; - that = rs(std::make_index_sequence{}, that); + return compare( other , [](auto a, auto b) { return a>=b;}, [](auto) { return true; } ); + } - return that; + //============================================================================================== + //! @brief Check if current shape contains the volume of another one exactly + //! + //! Check if a given shape's extents are all strictly less than current shape. + //! + //! @param other Shape to compare with + //! @return `true` if all extent of other fits exactly inside current shape. `false` otherwise. + //! + //============================================================================================== + template + constexpr bool strictly_contains( shape const& other) const noexcept + { + return compare( other , [](auto a, auto b) { return a>b;}, [](auto) { return true; } ); } -*/ + + /// Number of dimensions + static constexpr auto order() noexcept { return static_order; } //============================================================================================== //! @brief Number of non-trivial dimensions @@ -371,15 +319,17 @@ namespace kwk //! Computes the number of non-trivial dimensions, i.e dimension with size equals to 1 and that //! doesn't participate to the shape's extent. //============================================================================================== - constexpr int nbdims() const noexcept + constexpr std::ptrdiff_t nbdims() const noexcept { if constexpr(static_order == 0) return 0; - else return [&]( std::index_sequence const&) + else { - size_type m = this->template get<0>() == 1 ? 0 : 1; - ((m = std::max(m, size_type(this->template get() == 1 ? 0 : 1+I))),...); - return m; - }(std::make_index_sequence()); + std::ptrdiff_t r = get<0>(*this) == 1 ? 0 : 1; + kumi::for_each_index( [&r](std::ptrdiff_t i, auto m) { r = std::max(r, m == 1 ? 0 : i+1); } + , *this + ); + return r; + } } //============================================================================================== @@ -388,70 +338,49 @@ namespace kwk //! Computes the number of elements storable in current kwk::shape, i.e the product of all //! dimensions' size. //============================================================================================== - constexpr auto numel() const noexcept - { - if constexpr(static_order == 0) return 0; - else return [&]( std::index_sequence const&) - { - return (size_type{1} * ... * this->template get() ); - }(std::make_index_sequence()); - } - - /// Conversion to kwk::stride - constexpr auto as_stride() const requires(static_order > 0) { return stride_type(*this); } - - - /// Equality comparison operator - template - constexpr bool operator==( shape const& other) const noexcept + constexpr std::ptrdiff_t numel() const noexcept { - return compare( other , [](auto a, auto b) { return a == b; }, [](auto a) { return a == 1; } ); + if constexpr(static_order == 0) return 0LL; + else return kumi::fold_left([](auto a, auto b){ return a*b; }, *this, std::ptrdiff_t{1}); } - /// Inequality comparison operator - template - constexpr bool operator!=( shape const& other) const noexcept - { - return compare( other , [](auto a, auto b) { return a != b; },[](auto a) { return a == 1; } ); - } - - using parent::as_array; - - //============================================================================================== - // Check if current shape contains (maybe strictly) all the shape of another one - //============================================================================================== - template - constexpr bool contains( shape const& other) const noexcept + /// Stream insertion operator + friend std::ostream& operator<<(std::ostream& os, shape const& s) { - return compare( other , [](auto a, auto b) { return a>=b;}, [](auto) { return true; } ); + os << "["; + kumi::for_each_index( [&](auto i, auto) { os << " " << s.template extent(); }, s); + return os << " ]"; } - template - constexpr bool strictly_contains( shape const& other) const noexcept + template + constexpr bool is_similar( detail::combo const& o) const noexcept { - return compare( other , [](auto a, auto b) { return a>b;}, [](auto) { return true; } ); + return descriptor.is_similar(o); } - /// Stream insertion operator - friend std::ostream& operator<<(std::ostream& os, shape const& s) + template + constexpr bool is_similar( shape const& ) const noexcept { - os << "["; - - detail::constexpr_for - ( [&](std::integral_constant const&) - { - os << " " << +s.template get(); - } - ); - - os << " ]"; - return os; + return descriptor.is_similar(S2); } - private: - constexpr auto& storage() noexcept { return parent::storage(); } - constexpr auto const& storage() const noexcept { return parent::storage(); } + //============================================================================================== + //! @brief Shape slicing interface + //! + //! Computes the shape of the sub-volume described by the slicers passed as parameters + //! + //! Does not participate in overload resolution if the number of parameters is not equal to the + //! shape order. + //! + //! @param s Variadic list of [slicers](@ref kwk::concepts::slicer) instance + //! @return An instance of @ref kwk::shape corresponding to the shape of the selected + //! sub-volume + //============================================================================================== + template + inline constexpr auto operator()(Slicers const&... s) const noexcept + requires( sizeof...(Slicers) <= static_order); + protected: template constexpr bool compare( shape const& o, Comp const& op, Check const& check) const noexcept { @@ -461,7 +390,8 @@ namespace kwk { return [&](std::index_sequence const&) { - return (true && ... && op(this->template get(),o.template get()) ) ; + return (true && ... && op ( get(*this) + , get(o)) ) ; }(std::make_index_sequence()); } else @@ -472,7 +402,7 @@ namespace kwk bool result = true; [&](std::index_sequence const&) { - result = (result && ... && op(this->template get(),o.template get()) ); + result = (result && ... && op(get(*this),get(o)) ); }(std::make_index_sequence()); // Check that we have 1s everywhere in the other parts @@ -481,7 +411,7 @@ namespace kwk constexpr auto sz = o_size - static_order; return [&](std::index_sequence const&) { - return (result && ... && (o.template get() == 1)); + return (result && ... && (get(o) == 1)); }(std::make_index_sequence()); } else if constexpr( static_order > o_size ) @@ -489,53 +419,31 @@ namespace kwk constexpr auto sz = static_order - o_size; return [&](std::index_sequence const&) { - return (result && ... && check(this->template get())); + return (result && ... && check(get(*this))); }(std::make_index_sequence()); } } } }; -} - -// Shape supports structured bindings. -template -struct std::tuple_element> - : std::tuple_element::parent> -{}; -template -struct std::tuple_size> - : std::tuple_size::parent> -{}; - -namespace kwk -{ - // Product-type interface - template - constexpr auto get(shape const& s) noexcept { return s.template get(); } + /// Deduction guide for @ref kwk::shape + template... T> shape(T...) -> shape< _nD >; - template - constexpr decltype(auto) get(shape& s) noexcept { return s.template get(); } - - // Deduction guides - template shape(T... s) -> shape< _nD >; - - // Shape generators - namespace detail + //================================================================================================ + //! @brief Compress a kwk::shape to a given order + //! @tparam N Expected @ref glossary-order of the generated shape. + //! @param s Original shape to compress + //! @return A new kwk::shape instance which order has been set to N by compressing dimensions. + //================================================================================================ + template + constexpr auto compress(shape const& s) noexcept { - // Convert a sequence of dimensions to the proper shaper type - template - constexpr auto as_shape(Ds... ds) noexcept - { - return kumi::fold_right( [](auto a, T) - { - if constexpr( requires{ T::value; } ) return a[T::value]; - else return a(); - } - , kumi::tuple{ds...} - , detail::hybrid_sequence{} - ); - } + using old_t = typename shape::parent; + using new_t = typename shape(Desc)>::parent; + + shape(Desc)> that; + static_cast(that) = compress(static_cast(s)); + return that; } //================================================================================================ @@ -543,30 +451,54 @@ namespace kwk //! @tparam SizeType Integral type used to store sizes. If unspecified, `std::ptrdiff_t` is used. //! @param ds Variadic pack of sizes //================================================================================================ - template + template... Ds> constexpr auto of_size(Ds... ds) noexcept { - return kumi::apply( [](auto... v) - { - return kwk::shape(Ds{}...)>(v...); - } - , kumi::tuple{ds...} - ); + return detail::make_extent(ds...); } - template constexpr auto of_size( Ds... ds) noexcept + template... Ds> + constexpr auto of_size( Ds... ds) noexcept { using type_t = typename detail::largest_type...>::type; return of_size(ds...); } - template constexpr auto of_size( Ds ds) noexcept + template + constexpr auto of_size( Ds ds) noexcept { return kumi::apply([](auto... s) { return of_size(s...); }, ds); } - template constexpr auto of_size( Ds ds) noexcept + template + constexpr auto of_size( Ds ds) noexcept { return kumi::apply([](auto... s) { return of_size(s...); }, ds); } + + // Implementation of slicing interface + template + template + inline constexpr auto shape::operator()(Slicers const&... s) const noexcept + requires( sizeof...(Slicers) <= static_order) + { + auto shd = compress(*this); + auto sliced = kumi::map_index ( [&](auto i, auto m) { return reshape(shd,m,i); } + , kumi::tie(s...) + ); + + return kumi::apply( [](auto... v) { return of_size(v...); }, sliced ); + } } + +// Tuple interface adaptation +template +struct std::tuple_size> + : std::integral_constant::static_order> +{}; + +template +struct std::tuple_element> +{ + using type = typename kwk::shape::size_type; +}; diff --git a/include/kwk/utility/container/stride.hpp b/include/kwk/utility/container/stride.hpp new file mode 100644 index 00000000..58aca324 --- /dev/null +++ b/include/kwk/utility/container/stride.hpp @@ -0,0 +1,223 @@ +//================================================================================================== +/** + KIWAKU - Containers Well Made + Copyright : EVE Project Contributors + SPDX-License-Identifier: BSL-1.0 +**/ +//================================================================================================== +#pragma once + +#include +#include +#include + +namespace kwk::detail +{ + struct strides_; + + template + struct stride_base + { + static constexpr auto desc = combo_cast(Strides); + using type = prefilled; + }; +} + +namespace kwk +{ + //================================================================================================ + //! @ingroup containers + //! @brief Fixed order stride with mixed size capability + //! + //!
+ //! **Required header**: + //! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} + //! #include + //! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + //!
+ //! + //! kwk::stride defines and optimally stores a set of integral values representing the strides + //! used to walk through a given multi-dimensional container or view. + //! + //! kwk::stride can be defined in two ways: + //! + //! - using the kwk::with_strides function. + //! + //! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} + //! kwk::stride s1 = kwk::with_strides(kwk::fixed<5>); // Order 1 stride with static size + //! kwk::stride s2 = kwk::with_strides(n, m); // Order 2 stride with dynamic sizes + //! kwk::stride s3 = kwk::with_strides(kwk::fixed<2>,kwk::fixed<2>, n); // Order 3 stride with mixed sizes + //! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + //!
+ //! + //! - defining the layout of the kwk::stride and manually initializing it. The description of the + //! kwk::stride layout is done with the kwk::extent object or one of the pre-defined layouts. + //! + //! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~{.cpp} + //! kwk::stride< kwk::extent[5] > s1; // Order 1 stride with static size + //! kwk::stride< kwk::_2D > s2(n, m); // Order 2 stride with dynamic sizes + //! kwk::stride< kwk::extent[1]( )[3]> s4( _, n, _); // Order 3 stride with mixed sizes + //! ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + //! + //! @tparam Strider An instance of a stride descriptor + //================================================================================================ + template + struct stride : detail::stride_base::type + { + using parent = typename detail::stride_base::type; + + /// Compile-time value for @ref glossary-order + static constexpr std::ptrdiff_t static_order = parent::static_size; + + /// Type of dimensions' size + using size_type = typename parent::value_type; + + /// Checks a @ref kwk::stride is unit - ie it's first value is statically known to be 1 + static constexpr auto is_unit = []() + { + auto first = get<0>(parent::descriptor); + if constexpr(!is_joker_v) return first == 1; else return false; + }(); + + //============================================================================================== + // stride is its self option keyword + //============================================================================================== + using stored_value_type = stride; + using keyword_type = detail::strides_; + + constexpr auto operator()(keyword_type const&) const noexcept { return *this; } + + //============================================================================================== + //! @brief Constructs a default @ref kwk::stride equals to [1 1 ... 1] + //============================================================================================== + constexpr stride() : parent([](auto, auto) { return 1;}) {} + + //============================================================================================== + //! @brief Constructor from set of dimensions + //! + //! Constructs a kwk::stride with a variadic list of stride values. + //! Values can either be any integral value, any fixed integral value or kwk::_. + //! + //! If you pass kwk::_ as a stride's value, it means that the stride will be using the + //! default value for this dimension, i.e 1. + //! + //! Passing a runtime stride size where a static size is provided is undefined behavior if + //! both values are not equal. + //! + //! This constructor will not take part in overload resolution if the number of values is not + //! equal to the stride's order or if any value is neither convertible to std::ptrdiff_t + //! nor kwk::_. + //! + //! @param s Variadic list of dimensions' values + //============================================================================================== + constexpr stride(concepts::extent auto... vals) noexcept + requires( sizeof...(vals) == static_order ) + : stride() + { + parent::fill(vals...); + } + + template + constexpr explicit stride( stride const& other ) noexcept + requires( stride::static_order == static_order + && Strides.is_compatible(OtherDesc) + ) + { + auto& v = parent::storage(); + kumi::for_each_index( [&](I, auto const& m) + { + constexpr auto i = I::value; + if constexpr(parent::contains(i)) v[parent::location[i]] = m; + else + { + KIWAKU_ASSERT( m == get(Strides) + , "[KWK] - Static/Dynamic mismatch in constructor" + ); + } + } + , other + ); + } + + + /// Stream insertion operator + friend std::ostream& operator<<(std::ostream& os, stride const& s) + { + os << "["; + kumi::for_each_index( [&](auto i, auto) { os << " " << s.template extent(); }, s); + return os << " ]"; + } + + /// Number of dimensions + static constexpr auto order() noexcept { return static_order; } + + /// Swap @ref kwk::stride contents + friend constexpr void swap( stride& x, stride& y ) noexcept { x.swap(y); } + using parent::swap; + + /// Equality comparison operator + template + constexpr bool operator==( stride const& other) const noexcept + { + return kumi::to_tuple(*this) == kumi::to_tuple(other); + } + + /// Inequality comparison operator + template + constexpr bool operator!=( stride const& other) const noexcept + { + return kumi::to_tuple(*this) != kumi::to_tuple(other); + } + + /// Indexing interface + template... Is> + constexpr auto linearize(Is... is) const noexcept + requires( sizeof...(Is) <= static_order ) + { + return kumi::inner_product(*this, kumi::tie(is...), 0); + } + }; + + /// Converts a @ref kwk::shape into its corresponding @ref kwk::stride, conserving as much static + /// informations as possible. + template + constexpr auto as_stride(shape const& s) noexcept + { + constexpr auto prod = [](auto acc, auto m) { return push_back(acc, back(acc) * m); }; + + // Build the perfect descriptor and the suitable values tuple + constexpr auto d = kumi::pop_back(kumi::fold_right(prod, Shape, kumi::tuple{1})); + auto v = kumi::pop_back(kumi::fold_right(prod, s , kumi::tuple{1})); + + // Turn into a stride + return kumi::apply([&](auto... e) { return stride(d)>{e...}; }, v); + } + + //================================================================================================ + //! @brief Generates a kwk::stride from a list of stride value or joker + //! @param ds Variadic pack of sizes + //================================================================================================ + template... Ds> + constexpr auto with_strides(Ds... ds) noexcept + { + return detail::make_extent(ds...); + } + + template + constexpr auto with_strides( Ds ds) noexcept + { + return kumi::apply([](auto... s) { return with_strides(s...); }, ds); + } +} + +// Tuple interface adaptation +template +struct std::tuple_size> + : std::integral_constant::static_order> +{}; + +template +struct std::tuple_element> +{ + using type = typename kwk::stride::size_type; +}; diff --git a/include/kwk/utility/end.hpp b/include/kwk/utility/end.hpp new file mode 100644 index 00000000..db5b5b54 --- /dev/null +++ b/include/kwk/utility/end.hpp @@ -0,0 +1,96 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include +#include + +namespace kwk +{ + template + struct end_t + { + // Exact final formula : (end * factor + offset) / divisor + O shift; + R frac; + + constexpr auto offset() const noexcept { return shift; } + constexpr auto ratio() const noexcept { return frac; } + constexpr auto divisor() const noexcept { return frac.denum; } + constexpr auto factor() const noexcept { return frac.num; } + + constexpr end_t(O o, R f) noexcept : shift(o), frac(f) + {} + + friend + std::ostream& operator<<(std::ostream& os, end_t t) + { + if(t.factor() != 1) os << t.factor() << " * end"; else os << "end"; + if(t.divisor() != 1) os << '/' << t.divisor(); + if(t.offset() != 0) os << std::showpos << t.offset() << std::noshowpos; + return os; + } + + constexpr auto size(auto n) const noexcept + { + return (n * factor() + offset()) / divisor(); + } + }; + + /// Deduction guide + template end_t(O, R) -> end_t; + + template + constexpr auto operator+(end_t e, auto o) noexcept + { + return end_t{o * e.divisor(), e.frac}; + } + + template + constexpr auto operator+(auto o, end_t e) noexcept + { + return e+o; + } + + template + constexpr auto operator-(end_t e, auto o) noexcept + { + // Prevent overflow when end - large_unsigned occurs + return end_t{(fixed<-1>*o) * e.divisor(), e.frac}; + } + + template + constexpr auto operator-(auto o, end_t e) noexcept + { + return end_t{o * e.divisor(), - e.frac}; + } + + template + constexpr auto operator*(end_t e, auto o) noexcept + { + return end_t{e.offset() * o, e.ratio() * o}; + } + + template + constexpr auto operator*(auto o, end_t e) noexcept + { + return e * o; + } + + template + constexpr auto operator/(end_t e, auto o) noexcept + { + return end_t{e.offset(), e.ratio() / o}; + } + + /// Object representing a whole dimension in slicing + inline constexpr end_t end = {fixed<0>, ratio{fixed<1>,fixed<1>}}; +}; diff --git a/include/kwk/utility/fixed.hpp b/include/kwk/utility/fixed.hpp new file mode 100644 index 00000000..e4bc46bd --- /dev/null +++ b/include/kwk/utility/fixed.hpp @@ -0,0 +1,104 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include +#include + +namespace kwk +{ + struct joker; + + namespace detail + { + template struct to_int { using type = T; }; + template<> struct to_int { using type = char; }; + + template + struct to_int + { + using type = typename T::value_type; + }; + + template using to_int_t = typename to_int::type; + + template struct largest_type; + template struct largest_type { using type = T; }; + + template + struct largest_type : std::conditional + {}; + + template + struct largest_type : largest_type< typename largest_type::type, T2...> + {}; + + template constexpr auto clamp() + { + if constexpr (std::bit_width(Value) <= 7) return static_cast(Value); + else if constexpr (std::bit_width(Value) <= 15) return static_cast(Value); + else if constexpr (std::bit_width(Value) <= 31) return static_cast(Value); + else return Value; + } + } + + template + struct constant : std::integral_constant + { + friend std::ostream& operator<<(std::ostream& os, constant) + { + return os << +N << "_c"; + } + + constexpr auto operator-() noexcept { return constant<-1 * N>{}; } + }; + + template + constexpr auto operator+(constant, constant) noexcept { return constant{}; } + + template + constexpr auto operator-(constant, constant) noexcept { return constant{}; } + + template + constexpr auto operator*(constant, constant) noexcept { return constant{}; } + + template + constexpr auto operator/(constant, constant) noexcept { return constant{}; } + + //================================================================================================ + //! @ingroup utility + //! @brief Provides a short-cut to define a `std::integral_constant` value from a literal integer + //================================================================================================ + template + inline constexpr auto fixed = constant{}; + + namespace literals + { + template constexpr auto b10() + { + auto value = 0ULL; + ((value = value * 10 + (c - '0')), ...); + return value; + } + + //============================================================================================== + //! @ingroup utility + //! @brief User-defined literal suffix for compile-time constant + //! + //! The underlying type is computed from the actual value to be the smallest fitting type. + //! This means, for example, that `123_c` is an instance of `kwk::constant`. + //============================================================================================== + template constexpr auto operator"" _c() noexcept + { + return fixed()>()>; + } + } +} diff --git a/include/kwk/utility/joker.hpp b/include/kwk/utility/joker.hpp new file mode 100644 index 00000000..7f69a376 --- /dev/null +++ b/include/kwk/utility/joker.hpp @@ -0,0 +1,65 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include + +namespace kwk +{ + struct axis + { + axis& operator=(std::size_t s) { size = s; return *this;} + std::size_t dims; + std::ptrdiff_t size; + }; + + //================================================================================================ + //! @ingroup utility + //! @brief Type of the @ref kwk::_ object + //================================================================================================ + struct joker + { + friend std::ostream& operator<<(std::ostream& os, joker const&) { return os << "_"; } + constexpr auto operator[](std::size_t d) const noexcept { return axis{d,0}; } + + friend constexpr joker operator*(joker, joker) noexcept { return {}; } + friend constexpr joker operator*(joker, auto) noexcept { return {}; } + friend constexpr joker operator*(auto , joker) noexcept { return {}; } + }; + + //================================================================================================ + //! @ingroup traits + //! @brief Checks a type is equivalent to @ref kwk::joker + //! + //! @tparam T Type to check + //! + //! **Helper value** + //! + //! @code{.cpp} + //! template + //! inline constexpr bool is_joker_v = is_joker::value; + //! @endcode + //! + //================================================================================================ + template struct is_joker : std::false_type {}; + template<> struct is_joker : std::true_type {}; + template<> struct is_joker : std::true_type {}; + template<> struct is_joker : std::true_type {}; + template<> struct is_joker : std::true_type {}; + + template inline constexpr bool is_joker_v = is_joker::value; + + //================================================================================================ + //! @ingroup utility + //! @brief Joker value + //! + //! The joker value defined as @ref kwk::_ is used in various context to means 'just use the + //! most meaningful value'. + //================================================================================================ + inline constexpr joker _ = {}; +} diff --git a/include/kwk/container/linear_index.hpp b/include/kwk/utility/linear_index.hpp similarity index 89% rename from include/kwk/container/linear_index.hpp rename to include/kwk/utility/linear_index.hpp index 2b26bbfa..e080abc7 100644 --- a/include/kwk/container/linear_index.hpp +++ b/include/kwk/utility/linear_index.hpp @@ -1,40 +1,39 @@ //================================================================================================== -/** +/* KIWAKU - Containers Well Made Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 -**/ +*/ //================================================================================================== #pragma once -#include -#include -#include +#include #include +#include #include namespace kwk { //================================================================================================ - //! @ingroup containers + //! @ingroup utility //! @brief Computes a linear index from a order N list of indexes //! //! @param sh Shape used as a reference - //! @param idx Individual list of indexes representing the order N index to linearise + //! @param idx Individual list of indexes representing the order N index to linearize //! @return The linear index equivalent to (idx...) for the current shape //================================================================================================ template auto linear_index( shape const& sh, Index... idx ) { - return sh.as_stride().index(idx...); + return as_stride(sh).linearize(idx...); } //================================================================================================ - //! @ingroup containers + //! @ingroup utility //! @brief Computes a linear index from a tuple of N indexes //! //! @param sh Shape used as a reference - //! @param idx Individual list of indexes representing the order N index to linearise + //! @param idx Individual list of indexes representing the order N index to linearize //! @return The linear index equivalent to (idx...) for the current shape //================================================================================================ template Indexes> @@ -44,11 +43,11 @@ namespace kwk } //================================================================================================ - //! @ingroup containers + //! @ingroup utility //! @brief Computes a linear index from a range of N indexes //! //! @param sh Shape used as a reference - //! @param indexes Range of integer representing the order N index to linearise + //! @param indexes Range of integer representing the order N index to linearize //! @return The linear index equivalent to (indexes[0], ...) for the current shape //================================================================================================ template diff --git a/include/kwk/utility/memory/any_allocator.hpp b/include/kwk/utility/memory/any_allocator.hpp new file mode 100644 index 00000000..ae03a822 --- /dev/null +++ b/include/kwk/utility/memory/any_allocator.hpp @@ -0,0 +1,120 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include +#include + +namespace kwk +{ + //================================================================================================ + //! @ingroup memory + //! @brief Opaque allocator type + //! + //! Model of the kwk::concepts::allocator concept. kwk::any_allocator is a type-erased object able + //! to contains any allocator type modeling kwk::concepts::allocator. It is meant to be used as a + //! non-dependent type in containers or other functions one may want to be non-template + //================================================================================================ + struct any_allocator + { + private: + + struct api_t + { + virtual ~api_t() {} + virtual void* do_allocate(std::size_t) = 0; + virtual void do_deallocate(void* ) = 0; + virtual std::unique_ptr clone() const = 0; + }; + + template struct model_t final : api_t + { + using base_type = T; + + model_t() : object() {} + model_t(base_type t) : object(std::move(t)) {} + + void* do_allocate(std::size_t n) override { return allocate(object,n); } + void do_deallocate(void* b) override { deallocate(object,b); } + std::unique_ptr clone() const override { return std::make_unique(object); } + + private: + T object; + }; + + public: + + /// Default constructor + any_allocator() = default; + + /// Move constructor + any_allocator(any_allocator&& a) = default; + + /// Move assignment operator + any_allocator& operator=(any_allocator&& other) = default; + + /// Copy constructor + any_allocator(any_allocator const& a) : object( a.object->clone() ) {} + + /// Copy assignment operator + any_allocator& operator=(any_allocator const& other) + { + any_allocator that(other); + swap(that); + return *this; + } + + /// Constructor from an arbitrary allocator type + template + any_allocator ( T&& other ) + : object(std::make_unique>>(KWK_FWD(other))) + {} + + /// Assignment from an arbitrary allocator + template any_allocator& operator=(T&& other) + { + any_allocator that(KWK_FWD(other)); + swap(that); + return *this; + } + + /// Swap the contents of two instance of kwk::heap_allocator + void swap(any_allocator& other) noexcept { object.swap(other.object); } + friend void swap(any_allocator& a, any_allocator& b) noexcept { a.swap(b); } + + /// Access to internal allocator pointer + api_t* get() const { return object.get(); } + + private: + std::unique_ptr object; + }; + + //================================================================================================ + //! @ingroup memory + //! @brief Allocates data from an opaque allocator instance + //! @param n Number of bytes to allocate + //! @return A pointer to the newly allocated memory. + //================================================================================================ + [[nodiscard]] inline auto allocate(any_allocator& a, std::size_t n) + { + return a.get()->do_allocate(n); + } + + //================================================================================================ + //! @ingroup memory + //! @brief Deallocates data from an opaque allocator instance + //! @param ptr Pointer to the data to deallocates + //================================================================================================ + inline void deallocate(any_allocator& a, void* ptr) + { + return a.get()->do_deallocate(ptr); + } +} diff --git a/include/kwk/utility/memory/heap_allocator.hpp b/include/kwk/utility/memory/heap_allocator.hpp new file mode 100644 index 00000000..fdd9c8fd --- /dev/null +++ b/include/kwk/utility/memory/heap_allocator.hpp @@ -0,0 +1,46 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include + +namespace kwk +{ + //================================================================================================ + //! @ingroup memory + //! @brief Malloc based allocator + //! + //! Model of the kwk::concepts::allocator concept. kwk::heap allocates and deallocates + //! memory block on the heap using `malloc` and `free`. + //================================================================================================ + inline constexpr struct heap_allocator {} heap = {}; + + //================================================================================================ + //! @ingroup memory + //! @brief Allocates data on the heap + //! @param n Number of bytes to allocate + //! @return A pointer to the newly allocated memory. If zero byte was requested, the returned + //! pointer is equal to `nullptr`. + //================================================================================================ + [[nodiscard]] inline void* allocate(heap_allocator const&, std::size_t n) noexcept + { + return (n!=0) ? malloc(n) : nullptr; + } + + //================================================================================================ + //! @ingroup memory + //! @brief Deallocates data on the heap + //! + //! Free the heap memory from a pointer. If the deallocated memory was not allocated by an + //! instance of kwk::heap_allocator, the behavior is undefined. + //! + //! @param b Pointer to the memory to deallocate + //================================================================================================ + inline void deallocate(heap_allocator const&,void* ptr) noexcept { if(ptr) free(ptr); } +} diff --git a/include/kwk/utility/ratio.hpp b/include/kwk/utility/ratio.hpp new file mode 100644 index 00000000..5f100d15 --- /dev/null +++ b/include/kwk/utility/ratio.hpp @@ -0,0 +1,90 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include +#include + +namespace kwk +{ + template + struct ratio + { + constexpr ratio(N n, D d) : num(n), denum(d) {} + + friend std::ostream& operator<<(std::ostream& os, ratio r) + { + return os << r.num << "/" << r.denum; + } + + N num; + D denum; + }; + + template + constexpr auto operator-(ratio r) noexcept { return ratio{-r.num, r.denum}; } + + template + constexpr auto operator+(ratio a, ratio b ) noexcept + { + auto[n1,d1] = a; + auto[n2,d2] = b; + return ratio{n1*d2+n2*d1, d1*d2}; + } + + template + constexpr auto operator-(ratio a, ratio b ) noexcept + { + auto[n1,d1] = a; + auto[n2,d2] = b; + return ratio{n1*d2-n2*d1, d1*d2}; + } + + template + constexpr auto operator*(ratio a, ratio b ) noexcept + { + return ratio{a.num*b.num, a.denum*b.denum}; + } + + template + constexpr auto operator*(ratio a, auto c ) noexcept + { + return ratio{a.num * c, a.denum}; + } + + template + constexpr auto operator*(auto c, ratio a) noexcept + { + return a * c; + } + + template + constexpr auto operator/(ratio a, ratio b ) noexcept + { + return ratio{a.num*b.denum, a.denum*b.num}; + } + + template + constexpr auto operator/(ratio a, auto b ) noexcept + { + return ratio{a.num, a.denum*b}; + } + + template + constexpr bool operator==(ratio a, ratio b ) noexcept + { + return a.num*b.denum == a.denum*b.num; + } + + template + constexpr bool operator!=(ratio a, ratio b ) noexcept + { + return !(a == b); + } +}; \ No newline at end of file diff --git a/include/kwk/container/slicers.hpp b/include/kwk/utility/slicer.hpp similarity index 56% rename from include/kwk/container/slicers.hpp rename to include/kwk/utility/slicer.hpp index f1eb6408..f3a3df1a 100644 --- a/include/kwk/container/slicers.hpp +++ b/include/kwk/utility/slicer.hpp @@ -7,9 +7,9 @@ //================================================================================================== #pragma once -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include diff --git a/include/kwk/utility/slicer/all.hpp b/include/kwk/utility/slicer/all.hpp new file mode 100644 index 00000000..8a7ab0f8 --- /dev/null +++ b/include/kwk/utility/slicer/all.hpp @@ -0,0 +1,25 @@ +//================================================================================================== +/** + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +**/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include + +namespace kwk +{ + template struct shape; + + template + constexpr auto reshape(shape const& sh, joker const&, kumi::index_t const&) noexcept + { + if constexpr(is_dynamic_extent_v) return get(sh); + else return fixed(Desc)>; + } +} diff --git a/include/kwk/utility/slicer/between.hpp b/include/kwk/utility/slicer/between.hpp new file mode 100644 index 00000000..660fb8fc --- /dev/null +++ b/include/kwk/utility/slicer/between.hpp @@ -0,0 +1,133 @@ +//================================================================================================== +/** + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +**/ +//================================================================================================== +#pragma once + +#include +#include +#include + +namespace kwk +{ + template struct shape; + + template struct between + { + B begin; + E end; + between(B b, E e) : begin(b), end(e) + { + // Asserts that begin > end. + + if constexpr (requires{ B::value; } && requires{ E::value; }) + { + auto bv = fixed(B::value)>; + const auto ev = static_cast(E::value); + // TODO: const or auto seems to work + + static_assert ( bv < ev + , "[kwk] - Out of bound index for kwk::between (begin >= end)" + ); + } + else + { + auto bv = static_cast(begin); + auto ev = static_cast(end); + + KIWAKU_ASSERT ( bv < ev + , "[kwk] - Out of bound index for kwk::between (begin(" + << +begin << ") >= end(" + << +end << "))" + ); + } + } + + friend std::ostream& operator<<(std::ostream& os, between b) + { + return os << "between(" << +b.begin << ", " << +b.end << ")"; + } + }; + + template between(B, E) -> between; + + template + constexpr auto reshape( [[maybe_unused]] shape const& sh + , between b + , kumi::index_t const& + ) noexcept + { + // Static dimension + if constexpr (is_static_extent_v) + { + const auto dim_size = fixed(get(Desc))>; + + // If begin is static too, checks validity + if constexpr (requires{ B::value; }) + { + auto bv = fixed(B::value)>; + + static_assert ( (bv >= 0) && (bv < dim_size) + , "[kwk] - Out of bound index for kwk::between (begin)" + ); + } + else + { + auto bv = static_cast(b.begin); + + KIWAKU_ASSERT ( bv < dim_size // ?? static_cast(get(sh)) + , "[kwk] - Out of bound index for kwk::between: begin(" + << b.begin << ") exceeds or equals dim size: " << dim_size + ); + } + + // If end is static too, checks validity + // TODO : factorize this code (begin & end) + if constexpr (requires{ E::value; }) + { + auto ev = fixed(E::value)>; + + static_assert ( (ev >= 0) && (ev <= dim_size) + , "[kwk] - Out of bound index for kwk::between (end)" + ); + } + else + { + auto ev = static_cast(b.end); + + KIWAKU_ASSERT ( ev <= dim_size + , "[kwk] - Out of bound index for kwk::between: end(" + << b.end << ") strictly exceeds dim size: " << dim_size + ); + } + } + else // Dynamic dimension, runtime evaluation + { + auto dim_size = static_cast(get(sh)); + + auto bv = static_cast(b.begin); + KIWAKU_ASSERT ( bv < dim_size + , "[kwk] - Out of bound index for kwk::between: begin(" + << b.begin << ") exceeds or equals dim size: " << dim_size + ); + + auto ev = static_cast(b.end); + KIWAKU_ASSERT ( (ev >= 0) && (ev <= dim_size) + , "[kwk] - Out of bound index for kwk::between: begin(" + << b.begin << ") exceeds or equals dim size: " << dim_size + ); + } + + if constexpr (requires{ B::value; } && requires{ E::value; }) + { + return fixed; + } + else + { + return b.end - b.begin; + } + } +} diff --git a/include/kwk/utility/slicer/every.hpp b/include/kwk/utility/slicer/every.hpp new file mode 100644 index 00000000..25a410ca --- /dev/null +++ b/include/kwk/utility/slicer/every.hpp @@ -0,0 +1,44 @@ +//================================================================================================== +/** + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +**/ +//================================================================================================== +#pragma once + +#include +#include +#include + +namespace kwk +{ + template struct shape; + + template struct every + { + T value; + constexpr every(T b) : value(b) {} + + friend std::ostream& operator<<(std::ostream& os, every b) + { + return os << "every(" << +b.value << ")"; + } + }; + + template every(T) -> every; + + template + constexpr auto reshape( shape const& sh + , every e + , kumi::index_t const& + ) noexcept + { + auto fix = [](auto v, auto n) { return (v % n != 0) + v/n; }; + + if constexpr (is_static_extent_v && concepts::static_constant) + return fixed<(get(Desc) == 0) ? 0 : fix(get(Desc), T::value)>; + else + return (get(sh) == 0) ? 0 : fix(get(sh), e.value); + } +} diff --git a/include/kwk/utility/slicer/from.hpp b/include/kwk/utility/slicer/from.hpp new file mode 100644 index 00000000..69ad352c --- /dev/null +++ b/include/kwk/utility/slicer/from.hpp @@ -0,0 +1,47 @@ +//================================================================================================== +/** + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +**/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include +#include + +namespace kwk +{ + template struct shape; + + template struct from + { + T value; + constexpr from(T b) : value(b) {} + + friend std::ostream& operator<<(std::ostream& os, from f) + { + os << "from("; + if constexpr(std::integral) os << +f.value; + else os << f.value; + return os<< ")"; + } + }; + + template from(T) -> from; + + template + constexpr auto reshape(shape const& sh, from f, kumi::index_t const&) noexcept + { + const auto result = [&]() + { + if constexpr(concepts::extremum) return f.value.size(sh.template extent()); + else return f.value; + }(); + + return sh.template extent() - result; + } +} diff --git a/include/kwk/utility/slicer/single.hpp b/include/kwk/utility/slicer/single.hpp new file mode 100644 index 00000000..4bc2668e --- /dev/null +++ b/include/kwk/utility/slicer/single.hpp @@ -0,0 +1,29 @@ +//================================================================================================== +/** + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +**/ +//================================================================================================== +#pragma once + +#include +#include +#include + +namespace kwk +{ + template struct shape; + + template + constexpr auto reshape(shape const&, std::integral auto, kumi::index_t const&) noexcept + { + return fixed<1>; + } + + template + constexpr auto reshape(shape const&, end_t, kumi::index_t const&) noexcept + { + return fixed<1>; + } +} \ No newline at end of file diff --git a/include/kwk/utility/slicer/to.hpp b/include/kwk/utility/slicer/to.hpp new file mode 100644 index 00000000..2c342d87 --- /dev/null +++ b/include/kwk/utility/slicer/to.hpp @@ -0,0 +1,49 @@ +//================================================================================================== +/** + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +**/ +//================================================================================================== +#pragma once + +#include +#include +#include +#include + +namespace kwk +{ + template struct shape; + + template struct to + { + T value; + constexpr to(T e) : value(e) {} + + friend std::ostream& operator<<(std::ostream& os, to t) + { + os << "to("; + if constexpr(std::integral) os << +t.value; + else os << t.value; + return os<< ")"; + } + }; + + template to(T) -> to; + + template + constexpr auto reshape( [[maybe_unused]] shape const& sh + , to t + , kumi::index_t const& + ) noexcept + { + auto result = [&]() + { + if constexpr(concepts::extremum) return t.value.size(sh.template extent()); + else return t.value; + }(); + + return result; + } +} diff --git a/include/kwk/utility/traits/extent.hpp b/include/kwk/utility/traits/extent.hpp new file mode 100644 index 00000000..4dbf73b3 --- /dev/null +++ b/include/kwk/utility/traits/extent.hpp @@ -0,0 +1,59 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#pragma once + +#include +#include + +namespace kwk +{ + template + inline constexpr bool is_dynamic_extent_v = is_joker_v>; + + template + inline constexpr bool is_static_extent_v = !is_dynamic_extent_v; + + //================================================================================================ + //! @ingroup traits + //! @brief Checks if the Nth extent of a shape descriptor is only known at runtime + //! + //! @tparam N Index of the extent to check + //! @tparam Desc Extent descriptor to check + //! + //! **Helper value** + //! + //! @code{.cpp} + //! template + //! inline constexpr bool is_dynamic_extent_v = is_dynamic_extent::value; + //! @endcode + //! + //================================================================================================ + template + struct is_dynamic_extent : std::bool_constant> + {}; + + //================================================================================================ + //! @ingroup traits + //! @brief Checks if the Nth extent of a shape descriptor is known at compile-time + //! + //! @tparam N Index of the extent to check + //! @tparam Desc Extent descriptor to check + //! + //! **Helper value** + //! + //! @code{.cpp} + //! template + //! inline constexpr bool is_static_extent_v = is_static_extent::value; + //! @endcode + //! + //================================================================================================ + + template + struct is_static_extent : std::bool_constant> + {}; +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index a50dc364..13e1ed6a 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -5,6 +5,7 @@ ##================================================================================================== include(make_unit) +add_subdirectory(concepts) add_subdirectory(container) add_subdirectory(docs) add_subdirectory(utility) diff --git a/test/components/slicer/concept.cpp b/test/components/slicer/concept.cpp deleted file mode 100644 index 078d3b4e..00000000 --- a/test/components/slicer/concept.cpp +++ /dev/null @@ -1,45 +0,0 @@ -//================================================================================================== -/** - KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -**/ -//================================================================================================== -#include "test.hpp" -#include -#include - -TTS_CASE( "kwk::_ is a contiguous, unit slicer" ) -{ - TTS_EXPECT( (kwk::concepts::contiguous_slicer) ); - TTS_EXPECT( (kwk::concepts::contiguous_slicer) ); - TTS_EXPECT( kwk::concepts::unit_slicer ); -}; - -TTS_CASE( "kwk::_(b,e) is a non-contiguous, unit slicer" ) -{ - TTS_EXPECT_NOT( (kwk::concepts::contiguous_slicer) ); - TTS_EXPECT_NOT( (kwk::concepts::contiguous_slicer) ); - TTS_EXPECT( kwk::concepts::unit_slicer ); -}; - -TTS_CASE( "kwk::_(b,s,e) is a non-contiguous, non-unit slicer" ) -{ - TTS_EXPECT_NOT( (kwk::concepts::contiguous_slicer) ); - TTS_EXPECT_NOT( (kwk::concepts::contiguous_slicer) ); - TTS_EXPECT_NOT( kwk::concepts::unit_slicer ); -}; - -TTS_CASE( "kwk::_[d] is a non-contiguous, non-unit slicer" ) -{ - TTS_EXPECT_NOT( (kwk::concepts::contiguous_slicer) ); - TTS_EXPECT_NOT( (kwk::concepts::contiguous_slicer) ); - TTS_EXPECT_NOT( kwk::concepts::unit_slicer ); -}; - -TTS_CASE( "Any raw index is a maybe-contiguous, unit slicer" ) -{ - TTS_EXPECT_NOT( (kwk::concepts::contiguous_slicer) ); - TTS_EXPECT( (kwk::concepts::contiguous_slicer) ); - TTS_EXPECT( kwk::concepts::unit_slicer ); -}; diff --git a/test/components/slicer/CMakeLists.txt b/test/concepts/CMakeLists.txt similarity index 51% rename from test/components/slicer/CMakeLists.txt rename to test/concepts/CMakeLists.txt index ecef4b85..aa6b2471 100644 --- a/test/components/slicer/CMakeLists.txt +++ b/test/concepts/CMakeLists.txt @@ -3,8 +3,12 @@ ## Copyright : KIWAKU Contributors & Maintainers ## SPDX-License-Identifier: BSL-1.0 ##================================================================================================== +set ( SOURCES + allocator.cpp + container.cpp + extent.cpp + range.cpp + # values.cpp + ) -##================================================================================================== -## Check if various slicer expression satisfy the proper concept -##================================================================================================== -make_unit("misc.slicer" concept.cpp) +make_unit("concepts" ${SOURCES}) diff --git a/test/concepts/allocator.cpp b/test/concepts/allocator.cpp new file mode 100644 index 00000000..a4f02643 --- /dev/null +++ b/test/concepts/allocator.cpp @@ -0,0 +1,33 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include +#include "test.hpp" + +#include + +namespace ns +{ + struct fake_alloc {}; + void* allocate(fake_alloc& , std::size_t ) {return nullptr; } + void deallocate(fake_alloc&, void*) {} +}; + +namespace std +{ + template + void* allocate(allocator&, std::size_t ) { return nullptr; } + + template + void deallocate(allocator&, void*) { } +}; + +TTS_CASE( "Checks concepts::allocator adaptation" ) +{ + TTS_CONSTEXPR_EXPECT( kwk::concepts::allocator); + TTS_CONSTEXPR_EXPECT( kwk::concepts::allocator>); +}; diff --git a/test/concepts/container.cpp b/test/concepts/container.cpp new file mode 100644 index 00000000..12894a84 --- /dev/null +++ b/test/concepts/container.cpp @@ -0,0 +1,108 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include "test.hpp" +#include +#include + +TTS_CASE( "Checks concepts::container behavior" ) +{ + using table_2D_f32_t = kwk::make_table_t< kwk::as, kwk::_2D>; + using table_4xn_f32_t = kwk::make_table_t< kwk::as, kwk::extent[4][6]>; + using view_3D_i32_t = kwk::make_view_t< kwk::_3D, kwk::as>; + using view_5x5xn_i32_t = kwk::make_view_t< kwk::extent[5][5](), kwk::as>; + + TTS_CONSTEXPR_EXPECT (kwk::concepts::container); + TTS_CONSTEXPR_EXPECT ((kwk::concepts::container>)); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::container>)); + TTS_CONSTEXPR_EXPECT ((kwk::concepts::container)); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::container)); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::container)); + + TTS_CONSTEXPR_EXPECT (kwk::concepts::container); + TTS_CONSTEXPR_EXPECT ((kwk::concepts::container>)); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::container>)); + TTS_CONSTEXPR_EXPECT ((kwk::concepts::container)); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::container)); + TTS_CONSTEXPR_EXPECT ((kwk::concepts::container)); + + TTS_CONSTEXPR_EXPECT (kwk::concepts::container); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::container>)); + TTS_CONSTEXPR_EXPECT ((kwk::concepts::container>)); + TTS_CONSTEXPR_EXPECT ((kwk::concepts::container)); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::container)); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::container)); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::container)); + + TTS_CONSTEXPR_EXPECT (kwk::concepts::container); + TTS_CONSTEXPR_EXPECT ((kwk::concepts::container>)); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::container>)); + TTS_CONSTEXPR_EXPECT ((kwk::concepts::container)); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::container)); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::container)); + TTS_CONSTEXPR_EXPECT ((kwk::concepts::container)); +}; + +TTS_CASE( "Checks concepts::table behavior" ) +{ + using table_2D_f32_t = kwk::make_table_t< kwk::as, kwk::_2D>; + using table_4xn_f32_t = kwk::make_table_t< kwk::as, kwk::extent[4][6]>; + using view_3D_i32_t = kwk::make_view_t< kwk::_3D, kwk::as>; + using view_5x5xn_i32_t = kwk::make_view_t< kwk::extent[5][5](), kwk::as>; + + TTS_CONSTEXPR_EXPECT (kwk::concepts::table); + TTS_CONSTEXPR_EXPECT ((kwk::concepts::table)); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::table)); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::table)); + + TTS_CONSTEXPR_EXPECT (kwk::concepts::table); + TTS_CONSTEXPR_EXPECT ((kwk::concepts::table)); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::table)); + TTS_CONSTEXPR_EXPECT ((kwk::concepts::table)); + + TTS_CONSTEXPR_EXPECT_NOT(kwk::concepts::table); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::table)); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::table)); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::table)); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::table)); + + TTS_CONSTEXPR_EXPECT_NOT(kwk::concepts::table); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::table)); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::table)); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::table)); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::table)); +}; + +TTS_CASE( "Checks concepts::view behavior" ) +{ + using table_2D_f32_t = kwk::make_table_t< kwk::as, kwk::_2D>; + using table_4xn_f32_t = kwk::make_table_t< kwk::as, kwk::extent[4][6]>; + using view_3D_i32_t = kwk::make_view_t< kwk::_3D, kwk::as>; + using view_5x5xn_i32_t = kwk::make_view_t< kwk::extent[5][5](), kwk::as>; + + TTS_CONSTEXPR_EXPECT_NOT(kwk::concepts::view); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::view)); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::view)); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::view)); + + TTS_CONSTEXPR_EXPECT_NOT(kwk::concepts::view); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::view)); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::view)); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::view)); + + TTS_CONSTEXPR_EXPECT (kwk::concepts::view); + TTS_CONSTEXPR_EXPECT ((kwk::concepts::view)); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::view)); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::view)); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::view)); + + TTS_CONSTEXPR_EXPECT (kwk::concepts::view); + TTS_CONSTEXPR_EXPECT ((kwk::concepts::view)); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::view)); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::view)); + TTS_CONSTEXPR_EXPECT ((kwk::concepts::view)); +}; diff --git a/test/concepts/extent.cpp b/test/concepts/extent.cpp new file mode 100644 index 00000000..f427003f --- /dev/null +++ b/test/concepts/extent.cpp @@ -0,0 +1,24 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include "test.hpp" +#include + +TTS_CASE( "Checks concepts::joker behavior" ) +{ + TTS_CONSTEXPR_EXPECT ( kwk::concepts::joker); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::joker ); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::joker ); +}; + +TTS_CASE( "Checks concepts::extent behavior" ) +{ + TTS_CONSTEXPR_EXPECT ((kwk::concepts::extent) ); + TTS_CONSTEXPR_EXPECT ((kwk::concepts::extent) ); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::extent) ); + TTS_CONSTEXPR_EXPECT_NOT((kwk::concepts::extent) ); +}; diff --git a/test/concepts/range.cpp b/test/concepts/range.cpp new file mode 100644 index 00000000..fe26b126 --- /dev/null +++ b/test/concepts/range.cpp @@ -0,0 +1,37 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include "test.hpp" +#include +#include +#include +#include +#include + +TTS_CASE( "Checks concepts::range behavior" ) +{ + TTS_CONSTEXPR_EXPECT ((kwk::concepts::range>) ); + TTS_CONSTEXPR_EXPECT ( kwk::concepts::range> ); + TTS_CONSTEXPR_EXPECT ( kwk::concepts::range> ); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::range>); +}; + +TTS_CASE( "Checks concepts::contiguous_range behavior" ) +{ + TTS_CONSTEXPR_EXPECT ((kwk::concepts::contiguous_range>) ); + TTS_CONSTEXPR_EXPECT ( kwk::concepts::contiguous_range> ); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::contiguous_range> ); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::contiguous_range>); +}; + +TTS_CASE( "Checks concepts::contiguous_static_range behavior" ) +{ + TTS_CONSTEXPR_EXPECT ((kwk::concepts::contiguous_static_range>) ); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::contiguous_static_range> ); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::contiguous_static_range> ); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::contiguous_static_range>); +}; diff --git a/test/container/CMakeLists.txt b/test/container/CMakeLists.txt index 72c33020..d794d529 100644 --- a/test/container/CMakeLists.txt +++ b/test/container/CMakeLists.txt @@ -3,8 +3,6 @@ ## Copyright : KIWAKU Contributors & Maintainers ## SPDX-License-Identifier: BSL-1.0 ##================================================================================================== -add_subdirectory(shape) -add_subdirectory(stride) + add_subdirectory(table) -add_subdirectory(utility) add_subdirectory(view) diff --git a/test/container/shape/as_stride.cpp b/test/container/shape/as_stride.cpp deleted file mode 100644 index eda9e437..00000000 --- a/test/container/shape/as_stride.cpp +++ /dev/null @@ -1,42 +0,0 @@ -//================================================================================================== -/* - KIWAKU - Containers Well Made - Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -*/ -//================================================================================================== -#include "test.hpp" -#include -#include - -TTS_CASE( "Convert a 1D shape to 1D stride" ) -{ - TTS_EQUAL( kwk::shape(9).as_stride().get<0>(), 1 ); - TTS_EQUAL( kwk::shape(9).as_stride().is_unit, true ); -}; - -TTS_CASE( "Convert a 2D shape to 2D stride" ) -{ - TTS_EQUAL( kwk::shape(3,4).as_stride().get<0>(), 1); - TTS_EQUAL( kwk::shape(3,4).as_stride().get<1>(), 3); - TTS_EQUAL( kwk::shape(3,4).as_stride().is_unit, true ); -}; - -TTS_CASE( "Convert a 3D shape to 3D stride" ) -{ - TTS_EQUAL( kwk::shape(3,5,7).as_stride().get<0>(), 1 ); - TTS_EQUAL( kwk::shape(3,5,7).as_stride().get<1>(), 3 ); - TTS_EQUAL( kwk::shape(3,5,7).as_stride().get<2>(), 15); - TTS_EQUAL( kwk::shape(3,5,7).as_stride().is_unit, true ); -}; - -TTS_CASE( "Convert a 4D shape to 4D stride" ) -{ - TTS_EQUAL( kwk::shape(2,4,6,8).as_stride().get<0>(), 1 ); - TTS_EQUAL( kwk::shape(2,4,6,8).as_stride().get<1>(), 2 ); - TTS_EQUAL( kwk::shape(2,4,6,8).as_stride().get<2>(), 8 ); - TTS_EQUAL( kwk::shape(2,4,6,8).as_stride().get<3>(), 48); - TTS_EQUAL( kwk::shape(2,4,6,8).as_stride().is_unit, true ); -}; diff --git a/test/container/shape/ctor.cpp b/test/container/shape/ctor.cpp deleted file mode 100644 index d5c82d10..00000000 --- a/test/container/shape/ctor.cpp +++ /dev/null @@ -1,37 +0,0 @@ -//================================================================================================== -/** - KIWAKU - Containers Well Made - Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -**/ -//================================================================================================== -#include "test.hpp" -#include -#include "container/shape/shape.hpp" - -TTS_CASE_TPL( "Default constructed shape behavior", sizes<10>) -(::tts::type) -{ - auto sh = kwk::shape>(); - - TTS_EQUAL(sh.nbdims() , 1 ); - TTS_EQUAL(sh.numel() , 0 ); - TTS_EQUAL(sh.order() , T::value); - - TTS_EQUAL(kwk::get<0>(sh), 0); - if constexpr(T::value==1) TTS_EQUAL(kwk::get(sh) , 0); - else TTS_EQUAL(kwk::get(sh) , 1); -}; - -TTS_CASE_TPL( "Building a nD shape with kwk::shape{a1,...,an}", sizes<10>) -(::tts::type) -{ - auto f = [](std::index_sequence const&) - { - return kwk::shape{3*(1+Idx)...}; - }; - - test_nD(T{}, f(up_to{})); -}; diff --git a/test/container/stride/ctor.cpp b/test/container/stride/ctor.cpp deleted file mode 100644 index d70a678c..00000000 --- a/test/container/stride/ctor.cpp +++ /dev/null @@ -1,119 +0,0 @@ -//================================================================================================== -/** - KIWAKU - Containers Well Made - Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -**/ -//================================================================================================== -#include "test.hpp" -#include - -TTS_CASE( "Building a 1D stride using stride" ) -{ - TTS_EQUAL( kwk::with_stride(kwk::unit_).size() , 1 ); - TTS_EQUAL( kwk::with_stride(kwk::unit_).get<0>() , 1 ); - TTS_CONSTEXPR_EXPECT( kwk::with_stride(kwk::unit_).is_unit ); - TTS_CONSTEXPR_EXPECT_NOT( kwk::with_stride(kwk::unit_).is_implicit ); - - TTS_EQUAL( kwk::with_stride(9).size() , 1 ); - TTS_EQUAL( kwk::with_stride(9).get<0>() , 9 ); - TTS_CONSTEXPR_EXPECT_NOT( kwk::with_stride(9).is_unit ); - TTS_CONSTEXPR_EXPECT_NOT( kwk::with_stride(9).is_implicit ); -}; - -TTS_CASE( "Building a 2D stride using stride" ) -{ - TTS_EQUAL ( (kwk::with_stride(kwk::unit_,kwk::unit_).size() ) , 2 ); - TTS_EQUAL ( (kwk::with_stride(kwk::unit_,kwk::unit_).get<0>()) , 1 ); - TTS_EQUAL ( (kwk::with_stride(kwk::unit_,kwk::unit_).get<1>()) , 1 ); - TTS_CONSTEXPR_EXPECT( (kwk::with_stride(kwk::unit_, kwk::unit_).is_unit) ); - TTS_CONSTEXPR_EXPECT_NOT( (kwk::with_stride(kwk::unit_, kwk::unit_).is_implicit) ); - - TTS_EQUAL ( (kwk::with_stride(kwk::unit_, 42).size() ) , 2 ); - TTS_EQUAL ( (kwk::with_stride(kwk::unit_, 42).get<0>()) , 1 ); - TTS_EQUAL ( (kwk::with_stride(kwk::unit_, 42).get<1>()) , 42); - TTS_CONSTEXPR_EXPECT( (kwk::with_stride(kwk::unit_, 42).is_unit) ); - TTS_CONSTEXPR_EXPECT_NOT( (kwk::with_stride(kwk::unit_, 42).is_implicit) ); - - TTS_EQUAL ( (kwk::with_stride(6, 18).size() ) , 2 ); - TTS_EQUAL ( (kwk::with_stride(6, 18).get<0>()) , 6 ); - TTS_EQUAL ( (kwk::with_stride(6, 18).get<1>()) , 18 ); - TTS_CONSTEXPR_EXPECT_NOT( (kwk::with_stride(6, 18).is_unit) ); - TTS_CONSTEXPR_EXPECT_NOT( (kwk::with_stride(6, 18).is_implicit) ); -}; - -TTS_CASE( "Building a 3D stride using stride" ) -{ - TTS_EQUAL ( (kwk::with_stride(kwk::unit_,kwk::unit_,kwk::unit_).size() ) , 3 ); - TTS_EQUAL ( (kwk::with_stride(kwk::unit_,kwk::unit_,kwk::unit_).get<0>()) , 1 ); - TTS_EQUAL ( (kwk::with_stride(kwk::unit_,kwk::unit_,kwk::unit_).get<1>()) , 1 ); - TTS_EQUAL ( (kwk::with_stride(kwk::unit_,kwk::unit_,kwk::unit_).get<2>()) , 1 ); - TTS_CONSTEXPR_EXPECT( (kwk::with_stride(kwk::unit_,kwk::unit_,kwk::unit_).is_unit) ); - TTS_CONSTEXPR_EXPECT_NOT( (kwk::with_stride(kwk::unit_,kwk::unit_,kwk::unit_).is_implicit) ); - - TTS_EQUAL( (kwk::with_stride(kwk::unit_,kwk::unit_,16).size() ) , 3 ); - TTS_EQUAL( (kwk::with_stride(kwk::unit_,kwk::unit_,16).get<0>()) , 1 ); - TTS_EQUAL( (kwk::with_stride(kwk::unit_,kwk::unit_,16).get<1>()) , 1 ); - TTS_EQUAL( (kwk::with_stride(kwk::unit_,kwk::unit_,16).get<2>()) , 16 ); - TTS_CONSTEXPR_EXPECT( (kwk::with_stride(kwk::unit_,kwk::unit_,16).is_unit) ); - TTS_CONSTEXPR_EXPECT_NOT( (kwk::with_stride(kwk::unit_,kwk::unit_,16).is_implicit) ); - - TTS_EQUAL( (kwk::with_stride(kwk::unit_,8,16).size() ) , 3 ); - TTS_EQUAL( (kwk::with_stride(kwk::unit_,8,16).get<0>()) , 1 ); - TTS_EQUAL( (kwk::with_stride(kwk::unit_,8,16).get<1>()) , 8 ); - TTS_EQUAL( (kwk::with_stride(kwk::unit_,8,16).get<2>()) , 16 ); - TTS_CONSTEXPR_EXPECT( (kwk::with_stride(kwk::unit_,8,16).is_unit) ); - TTS_CONSTEXPR_EXPECT_NOT( (kwk::with_stride(kwk::unit_,8,16).is_implicit) ); - - TTS_EQUAL( (kwk::with_stride(2,8,16).size() ) , 3 ); - TTS_EQUAL( (kwk::with_stride(2,8,16).get<0>()) , 2 ); - TTS_EQUAL( (kwk::with_stride(2,8,16).get<1>()) , 8 ); - TTS_EQUAL( (kwk::with_stride(2,8,16).get<2>()) , 16 ); - TTS_CONSTEXPR_EXPECT_NOT( (kwk::with_stride(2,8,16).is_unit) ); - TTS_CONSTEXPR_EXPECT_NOT( (kwk::with_stride(2,8,16).is_implicit) ); -}; - -TTS_CASE( "Building a 4D stride using stride" ) -{ - TTS_EQUAL( (kwk::with_stride(kwk::unit_,kwk::unit_,kwk::unit_,kwk::unit_).size() ), 4 ); - TTS_EQUAL( (kwk::with_stride(kwk::unit_,kwk::unit_,kwk::unit_,kwk::unit_).get<0>()), 1 ); - TTS_EQUAL( (kwk::with_stride(kwk::unit_,kwk::unit_,kwk::unit_,kwk::unit_).get<1>()), 1 ); - TTS_EQUAL( (kwk::with_stride(kwk::unit_,kwk::unit_,kwk::unit_,kwk::unit_).get<2>()), 1 ); - TTS_EQUAL( (kwk::with_stride(kwk::unit_,kwk::unit_,kwk::unit_,kwk::unit_).get<3>()), 1 ); - TTS_CONSTEXPR_EXPECT( (kwk::with_stride(kwk::unit_,kwk::unit_,kwk::unit_,kwk::unit_).is_unit) ); - TTS_CONSTEXPR_EXPECT_NOT( (kwk::with_stride(kwk::unit_,kwk::unit_,kwk::unit_,kwk::unit_).is_implicit) ); - - TTS_EQUAL( (kwk::with_stride(kwk::unit_,kwk::unit_,kwk::unit_,32).size() ), 4 ); - TTS_EQUAL( (kwk::with_stride(kwk::unit_,kwk::unit_,kwk::unit_,32).get<0>()), 1 ); - TTS_EQUAL( (kwk::with_stride(kwk::unit_,kwk::unit_,kwk::unit_,32).get<1>()), 1 ); - TTS_EQUAL( (kwk::with_stride(kwk::unit_,kwk::unit_,kwk::unit_,32).get<2>()), 1 ); - TTS_EQUAL( (kwk::with_stride(kwk::unit_,kwk::unit_,kwk::unit_,32).get<3>()), 32 ); - TTS_CONSTEXPR_EXPECT( (kwk::with_stride(kwk::unit_,kwk::unit_,kwk::unit_,32).is_unit) ); - TTS_CONSTEXPR_EXPECT_NOT( (kwk::with_stride(kwk::unit_,kwk::unit_,kwk::unit_,32).is_implicit) ); - - TTS_EQUAL( (kwk::with_stride(kwk::unit_,kwk::unit_,16,32).size() ), 4 ); - TTS_EQUAL( (kwk::with_stride(kwk::unit_,kwk::unit_,16,32).get<0>()), 1 ); - TTS_EQUAL( (kwk::with_stride(kwk::unit_,kwk::unit_,16,32).get<1>()), 1 ); - TTS_EQUAL( (kwk::with_stride(kwk::unit_,kwk::unit_,16,32).get<2>()), 16); - TTS_EQUAL( (kwk::with_stride(kwk::unit_,kwk::unit_,16,32).get<3>()), 32); - TTS_CONSTEXPR_EXPECT( (kwk::with_stride(kwk::unit_,kwk::unit_,16,32).is_unit) ); - TTS_CONSTEXPR_EXPECT_NOT( (kwk::with_stride(kwk::unit_,kwk::unit_,16,32).is_implicit) ); - - TTS_EQUAL( (kwk::with_stride(kwk::unit_,8,16,32).size() ), 4 ); - TTS_EQUAL( (kwk::with_stride(kwk::unit_,8,16,32).get<0>()), 1 ); - TTS_EQUAL( (kwk::with_stride(kwk::unit_,8,16,32).get<1>()), 8 ); - TTS_EQUAL( (kwk::with_stride(kwk::unit_,8,16,32).get<2>()), 16); - TTS_EQUAL( (kwk::with_stride(kwk::unit_,8,16,32).get<3>()), 32); - TTS_CONSTEXPR_EXPECT( (kwk::with_stride(kwk::unit_,8,16,32).is_unit) ); - TTS_CONSTEXPR_EXPECT_NOT( (kwk::with_stride(kwk::unit_,8,16,32).is_implicit) ); - - TTS_EQUAL( (kwk::with_stride(2,8,16,32).size() ), 4 ); - TTS_EQUAL( (kwk::with_stride(2,8,16,32).get<0>()), 2 ); - TTS_EQUAL( (kwk::with_stride(2,8,16,32).get<1>()), 8 ); - TTS_EQUAL( (kwk::with_stride(2,8,16,32).get<2>()), 16); - TTS_EQUAL( (kwk::with_stride(2,8,16,32).get<3>()), 32); - TTS_CONSTEXPR_EXPECT_NOT( (kwk::with_stride(2,8,16,32).is_unit) ); - TTS_CONSTEXPR_EXPECT_NOT( (kwk::with_stride(2,8,16,32).is_implicit) ); -}; diff --git a/test/container/stride/indexing.cpp b/test/container/stride/indexing.cpp deleted file mode 100644 index 8009d057..00000000 --- a/test/container/stride/indexing.cpp +++ /dev/null @@ -1,164 +0,0 @@ -//================================================================================================== -/** - KIWAKU - Containers Well Made - Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -**/ -//================================================================================================== -#include "test.hpp" -#include -#include -#include -#include - -TTS_CASE( "1D index computation" ) -{ - auto st = kwk::with_stride(2); - - std::vector base(13); - std::vector ref(13); - std::vector output(13); - - std::iota(base.begin(),base.end(), 0); - - for(auto i=0;i<13;++i) ref[i] = 2*base[i]; - std::transform(base.begin(),base.end(), output.begin(), [&](auto e) { return st.index(e); } ); - - TTS_ALL_EQUAL(output, ref); -}; - -TTS_CASE( "2D Index computation" ) -{ - auto st = kwk::with_stride(2,6); - - std::vector ref; - std::vector output; - - { - for(auto i=0;i<15;++i) - ref.push_back(2*i); - - for(auto i=0;i<15;++i) - output.push_back( st.index(i) ); - - TTS_ALL_EQUAL(output, ref); - } - - { - for(auto j=0;j<5;++j) - for(auto i=0;i<3;++i) - ref.push_back(2*i + 6*j); - - for(auto j=0;j<5;++j) - for(auto i=0;i<3;++i) - output.push_back( st.index(i,j) ); - - TTS_ALL_EQUAL(output, ref); - } -}; - -TTS_CASE( "3D index computation" ) -{ - auto st = kwk::with_stride(2,6,30); - - std::vector ref; - std::vector output; - - { - for(auto i=0;i<60;++i) - ref.push_back(2*i); - - for(auto i=0;i<60;++i) - output.push_back( st.index(i) ); - - TTS_ALL_EQUAL(output, ref); - } - - { - for(auto j=0;j<20;++j) - for(auto i=0;i<3;++i) - ref.push_back(2*i + 6*j); - - for(auto j=0;j<20;++j) - for(auto i=0;i<3;++i) - output.push_back( st.index(i,j) ); - - TTS_ALL_EQUAL(output, ref); - } - - { - for(auto k=0;k<4;++k) - for(auto j=0;j<5;++j) - for(auto i=0;i<3;++i) - ref.push_back(2*i + 6*j + 30*k); - - for(auto k=0;k<4;++k) - for(auto j=0;j<5;++j) - for(auto i=0;i<3;++i) - output.push_back( st.index(i,j,k) ); - - TTS_ALL_EQUAL(output, ref); - } -}; - -TTS_CASE( "4D index computation" ) -{ - auto st = kwk::with_stride(2,6,30,60); - - std::vector ref; - std::vector output; - - { - for(auto i=0;i<60;++i) - ref.push_back(2*i); - - for(auto i=0;i<60;++i) - output.push_back( st.index(i) ); - - TTS_ALL_EQUAL(output, ref); - } - - { - for(auto j=0;j<20;++j) - for(auto i=0;i<3;++i) - ref.push_back(2*i + 6*j); - - for(auto j=0;j<20;++j) - for(auto i=0;i<3;++i) - output.push_back( st.index(i,j) ); - - TTS_ALL_EQUAL(output, ref); - } - - { - for(auto k=0;k<4;++k) - for(auto j=0;j<5;++j) - for(auto i=0;i<3;++i) - ref.push_back(2*i + 6*j + 30*k); - - for(auto k=0;k<4;++k) - for(auto j=0;j<5;++j) - for(auto i=0;i<3;++i) - output.push_back( st.index(i,j,k) ); - - TTS_ALL_EQUAL(output, ref); - } - - { - for(auto l=0;l<2;++l) - for(auto k=0;k<4;++k) - for(auto j=0;j<5;++j) - for(auto i=0;i<3;++i) - ref.push_back(2*i + 6*j + 30*k + 60*l); - - for(auto l=0;l<2;++l) - for(auto k=0;k<4;++k) - for(auto j=0;j<5;++j) - for(auto i=0;i<3;++i) - output.push_back( st.index(i,j,k,l) ); - - TTS_ALL_EQUAL(output, ref); - } -}; diff --git a/test/container/stride/unit_indexing.cpp b/test/container/stride/unit_indexing.cpp deleted file mode 100644 index 412fff48..00000000 --- a/test/container/stride/unit_indexing.cpp +++ /dev/null @@ -1,145 +0,0 @@ -//================================================================================================== -/** - KIWAKU - Containers Well Made - Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -**/ -//================================================================================================== -#include "test.hpp" -#include -#include -#include -#include -#include - -TTS_CASE( "1D index computation from unit stride" ) -{ - kwk::shape sh{13}; - auto st = sh.as_stride(); - - std::vector ref(13); - std::iota(ref.begin(),ref.end(), 0); - - std::vector output(13); - std::transform(ref.begin(),ref.end(), output.begin(), [&](auto e) { return st.index(e); } ); - - TTS_ALL_EQUAL(output, ref); -}; - -TTS_CASE( "2D Index computation from unit stride" ) -{ - kwk::shape sh{6,7}; - auto st = sh.as_stride(); - - std::vector ref(sh.numel()); - std::iota(ref.begin(),ref.end(), 0); - - { - std::vector output; - for(auto i=0;i output; - auto[sh0,sh1] = sh; - for(auto j=0;j ref(sh.numel()); - std::iota(ref.begin(),ref.end(), 0); - - { - std::vector output; - for(auto i=0;i output; - for(auto j=0;j output; - for(auto k=0;k ref(sh.numel()); - std::iota(ref.begin(),ref.end(), 0); - - { - std::vector output; - - for(auto i=0;i output; - auto[sh0,sh1,sh2,sh3] = sh; - for(auto j=0;j output; - auto[sh0,sh1,sh2,sh3] = sh; - for(auto k=0;k output; - auto[sh0,sh1,sh2,sh3] = sh; - for(auto l=0;l -#include +#include #include #include @@ -22,25 +20,21 @@ TTS_CASE( "Build a 2D table with dynamic shape settings from a C array" ) std::ptrdiff_t sz = 4; auto v = kwk::table{ kwk::source = ref, kwk::of_size(sz,sz-1) }; - TTS_EQUAL ( sizeof(v), 48ULL ); + TTS_EQUAL ( sizeof(v), 32ULL ); TTS_EQUAL ( v.size() , 12 ); TTS_EQUAL ( v.shape(), kwk::of_size(4,3) ); TTS_EXPECT_NOT( v.shape().is_fully_static ); - for(std::ptrdiff_t i1 = 0;i1(v);++i1) - for(std::ptrdiff_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1), ref[i0+i1*kwk::dim<0>(v)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*sz]); }, v); auto w = kwk::table{ kwk::source = ref, kwk::of_size(sz-1,sz) }; - TTS_EQUAL ( sizeof(w), 48ULL ); + TTS_EQUAL ( sizeof(w), 32ULL ); TTS_EQUAL ( w.size() , 12 ); TTS_EQUAL ( w.shape(), kwk::of_size(3,4) ); TTS_EXPECT_NOT( w.shape().is_fully_static ); - for(std::ptrdiff_t i1 = 0;i1(w);++i1) - for(std::ptrdiff_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1), ref[i0+i1*kwk::dim<0>(w)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*(sz-1)]); }, w); }; TTS_CASE( "Build a 2D table with dynamic shape settings from std::array" ) @@ -52,25 +46,21 @@ TTS_CASE( "Build a 2D table with dynamic shape settings from std::array" ) std::ptrdiff_t sz = 4; auto v = kwk::table{ kwk::source = ref, kwk::of_size(sz,sz-1) }; - TTS_EQUAL ( sizeof(v), 48ULL ); + TTS_EQUAL ( sizeof(v), 32ULL ); TTS_EQUAL ( v.size() , 12 ); TTS_EQUAL ( v.shape(), kwk::of_size(4,3) ); TTS_EXPECT_NOT( v.shape().is_fully_static ); - for(std::ptrdiff_t i1 = 0;i1(v);++i1) - for(std::ptrdiff_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1), ref[i0+i1*kwk::dim<0>(v)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*sz]); }, v); auto w = kwk::table{ kwk::source = ref, kwk::of_size(sz-1,sz) }; - TTS_EQUAL ( sizeof(w), 48ULL ); + TTS_EQUAL ( sizeof(w), 32ULL ); TTS_EQUAL ( w.size() , 12 ); TTS_EQUAL ( w.shape(), kwk::of_size(3,4) ); TTS_EXPECT_NOT( w.shape().is_fully_static ); - for(std::ptrdiff_t i1 = 0;i1(w);++i1) - for(std::ptrdiff_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1), ref[i0+i1*kwk::dim<0>(w)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*(sz-1)]); }, w); }; TTS_CASE( "Build a 2D table with dynamic shape settings from a ContiguousRange" ) @@ -82,27 +72,23 @@ TTS_CASE( "Build a 2D table with dynamic shape settings from a ContiguousRange" std::ptrdiff_t sz = 4; auto v = kwk::table{ kwk::source = ref, kwk::of_size(sz,sz-1) }; - TTS_EQUAL ( sizeof(v), 48ULL ); + TTS_EQUAL ( sizeof(v), 32ULL ); TTS_EQUAL ( v.size() , 12 ); TTS_EQUAL ( v.shape(), kwk::of_size(4,3) ); TTS_EXPECT_NOT( v.shape().is_fully_static ); - for(std::ptrdiff_t i1 = 0;i1(v);++i1) - for(std::ptrdiff_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1), ref[i0+i1*kwk::dim<0>(v)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*sz]); }, v); std::vector const cref = {1,2,3,4,5,6,7,8,9,10,11,12}; auto w = kwk::table{ kwk::source = cref, kwk::of_size(sz-1,sz) }; - TTS_EQUAL ( sizeof(w), 48ULL ); + TTS_EQUAL ( sizeof(w), 32ULL ); TTS_EQUAL ( w.size() , 12 ); TTS_EQUAL ( w.shape(), kwk::of_size(3,4) ); TTS_EXPECT_NOT( w.shape().is_fully_static ); - for(std::ptrdiff_t i1 = 0;i1(w);++i1) - for(std::ptrdiff_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1), ref[i0+i1*kwk::dim<0>(w)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*(sz-1)]); }, w); }; TTS_CASE( "Build a 2D table with dynamic shape settings from a pointer" ) @@ -114,25 +100,21 @@ TTS_CASE( "Build a 2D table with dynamic shape settings from a pointer" ) std::ptrdiff_t sz = 4; auto v = kwk::table{ kwk::source = ref.data(), kwk::of_size(sz,sz-1) }; - TTS_EQUAL ( sizeof(v), 48ULL ); + TTS_EQUAL ( sizeof(v), 32ULL ); TTS_EQUAL ( v.size() , 12 ); TTS_EQUAL ( v.shape(), kwk::of_size(4,3) ); TTS_EXPECT_NOT( v.shape().is_fully_static ); - for(std::ptrdiff_t i1 = 0;i1(v);++i1) - for(std::ptrdiff_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1), ref[i0+i1*kwk::dim<0>(v)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*sz]); }, v); std::vector const cref = {1,2,3,4,5,6,7,8,9,10,11,12}; auto w = kwk::table{ kwk::source = cref.data(), kwk::of_size(sz-1,sz) }; - TTS_EQUAL ( sizeof(w), 48ULL ); + TTS_EQUAL ( sizeof(w), 32ULL ); TTS_EQUAL ( w.size() , 12 ); TTS_EQUAL ( w.shape(), kwk::of_size(3,4) ); TTS_EXPECT_NOT( w.shape().is_fully_static ); - for(std::ptrdiff_t i1 = 0;i1(w);++i1) - for(std::ptrdiff_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1), ref[i0+i1*kwk::dim<0>(w)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*(sz-1)]); }, w); }; diff --git a/test/container/table/dynamic.3d.cpp b/test/container/table/dynamic.3d.cpp index dd79c579..42be9848 100644 --- a/test/container/table/dynamic.3d.cpp +++ b/test/container/table/dynamic.3d.cpp @@ -2,14 +2,12 @@ /* KIWAKU - Containers Well Made Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 */ //================================================================================================== #include "test.hpp" #include -#include +#include #include #include @@ -24,27 +22,31 @@ TTS_CASE( "Build a 3D table with dynamic shape settings from a C array" ) std::ptrdiff_t sz = 4; auto v = kwk::table{ kwk::source = ref, kwk::of_size(sz,sz-1,sz-2) }; - TTS_EQUAL ( sizeof(v), 72ULL ); + TTS_EQUAL ( sizeof(v), 56ULL ); TTS_EQUAL ( v.size() , 24 ); TTS_EQUAL ( v.shape(), kwk::of_size(4,3,2)); TTS_EXPECT_NOT( v.shape().is_fully_static ); - for(std::ptrdiff_t i2 = 0;i2(v);++i2) - for(std::ptrdiff_t i1 = 0;i1(v);++i1) - for(std::ptrdiff_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) + { + TTS_EQUAL(e, ref[i0+sz*(i1+i2*(sz-1))]); + } + , v + ); auto w = kwk::table{ kwk::source = ref, kwk::of_size(sz-1,sz,sz-2) }; - TTS_EQUAL ( sizeof(w), 72ULL ); + TTS_EQUAL ( sizeof(w), 56ULL ); TTS_EQUAL ( w.size() , 24 ); TTS_EQUAL ( w.shape(), kwk::of_size(3,4,2)); TTS_EXPECT_NOT( w.shape().is_fully_static ); - for(std::ptrdiff_t i2 = 0;i2(w);++i2) - for(std::ptrdiff_t i1 = 0;i1(w);++i1) - for(std::ptrdiff_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) + { + TTS_EQUAL(e, ref[i0+(sz-1)*(i1+i2*sz)]); + } + , w + ); }; TTS_CASE( "Build a 3D table with dynamic shape settings from std::array" ) @@ -58,27 +60,31 @@ TTS_CASE( "Build a 3D table with dynamic shape settings from std::array" ) std::ptrdiff_t sz = 4; auto v = kwk::table{ kwk::source = ref, kwk::of_size(sz,sz-1,sz-2) }; - TTS_EQUAL ( sizeof(v), 72ULL ); + TTS_EQUAL ( sizeof(v), 56ULL ); TTS_EQUAL ( v.size() , 24 ); TTS_EQUAL ( v.shape(), kwk::of_size(4,3,2)); TTS_EXPECT_NOT( v.shape().is_fully_static ); - for(std::ptrdiff_t i2 = 0;i2(v);++i2) - for(std::ptrdiff_t i1 = 0;i1(v);++i1) - for(std::ptrdiff_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) + { + TTS_EQUAL(e, ref[i0+sz*(i1+i2*(sz-1))]); + } + , v + ); auto w = kwk::table{ kwk::source = ref, kwk::of_size(sz-1,sz,sz-2) }; - TTS_EQUAL ( sizeof(w), 72ULL ); + TTS_EQUAL ( sizeof(w), 56ULL ); TTS_EQUAL ( w.size() , 24 ); TTS_EQUAL ( w.shape(), kwk::of_size(3,4,2)); TTS_EXPECT_NOT( w.shape().is_fully_static ); - for(std::ptrdiff_t i2 = 0;i2(w);++i2) - for(std::ptrdiff_t i1 = 0;i1(w);++i1) - for(std::ptrdiff_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) + { + TTS_EQUAL(e, ref[i0+(sz-1)*(i1+i2*sz)]); + } + , w + ); }; TTS_CASE( "Build a 3D table with dynamic shape settings from a ContiguousRange" ) @@ -92,15 +98,17 @@ TTS_CASE( "Build a 3D table with dynamic shape settings from a ContiguousRange" std::ptrdiff_t sz = 4; auto v = kwk::table{ kwk::source = ref, kwk::of_size(sz,sz-1,sz-2) }; - TTS_EQUAL ( sizeof(v), 72ULL ); + TTS_EQUAL ( sizeof(v), 56ULL ); TTS_EQUAL ( v.size() , 24 ); TTS_EQUAL ( v.shape(), kwk::of_size(4,3,2)); TTS_EXPECT_NOT( v.shape().is_fully_static ); - for(std::ptrdiff_t i2 = 0;i2(v);++i2) - for(std::ptrdiff_t i1 = 0;i1(v);++i1) - for(std::ptrdiff_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) + { + TTS_EQUAL(e, ref[i0+sz*(i1+i2*(sz-1))]); + } + , v + ); std::vector const cref = { 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12 ,13,14,15,16,17,18,19,20,21,22,23,24 @@ -108,15 +116,17 @@ TTS_CASE( "Build a 3D table with dynamic shape settings from a ContiguousRange" auto w = kwk::table{ kwk::source = cref, kwk::of_size(sz-1,sz,sz-2) }; - TTS_EQUAL ( sizeof(w), 72ULL ); + TTS_EQUAL ( sizeof(w), 56ULL ); TTS_EQUAL ( w.size() , 24 ); TTS_EQUAL ( w.shape(), kwk::of_size(3,4,2)); TTS_EXPECT_NOT( w.shape().is_fully_static ); - for(std::ptrdiff_t i2 = 0;i2(w);++i2) - for(std::ptrdiff_t i1 = 0;i1(w);++i1) - for(std::ptrdiff_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) + { + TTS_EQUAL(e, ref[i0+(sz-1)*(i1+i2*sz)]); + } + , w + ); }; TTS_CASE( "Build a 3D table with dynamic shape settings from a pointer" ) @@ -130,15 +140,17 @@ TTS_CASE( "Build a 3D table with dynamic shape settings from a pointer" ) std::ptrdiff_t sz = 4; auto v = kwk::table{ kwk::source = ref.data(), kwk::of_size(sz,sz-1,sz-2) }; - TTS_EQUAL ( sizeof(v), 72ULL ); + TTS_EQUAL ( sizeof(v), 56ULL ); TTS_EQUAL ( v.size() , 24 ); TTS_EQUAL ( v.shape(), kwk::of_size(4,3,2)); TTS_EXPECT_NOT( v.shape().is_fully_static ); - for(std::ptrdiff_t i2 = 0;i2(v);++i2) - for(std::ptrdiff_t i1 = 0;i1(v);++i1) - for(std::ptrdiff_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) + { + TTS_EQUAL(e, ref[i0+sz*(i1+i2*(sz-1))]); + } + , v + ); std::vector const cref = { 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12 ,13,14,15,16,17,18,19,20,21,22,23,24 @@ -146,13 +158,15 @@ TTS_CASE( "Build a 3D table with dynamic shape settings from a pointer" ) auto w = kwk::table{ kwk::source = cref.data(), kwk::of_size(sz-1,sz,sz-2) }; - TTS_EQUAL ( sizeof(w), 72ULL ); + TTS_EQUAL ( sizeof(w), 56ULL ); TTS_EQUAL ( w.size() , 24 ); TTS_EQUAL ( w.shape(), kwk::of_size(3,4,2)); TTS_EXPECT_NOT( w.shape().is_fully_static ); - for(std::ptrdiff_t i2 = 0;i2(w);++i2) - for(std::ptrdiff_t i1 = 0;i1(w);++i1) - for(std::ptrdiff_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) + { + TTS_EQUAL(e, ref[i0+(sz-1)*(i1+i2*sz)]); + } + , w + ); }; diff --git a/test/container/table/dynamic.4d.cpp b/test/container/table/dynamic.4d.cpp index 935d489f..bf40c1b5 100644 --- a/test/container/table/dynamic.4d.cpp +++ b/test/container/table/dynamic.4d.cpp @@ -2,8 +2,6 @@ /* KIWAKU - Containers Well Made Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 */ //================================================================================================== @@ -24,29 +22,31 @@ TTS_CASE( "Build a 4D table with dynamic shape settings from a C array" ) std::ptrdiff_t sz = 2; auto v = kwk::table{ kwk::source = ref, kwk::of_size(sz,sz+1,sz,sz) }; - TTS_EQUAL ( sizeof(v), 88ULL ); + TTS_EQUAL ( sizeof(v), 72ULL ); TTS_EQUAL ( v.size() , 24 ); TTS_EQUAL ( v.shape(), kwk::of_size(2,3,2,2)); TTS_EXPECT_NOT( v.shape().is_fully_static ); - for(std::ptrdiff_t i3 = 0;i3(v);++i3) - for(std::ptrdiff_t i2 = 0;i2(v);++i2) - for(std::ptrdiff_t i1 = 0;i1(v);++i1) - for(std::ptrdiff_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2,i3), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*(i2+kwk::dim<2>(v)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+sz*(i1+(sz+1)*(i2+sz*i3))]); + } + , v + ); auto w = kwk::table{ kwk::source = ref, kwk::of_size(sz+1,sz,sz,sz) }; - TTS_EQUAL ( sizeof(w), 88ULL ); + TTS_EQUAL ( sizeof(w), 72ULL ); TTS_EQUAL ( w.size() , 24 ); TTS_EQUAL ( w.shape(), kwk::of_size(3,2,2,2)); TTS_EXPECT_NOT( w.shape().is_fully_static ); - for(std::ptrdiff_t i3 = 0;i3(w);++i3) - for(std::ptrdiff_t i2 = 0;i2(w);++i2) - for(std::ptrdiff_t i1 = 0;i1(w);++i1) - for(std::ptrdiff_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2,i3), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*(i2+kwk::dim<2>(w)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+(sz+1)*(i1+sz*(i2+sz*i3))]); + } + , w + ); }; TTS_CASE( "Build a 4D table with dynamic shape settings from std::array" ) @@ -60,29 +60,31 @@ TTS_CASE( "Build a 4D table with dynamic shape settings from std::array" ) std::ptrdiff_t sz = 2; auto v = kwk::table{ kwk::source = ref, kwk::of_size(sz,sz+1,sz,sz) }; - TTS_EQUAL ( sizeof(v), 88ULL ); + TTS_EQUAL ( sizeof(v), 72ULL ); TTS_EQUAL ( v.size() , 24 ); TTS_EQUAL ( v.shape(), kwk::of_size(2,3,2,2)); TTS_EXPECT_NOT( v.shape().is_fully_static ); - for(std::ptrdiff_t i3 = 0;i3(v);++i3) - for(std::ptrdiff_t i2 = 0;i2(v);++i2) - for(std::ptrdiff_t i1 = 0;i1(v);++i1) - for(std::ptrdiff_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2,i3), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*(i2+kwk::dim<2>(v)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+sz*(i1+(sz+1)*(i2+sz*i3))]); + } + , v + ); auto w = kwk::table{ kwk::source = ref, kwk::of_size(sz+1,sz,sz,sz) }; - TTS_EQUAL ( sizeof(w), 88ULL ); + TTS_EQUAL ( sizeof(w), 72ULL ); TTS_EQUAL ( w.size() , 24 ); TTS_EQUAL ( w.shape(), kwk::of_size(3,2,2,2)); TTS_EXPECT_NOT( w.shape().is_fully_static ); - for(std::ptrdiff_t i3 = 0;i3(w);++i3) - for(std::ptrdiff_t i2 = 0;i2(w);++i2) - for(std::ptrdiff_t i1 = 0;i1(w);++i1) - for(std::ptrdiff_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2,i3), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*(i2+kwk::dim<2>(w)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+(sz+1)*(i1+sz*(i2+sz*i3))]); + } + , w + ); }; TTS_CASE( "Build a 4D table with dynamic shape settings from a ContiguousRange" ) @@ -96,16 +98,17 @@ TTS_CASE( "Build a 4D table with dynamic shape settings from a ContiguousRange" std::ptrdiff_t sz = 2; auto v = kwk::table{ kwk::source = ref, kwk::of_size(sz,sz+1,sz,sz) }; - TTS_EQUAL ( sizeof(v), 88ULL ); + TTS_EQUAL ( sizeof(v), 72ULL ); TTS_EQUAL ( v.size() , 24 ); TTS_EQUAL ( v.shape(), kwk::of_size(2,3,2,2)); TTS_EXPECT_NOT( v.shape().is_fully_static ); - for(std::ptrdiff_t i3 = 0;i3(v);++i3) - for(std::ptrdiff_t i2 = 0;i2(v);++i2) - for(std::ptrdiff_t i1 = 0;i1(v);++i1) - for(std::ptrdiff_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2,i3), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*(i2+kwk::dim<2>(v)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+sz*(i1+(sz+1)*(i2+sz*i3))]); + } + , v + ); std::vector const cref = { 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12 ,13,14,15,16,17,18,19,20,21,22,23,24 @@ -113,16 +116,17 @@ TTS_CASE( "Build a 4D table with dynamic shape settings from a ContiguousRange" auto w = kwk::table{ kwk::source = cref, kwk::of_size(sz+1,sz,sz,sz) }; - TTS_EQUAL ( sizeof(w), 88ULL ); + TTS_EQUAL ( sizeof(w), 72ULL ); TTS_EQUAL ( w.size() , 24 ); TTS_EQUAL ( w.shape(), kwk::of_size(3,2,2,2)); TTS_EXPECT_NOT( w.shape().is_fully_static ); - for(std::ptrdiff_t i3 = 0;i3(w);++i3) - for(std::ptrdiff_t i2 = 0;i2(w);++i2) - for(std::ptrdiff_t i1 = 0;i1(w);++i1) - for(std::ptrdiff_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2,i3), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*(i2+kwk::dim<2>(w)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+(sz+1)*(i1+sz*(i2+sz*i3))]); + } + , w + ); }; TTS_CASE( "Build a 4D table with dynamic shape settings from a pointer" ) @@ -136,16 +140,17 @@ TTS_CASE( "Build a 4D table with dynamic shape settings from a pointer" ) std::ptrdiff_t sz = 2; auto v = kwk::table{ kwk::source = ref.data(), kwk::of_size(sz,sz+1,sz,sz) }; - TTS_EQUAL ( sizeof(v), 88ULL ); + TTS_EQUAL ( sizeof(v), 72ULL ); TTS_EQUAL ( v.size() , 24 ); TTS_EQUAL ( v.shape(), kwk::of_size(2,3,2,2)); TTS_EXPECT_NOT( v.shape().is_fully_static ); - for(std::ptrdiff_t i3 = 0;i3(v);++i3) - for(std::ptrdiff_t i2 = 0;i2(v);++i2) - for(std::ptrdiff_t i1 = 0;i1(v);++i1) - for(std::ptrdiff_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2,i3), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*(i2+kwk::dim<2>(v)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+sz*(i1+(sz+1)*(i2+sz*i3))]); + } + , v + ); std::vector const cref = { 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12 ,13,14,15,16,17,18,19,20,21,22,23,24 @@ -153,14 +158,15 @@ TTS_CASE( "Build a 4D table with dynamic shape settings from a pointer" ) auto w = kwk::table{ kwk::source = cref.data(), kwk::of_size(sz+1,sz,sz,sz) }; - TTS_EQUAL ( sizeof(w), 88ULL ); + TTS_EQUAL ( sizeof(w), 72ULL ); TTS_EQUAL ( w.size() , 24 ); TTS_EQUAL ( w.shape(), kwk::of_size(3,2,2,2)); TTS_EXPECT_NOT( w.shape().is_fully_static ); - for(std::ptrdiff_t i3 = 0;i3(w);++i3) - for(std::ptrdiff_t i2 = 0;i2(w);++i2) - for(std::ptrdiff_t i1 = 0;i1(w);++i1) - for(std::ptrdiff_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2,i3), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*(i2+kwk::dim<2>(w)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+(sz+1)*(i1+sz*(i2+sz*i3))]); + } + , w + ); }; diff --git a/test/container/table/static.1d.cpp b/test/container/table/static.1d.cpp index 2690636c..103f72e8 100644 --- a/test/container/table/static.1d.cpp +++ b/test/container/table/static.1d.cpp @@ -2,8 +2,6 @@ /* KIWAKU - Containers Well Made Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 */ //================================================================================================== diff --git a/test/container/table/static.2d.cpp b/test/container/table/static.2d.cpp index 28f204ef..b62e7090 100644 --- a/test/container/table/static.2d.cpp +++ b/test/container/table/static.2d.cpp @@ -2,15 +2,12 @@ /* KIWAKU - Containers Well Made Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 */ //================================================================================================== #include "test.hpp" -#include "tts.hpp" #include -#include +#include #include #include @@ -28,9 +25,7 @@ TTS_CASE( "Build a 2D table from a C array" ) TTS_EXPECT( v.shape().is_fully_static ); TTS_NOT_EQUAL(&ref[0], &v(0,0)); - for(std::size_t i1 = 0;i1(v);++i1) - for(std::size_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1), ref[i0+i1*kwk::dim<0>(v)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*4]); }, v); auto w = kwk::table{ kwk::source = ref, kwk::of_size(3_c, 4_c) }; @@ -40,9 +35,7 @@ TTS_CASE( "Build a 2D table from a C array" ) TTS_EXPECT( w.shape().is_fully_static ); TTS_NOT_EQUAL(&ref[0], &w(0,0)); - for(std::size_t i1 = 0;i1(w);++i1) - for(std::size_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1), ref[i0+i1*kwk::dim<0>(w)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*3]); }, w); }; TTS_CASE( "Build a 2D table from std::array" ) @@ -59,9 +52,7 @@ TTS_CASE( "Build a 2D table from std::array" ) TTS_EXPECT( v.shape().is_fully_static ); TTS_NOT_EQUAL(&ref[0], &v(0,0)); - for(std::size_t i1 = 0;i1(v);++i1) - for(std::size_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1), ref[i0+i1*kwk::dim<0>(v)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*4]); }, v); auto w = kwk::table{ kwk::source = ref, kwk::of_size(3_c, 4_c) }; @@ -71,9 +62,7 @@ TTS_CASE( "Build a 2D table from std::array" ) TTS_EXPECT( w.shape().is_fully_static ); TTS_NOT_EQUAL(&ref[0], &w(0,0)); - for(std::size_t i1 = 0;i1(w);++i1) - for(std::size_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1), ref[i0+i1*kwk::dim<0>(w)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*3]); }, w); }; TTS_CASE( "Build a 2D table with constexpr shape settings from a ContiguousRange" ) @@ -90,9 +79,7 @@ TTS_CASE( "Build a 2D table with constexpr shape settings from a ContiguousRange TTS_EXPECT( v.shape().is_fully_static ); TTS_NOT_EQUAL(&ref[0], &v(0,0)); - for(std::size_t i1 = 0;i1(v);++i1) - for(std::size_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1), ref[i0+i1*kwk::dim<0>(v)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*4]); }, v); std::vector const cref = {1,2,3,4,5,6,7,8,9,10,11,12}; @@ -104,9 +91,7 @@ TTS_CASE( "Build a 2D table with constexpr shape settings from a ContiguousRange TTS_EXPECT( w.shape().is_fully_static ); TTS_NOT_EQUAL(&cref[0], &w(0,0)); - for(std::size_t i1 = 0;i1(w);++i1) - for(std::size_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1), ref[i0+i1*kwk::dim<0>(w)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*3]); }, w); }; TTS_CASE( "Build a 2D table with constexpr shape settings from a pointer" ) @@ -123,9 +108,7 @@ TTS_CASE( "Build a 2D table with constexpr shape settings from a pointer" ) TTS_EXPECT( v.shape().is_fully_static ); TTS_NOT_EQUAL(&ref[0], &v(0,0)); - for(std::size_t i1 = 0;i1(v);++i1) - for(std::size_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1), ref[i0+i1*kwk::dim<0>(v)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*4]); }, v); std::vector const cref = {1,2,3,4,5,6,7,8,9,10,11,12}; @@ -137,7 +120,5 @@ TTS_CASE( "Build a 2D table with constexpr shape settings from a pointer" ) TTS_EXPECT( w.shape().is_fully_static ); TTS_NOT_EQUAL(&cref[0], &w(0,0)); - for(std::size_t i1 = 0;i1(w);++i1) - for(std::size_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1), ref[i0+i1*kwk::dim<0>(w)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*3]); }, w); }; diff --git a/test/container/table/static.3d.cpp b/test/container/table/static.3d.cpp index 4e63e623..d793f927 100644 --- a/test/container/table/static.3d.cpp +++ b/test/container/table/static.3d.cpp @@ -2,14 +2,12 @@ /* KIWAKU - Containers Well Made Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 */ //================================================================================================== #include "test.hpp" #include -#include +#include #include #include @@ -29,10 +27,9 @@ TTS_CASE( "Build a 3D table from a C array" ) TTS_EXPECT( v.shape().is_fully_static ); TTS_NOT_EQUAL(&v(0,0,0),&ref[0]); - for(std::size_t i2 = 0;i2(v);++i2) - for(std::size_t i1 = 0;i1(v);++i1) - for(std::size_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) { TTS_EQUAL(e, ref[i0+4*(i1+i2*3)]); } + , v + ); auto w = kwk::table{ kwk::source = ref, kwk::of_size(3_c, 4_c, 2_c) }; @@ -42,10 +39,9 @@ TTS_CASE( "Build a 3D table from a C array" ) TTS_EXPECT( w.shape().is_fully_static ); TTS_NOT_EQUAL(&w(0,0,0),&ref[0]); - for(std::size_t i2 = 0;i2(w);++i2) - for(std::size_t i1 = 0;i1(w);++i1) - for(std::size_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) { TTS_EQUAL(e, ref[i0+3*(i1+i2*4)]); } + , w + ); }; TTS_CASE( "Build a 3D table from std::array" ) @@ -64,10 +60,9 @@ TTS_CASE( "Build a 3D table from std::array" ) TTS_EXPECT( v.shape().is_fully_static ); TTS_NOT_EQUAL(&v(0,0,0),&ref[0]); - for(std::size_t i2 = 0;i2(v);++i2) - for(std::size_t i1 = 0;i1(v);++i1) - for(std::size_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) { TTS_EQUAL(e, ref[i0+4*(i1+i2*3)]); } + , v + ); auto w = kwk::table{ kwk::source = ref, kwk::of_size(3_c, 4_c, 2_c) }; @@ -77,10 +72,9 @@ TTS_CASE( "Build a 3D table from std::array" ) TTS_EXPECT( w.shape().is_fully_static ); TTS_NOT_EQUAL(&w(0,0,0),&ref[0]); - for(std::size_t i2 = 0;i2(w);++i2) - for(std::size_t i1 = 0;i1(w);++i1) - for(std::size_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) { TTS_EQUAL(e, ref[i0+3*(i1+i2*4)]); } + , w + ); }; TTS_CASE( "Build a 3D table with constexpr shape settings from a ContiguousRange" ) @@ -99,10 +93,9 @@ TTS_CASE( "Build a 3D table with constexpr shape settings from a ContiguousRange TTS_EXPECT( v.shape().is_fully_static ); TTS_NOT_EQUAL(&v(0,0,0),&ref[0]); - for(std::size_t i2 = 0;i2(v);++i2) - for(std::size_t i1 = 0;i1(v);++i1) - for(std::size_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) { TTS_EQUAL(e, ref[i0+4*(i1+i2*3)]); } + , v + ); auto w = kwk::table{ kwk::source = ref, kwk::of_size(3_c, 4_c, 2_c) }; @@ -112,10 +105,9 @@ TTS_CASE( "Build a 3D table with constexpr shape settings from a ContiguousRange TTS_EXPECT( w.shape().is_fully_static ); TTS_NOT_EQUAL(&w(0,0,0),&ref[0]); - for(std::size_t i2 = 0;i2(w);++i2) - for(std::size_t i1 = 0;i1(w);++i1) - for(std::size_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) { TTS_EQUAL(e, ref[i0+3*(i1+i2*4)]); } + , w + ); }; TTS_CASE( "Build a 3D table with constexpr shape settings from a pointer" ) @@ -134,10 +126,9 @@ TTS_CASE( "Build a 3D table with constexpr shape settings from a pointer" ) TTS_EXPECT( v.shape().is_fully_static ); TTS_NOT_EQUAL(&v(0,0,0),&ref[0]); - for(std::size_t i2 = 0;i2(v);++i2) - for(std::size_t i1 = 0;i1(v);++i1) - for(std::size_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) { TTS_EQUAL(e, ref[i0+4*(i1+i2*3)]); } + , v + ); auto w = kwk::table{ kwk::source = ref, kwk::of_size(3_c, 4_c, 2_c) }; @@ -147,8 +138,7 @@ TTS_CASE( "Build a 3D table with constexpr shape settings from a pointer" ) TTS_EQUAL ( w.shape(), kwk::of_size(3,4,2) ); TTS_EXPECT( w.shape().is_fully_static ); - for(std::size_t i2 = 0;i2(w);++i2) - for(std::size_t i1 = 0;i1(w);++i1) - for(std::size_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) { TTS_EQUAL(e, ref[i0+3*(i1+i2*4)]); } + , w + ); }; diff --git a/test/container/table/static.4d.cpp b/test/container/table/static.4d.cpp index 99dbfdd0..31e79442 100644 --- a/test/container/table/static.4d.cpp +++ b/test/container/table/static.4d.cpp @@ -2,8 +2,6 @@ /* KIWAKU - Containers Well Made Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 */ //================================================================================================== @@ -31,11 +29,12 @@ TTS_CASE( "Build a 4D table from a C array" ) TTS_EXPECT( v.shape().is_fully_static ); TTS_NOT_EQUAL(&v(0,0,0,0),&ref[0]); - for(std::size_t i3 = 0;i3(v);++i3) - for(std::size_t i2 = 0;i2(v);++i2) - for(std::size_t i1 = 0;i1(v);++i1) - for(std::size_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2,i3), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*(i2+kwk::dim<2>(v)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+2*(i1+3*(i2+2*i3))]); + } + , v + ); auto w = kwk::table{ kwk::source = ref , kwk::of_size(3_c, 2_c, 2_c, 2_c) @@ -47,11 +46,12 @@ TTS_CASE( "Build a 4D table from a C array" ) TTS_EXPECT( w.shape().is_fully_static ); TTS_NOT_EQUAL(&w(0,0,0,0),&ref[0]); - for(std::size_t i3 = 0;i3(w);++i3) - for(std::size_t i2 = 0;i2(w);++i2) - for(std::size_t i1 = 0;i1(w);++i1) - for(std::size_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2,i3), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*(i2+kwk::dim<2>(w)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+3*(i1+2*(i2+2*i3))]); + } + , w + ); }; TTS_CASE( "Build a 4D table from std::array" ) @@ -73,11 +73,12 @@ TTS_CASE( "Build a 4D table from std::array" ) TTS_EXPECT( v.shape().is_fully_static ); TTS_NOT_EQUAL(&v(0,0,0,0),&ref[0]); - for(std::size_t i3 = 0;i3(v);++i3) - for(std::size_t i2 = 0;i2(v);++i2) - for(std::size_t i1 = 0;i1(v);++i1) - for(std::size_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2,i3), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*(i2+kwk::dim<2>(v)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+2*(i1+3*(i2+2*i3))]); + } + , v + ); auto w = kwk::table{ kwk::source = ref , kwk::of_size(3_c, 2_c, 2_c, 2_c) @@ -89,11 +90,12 @@ TTS_CASE( "Build a 4D table from std::array" ) TTS_EXPECT( w.shape().is_fully_static ); TTS_NOT_EQUAL(&w(0,0,0,0),&ref[0]); - for(std::size_t i3 = 0;i3(w);++i3) - for(std::size_t i2 = 0;i2(w);++i2) - for(std::size_t i1 = 0;i1(w);++i1) - for(std::size_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2,i3), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*(i2+kwk::dim<2>(w)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+3*(i1+2*(i2+2*i3))]); + } + , w + ); }; TTS_CASE( "Build a 4D table with constexpr shape settings from a ContiguousRange" ) @@ -114,11 +116,12 @@ TTS_CASE( "Build a 4D table with constexpr shape settings from a ContiguousRange TTS_EXPECT( v.shape().is_fully_static ); TTS_NOT_EQUAL(&v(0,0,0,0),&ref[0]); - for(std::size_t i3 = 0;i3(v);++i3) - for(std::size_t i2 = 0;i2(v);++i2) - for(std::size_t i1 = 0;i1(v);++i1) - for(std::size_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2,i3), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*(i2+kwk::dim<2>(v)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+2*(i1+3*(i2+2*i3))]); + } + , v + ); auto w = kwk::table { kwk::source = ref , kwk::of_size(3_c, 2_c, 2_c, 2_c) @@ -130,11 +133,12 @@ TTS_CASE( "Build a 4D table with constexpr shape settings from a ContiguousRange TTS_EXPECT( w.shape().is_fully_static ); TTS_NOT_EQUAL(&w(0,0,0,0),&ref[0]); - for(std::size_t i3 = 0;i3(w);++i3) - for(std::size_t i2 = 0;i2(w);++i2) - for(std::size_t i1 = 0;i1(w);++i1) - for(std::size_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2,i3), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*(i2+kwk::dim<2>(w)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+3*(i1+2*(i2+2*i3))]); + } + , w + ); }; TTS_CASE( "Build a 4D table with constexpr shape settings from a pointer" ) @@ -155,11 +159,12 @@ TTS_CASE( "Build a 4D table with constexpr shape settings from a pointer" ) TTS_EXPECT( v.shape().is_fully_static ); TTS_NOT_EQUAL(&v(0,0,0,0),&ref[0]); - for(std::size_t i3 = 0;i3(v);++i3) - for(std::size_t i2 = 0;i2(v);++i2) - for(std::size_t i1 = 0;i1(v);++i1) - for(std::size_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2,i3), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*(i2+kwk::dim<2>(v)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+2*(i1+3*(i2+2*i3))]); + } + , v + ); auto w = kwk::table { kwk::source = ref , kwk::of_size(3_c, 2_c, 2_c, 2_c) @@ -171,9 +176,10 @@ TTS_CASE( "Build a 4D table with constexpr shape settings from a pointer" ) TTS_EXPECT( w.shape().is_fully_static ); TTS_NOT_EQUAL(&w(0,0,0,0),&ref[0]); - for(std::size_t i3 = 0;i3(w);++i3) - for(std::size_t i2 = 0;i2(w);++i2) - for(std::size_t i1 = 0;i1(w);++i1) - for(std::size_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2,i3), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*(i2+kwk::dim<2>(w)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+3*(i1+2*(i2+2*i3))]); + } + , w + ); }; diff --git a/test/container/view/dynamic.1d.cpp b/test/container/view/dynamic.1d.cpp index c5617d88..1a695950 100644 --- a/test/container/view/dynamic.1d.cpp +++ b/test/container/view/dynamic.1d.cpp @@ -2,8 +2,6 @@ /* KIWAKU - Containers Well Made Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 */ //================================================================================================== diff --git a/test/container/view/dynamic.2d.cpp b/test/container/view/dynamic.2d.cpp index 76b76a1b..f1db271f 100644 --- a/test/container/view/dynamic.2d.cpp +++ b/test/container/view/dynamic.2d.cpp @@ -2,14 +2,12 @@ /* KIWAKU - Containers Well Made Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 */ //================================================================================================== #include "test.hpp" #include -#include +#include #include #include @@ -27,9 +25,7 @@ TTS_CASE( "Build a 2D view with dynamic shape settings from a C array" ) TTS_EQUAL ( v.shape(), kwk::of_size(4,3) ); TTS_EXPECT_NOT( v.shape().is_fully_static ); - for(std::ptrdiff_t i1 = 0;i1(v);++i1) - for(std::ptrdiff_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1), ref[i0+i1*kwk::dim<0>(v)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*sz]); }, v); auto w = kwk::view{ kwk::source = ref, kwk::of_size(sz-1,sz) }; @@ -38,9 +34,7 @@ TTS_CASE( "Build a 2D view with dynamic shape settings from a C array" ) TTS_EQUAL ( w.shape(), kwk::of_size(3,4) ); TTS_EXPECT_NOT( w.shape().is_fully_static ); - for(std::ptrdiff_t i1 = 0;i1(w);++i1) - for(std::ptrdiff_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1), ref[i0+i1*kwk::dim<0>(w)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*(sz-1)]); }, w); }; TTS_CASE( "Build a 2D view with dynamic shape settings from std::array" ) @@ -57,9 +51,7 @@ TTS_CASE( "Build a 2D view with dynamic shape settings from std::array" ) TTS_EQUAL ( v.shape(), kwk::of_size(4,3) ); TTS_EXPECT_NOT( v.shape().is_fully_static ); - for(std::ptrdiff_t i1 = 0;i1(v);++i1) - for(std::ptrdiff_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1), ref[i0+i1*kwk::dim<0>(v)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*sz]); }, v); auto w = kwk::view{ kwk::source = ref, kwk::of_size(sz-1,sz) }; @@ -68,9 +60,7 @@ TTS_CASE( "Build a 2D view with dynamic shape settings from std::array" ) TTS_EQUAL ( w.shape(), kwk::of_size(3,4) ); TTS_EXPECT_NOT( w.shape().is_fully_static ); - for(std::ptrdiff_t i1 = 0;i1(w);++i1) - for(std::ptrdiff_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1), ref[i0+i1*kwk::dim<0>(w)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*(sz-1)]); }, w); }; TTS_CASE( "Build a 2D view with dynamic shape settings from a ContiguousRange" ) @@ -87,9 +77,7 @@ TTS_CASE( "Build a 2D view with dynamic shape settings from a ContiguousRange" ) TTS_EQUAL ( v.shape(), kwk::of_size(4,3) ); TTS_EXPECT_NOT( v.shape().is_fully_static ); - for(std::ptrdiff_t i1 = 0;i1(v);++i1) - for(std::ptrdiff_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1), ref[i0+i1*kwk::dim<0>(v)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*sz]); }, v); std::vector const cref = {1,2,3,4,5,6,7,8,9,10,11,12}; @@ -100,9 +88,7 @@ TTS_CASE( "Build a 2D view with dynamic shape settings from a ContiguousRange" ) TTS_EQUAL ( w.shape(), kwk::of_size(3,4) ); TTS_EXPECT_NOT( w.shape().is_fully_static ); - for(std::ptrdiff_t i1 = 0;i1(w);++i1) - for(std::ptrdiff_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1), ref[i0+i1*kwk::dim<0>(w)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*(sz-1)]); }, w); }; TTS_CASE( "Build a 2D view with dynamic shape settings from a pointer" ) @@ -119,9 +105,7 @@ TTS_CASE( "Build a 2D view with dynamic shape settings from a pointer" ) TTS_EQUAL ( v.shape(), kwk::of_size(4,3) ); TTS_EXPECT_NOT( v.shape().is_fully_static ); - for(std::ptrdiff_t i1 = 0;i1(v);++i1) - for(std::ptrdiff_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1), ref[i0+i1*kwk::dim<0>(v)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*sz]); }, v); std::vector const cref = {1,2,3,4,5,6,7,8,9,10,11,12}; @@ -132,7 +116,5 @@ TTS_CASE( "Build a 2D view with dynamic shape settings from a pointer" ) TTS_EQUAL ( w.shape(), kwk::of_size(3,4) ); TTS_EXPECT_NOT( w.shape().is_fully_static ); - for(std::ptrdiff_t i1 = 0;i1(w);++i1) - for(std::ptrdiff_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1), ref[i0+i1*kwk::dim<0>(w)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*(sz-1)]); }, w); }; diff --git a/test/container/view/dynamic.3d.cpp b/test/container/view/dynamic.3d.cpp index f417d6d6..e66688f4 100644 --- a/test/container/view/dynamic.3d.cpp +++ b/test/container/view/dynamic.3d.cpp @@ -2,8 +2,6 @@ /* KIWAKU - Containers Well Made Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 */ //================================================================================================== @@ -29,10 +27,12 @@ TTS_CASE( "Build a 3D view with dynamic shape settings from a C array" ) TTS_EQUAL ( v.shape(), kwk::of_size(4,3,2) ); TTS_EXPECT_NOT( v.shape().is_fully_static ); - for(std::ptrdiff_t i2 = 0;i2(v);++i2) - for(std::ptrdiff_t i1 = 0;i1(v);++i1) - for(std::ptrdiff_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) + { + TTS_EQUAL(e, ref[i0+sz*(i1+i2*(sz-1))]); + } + , v + ); auto w = kwk::view{ kwk::source = ref, kwk::of_size(sz-1,sz,sz-2) }; @@ -41,10 +41,12 @@ TTS_CASE( "Build a 3D view with dynamic shape settings from a C array" ) TTS_EQUAL ( w.shape(), kwk::of_size(3,4,2) ); TTS_EXPECT_NOT( w.shape().is_fully_static ); - for(std::ptrdiff_t i2 = 0;i2(w);++i2) - for(std::ptrdiff_t i1 = 0;i1(w);++i1) - for(std::ptrdiff_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) + { + TTS_EQUAL(e, ref[i0+(sz-1)*(i1+i2*sz)]); + } + , w + ); }; TTS_CASE( "Build a 3D view with dynamic shape settings from std::array" ) @@ -63,10 +65,12 @@ TTS_CASE( "Build a 3D view with dynamic shape settings from std::array" ) TTS_EQUAL ( v.shape(), kwk::of_size(4,3,2) ); TTS_EXPECT_NOT( v.shape().is_fully_static ); - for(std::ptrdiff_t i2 = 0;i2(v);++i2) - for(std::ptrdiff_t i1 = 0;i1(v);++i1) - for(std::ptrdiff_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) + { + TTS_EQUAL(e, ref[i0+sz*(i1+i2*(sz-1))]); + } + , v + ); auto w = kwk::view{ kwk::source = ref, kwk::of_size(sz-1,sz,sz-2) }; @@ -75,10 +79,12 @@ TTS_CASE( "Build a 3D view with dynamic shape settings from std::array" ) TTS_EQUAL ( w.shape(), kwk::of_size(3,4,2) ); TTS_EXPECT_NOT( w.shape().is_fully_static ); - for(std::ptrdiff_t i2 = 0;i2(w);++i2) - for(std::ptrdiff_t i1 = 0;i1(w);++i1) - for(std::ptrdiff_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) + { + TTS_EQUAL(e, ref[i0+(sz-1)*(i1+i2*sz)]); + } + , w + ); }; TTS_CASE( "Build a 3D view with dynamic shape settings from a ContiguousRange" ) @@ -97,10 +103,12 @@ TTS_CASE( "Build a 3D view with dynamic shape settings from a ContiguousRange" ) TTS_EQUAL ( v.shape(), kwk::of_size(4,3,2) ); TTS_EXPECT_NOT( v.shape().is_fully_static ); - for(std::ptrdiff_t i2 = 0;i2(v);++i2) - for(std::ptrdiff_t i1 = 0;i1(v);++i1) - for(std::ptrdiff_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) + { + TTS_EQUAL(e, ref[i0+sz*(i1+i2*(sz-1))]); + } + , v + ); std::vector const cref = { 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12 ,13,14,15,16,17,18,19,20,21,22,23,24 @@ -113,10 +121,12 @@ TTS_CASE( "Build a 3D view with dynamic shape settings from a ContiguousRange" ) TTS_EQUAL ( w.shape(), kwk::of_size(3,4,2) ); TTS_EXPECT_NOT( w.shape().is_fully_static ); - for(std::ptrdiff_t i2 = 0;i2(w);++i2) - for(std::ptrdiff_t i1 = 0;i1(w);++i1) - for(std::ptrdiff_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) + { + TTS_EQUAL(e, ref[i0+(sz-1)*(i1+i2*sz)]); + } + , w + ); }; TTS_CASE( "Build a 3D view with dynamic shape settings from a pointer" ) @@ -135,10 +145,12 @@ TTS_CASE( "Build a 3D view with dynamic shape settings from a pointer" ) TTS_EQUAL ( v.shape(), kwk::of_size(4,3,2) ); TTS_EXPECT_NOT( v.shape().is_fully_static ); - for(std::ptrdiff_t i2 = 0;i2(v);++i2) - for(std::ptrdiff_t i1 = 0;i1(v);++i1) - for(std::ptrdiff_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) + { + TTS_EQUAL(e, ref[i0+sz*(i1+i2*(sz-1))]); + } + , v + ); std::vector const cref = { 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12 ,13,14,15,16,17,18,19,20,21,22,23,24 @@ -151,8 +163,10 @@ TTS_CASE( "Build a 3D view with dynamic shape settings from a pointer" ) TTS_EQUAL ( w.shape(), kwk::of_size(3,4,2) ); TTS_EXPECT_NOT( w.shape().is_fully_static ); - for(std::ptrdiff_t i2 = 0;i2(w);++i2) - for(std::ptrdiff_t i1 = 0;i1(w);++i1) - for(std::ptrdiff_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) + { + TTS_EQUAL(e, ref[i0+(sz-1)*(i1+i2*sz)]); + } + , w + ); }; diff --git a/test/container/view/dynamic.4d.cpp b/test/container/view/dynamic.4d.cpp index df542266..9a92ecac 100644 --- a/test/container/view/dynamic.4d.cpp +++ b/test/container/view/dynamic.4d.cpp @@ -2,8 +2,6 @@ /* KIWAKU - Containers Well Made Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 */ //================================================================================================== @@ -29,11 +27,12 @@ TTS_CASE( "Build a 4D view with dynamic shape settings from a C array" ) TTS_EQUAL ( v.shape(), kwk::of_size(2,3,2,2) ); TTS_EXPECT_NOT( v.shape().is_fully_static ); - for(std::ptrdiff_t i3 = 0;i3(v);++i3) - for(std::ptrdiff_t i2 = 0;i2(v);++i2) - for(std::ptrdiff_t i1 = 0;i1(v);++i1) - for(std::ptrdiff_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2,i3), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*(i2+kwk::dim<2>(v)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+sz*(i1+(sz+1)*(i2+sz*i3))]); + } + , v + ); auto w = kwk::view{ kwk::source = ref, kwk::of_size(sz+1,sz,sz,sz) }; @@ -42,11 +41,12 @@ TTS_CASE( "Build a 4D view with dynamic shape settings from a C array" ) TTS_EQUAL ( w.shape(), kwk::of_size(3,2,2,2) ); TTS_EXPECT_NOT( w.shape().is_fully_static ); - for(std::ptrdiff_t i3 = 0;i3(w);++i3) - for(std::ptrdiff_t i2 = 0;i2(w);++i2) - for(std::ptrdiff_t i1 = 0;i1(w);++i1) - for(std::ptrdiff_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2,i3), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*(i2+kwk::dim<2>(w)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+(sz+1)*(i1+sz*(i2+sz*i3))]); + } + , w + ); }; TTS_CASE( "Build a 4D view with dynamic shape settings from std::array" ) @@ -65,11 +65,12 @@ TTS_CASE( "Build a 4D view with dynamic shape settings from std::array" ) TTS_EQUAL ( v.shape(), kwk::of_size(2,3,2,2) ); TTS_EXPECT_NOT( v.shape().is_fully_static ); - for(std::ptrdiff_t i3 = 0;i3(v);++i3) - for(std::ptrdiff_t i2 = 0;i2(v);++i2) - for(std::ptrdiff_t i1 = 0;i1(v);++i1) - for(std::ptrdiff_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2,i3), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*(i2+kwk::dim<2>(v)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+sz*(i1+(sz+1)*(i2+sz*i3))]); + } + , v + ); auto w = kwk::view{ kwk::source = ref, kwk::of_size(sz+1,sz,sz,sz) }; @@ -78,11 +79,12 @@ TTS_CASE( "Build a 4D view with dynamic shape settings from std::array" ) TTS_EQUAL ( w.shape(), kwk::of_size(3,2,2,2) ); TTS_EXPECT_NOT( w.shape().is_fully_static ); - for(std::ptrdiff_t i3 = 0;i3(w);++i3) - for(std::ptrdiff_t i2 = 0;i2(w);++i2) - for(std::ptrdiff_t i1 = 0;i1(w);++i1) - for(std::ptrdiff_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2,i3), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*(i2+kwk::dim<2>(w)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+(sz+1)*(i1+sz*(i2+sz*i3))]); + } + , w + ); }; TTS_CASE( "Build a 4D view with dynamic shape settings from a ContiguousRange" ) @@ -101,11 +103,12 @@ TTS_CASE( "Build a 4D view with dynamic shape settings from a ContiguousRange" ) TTS_EQUAL ( v.shape(), kwk::of_size(2,3,2,2) ); TTS_EXPECT_NOT( v.shape().is_fully_static ); - for(std::ptrdiff_t i3 = 0;i3(v);++i3) - for(std::ptrdiff_t i2 = 0;i2(v);++i2) - for(std::ptrdiff_t i1 = 0;i1(v);++i1) - for(std::ptrdiff_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2,i3), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*(i2+kwk::dim<2>(v)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+sz*(i1+(sz+1)*(i2+sz*i3))]); + } + , v + ); std::vector const cref = { 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12 ,13,14,15,16,17,18,19,20,21,22,23,24 @@ -118,11 +121,12 @@ TTS_CASE( "Build a 4D view with dynamic shape settings from a ContiguousRange" ) TTS_EQUAL ( w.shape(), kwk::of_size(3,2,2,2) ); TTS_EXPECT_NOT( w.shape().is_fully_static ); - for(std::ptrdiff_t i3 = 0;i3(w);++i3) - for(std::ptrdiff_t i2 = 0;i2(w);++i2) - for(std::ptrdiff_t i1 = 0;i1(w);++i1) - for(std::ptrdiff_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2,i3), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*(i2+kwk::dim<2>(w)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+(sz+1)*(i1+sz*(i2+sz*i3))]); + } + , w + ); }; TTS_CASE( "Build a 4D view with dynamic shape settings from a pointer" ) @@ -141,11 +145,12 @@ TTS_CASE( "Build a 4D view with dynamic shape settings from a pointer" ) TTS_EQUAL ( v.shape(), kwk::of_size(2,3,2,2) ); TTS_EXPECT_NOT( v.shape().is_fully_static ); - for(std::ptrdiff_t i3 = 0;i3(v);++i3) - for(std::ptrdiff_t i2 = 0;i2(v);++i2) - for(std::ptrdiff_t i1 = 0;i1(v);++i1) - for(std::ptrdiff_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2,i3), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*(i2+kwk::dim<2>(v)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+sz*(i1+(sz+1)*(i2+sz*i3))]); + } + , v + ); std::vector const cref = { 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12 ,13,14,15,16,17,18,19,20,21,22,23,24 @@ -158,9 +163,10 @@ TTS_CASE( "Build a 4D view with dynamic shape settings from a pointer" ) TTS_EQUAL ( w.shape(), kwk::of_size(3,2,2,2) ); TTS_EXPECT_NOT( w.shape().is_fully_static ); - for(std::ptrdiff_t i3 = 0;i3(w);++i3) - for(std::ptrdiff_t i2 = 0;i2(w);++i2) - for(std::ptrdiff_t i1 = 0;i1(w);++i1) - for(std::ptrdiff_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2,i3), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*(i2+kwk::dim<2>(w)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+(sz+1)*(i1+sz*(i2+sz*i3))]); + } + , w + ); }; diff --git a/test/container/view/static.1d.cpp b/test/container/view/static.1d.cpp index cdbffc8f..7d733513 100644 --- a/test/container/view/static.1d.cpp +++ b/test/container/view/static.1d.cpp @@ -2,8 +2,6 @@ /* KIWAKU - Containers Well Made Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 */ //================================================================================================== diff --git a/test/container/view/static.2d.cpp b/test/container/view/static.2d.cpp index d29042ce..79374500 100644 --- a/test/container/view/static.2d.cpp +++ b/test/container/view/static.2d.cpp @@ -2,14 +2,12 @@ /* KIWAKU - Containers Well Made Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 */ //================================================================================================== #include "test.hpp" #include -#include +#include #include #include @@ -26,9 +24,7 @@ TTS_CASE( "Build a 2D view from a C array" ) TTS_EQUAL ( v.shape(), kwk::of_size(4,3)); TTS_EXPECT( v.shape().is_fully_static ); - for(std::size_t i1 = 0;i1(v);++i1) - for(std::size_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1), ref[i0+i1*kwk::dim<0>(v)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*4]); }, v); auto w = kwk::view{ kwk::source = ref, kwk::of_size(3_c, 4_c) }; @@ -37,9 +33,7 @@ TTS_CASE( "Build a 2D view from a C array" ) TTS_EQUAL ( w.shape(), kwk::of_size(3,4)); TTS_EXPECT( w.shape().is_fully_static ); - for(std::size_t i1 = 0;i1(w);++i1) - for(std::size_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1), ref[i0+i1*kwk::dim<0>(w)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*3]); }, w); }; TTS_CASE( "Build a 2D view from std::array" ) @@ -55,9 +49,7 @@ TTS_CASE( "Build a 2D view from std::array" ) TTS_EQUAL ( v.shape(), kwk::of_size(4,3)); TTS_EXPECT( v.shape().is_fully_static ); - for(std::size_t i1 = 0;i1(v);++i1) - for(std::size_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1), ref[i0+i1*kwk::dim<0>(v)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*4]); }, v); auto w = kwk::view{ kwk::source = ref, kwk::of_size(3_c, 4_c) }; @@ -66,9 +58,7 @@ TTS_CASE( "Build a 2D view from std::array" ) TTS_EQUAL ( w.shape(), kwk::of_size(3,4)); TTS_EXPECT( w.shape().is_fully_static ); - for(std::size_t i1 = 0;i1(w);++i1) - for(std::size_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1), ref[i0+i1*kwk::dim<0>(w)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*3]); }, w); }; TTS_CASE( "Build a 2D view with constexpr shape settings from a ContiguousRange" ) @@ -84,9 +74,7 @@ TTS_CASE( "Build a 2D view with constexpr shape settings from a ContiguousRange" TTS_EQUAL ( v.shape(), kwk::of_size(4,3)); TTS_EXPECT( v.shape().is_fully_static ); - for(std::size_t i1 = 0;i1(v);++i1) - for(std::size_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1), ref[i0+i1*kwk::dim<0>(v)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*4]); }, v); std::vector const cref = {1,2,3,4,5,6,7,8,9,10,11,12}; @@ -97,9 +85,7 @@ TTS_CASE( "Build a 2D view with constexpr shape settings from a ContiguousRange" TTS_EQUAL ( w.shape(), kwk::of_size(3,4)); TTS_EXPECT( w.shape().is_fully_static ); - for(std::size_t i1 = 0;i1(w);++i1) - for(std::size_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1), ref[i0+i1*kwk::dim<0>(w)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*3]); }, w); }; @@ -116,9 +102,7 @@ TTS_CASE( "Build a 2D view with constexpr shape settings from a pointer" ) TTS_EQUAL ( v.shape(), kwk::of_size(4,3)); TTS_EXPECT( v.shape().is_fully_static ); - for(std::size_t i1 = 0;i1(v);++i1) - for(std::size_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1), ref[i0+i1*kwk::dim<0>(v)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*4]); }, v); std::vector const cref = {1,2,3,4,5,6,7,8,9,10,11,12}; @@ -129,7 +113,5 @@ TTS_CASE( "Build a 2D view with constexpr shape settings from a pointer" ) TTS_EQUAL ( w.shape(), kwk::of_size(3,4)); TTS_EXPECT( w.shape().is_fully_static ); - for(std::size_t i1 = 0;i1(w);++i1) - for(std::size_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1), ref[i0+i1*kwk::dim<0>(w)]); + kwk::for_each_index([&](auto e, auto i0, auto i1) { TTS_EQUAL(e, ref[i0+i1*3]); }, w); }; diff --git a/test/container/view/static.3d.cpp b/test/container/view/static.3d.cpp index 81d3aa4e..ef75a70c 100644 --- a/test/container/view/static.3d.cpp +++ b/test/container/view/static.3d.cpp @@ -2,8 +2,6 @@ /* KIWAKU - Containers Well Made Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 */ //================================================================================================== @@ -28,10 +26,9 @@ TTS_CASE( "Build a 3D view from a C array" ) TTS_EQUAL ( v.shape(), kwk::of_size(4,3,2)); TTS_EXPECT( v.shape().is_fully_static ); - for(std::size_t i2 = 0;i2(v);++i2) - for(std::size_t i1 = 0;i1(v);++i1) - for(std::size_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) { TTS_EQUAL(e, ref[i0+4*(i1+i2*3)]); } + , v + ); auto w = kwk::view{ kwk::source = ref, kwk::of_size(3_c, 4_c, 2_c) }; @@ -40,10 +37,9 @@ TTS_CASE( "Build a 3D view from a C array" ) TTS_EQUAL ( w.shape(), kwk::of_size(3,4,2)); TTS_EXPECT( w.shape().is_fully_static ); - for(std::size_t i2 = 0;i2(w);++i2) - for(std::size_t i1 = 0;i1(w);++i1) - for(std::size_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) { TTS_EQUAL(e, ref[i0+3*(i1+i2*4)]); } + , w + ); }; TTS_CASE( "Build a 3D view from std::array" ) @@ -61,10 +57,9 @@ TTS_CASE( "Build a 3D view from std::array" ) TTS_EQUAL ( v.shape(), kwk::of_size(4,3,2)); TTS_EXPECT( v.shape().is_fully_static ); - for(std::size_t i2 = 0;i2(v);++i2) - for(std::size_t i1 = 0;i1(v);++i1) - for(std::size_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) { TTS_EQUAL(e, ref[i0+4*(i1+i2*3)]); } + , v + ); auto w = kwk::view{ kwk::source = ref, kwk::of_size(3_c, 4_c, 2_c) }; @@ -73,10 +68,9 @@ TTS_CASE( "Build a 3D view from std::array" ) TTS_EQUAL ( w.shape(), kwk::of_size(3,4,2)); TTS_EXPECT( w.shape().is_fully_static ); - for(std::size_t i2 = 0;i2(w);++i2) - for(std::size_t i1 = 0;i1(w);++i1) - for(std::size_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) { TTS_EQUAL(e, ref[i0+3*(i1+i2*4)]); } + , w + ); }; TTS_CASE( "Build a 3D view with constexpr shape settings from a ContiguousRange" ) @@ -94,10 +88,9 @@ TTS_CASE( "Build a 3D view with constexpr shape settings from a ContiguousRange" TTS_EQUAL ( v.shape(), kwk::of_size(4,3,2)); TTS_EXPECT( v.shape().is_fully_static ); - for(std::size_t i2 = 0;i2(v);++i2) - for(std::size_t i1 = 0;i1(v);++i1) - for(std::size_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) { TTS_EQUAL(e, ref[i0+4*(i1+i2*3)]); } + , v + ); auto w = kwk::view{ kwk::source = ref, kwk::of_size(3_c, 4_c, 2_c) }; @@ -106,10 +99,9 @@ TTS_CASE( "Build a 3D view with constexpr shape settings from a ContiguousRange" TTS_EQUAL ( w.shape(), kwk::of_size(3,4,2)); TTS_EXPECT( w.shape().is_fully_static ); - for(std::size_t i2 = 0;i2(w);++i2) - for(std::size_t i1 = 0;i1(w);++i1) - for(std::size_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) { TTS_EQUAL(e, ref[i0+3*(i1+i2*4)]); } + , w + ); }; @@ -128,10 +120,9 @@ TTS_CASE( "Build a 3D view with constexpr shape settings from a pointer" ) TTS_EQUAL ( v.shape(), kwk::of_size(4,3,2)); TTS_EXPECT( v.shape().is_fully_static ); - for(std::size_t i2 = 0;i2(v);++i2) - for(std::size_t i1 = 0;i1(v);++i1) - for(std::size_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) { TTS_EQUAL(e, ref[i0+4*(i1+i2*3)]); } + , v + ); auto w = kwk::view{ kwk::source = ref, kwk::of_size(3_c, 4_c, 2_c) }; @@ -140,8 +131,7 @@ TTS_CASE( "Build a 3D view with constexpr shape settings from a pointer" ) TTS_EQUAL ( w.shape(), kwk::of_size(3,4,2)); TTS_EXPECT( w.shape().is_fully_static ); - for(std::size_t i2 = 0;i2(w);++i2) - for(std::size_t i1 = 0;i1(w);++i1) - for(std::size_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*i2)]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2) { TTS_EQUAL(e, ref[i0+3*(i1+i2*4)]); } + , w + ); }; diff --git a/test/container/view/static.4d.cpp b/test/container/view/static.4d.cpp index 624589ad..c1c3c463 100644 --- a/test/container/view/static.4d.cpp +++ b/test/container/view/static.4d.cpp @@ -2,8 +2,6 @@ /* KIWAKU - Containers Well Made Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 */ //================================================================================================== @@ -30,11 +28,12 @@ TTS_CASE( "Build a 4D view from a C array" ) TTS_EQUAL ( v.shape(), kwk::of_size(2,3,2,2)); TTS_EXPECT( v.shape().is_fully_static ); - for(std::size_t i3 = 0;i3(v);++i3) - for(std::size_t i2 = 0;i2(v);++i2) - for(std::size_t i1 = 0;i1(v);++i1) - for(std::size_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2,i3), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*(i2+kwk::dim<2>(v)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+2*(i1+3*(i2+2*i3))]); + } + , v + ); auto w = kwk::view{ kwk::source = ref , kwk::of_size(3_c, 2_c, 2_c, 2_c) @@ -45,11 +44,12 @@ TTS_CASE( "Build a 4D view from a C array" ) TTS_EQUAL ( w.shape(), kwk::of_size(3,2,2,2)); TTS_EXPECT( w.shape().is_fully_static ); - for(std::size_t i3 = 0;i3(w);++i3) - for(std::size_t i2 = 0;i2(w);++i2) - for(std::size_t i1 = 0;i1(w);++i1) - for(std::size_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2,i3), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*(i2+kwk::dim<2>(w)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+3*(i1+2*(i2+2*i3))]); + } + , w + ); }; TTS_CASE( "Build a 4D view from std::array" ) @@ -70,11 +70,12 @@ TTS_CASE( "Build a 4D view from std::array" ) TTS_EQUAL ( v.shape(), kwk::of_size(2,3,2,2)); TTS_EXPECT( v.shape().is_fully_static ); - for(std::size_t i3 = 0;i3(v);++i3) - for(std::size_t i2 = 0;i2(v);++i2) - for(std::size_t i1 = 0;i1(v);++i1) - for(std::size_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2,i3), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*(i2+kwk::dim<2>(v)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+2*(i1+3*(i2+2*i3))]); + } + , v + ); auto w = kwk::view{ kwk::source = ref , kwk::of_size(3_c, 2_c, 2_c, 2_c) @@ -85,11 +86,12 @@ TTS_CASE( "Build a 4D view from std::array" ) TTS_EQUAL ( w.shape(), kwk::of_size(3,2,2,2)); TTS_EXPECT( w.shape().is_fully_static ); - for(std::size_t i3 = 0;i3(w);++i3) - for(std::size_t i2 = 0;i2(w);++i2) - for(std::size_t i1 = 0;i1(w);++i1) - for(std::size_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2,i3), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*(i2+kwk::dim<2>(w)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+3*(i1+2*(i2+2*i3))]); + } + , w + ); }; TTS_CASE( "Build a 4D view with constexpr shape settings from a ContiguousRange" ) @@ -110,11 +112,12 @@ TTS_CASE( "Build a 4D view with constexpr shape settings from a ContiguousRange" TTS_EQUAL ( v.shape(), kwk::of_size(2,3,2,2)); TTS_EXPECT( v.shape().is_fully_static ); - for(std::size_t i3 = 0;i3(v);++i3) - for(std::size_t i2 = 0;i2(v);++i2) - for(std::size_t i1 = 0;i1(v);++i1) - for(std::size_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2,i3), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*(i2+kwk::dim<2>(v)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+2*(i1+3*(i2+2*i3))]); + } + , v + ); auto w = kwk::view{ kwk::source = ref , kwk::of_size(3_c, 2_c, 2_c, 2_c) @@ -125,11 +128,12 @@ TTS_CASE( "Build a 4D view with constexpr shape settings from a ContiguousRange" TTS_EQUAL ( w.shape(), kwk::of_size(3,2,2,2)); TTS_EXPECT( w.shape().is_fully_static ); - for(std::size_t i3 = 0;i3(w);++i3) - for(std::size_t i2 = 0;i2(w);++i2) - for(std::size_t i1 = 0;i1(w);++i1) - for(std::size_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2,i3), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*(i2+kwk::dim<2>(w)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+3*(i1+2*(i2+2*i3))]); + } + , w + ); }; @@ -151,11 +155,12 @@ TTS_CASE( "Build a 4D view with constexpr shape settings from a pointer" ) TTS_EQUAL ( v.shape(), kwk::of_size(2,3,2,2)); TTS_EXPECT( v.shape().is_fully_static ); - for(std::size_t i3 = 0;i3(v);++i3) - for(std::size_t i2 = 0;i2(v);++i2) - for(std::size_t i1 = 0;i1(v);++i1) - for(std::size_t i0 = 0;i0(v);++i0) - TTS_EQUAL(v(i0,i1,i2,i3), ref[i0+kwk::dim<0>(v)*(i1+kwk::dim<1>(v)*(i2+kwk::dim<2>(v)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+2*(i1+3*(i2+2*i3))]); + } + , v + ); auto w = kwk::view{ kwk::source = ref , kwk::of_size(3_c, 2_c, 2_c, 2_c) @@ -166,9 +171,10 @@ TTS_CASE( "Build a 4D view with constexpr shape settings from a pointer" ) TTS_EQUAL ( w.shape(), kwk::of_size(3,2,2,2)); TTS_EXPECT( w.shape().is_fully_static ); - for(std::size_t i3 = 0;i3(w);++i3) - for(std::size_t i2 = 0;i2(w);++i2) - for(std::size_t i1 = 0;i1(w);++i1) - for(std::size_t i0 = 0;i0(w);++i0) - TTS_EQUAL(w(i0,i1,i2,i3), ref[i0+kwk::dim<0>(w)*(i1+kwk::dim<1>(w)*(i2+kwk::dim<2>(w)*i3))]); + kwk::for_each_index([&](auto e, auto i0, auto i1, auto i2, auto i3) + { + TTS_EQUAL(e, ref[i0+3*(i1+2*(i2+2*i3))]); + } + , w + ); }; diff --git a/test/docs/shape/odd_sized.cpp b/test/docs/shape/odd_sized.cpp index 7b96fc0c..465a354e 100644 --- a/test/docs/shape/odd_sized.cpp +++ b/test/docs/shape/odd_sized.cpp @@ -15,6 +15,6 @@ int main() std::cout << x << "\n"; // y will contains 7 x 1 x 1 - kwk::shape< kwk::_3D > y = kwk::of_size(7); + kwk::shape< kwk::_3D > y{kwk::of_size(7)}; std::cout << y << "\n"; } diff --git a/test/tts.hpp b/test/tts.hpp index 31bd3c94..01aee79c 100644 --- a/test/tts.hpp +++ b/test/tts.hpp @@ -2,9 +2,7 @@ /** TTS - Tiny Test System Copyright : TTS Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 + SPDX-License-Identifier: MIT **/ //================================================================================================== #pragma once @@ -135,7 +133,10 @@ namespace tts return global_runtime.report(fails,invalids); } } +#include +#include #include +#include #include #include namespace tts @@ -188,11 +189,38 @@ namespace tts { return value({f},that); } + bool is_valid() { return argc && argv != nullptr; } int argc; char const** argv; }; - inline ::tts::options arguments; - inline bool verbose_status; + namespace detail + { + inline ::tts::options current_arguments = {0,nullptr}; + inline std::int32_t current_seed = -1; + } + inline void initialize(int argc, const char** argv) + { + if(!detail::current_arguments.is_valid()) + detail::current_arguments = ::tts::options{argc,argv}; + } + inline ::tts::options const& arguments() + { + return detail::current_arguments; + } + inline std::int32_t random_seed(int base_seed = -1) + { + if(detail::current_seed == -1) + { + auto s = ::tts::arguments().value( "--seed", base_seed ); + if(s == -1 ) + { + auto now = std::chrono::high_resolution_clock::now(); + s = static_cast(now.time_since_epoch().count()); + } + detail::current_seed = s; + } + return detail::current_seed; + } } #if !defined(TTS_CUSTOM_DRIVER_FUNCTION) # define TTS_CUSTOM_DRIVER_FUNCTION main @@ -204,10 +232,9 @@ namespace tts::detail { struct fatal_signal {}; } #if defined(TTS_MAIN) int TTS_CUSTOM_DRIVER_FUNCTION([[maybe_unused]] int argc,[[maybe_unused]] char const** argv) { - ::tts::arguments = ::tts::options{argc,argv}; - if( ::tts::arguments[{"-h","--help"}] ) + ::tts::initialize(argc,argv); + if( ::tts::arguments()[{"-h","--help"}] ) return ::tts::usage(argv[0]); - ::tts::verbose_status = ::tts::arguments[{"-p","--pass"}]; auto nb_tests = ::tts::detail::suite.size(); std::size_t done_tests = 0; try @@ -239,6 +266,22 @@ int TTS_CUSTOM_DRIVER_FUNCTION([[maybe_unused]] int argc,[[maybe_unused]] char c else return 0; } #endif +#include +#include +#include +namespace tts +{ + template + concept support_std_to_string = requires(T e) { std::to_string(e); }; + template + concept support_to_string = requires(T e) { to_string(e); }; + template + concept has_to_string = requires(T e) { e.to_string(); }; + template + concept sequence = requires(T e) {std::begin(e); std::end(e); }; + template + concept streamable = requires(T e, std::ostream& o) { o << e; }; +} #ifndef TTS_FUNCTION #define TTS_FUNCTION TTS_UNIQUE(tts_function) #endif @@ -248,11 +291,33 @@ int TTS_CUSTOM_DRIVER_FUNCTION([[maybe_unused]] int argc,[[maybe_unused]] char c #define TTS_UNIQUE3(ID, LINE) ID##LINE #define TTS_UNIQUE2(ID, LINE) TTS_UNIQUE3(ID, LINE) #define TTS_UNIQUE(ID) TTS_UNIQUE2(ID, __COUNTER__) -#define TTS_CAT(x, y) TTS_CAT_I(x, y) -#define TTS_CAT_I(x, y) x##y +#define TTS_CAT(x, y) TTS_CAT_I(x, y) +#define TTS_CAT_I(x, y) x##y #define TTS_STRING(...) TTS_STRING_((__VA_ARGS__)) #define TTS_STRING__(...) #__VA_ARGS__ #define TTS_STRING_(TXT) TTS_STRING__ TXT +#define TTS_COUNT(...) TTS_COUNT_(__VA_ARGS__, 7, 6, 5, 4, 3, 2, 1, 0) +#define TTS_COUNT_(A0, A1, A2, A3, A4, A5, A6, A7, ...) A7 +#define TTS_ARG0() +#define TTS_ARG1(A0) auto&& A0 +#define TTS_ARG2(A0, A1) auto&& A0, auto&& A1 +#define TTS_ARG3(A0, A1, A2) TTS_ARG2(A0, A1) , auto&& A2 +#define TTS_ARG4(A0, A1, A2, A3) TTS_ARG3(A0, A1, A2) , auto&& A3 +#define TTS_ARG5(A0, A1, A2, A3, A4) TTS_ARG4(A0, A1, A2, A3) , auto&& A4 +#define TTS_ARG6(A0, A1, A2, A3, A4, A5) TTS_ARG5(A0, A1, A2, A3, A4) , auto&& A5 +#define TTS_ARG7(A0, A1, A2, A3, A4, A5, A6) TTS_ARG6(A0, A1, A2, A3, A4, A5), auto&& A6 +#define TTS_ARG(...) TTS_CAT(TTS_ARG, TTS_COUNT(__VA_ARGS__))(__VA_ARGS__) +#define TTS_VAL(x) x +#define TTS_REVERSE_1(a) (a) +#define TTS_REVERSE_2(a,b) (b, a) +#define TTS_REVERSE_3(a,b,c) (c, b, a) +#define TTS_REVERSE_4(a,b,c,d) (d, c, b, a) +#define TTS_REVERSE_5(a,b,c,d,e) (e, d, c, b, a) +#define TTS_REVERSE_6(a,b,c,d,e,f) (f, e, d, c, b, a) +#define TTS_REVERSE_7(a,b,c,d,e,f,g) (g, f, e, d, c, b, a) +#define TTS_REVERSE_IMPL(N,...) TTS_VAL(TTS_REVERSE_ ## N(__VA_ARGS__)) +#define TTS_REVERSE_(N,...) TTS_REVERSE_IMPL( N, __VA_ARGS__) +#define TTS_REVERSE(...) TTS_REVERSE_( TTS_COUNT(__VA_ARGS__), __VA_ARGS__) #define TTS_REMOVE_PARENS(x) TTS_EVAL((TTS_REMOVE_PARENS_I x), x) #define TTS_REMOVE_PARENS_I(...) 1, 1 #define TTS_APPLY(macro, args) TTS_APPLY_I(macro, args) @@ -294,6 +359,7 @@ namespace tts template inline auto const typename_ = detail::typename_impl::value(); template constexpr auto name(T const&){ return typename_; } } +#include namespace tts { template @@ -308,8 +374,10 @@ namespace tts using int_types = types < std::int64_t , std::int32_t , std::int16_t , std::int8_t>; using signed_types = concatenate_t; using uint_types = types < std::uint64_t , std::uint32_t , std::uint16_t , std::uint8_t>; + using integral_types = concatenate_t; using arithmetic_types = concatenate_t; } +#include namespace tts::detail { struct test_capture @@ -347,11 +415,59 @@ namespace tts::detail struct test_captures : test_captures {}; } +namespace tts::detail +{ + template struct test_generators + { + test_generators(const char* id, Generator g, Types...) : name(id), generator(g) {} + friend auto operator<<(test_generators tg, auto body) + { + return test::acknowledge( { tg.name + , [tg,body]() mutable + { + std::mt19937 gen(::tts::random_seed()); + ( ( (current_type = " with [T = " + typename_ + "]") + , std::apply(body, tg.generator(type{}, gen)) + ), ... + ); + current_type.clear(); + } + } + ); + } + std::string name; + Generator generator; + }; + template + test_generators(const char*,Generator,Types...) -> test_generators; + template + struct test_generators> + : test_generators + { + using parent = test_generators; + test_generators(const char* id, Generator g, types) : parent(id,g,Types{}...) {} + }; + template + requires requires(TypeGenerator g) { typename TypeGenerator::types_list; } + struct test_generators + : test_generators + { + using parent = test_generators; + test_generators ( const char* id, Generator g, TypeGenerator ) + : parent(id,g,typename TypeGenerator::types_list{}) {} + }; +} +#define TTS_PROTOTYPE(...) [] __VA_ARGS__ #define TTS_CASE(ID) \ -static bool const TTS_CAT(case_,TTS_FUNCTION) = ::tts::detail::test_capture{ID} + []() \ +static bool const TTS_CAT(case_,TTS_FUNCTION) = ::tts::detail::test_capture{ID} + TTS_PROTOTYPE(()) \ #define TTS_CASE_TPL(ID,...) \ -static bool const TTS_CAT(case_,TTS_FUNCTION) = ::tts::detail::test_captures<__VA_ARGS__>{ID} + [] \ +static bool const TTS_CAT(case_,TTS_FUNCTION) = ::tts::detail::test_captures<__VA_ARGS__>{ID} \ + + TTS_PROTOTYPE() \ + +#define TTS_CASE_WITH(ID, TYPES, GENERATOR) \ +static bool const TTS_CAT(case_,TTS_FUNCTION) \ + = ::tts::detail::test_generators{ID,GENERATOR,TYPES{}} << TTS_PROTOTYPE() \ #include #include @@ -384,6 +500,11 @@ namespace tts int line_{}; }; } +#define TTS_PASS(Message) \ + [&]() \ + { \ + ::tts::global_runtime.pass(); \ + }() #define TTS_FAIL(Message) \ [&]() \ { \ @@ -391,7 +512,7 @@ namespace tts if(!::tts::global_runtime.fail_status) \ { \ ::tts::global_runtime.fail_status = true; \ - std::cout << "[X] - " << ::tts::detail::current_test<< "\n"; \ + std::cout << "[X] - " << ::tts::detail::current_test << "\n"; \ } \ if( !::tts::detail::current_type.empty()) \ { \ @@ -474,24 +595,328 @@ namespace tts } \ }(EXPR) \ -#define TTS_CONSTEXPR_EXPECT(EXPR) \ -[](C ) \ +#define TTS_CONSTEXPR_EXPECT(EXPR, ...) TTS_CEXPR_EXPECT_ ## __VA_ARGS__ ( EXPR ) +#define TTS_CEXPR_EXPECT_(EXPR) TTS_CEXPR_EXPECT_IMPL(EXPR,TTS_FAIL) +#define TTS_CEXPR_EXPECT_REQUIRED(EXPR) TTS_CEXPR_EXPECT_IMPL(EXPR,TTS_FATAL) +#define TTS_CEXPR_EXPECT_IMPL(EXPR,FAILURE) \ +[&]() \ { \ - static_assert ( C::value \ - , "[TTS] - Error: " TTS_STRING(EXPR) " evaluates to false at compile-time." \ - ); \ - ::tts::global_runtime.pass(); \ -}(std::bool_constant{}) \ + using result_tts = std::bool_constant; \ + if constexpr( result_tts::value ) \ + { \ + ::tts::global_runtime.pass(); return ::tts::logger{false}; \ + } \ + else \ + { \ + FAILURE ( "Expression: " << TTS_STRING(EXPR) << " evaluates to true." ); \ + return ::tts::logger{}; \ + } \ +}() \ -#define TTS_CONSTEXPR_EXPECT_NOT(EXPR) \ -[](C ) \ +#define TTS_CONSTEXPR_EXPECT_NOT(EXPR, ...) TTS_CEXPR_EXPECT_NOT_ ## __VA_ARGS__ ( EXPR ) +#define TTS_CEXPR_EXPECT_NOT_(EXPR) TTS_CEXPR_EXPECT_NOT_IMPL(EXPR,TTS_FAIL) +#define TTS_CEXPR_EXPECT_NOT_REQUIRED(EXPR) TTS_CEXPR_EXPECT_NOT_IMPL(EXPR,TTS_FATAL) +#define TTS_CEXPR_EXPECT_NOT_IMPL(EXPR,FAILURE) \ +[&]() \ { \ - static_assert ( !C::value \ - , "[TTS] - Error: " TTS_STRING(EXPR) " evaluates to true at compile-time." \ - ); \ - ::tts::global_runtime.pass(); \ -}(std::bool_constant{}) \ + using result_tts = std::bool_constant; \ + if constexpr( !result_tts::value ) \ + { \ + ::tts::global_runtime.pass(); return ::tts::logger{false}; \ + } \ + else \ + { \ + FAILURE ( "Expression: " << TTS_STRING(EXPR) << " evaluates to true." ); \ + return ::tts::logger{}; \ + } \ +}() \ +#include +#include +namespace tts::detail +{ + template + struct block + { + block() : nbelems{0} {} + block(std::size_t sz) : storage{} ,nbelems{sz} {} + std::size_t size() const { return nbelems; } + std::size_t capacity() const { return N; } + std::size_t empty() const { return nbelems == 0; } + void resize(std::size_t n) { nbelems = n; } + void push_back(T v) { storage[nbelems] = v; nbelems++; } + void push_front(T v) { insert(begin(),v); } + void insert(auto it, T v) + { + std::memmove(it+1, it, size()*sizeof(T)); + *it = v; + nbelems++; + } + void clear() { nbelems = 0; } + T& back() { return storage[size()-1]; } + T back() const { return storage[size()-1]; } + T& front() { return storage[0]; } + T front() const { return storage[0]; } + T& operator[](std::size_t i) { return storage[i]; } + T operator[](std::size_t i) const { return storage[i]; } + auto begin() { return &storage[0]; } + auto end() { return begin() + nbelems; } + auto begin() const { return &storage[0]; } + auto end() const { return begin() + nbelems; } + private: + std::array storage; + std::size_t nbelems; + }; +} +#include +#include +#include +#include +#include +namespace tts +{ + template + struct fp_dist + { + using result_type = T; + struct param_type + { + param_type( T pa = 0, T pb = 1 + , std::size_t sz = 65536 + , T mnp = std::numeric_limits::epsilon() + , T mxp = 1./std::numeric_limits::epsilon() + ) + : a(pa), b(pb), n(sz), minpos(mnp), maxpos(mxp) + { + if(b0 && a < minpos) a = minpos; + if(b > maxpos) b = maxpos; + else if(b<0 && b < -minpos) b = -minpos; + } + T a, b; + std::size_t n; + T minpos, maxpos; + }; + fp_dist() noexcept : fp_dist(param_type{}) {} + fp_dist(T a, T b) noexcept : fp_dist(param_type{a,b}) {} + fp_dist(T a, T b, std::size_t n) noexcept : fp_dist(param_type{a,b,n}) {} + fp_dist(T a, T b, std::size_t n, T mn ) noexcept : fp_dist(param_type{a,b,n,mn}) {} + fp_dist(T a, T b, std::size_t n, T mn, T mx) noexcept : fp_dist(param_type{a,b,n,mn,mx}) {} + fp_dist(param_type const& pr) noexcept { param(pr); } + param_type const& param() const { return params; } + void param(param_type const& p) + { + params = p; + find_limits(); + find_indexes(1+params.minpos/2); + selector.param( std::uniform_int_distribution::param_type(0, size()-1)); + } + auto size() const noexcept { return sizes.back(); } + auto min() const noexcept { return params.a; } + auto max() const noexcept { return params.b; } + template< class Generator > result_type operator()( Generator& gen ) + { + auto p = selector(gen); + auto it = std::upper_bound(sizes.begin(), sizes.end(), p) - 1; + auto i = std::distance(sizes.begin(),it); + return generate(limits[i],limits[i+1],p - *it,params.n); + } + tts::detail::block limits; + tts::detail::block sizes; + std::uniform_int_distribution selector; + param_type params; + private: + void find_limits() noexcept + { + limits.clear(); + std::array zs{-params.maxpos,-1,-params.minpos,0,params.minpos,1,params.maxpos}; + for(auto z : zs) + { + if(z>=params.a && z<=params.b) limits.push_back(z); + } + if(limits.empty()) { limits.push_back(params.a); limits.push_back(params.b);} + else + { + if(limits.front() > params.a) { limits.push_front(params.a); } + if(limits.back() < params.b) { limits.push_back(params.b); } + } + } + void find_indexes(std::size_t nbzero) noexcept + { + sizes.resize(limits.size()); + std::size_t t = 0; + sizes[0] = 0; + for(std::size_t i=1;i double + { + if(x<1) return 1./std::exp2(std::lerp(std::log2(1./y), std::log2(1./x), i/sz)); + else return std::exp2(std::lerp(std::log2(x) , std::log2(y) , i/sz)); + }; + if(va==0 || vb==0) return 0.; + auto f = va<0 ? -1 : 1; + return f * eval(f * va, f * vb,p,n-1); + } + }; + template + struct char_dist + : std::uniform_int_distribution < std::conditional_t< std::is_signed_v + , short + , unsigned short + > > + { + using parent = std::uniform_int_distribution< std::conditional_t + , short + , unsigned short + > + >; + using result_type = T; + using parent::parent; + template< class Generator > result_type operator()( Generator& gen ) + { + return static_cast(parent::operator()(gen)); + } + }; + template + struct choose_distribution; + template + requires(sizeof(T) > 1) + struct choose_distribution + { + using type = std::uniform_int_distribution; + }; + template + requires(sizeof(T) == 1) + struct choose_distribution + { + using type = char_dist; + }; + template + struct choose_distribution + { + using type = fp_dist; + }; + template + using realistic_distribution = typename choose_distribution::type; +} +#include +namespace tts +{ + template auto as_value(V const& v) { return static_cast(v); } + template auto produce(type const& t, auto g, auto& rng, auto... others) + { + return g(t,rng, others...); + } + template inline auto generate(G... g) + { + return [=](auto const& t, auto& rng, auto... others) + { + return std::make_tuple(produce(t,g,rng,others...)...); + }; + } + template struct rebuild; + template class Seq, typename T, typename... S, typename U> + struct rebuild,U> { using type = Seq; }; + template class Seq, typename T, std::size_t N, typename U> + struct rebuild,U> { using type = Seq; }; + template + auto produce(type const&, auto g, auto& rng, auto... args) + { + using elmt_type = std::remove_cvref_t()))>; + using value_type = decltype(g(tts::type{},rng,0,0ULL,args...)); + typename rebuild::type that; + auto b = std::begin(that); + auto e = std::end(that); + auto sz = e - b; + for(std::ptrdiff_t i=0;i(g(tts::type{},rng,i,sz,args...)); + } + return that; + } + template struct value + { + value(T v) : seed(v) {} + template + auto operator()(tts::type, auto&, auto...) const + { + return as_value(seed); + } + T seed; + }; + template struct ramp + { + ramp(T s) : start(s), step(1) {} + ramp(T s, U st) : start(s), step(st) {} + template + auto operator()(tts::type, auto&) const { return as_value(start); } + template + auto operator()(tts::type, auto&, auto idx, auto...) const + { + return as_value(start+idx*step); + } + T start; + U step; + }; + template struct reverse_ramp + { + reverse_ramp(T s) : start(s), step(1) {} + reverse_ramp(T s, U st) : start(s), step(st) {} + template + auto operator()(tts::type, auto&) const { return as_value(start); } + template + auto operator()(tts::type, auto&, auto idx, auto sz, auto...) const + { + return as_value(start+(sz-1-idx)*step); + } + T start; + U step; + }; + template struct between + { + between(T s, U st) : first(s), last(st) {} + template + auto operator()(tts::type, auto&) const { return as_value(first); } + template + auto operator()(tts::type, auto&, auto idx, auto sz, auto...) const + { + auto w1 = as_value(first); + auto w2 = as_value(last); + auto step = (sz-1) ? (w2-w1)/(sz-1) : 0; + return std::min( as_value(w1 + idx*step), w2); + } + T first; + U last; + }; + template struct sample + { + sample(Distribution d) : dist(std::move(d)) {} + template auto operator()(tts::type, auto& rng, auto...) + { + return dist(rng); + } + Distribution dist; + }; + template struct randoms + { + randoms(Mn mn, Mx mx) : mini(mn), maxi(mx) {} + template auto operator()(tts::type, auto& rng, auto...) + { + tts::realistic_distribution dist(as_value(mini), as_value(maxi)); + return dist(rng); + } + Mn mini; + Mx maxi; + }; +} namespace tts::detail { template @@ -530,29 +955,19 @@ namespace tts::detail #include namespace tts { - template - concept support_std_to_string = requires(T e) { std::to_string(e); }; - template - concept support_to_string = requires(T e) { to_string(e); }; - template - concept has_to_string = requires(T e) { e.to_string(); }; - template - concept sequence = requires(T e) {std::begin(e); std::end(e); }; - template - concept streamable = requires(T e, std::ostream& o) { o << e; }; template std::string as_string(T const& e) { if constexpr( std::is_pointer_v ) { std::ostringstream os; - os << std::string(typename_) << "(" << e << ")"; + os << typename_ << "(" << (void*)(e) << ")"; return os.str(); } else if constexpr( std::floating_point ) { - auto precision = ::tts::arguments.value({"--precision"}, -1); - bool hexmode = ::tts::arguments[{"-x","--hex"}]; - bool scimode = ::tts::arguments[{"-s","--scientific"}]; + auto precision = ::tts::arguments().value({"--precision"}, -1); + bool hexmode = ::tts::arguments()[{"-x","--hex"}]; + bool scimode = ::tts::arguments()[{"-s","--scientific"}]; std::ostringstream os; if(precision != -1 ) os << std::setprecision(precision); if(hexmode) os << std::hexfloat << e << std::defaultfloat; @@ -560,20 +975,27 @@ namespace tts else os << e; return os.str(); } + else if constexpr( support_std_to_string ) + { + return std::to_string(e); + } else if constexpr( streamable ) { std::ostringstream os; + auto precision = ::tts::arguments().value({"--precision"}, -1); + bool hexmode = ::tts::arguments()[{"-x","--hex"}]; + bool scimode = ::tts::arguments()[{"-s","--scientific"}]; + if(precision != -1 ) os << std::setprecision(precision); + if(hexmode) os << std::hexfloat; + else if(scimode) os << std::scientific << e << std::defaultfloat; os << e; + if(hexmode || scimode) os << std::defaultfloat; return os.str(); } else if constexpr( support_to_string ) { return to_string(e); } - else if constexpr( support_std_to_string ) - { - return std::to_string(e); - } else if constexpr( sequence ) { std::string that = "{ "; @@ -584,7 +1006,7 @@ namespace tts else { std::ostringstream os; - os << "[" << std::string(typename_) << "]@(" << &e << ")"; + os << "[" << typename_ << "]@(" << &e << ")"; return os.str(); } } @@ -592,74 +1014,195 @@ namespace tts inline std::string as_string(std::string const& e) { return e; } inline std::string as_string(std::string_view const& e) { return std::string(e); } inline std::string as_string(std::nullptr_t) { return std::string("nullptr"); } - inline std::string as_string(const char* e) - { - std::ostringstream os; - os << "char*(" << (void*)e << ")"; - return os.str(); - } - inline std::string as_string(char* e ) - { - std::ostringstream os; - os << "char*(" << (void*)e << ")"; - return os.str(); - } } -#define TTS_RELATION(A, B, OP, T, F, ...) TTS_RELATION_ ## __VA_ARGS__ (A,B,OP,T,F) +#define TTS_RELATION_BASE(A, B, OP, T, F, FAILURE) \ +if( ::tts::detail::OP(a,b) ) \ +{ \ + ::tts::global_runtime.pass(); return ::tts::logger{false}; \ +} \ +else \ +{ \ + FAILURE ( "Expression: " << TTS_STRING(A) << " " T " " << TTS_STRING(B) \ + << " is false because: " << ::tts::as_string(a) << " " F " " << ::tts::as_string(b) \ + ); \ + return ::tts::logger{}; \ +} \ + +#define TTS_CEXPR_RELATION_BASE(A, B, OP, T, F, FAILURE) \ +using result_tts = std::bool_constant<::tts::detail::OP(A,B)>; \ +if constexpr( result_tts::value ) \ +{ \ + ::tts::global_runtime.pass(); return ::tts::logger{false}; \ +} \ +else \ +{ \ + FAILURE ( "Expression: " << TTS_STRING(A) << " " << T << " " << TTS_STRING(B) \ + << " is false because: " \ + << ::tts::as_string(a) << " " << F << " " << ::tts::as_string(b) \ + ); \ + return ::tts::logger{}; \ +} \ + +#define TTS_RELATION(A, B, OP, T, F, ...) TTS_RELATION_ ## __VA_ARGS__ (A,B,OP,T,F) #define TTS_RELATION_(A, B, OP, T, F) TTS_RELATION_IMPL(A,B,OP,T,F,TTS_FAIL) #define TTS_RELATION_REQUIRED(A, B, OP, T, F) TTS_RELATION_IMPL(A,B,OP,T,F,TTS_FATAL) #define TTS_RELATION_IMPL(A, B, OP, T, F, FAILURE) \ [&](auto&& a, auto&& b) \ { \ - if( ::tts::detail::OP(a,b) ) \ + TTS_RELATION_BASE(A, B, OP, T, F, FAILURE) \ +}(A,B) \ + +#define TTS_EQUAL(LHS, RHS, ...) TTS_RELATION(LHS,RHS, eq , "==" , "!=" , __VA_ARGS__) +#define TTS_NOT_EQUAL(LHS, RHS, ...) TTS_RELATION(LHS,RHS, neq, "!=" , "==" , __VA_ARGS__) +#define TTS_LESS(LHS, RHS, ...) TTS_RELATION(LHS,RHS, lt , "<" , ">=" , __VA_ARGS__) +#define TTS_GREATER(LHS, RHS, ...) TTS_RELATION(LHS,RHS, gt , ">" , "<=" , __VA_ARGS__) +#define TTS_LESS_EQUAL(LHS, RHS, ...) TTS_RELATION(LHS,RHS, le , "<=" , ">" , __VA_ARGS__) +#define TTS_GREATER_EQUAL(LHS, RHS, ...) TTS_RELATION(LHS,RHS, ge , ">=" , "<=" , __VA_ARGS__) +#define TTS_CEXPR_RELATION(A, B, OP, T, F, ...) TTS_CEXPR_RELATION_ ## __VA_ARGS__ (A,B,OP,T,F) +#define TTS_CEXPR_RELATION_(A, B, OP, T, F) TTS_CEXPR_RELATION_IMPL(A,B,OP,T,F,TTS_FAIL) +#define TTS_CEXPR_RELATION_REQUIRED(A, B, OP, T, F) TTS_CEXPR_RELATION_IMPL(A,B,OP,T,F,TTS_FATAL) +#define TTS_CEXPR_RELATION_IMPL(A, B, OP, T, F, FAILURE) \ +[&](auto&& a, auto&& b) \ +{ \ + TTS_CEXPR_RELATION_BASE(A, B, OP, T, F, FAILURE) \ +}(A,B) \ + +#define TTS_CONSTEXPR_EQUAL(LHS, RHS, ...) TTS_CEXPR_RELATION(LHS,RHS, eq , "==" , "!=", __VA_ARGS__) +#define TTS_CONSTEXPR_NOT_EQUAL(LHS, RHS, ...) TTS_CEXPR_RELATION(LHS,RHS, neq, "!=" , "==", __VA_ARGS__) +#define TTS_CONSTEXPR_LESS(LHS, RHS, ...) TTS_CEXPR_RELATION(LHS,RHS, lt , "<" , ">=", __VA_ARGS__) +#define TTS_CONSTEXPR_GREATER(LHS, RHS, ...) TTS_CEXPR_RELATION(LHS,RHS, gt , ">" , "<=", __VA_ARGS__) +#define TTS_CONSTEXPR_LESS_EQUAL(LHS, RHS, ...) TTS_CEXPR_RELATION(LHS,RHS, le , "<=" , ">" , __VA_ARGS__) +#define TTS_CONSTEXPR_GREATER_EQUAL(LHS, RHS, ...) TTS_CEXPR_RELATION(LHS,RHS, ge , ">=" , "<=", __VA_ARGS__) +#define TTS_TYPED_RELATION(A, B, OP, T, F, ...) TTS_TYPED_RELATION_ ## __VA_ARGS__ (A,B,OP,T,F) +#define TTS_TYPED_RELATION_(A, B, OP, T, F) TTS_TYPED_RELATION_IMPL(A,B,OP,T,F,TTS_FAIL) +#define TTS_TYPED_RELATION_REQUIRED(A, B, OP, T, F) TTS_TYPED_RELATION_IMPL(A,B,OP,T,F,TTS_FATAL) +#define TTS_TYPED_RELATION_IMPL(A, B, OP, T, F, FAILURE) \ +[&](auto&& a, auto&& b) \ +{ \ + using type_a = std::remove_cvref_t; \ + using type_b = std::remove_cvref_t; \ + \ + if constexpr( !std::same_as ) \ + { \ + FAILURE ( "Expression: " << TTS_STRING(A) << " " T " " << TTS_STRING(B) \ + << " is false because: " << ::tts::typename_ << " is not " \ + << ::tts::typename_ \ + ); \ + return ::tts::logger{}; \ + } \ + else \ + { \ + TTS_RELATION_BASE(A, B, OP, T, F, FAILURE) \ + } \ +}(A,B) \ + +#define TTS_TYPED_EQUAL(LHS, RHS, ...) TTS_TYPED_RELATION(LHS,RHS, eq , "==" , "!=" , __VA_ARGS__) +#define TTS_TYPED_NOT_EQUAL(LHS, RHS, ...) TTS_TYPED_RELATION(LHS,RHS, neq, "!=" , "==" , __VA_ARGS__) +#define TTS_TYPED_LESS(LHS, RHS, ...) TTS_TYPED_RELATION(LHS,RHS, lt , "<" , ">=" , __VA_ARGS__) +#define TTS_TYPED_GREATER(LHS, RHS, ...) TTS_TYPED_RELATION(LHS,RHS, gt , ">" , "<=" , __VA_ARGS__) +#define TTS_TYPED_LESS_EQUAL(LHS, RHS, ...) TTS_TYPED_RELATION(LHS,RHS, le , "<=" , ">" , __VA_ARGS__) +#define TTS_TYPED_GREATER_EQUAL(LHS, RHS, ...) TTS_TYPED_RELATION(LHS,RHS, ge , ">=" , "<=" , __VA_ARGS__) +#define TTS_TYPED_CEXPR_RELATION(A, B, OP, T, F, ...) TTS_TYPED_CEXPR_RELATION_ ## __VA_ARGS__ (A,B,OP,T,F) +#define TTS_TYPED_CEXPR_RELATION_(A, B, OP, T, F) TTS_TYPED_CEXPR_RELATION_IMPL(A,B,OP,T,F,TTS_FAIL) +#define TTS_TYPED_CEXPR_RELATION_REQUIRED(A, B, OP, T, F) TTS_TYPED_CEXPR_RELATION_IMPL(A,B,OP,T,F,TTS_FATAL) +#define TTS_TYPED_CEXPR_RELATION_IMPL(A, B, OP, T, F, FAILURE) \ +[&](auto&& a, auto&& b) \ +{ \ + using type_a = std::remove_cvref_t; \ + using type_b = std::remove_cvref_t; \ + \ + if constexpr( !std::same_as ) \ + { \ + FAILURE ( "Expression: " << TTS_STRING(A) << " " T " " << TTS_STRING(B) \ + << " is false because: " << ::tts::typename_ << " is not " \ + << ::tts::typename_ \ + ); \ + return ::tts::logger{}; \ + } \ + else \ + { \ + TTS_CEXPR_RELATION_BASE(A, B, OP, T, F, FAILURE) \ + } \ +}(A,B) \ + +#define TTS_TYPED_CONSTEXPR_EQUAL(LHS, RHS, ...) TTS_TYPED_CEXPR_RELATION(LHS,RHS, eq , "==" , "!=", __VA_ARGS__) +#define TTS_TYPED_CONSTEXPR_NOT_EQUAL(LHS, RHS, ...) TTS_TYPED_CEXPR_RELATION(LHS,RHS, neq, "!=" , "==", __VA_ARGS__) +#define TTS_TYPED_CONSTEXPR_LESS(LHS, RHS, ...) TTS_TYPED_CEXPR_RELATION(LHS,RHS, lt , "<" , ">=", __VA_ARGS__) +#define TTS_TYPED_CONSTEXPR_GREATER(LHS, RHS, ...) TTS_TYPED_CEXPR_RELATION(LHS,RHS, gt , ">" , "<=", __VA_ARGS__) +#define TTS_TYPED_CONSTEXPR_LESS_EQUAL(LHS, RHS, ...) TTS_TYPED_CEXPR_RELATION(LHS,RHS, le , "<=" , ">" , __VA_ARGS__) +#define TTS_TYPED_CONSTEXPR_GREATER_EQUAL(LHS, RHS, ...) TTS_TYPED_CEXPR_RELATION(LHS,RHS, ge , ">=" , "<=", __ +#define TTS_TYPE_IS(TYPE, REF, ...) TTS_TYPE_IS_ ## __VA_ARGS__ (TYPE, REF) +#define TTS_TYPE_IS_(TYPE, REF) TTS_TYPE_IS_IMPL(TYPE, REF,TTS_FAIL) +#define TTS_TYPE_IS_REQUIRED(TYPE, REF) TTS_TYPE_IS_IMPL(TYPE, REF,TTS_FATAL) +#define TTS_TYPE_IS_IMPL(TYPE, REF, FAILURE) \ +[&](::tts::type, ::tts::type) \ +{ \ + if constexpr( std::is_same_v ) \ { \ ::tts::global_runtime.pass(); return ::tts::logger{false}; \ } \ else \ { \ - FAILURE ( "Expression: " << TTS_STRING(A) << " " T " " << TTS_STRING(B) \ - << " is false because: " << ::tts::as_string(a) << " " F " " << ::tts::as_string(b) \ + FAILURE ( "Type: " << TTS_STRING(TTS_REMOVE_PARENS(TYPE)) << " is not the same as " \ + << TTS_STRING(TTS_REMOVE_PARENS(REF)) << " because " \ + << ::tts::typename_ << " is not " << ::tts::typename_ \ ); \ return ::tts::logger{}; \ } \ -}(A,B) \ +}(::tts::type{}, ::tts::type{}) \ -#define TTS_EQUAL(LHS, RHS, ...) TTS_RELATION(LHS,RHS, eq , "==" , "!=" , __VA_ARGS__) -#define TTS_NOT_EQUAL(LHS, RHS, ...) TTS_RELATION(LHS,RHS, neq, "!=" , "==" , __VA_ARGS__) -#define TTS_LESS(LHS, RHS, ...) TTS_RELATION(LHS,RHS, lt , "<" , ">=" , __VA_ARGS__) -#define TTS_GREATER(LHS, RHS, ...) TTS_RELATION(LHS,RHS, gt , ">" , "<=" , __VA_ARGS__) -#define TTS_LESS_EQUAL(LHS, RHS, ...) TTS_RELATION(LHS,RHS, le , "<=" , ">" , __VA_ARGS__) -#define TTS_GREATER_EQUAL(LHS, RHS, ...) TTS_RELATION(LHS,RHS, ge , ">=" , "<=" , __VA_ARGS__) -#define TTS_CONSTEXPR_RELATION(A, B, OP, T, F) \ +#define TTS_EXPR_IS(EXPR, TYPE, ...) TTS_EXPR_IS_ ## __VA_ARGS__ (EXPR, TYPE) +#define TTS_EXPR_IS_(EXPR, TYPE) TTS_EXPR_IS_IMPL(EXPR, TYPE,TTS_FAIL) +#define TTS_EXPR_IS_REQUIRED(EXPR, TYPE) TTS_EXPR_IS_IMPL(EXPR, TYPE,TTS_FATAL) +#define TTS_EXPR_IS_IMPL(EXPR, TYPE, FAILURE) \ +[&](::tts::type, ::tts::type) \ { \ - static_assert ( std::bool_constant<::tts::detail::OP(A,B)>::value \ - , "[TTS] - ** FAILURE** : " TTS_STRING(A) " " T " " TTS_STRING(B) " is false." \ - ); \ - ::tts::global_runtime.pass(); \ -} \ + if constexpr( std::is_same_v ) \ + { \ + ::tts::global_runtime.pass(); return ::tts::logger{false}; \ + } \ + else \ + { \ + FAILURE ( "Type: " << TTS_STRING(TTS_REMOVE_PARENS(EXPR)) << " is not the same as " \ + << TTS_STRING(TTS_REMOVE_PARENS(TYPE)) << " because " \ + << ::tts::typename_ << " is not " << ::tts::typename_ \ + ); \ + return ::tts::logger{}; \ + } \ +}(::tts::type{}, ::tts::type{}) \ -#define TTS_CONSTEXPR_EQUAL(LHS, RHS) TTS_CONSTEXPR_RELATION(LHS,RHS, eq , "==" , "!=") -#define TTS_CONSTEXPR_NOT_EQUAL(LHS, RHS) TTS_CONSTEXPR_RELATION(LHS,RHS, neq, "!=" , "==") -#define TTS_CONSTEXPR_LESS(LHS, RHS) TTS_CONSTEXPR_RELATION(LHS,RHS, lt , "<" , ">=") -#define TTS_CONSTEXPR_GREATER(LHS, RHS) TTS_CONSTEXPR_RELATION(LHS,RHS, gt , ">" , "<=") -#define TTS_CONSTEXPR_LESS_EQUAL(LHS, RHS) TTS_CONSTEXPR_RELATION(LHS,RHS, le , "<=" , ">" ) -#define TTS_CONSTEXPR_GREATER_EQUAL(LHS, RHS) TTS_CONSTEXPR_RELATION(LHS,RHS, ge , ">=" , "<=") -#define TTS_TYPE_IS(TYPE, REF) \ +#define TTS_EXPECT_COMPILES_IMPL(EXPR, ...) \ +[&]( TTS_ARG(__VA_ARGS__) ) \ { \ - static_assert ( std::is_same_v \ - , "[TTS] - ** FAILURE** : " TTS_STRING(TTS_REMOVE_PARENS(TYPE)) \ - " is not the same as " TTS_STRING(TTS_REMOVE_PARENS(REF)) "." \ - ); \ - ::tts::global_runtime.pass(); \ -} -#define TTS_EXPR_IS(EXPR, TYPE) \ + if constexpr( requires TTS_REMOVE_PARENS(EXPR) ) \ + { \ + ::tts::global_runtime.pass(); return ::tts::logger{false}; \ + } \ + else \ + { \ + TTS_FAIL( "Expression: " << TTS_STRING(TTS_REMOVE_PARENS(EXPR)) \ + << " does not compile as expected." \ + ); \ + return ::tts::logger{}; \ + } \ +}(__VA_ARGS__) \ + +#define TTS_EXPECT_COMPILES(...) TTS_VAL(TTS_EXPECT_COMPILES_IMPL TTS_REVERSE(__VA_ARGS__) ) +#define TTS_EXPECT_NOT_COMPILES_IMPL(EXPR, ...) \ +[&]( TTS_ARG(__VA_ARGS__) ) \ { \ - static_assert ( std::is_same_v \ - , "[TTS] - ** FAILURE** : " TTS_STRING(TTS_REMOVE_PARENS(EXPR)) \ - " does not evaluates to an instance of " TTS_STRING(TTS_REMOVE_PARENS(TYPE)) "." \ - ); \ - ::tts::global_runtime.pass(); \ -} + if constexpr( !(requires TTS_REMOVE_PARENS(EXPR)) ) \ + { \ + ::tts::global_runtime.pass(); return ::tts::logger{false}; \ + } \ + else \ + { \ + TTS_FAIL("Expression: " << TTS_STRING(TTS_REMOVE_PARENS(EXPR)) << " compiles unexpectedly." ); \ + return ::tts::logger{}; \ + } \ +}(__VA_ARGS__) \ + +#define TTS_EXPECT_NOT_COMPILES(...) TTS_VAL(TTS_EXPECT_NOT_COMPILES_IMPL TTS_REVERSE(__VA_ARGS__)) #define TTS_THROW_IMPL(EXPR, EXCEPTION, FAILURE) \ [&]() \ { \ @@ -833,14 +1376,10 @@ namespace tts } } } -#define TTS_PRECISION_IMPL(LHS, RHS, N, UNIT, FUNC, FAILURE) \ -[&](auto&& lhs, auto&& rhs) \ +#define TTS_PRECISION_IMPL(LHS, RHS, N, UNIT, FUNC, PREC,FAILURE) \ +[&](auto lhs, auto rhs) \ { \ - auto eval_a = (lhs); \ - auto eval_b = (rhs); \ - auto r = FUNC (eval_a,eval_b); \ - auto& fmt_n = N<1000 ? std::defaultfloat : std::scientific; \ - auto& fmt_r = r<1000 ? std::defaultfloat : std::scientific; \ + auto r = FUNC (lhs,rhs); \ \ if(r <= N) \ { \ @@ -850,11 +1389,11 @@ namespace tts { \ FAILURE ( "Expected: " << TTS_STRING(LHS) << " == " << TTS_STRING(RHS) \ << " but " \ - << ::tts::as_string(eval_a) << " == " << ::tts::as_string(eval_b) \ - << " within " << std::setprecision(2) << fmt_r \ + << ::tts::as_string(lhs) << " == " << ::tts::as_string(rhs) \ + << " within " << std::setprecision(PREC) << std::fixed \ << r << std::defaultfloat \ << " " << UNIT << " when " \ - << std::setprecision(2) << fmt_n \ + << std::setprecision(PREC) << std::fixed \ << N << std::defaultfloat \ << " " << UNIT << " was expected." \ ); \ @@ -862,12 +1401,12 @@ namespace tts } \ }(LHS,RHS) \ -#define TTS_PRECISION(L,R,N,U,F, ...) TTS_PRECISION_ ## __VA_ARGS__ (L,R,N,U,F) -#define TTS_PRECISION_(L,R,N,U,F) TTS_PRECISION_IMPL(L,R,N,U,F,TTS_FAIL) -#define TTS_PRECISION_REQUIRED(L,R,N,U,F) TTS_PRECISION_IMPL(L,R,N,U,F,TTS_FATAL) -#define TTS_ABSOLUTE_EQUAL(L,R,N,...) TTS_PRECISION(L,R,N,"unit", ::tts::absolute_distance, __VA_ARGS__ ) -#define TTS_RELATIVE_EQUAL(L,R,N,...) TTS_PRECISION(L,R,N,"%" , ::tts::relative_distance, __VA_ARGS__ ) -#define TTS_ULP_EQUAL(L,R,N,...) TTS_PRECISION(L,R,N,"ULP" , ::tts::ulp_distance , __VA_ARGS__ ) +#define TTS_PRECISION(L,R,N,U,F,P,...) TTS_PRECISION_ ## __VA_ARGS__ (L,R,N,U,F,P) +#define TTS_PRECISION_(L,R,N,U,F,P) TTS_PRECISION_IMPL(L,R,N,U,F,P,TTS_FAIL) +#define TTS_PRECISION_REQUIRED(L,R,N,U,F,P) TTS_PRECISION_IMPL(L,R,N,U,F,P,TTS_FATAL) +#define TTS_ABSOLUTE_EQUAL(L,R,N,...) TTS_PRECISION(L,R,N,"unit", ::tts::absolute_distance, 8, __VA_ARGS__ ) +#define TTS_RELATIVE_EQUAL(L,R,N,...) TTS_PRECISION(L,R,N,"%" , ::tts::relative_distance, 8, __VA_ARGS__ ) +#define TTS_ULP_EQUAL(L,R,N,...) TTS_PRECISION(L,R,N,"ULP" , ::tts::ulp_distance , 2, __VA_ARGS__ ) #define TTS_IEEE_EQUAL(L,R,...) TTS_ULP_EQUAL(L, R, 0, __VA_ARGS__ ) #include namespace tts::detail @@ -912,7 +1451,7 @@ namespace tts::detail if( !failures.empty( ) ) \ { \ FAILURE ( "Expected: " << TTS_STRING(SEQ1) << " == " << TTS_STRING(SEQ2) \ - << " but values differ from more than " << N << " "<< UNIT \ + << " but values differ by more than " << N << " "<< UNIT \ ); \ \ for(auto f : failures) \ @@ -935,3 +1474,44 @@ namespace tts::detail #define TTS_ALL_ULP_EQUAL(L,R,N,...) TTS_ALL(L,R, ::tts::ulp_distance ,N,"ULP" , __VA_ARGS__ ) #define TTS_ALL_IEEE_EQUAL(S1,S2,...) TTS_ALL_ULP_EQUAL(S1,S2,0, __VA_ARGS__) #define TTS_ALL_EQUAL(L,R,...) TTS_ALL_ABSOLUTE_EQUAL(L,R, 0 __VA_ARGS__ ) +#include +namespace tts::detail +{ + struct section_guard + { + int & id; + int const & section; + section_guard(int &id_, int const §ion_, int &count) : id(id_) , section(section_) + { + if(section == 0) id = count++ - 1; + } + template bool check(Desc const& desc) + { + if(id == section) std::cout << " And then: " << desc << std::endl; + return id == section; + } + }; + struct only_once + { + bool once = true; + explicit operator bool() { bool result = once; once = false; return result; } + }; +} +#define TTS_WHEN(STORY) \ + std::cout << "[?] - For: " << ::tts::detail::current_test << "\n"; \ + std::cout << "When : " << STORY << std::endl; \ + for(int tts_section = 0, tts_count = 1; tts_section < tts_count; tts_count -= 0==tts_section++) \ + for( tts::detail::only_once tts_only_once_setup{}; tts_only_once_setup; ) \ + +#define TTS_AND_THEN_IMPL(TTS_LOCAL_ID, ...) \ + static int TTS_LOCAL_ID = 0; \ + std::ostringstream TTS_CAT(desc_,TTS_LOCAL_ID); \ + if(::tts::detail::section_guard(TTS_LOCAL_ID, tts_section, tts_count ) \ + .check( ((TTS_CAT(desc_,TTS_LOCAL_ID) << __VA_ARGS__) \ + , TTS_CAT(desc_,TTS_LOCAL_ID).str()) \ + ) \ + ) \ + for(int tts_section = 0, tts_count = 1; tts_section < tts_count; tts_count -= 0==tts_section++ ) \ + for(tts::detail::only_once tts__only_once_section{}; tts__only_once_section; ) \ + +#define TTS_AND_THEN(...) TTS_AND_THEN_IMPL(TTS_UNIQUE(id), __VA_ARGS__) diff --git a/test/utility/CMakeLists.txt b/test/utility/CMakeLists.txt index cbfec54a..1b2e9171 100644 --- a/test/utility/CMakeLists.txt +++ b/test/utility/CMakeLists.txt @@ -3,10 +3,8 @@ ## Copyright : KIWAKU Contributors & Maintainers ## SPDX-License-Identifier: BSL-1.0 ##================================================================================================== -set ( SOURCES - allocator.cpp - fixed.cpp - heap.cpp - ) - -make_unit("utility" ${SOURCES}) +add_subdirectory(memory ) +add_subdirectory(meta ) +add_subdirectory(shape ) +add_subdirectory(slicer ) +add_subdirectory(stride ) diff --git a/test/utility/fixed.cpp b/test/utility/fixed.cpp deleted file mode 100644 index 39f3b8a7..00000000 --- a/test/utility/fixed.cpp +++ /dev/null @@ -1,25 +0,0 @@ -//================================================================================================== -/* - KIWAKU - Containers Well Made - Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors - SPDX-License-Identifier: BSL-1.0 -*/ -//================================================================================================== -#include "test.hpp" -#include - -TTS_CASE( "fixed behavior - Explicit usage" ) -{ - TTS_CONSTEXPR_EQUAL ( kwk::fixed<0>.value , 0 ); - TTS_CONSTEXPR_EQUAL ( kwk::fixed.value , short(-1) ); - TTS_CONSTEXPR_EQUAL ( kwk::fixed<0x1234567812345678ULL>.value , 0x1234567812345678ULL ); -}; - -TTS_CASE( "fixed behavior - Literal API" ) -{ - TTS_CONSTEXPR_EQUAL ( kwk::fixed<0>.value , 0 ); - TTS_CONSTEXPR_EQUAL ( kwk::fixed.value , short(-1) ); - TTS_CONSTEXPR_EQUAL ( kwk::fixed<0x1234567812345678ULL>.value , 0x1234567812345678ULL ); -}; diff --git a/test/container/utility/CMakeLists.txt b/test/utility/memory/CMakeLists.txt similarity index 82% rename from test/container/utility/CMakeLists.txt rename to test/utility/memory/CMakeLists.txt index f22a8c20..05476383 100644 --- a/test/container/utility/CMakeLists.txt +++ b/test/utility/memory/CMakeLists.txt @@ -4,7 +4,8 @@ ## SPDX-License-Identifier: BSL-1.0 ##================================================================================================== set ( SOURCES - linear_index.cpp + allocator.cpp + heap.cpp ) -make_unit("components.utility" ${SOURCES}) +make_unit("utility.memory" ${SOURCES}) diff --git a/test/utility/allocator.cpp b/test/utility/memory/allocator.cpp similarity index 89% rename from test/utility/allocator.cpp rename to test/utility/memory/allocator.cpp index 2c6eb3b1..2411376a 100644 --- a/test/utility/allocator.cpp +++ b/test/utility/memory/allocator.cpp @@ -2,13 +2,12 @@ /* KIWAKU - Containers Well Made Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 */ //================================================================================================== #include "test.hpp" -#include +#include +#include struct box { @@ -17,7 +16,7 @@ struct box template box ( std::ptrdiff_t n, A a) : alloc(std::move(a)) - , data_( reinterpret_cast(alloc.allocate(n*sizeof(float))) ) + , data_( reinterpret_cast(allocate(alloc, n*sizeof(float))) ) , size_(n) {} @@ -54,7 +53,7 @@ struct box float * end() noexcept { return begin() + size_; } float const* end() const noexcept { return begin() + size_; } - ~box() { if(size_ != 0) alloc.deallocate( data_ ); } + ~box() { if(size_ != 0) deallocate( alloc, data_ ); } void swap(box& b) noexcept { @@ -70,8 +69,8 @@ struct box TTS_CASE( "Checks allocator is suitable for pseudo-container support" ) { - box b( 5, kwk::heap_allocator{} ); - box c( 7, kwk::heap_allocator{} ); + box b( 5, kwk::heap ); + box c( 7, kwk::heap ); for(int i=0;i<5;i++) b.get(i) = 1.f/(1+i); for(int i=0;i<7;i++) c.get(i) = 1.5f*(1+i); diff --git a/test/utility/heap.cpp b/test/utility/memory/heap.cpp similarity index 69% rename from test/utility/heap.cpp rename to test/utility/memory/heap.cpp index d4b96d4c..f11911f0 100644 --- a/test/utility/heap.cpp +++ b/test/utility/memory/heap.cpp @@ -2,31 +2,26 @@ /* KIWAKU - Containers Well Made Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 */ //================================================================================================== #include "test.hpp" -#include +#include TTS_CASE( "Nullpotent Allocation/Deallocation through heap_allocator" ) { kwk::heap_allocator a; - auto memory = a.allocate( 0 ); + auto memory = allocate( a, 0 ); TTS_EQUAL ( memory , nullptr ); - - a.deallocate(memory); + deallocate(a, memory); }; TTS_CASE( "Allocation/Deallocation through heap_allocator" ) { kwk::heap_allocator a; - - auto memory = a.allocate( 64 ); + auto memory = allocate( a, 64 ); TTS_NOT_EQUAL ( memory, nullptr ); - - a.deallocate(memory); + deallocate(a, memory); }; diff --git a/test/container/stride/CMakeLists.txt b/test/utility/meta/CMakeLists.txt similarity index 77% rename from test/container/stride/CMakeLists.txt rename to test/utility/meta/CMakeLists.txt index b46291a4..c986ea76 100644 --- a/test/container/stride/CMakeLists.txt +++ b/test/utility/meta/CMakeLists.txt @@ -4,9 +4,9 @@ ## SPDX-License-Identifier: BSL-1.0 ##================================================================================================== set ( SOURCES - ctor.cpp - indexing.cpp - unit_indexing.cpp + end.cpp + fixed.cpp + ratio.cpp ) -make_unit("components.stride" ${SOURCES}) +make_unit("utility.meta" ${SOURCES}) diff --git a/test/utility/meta/end.cpp b/test/utility/meta/end.cpp new file mode 100644 index 00000000..a28afbd5 --- /dev/null +++ b/test/utility/meta/end.cpp @@ -0,0 +1,76 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include "test.hpp" +#include +#include + +TTS_CASE( "Check end default state" ) +{ + using kwk::end; + + TTS_EQUAL(end.offset() , 0); + TTS_EQUAL(end.factor() , 1); + TTS_EQUAL(end.divisor(), 1); +}; + +TTS_CASE( "Check end + k and k + end" ) +{ + using kwk::end; + + TTS_EQUAL((end + 3).offset() , 3); + TTS_EQUAL((end + 3).ratio(), (kwk::ratio{1,1})); + + TTS_EQUAL((5 + end).offset() , 5); + TTS_EQUAL((5 + end).ratio(), (kwk::ratio{1,1})); +}; + +TTS_CASE( "Check end - k and k - end" ) +{ + using kwk::end; + + TTS_EQUAL((end - 3).offset() , -3); + TTS_EQUAL((end - 3).ratio(), (kwk::ratio{1,1})); + + TTS_EQUAL((5 - end).offset() , 5); + TTS_EQUAL((5 - end).ratio(), (kwk::ratio{-1,1})); +}; + +TTS_CASE( "Check end * k and k * end" ) +{ + using kwk::end; + + TTS_EQUAL((end * 3).offset() , 0); + TTS_EQUAL((end * 3).ratio(), (kwk::ratio{3,1})); + + TTS_EQUAL(((end + 2) * 3).offset() , 2*3); + TTS_EQUAL(((end + 2) * 3).ratio(), (kwk::ratio{3,1})); + + TTS_EQUAL((5 * end).offset() , 0); + TTS_EQUAL((5 * end).ratio(), (kwk::ratio{5,1})); + + TTS_EQUAL((5 * (end + 7)).offset() , 5 * 7); + TTS_EQUAL((5 * (end + 7)).ratio(), (kwk::ratio{5,1})); +}; + +TTS_CASE( "Check end / k and k / end and corner cases" ) +{ + using kwk::end; + + TTS_EQUAL((end / 3).offset(), 0); + TTS_EQUAL((end / 3).ratio() , (kwk::ratio{1,3})); + + TTS_EQUAL(((end + 2) / 3).offset(), 2); + TTS_EQUAL(((end + 2) / 3).ratio() , (kwk::ratio{1,3})); + + TTS_EQUAL(((2 * end) / 3 + 1).offset(), 3); + TTS_EQUAL(((2 * end) / 3 + 1).ratio() , (kwk::ratio{2,3})); + + TTS_EQUAL((((2 * end) / 3 + 1) / 2).offset(), 3); + TTS_EQUAL((((2 * end) / 3 + 1) / 2).ratio() , (kwk::ratio{2,6})); +}; + diff --git a/test/utility/meta/fixed.cpp b/test/utility/meta/fixed.cpp new file mode 100644 index 00000000..e6bb0f29 --- /dev/null +++ b/test/utility/meta/fixed.cpp @@ -0,0 +1,37 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include "test.hpp" +#include + +TTS_CASE( "fixed behavior - Explicit usage" ) +{ + TTS_CONSTEXPR_EQUAL ( kwk::fixed<0>.value , 0 ); + TTS_CONSTEXPR_EQUAL ( kwk::fixed.value , short(-1) ); + TTS_CONSTEXPR_EQUAL ( kwk::fixed<0x1234567812345678ULL>.value , 0x1234567812345678ULL ); + + TTS_EXPR_IS ( kwk::fixed<0>.value , std::int32_t const ); + TTS_EXPR_IS ( kwk::fixed.value , std::int16_t const ); + TTS_EXPR_IS ( kwk::fixed.value , std::int64_t const ); +}; + +TTS_CASE( "fixed behavior - Literal API" ) +{ + using namespace kwk::literals; + + constexpr auto cst_0 = 0_c; + constexpr auto cst_1 = 16540_c; + constexpr auto cst_2 = 123456_c; + + TTS_EQUAL ( cst_0.value , 0 ); + TTS_EQUAL ( cst_1.value , short(16540) ); + TTS_EQUAL ( cst_2.value , 123456 ); + + TTS_EXPR_IS( cst_0.value , std::int8_t const); + TTS_EXPR_IS( cst_1.value , std::int16_t const); + TTS_EXPR_IS( cst_2.value , std::int32_t const); +}; diff --git a/test/utility/meta/ratio.cpp b/test/utility/meta/ratio.cpp new file mode 100644 index 00000000..6034921e --- /dev/null +++ b/test/utility/meta/ratio.cpp @@ -0,0 +1,136 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include "test.hpp" +#include +#include + + +TTS_CASE( "Check ratio addition" ) +{ + using kwk::ratio; + using namespace kwk::literals; + + ratio rdd{1 , 3}; + ratio rsd{5_c , 7}; + ratio rds{9 , 11_c}; + ratio rss{13_c , 15_c}; + + TTS_EQUAL(rdd + rdd, (ratio{2, 3})); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::static_constant ); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::static_constant ); + + TTS_EQUAL(rdd + rsd, (ratio{7*1+5*3, 3*7})); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::static_constant ); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::static_constant ); + + TTS_EQUAL(rsd + rds, (ratio{5*11+9*7, 7*11})); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::static_constant ); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::static_constant ); + + TTS_EQUAL(rds + rss, (ratio{9*15+13*11, 11*15})); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::static_constant ); + TTS_CONSTEXPR_EXPECT ( kwk::concepts::static_constant ); + + TTS_EQUAL(rss + rss, (ratio{13*15+13*15, 15*15})); + TTS_CONSTEXPR_EXPECT ( kwk::concepts::static_constant ); + TTS_CONSTEXPR_EXPECT ( kwk::concepts::static_constant ); + +}; + +TTS_CASE( "Check ratio subtraction" ) +{ + using kwk::ratio; + using namespace kwk::literals; + + ratio rdd{1 , 3}; + ratio rsd{5_c , 7}; + ratio rds{9 , 11_c}; + ratio rss{13_c , 15_c}; + + TTS_EQUAL(rdd - rdd, (ratio{0, 3})); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::static_constant ); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::static_constant ); + + TTS_EQUAL(rdd - rsd, (ratio{7*1-5*3, 3*7})); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::static_constant ); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::static_constant ); + + TTS_EQUAL(rsd - rds, (ratio{5*11-9*7, 7*11})); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::static_constant ); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::static_constant ); + + TTS_EQUAL(rds - rss, (ratio{9*15-13*11, 11*15})); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::static_constant ); + TTS_CONSTEXPR_EXPECT ( kwk::concepts::static_constant ); + + TTS_EQUAL(rss - rss, (ratio{13*15-13*15, 15*15})); + TTS_CONSTEXPR_EXPECT ( kwk::concepts::static_constant ); + TTS_CONSTEXPR_EXPECT ( kwk::concepts::static_constant ); +}; + +TTS_CASE( "Check ratio product" ) +{ + using kwk::ratio; + using namespace kwk::literals; + + ratio rdd{1 , 3}; + ratio rsd{5_c , 7}; + ratio rds{9 , 11_c}; + ratio rss{13_c , 15_c}; + + TTS_EQUAL(rdd * rdd, (ratio{1, 9})); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::static_constant ); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::static_constant ); + + TTS_EQUAL(rdd * rsd, (ratio{1*5, 3*7})); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::static_constant ); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::static_constant ); + + TTS_EQUAL(rsd * rds, (ratio{5*9, 7*11})); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::static_constant ); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::static_constant ); + + TTS_EQUAL(rds * rss, (ratio{9*13, 11*15})); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::static_constant ); + TTS_CONSTEXPR_EXPECT ( kwk::concepts::static_constant ); + + TTS_EQUAL(rss * rss, (ratio{13*13, 15*15})); + TTS_CONSTEXPR_EXPECT ( kwk::concepts::static_constant ); + TTS_CONSTEXPR_EXPECT ( kwk::concepts::static_constant ); +}; + +TTS_CASE( "Check ratio division" ) +{ + using kwk::ratio; + using namespace kwk::literals; + + ratio rdd{1 , 3}; + ratio rsd{5_c , 7}; + ratio rds{9 , 11_c}; + ratio rss{13_c , 15_c}; + + TTS_EQUAL(rdd / rdd, (ratio{1, 1})); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::static_constant ); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::static_constant ); + + TTS_EQUAL(rdd / rsd, (ratio{1*7, 5*3})); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::static_constant ); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::static_constant ); + + TTS_EQUAL(rsd / rds, (ratio{5*11, 9*7})); + TTS_CONSTEXPR_EXPECT ( kwk::concepts::static_constant ); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::static_constant ); + + TTS_EQUAL(rds / rss, (ratio{9*15, 11*13})); + TTS_CONSTEXPR_EXPECT_NOT( kwk::concepts::static_constant ); + TTS_CONSTEXPR_EXPECT ( kwk::concepts::static_constant ); + + TTS_EQUAL(rss / rss, (ratio{13*15, 15*13})); + TTS_CONSTEXPR_EXPECT ( kwk::concepts::static_constant ); + TTS_CONSTEXPR_EXPECT ( kwk::concepts::static_constant ); +}; \ No newline at end of file diff --git a/test/container/shape/CMakeLists.txt b/test/utility/shape/CMakeLists.txt similarity index 87% rename from test/container/shape/CMakeLists.txt rename to test/utility/shape/CMakeLists.txt index 4edd4596..8c2ea244 100644 --- a/test/container/shape/CMakeLists.txt +++ b/test/utility/shape/CMakeLists.txt @@ -5,18 +5,18 @@ ##================================================================================================== set ( SOURCES as_array.cpp - as_stride.cpp compare.cpp contain.cpp convert.cpp ctor.cpp + default_ctor.cpp joker.cpp properties.cpp - of_shape.cpp + of_size.cpp mixed.cpp strictly_contain.cpp swap.cpp tuple.cpp ) -make_unit("components.shape" ${SOURCES}) +make_unit("utility.shape" ${SOURCES}) diff --git a/test/container/shape/as_array.cpp b/test/utility/shape/as_array.cpp similarity index 55% rename from test/container/shape/as_array.cpp rename to test/utility/shape/as_array.cpp index 9fbcbede..7a33857b 100644 --- a/test/container/shape/as_array.cpp +++ b/test/utility/shape/as_array.cpp @@ -1,15 +1,12 @@ //================================================================================================== /* KIWAKU - Containers Well Made - Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 */ //================================================================================================== #include "test.hpp" -#include -#include +#include template using type = std::array; @@ -17,31 +14,31 @@ using type = std::array; TTS_CASE( "Convert a 1D shape to std::array" ) { using namespace kwk::literals; - TTS_EQUAL( kwk::of_size(9 ).as_array(), (type{9}) ); - TTS_EQUAL( kwk::of_size(9_c ).as_array(), (type{9}) ); - TTS_EQUAL( kwk::of_size(390_c ).as_array(), (type{390}) ); + TTS_EQUAL( kwk::of_size(9 ).as_array(), (type{9}) ); + TTS_EQUAL( kwk::of_size(9_c ).as_array(), (type{9}) ); + TTS_EQUAL( kwk::of_size(390_c ).as_array(), (type{390}) ); }; TTS_CASE( "Convert a 2D shape to std::array" ) { using namespace kwk::literals; - TTS_EQUAL( kwk::of_size(9 , 7 ).as_array(), (type{9,7}) ); - TTS_EQUAL( kwk::of_size(9_c , 7_c).as_array(), (type{9,7}) ); - TTS_EQUAL( kwk::of_size(390_c, 7_c).as_array(), (type{390,7}) ); + TTS_EQUAL( kwk::of_size(9 , 7 ).as_array(), (type{9,7}) ); + TTS_EQUAL( kwk::of_size(9_c , 7_c).as_array(), (type{9,7}) ); + TTS_EQUAL( kwk::of_size(390_c, 7_c).as_array(), (type{390,7}) ); }; TTS_CASE( "Convert a 3D shape to std::array" ) { using namespace kwk::literals; - TTS_EQUAL( kwk::of_size(9 , 7 , 11 ).as_array(), (type{9,7,11}) ); - TTS_EQUAL( kwk::of_size(9_c , 7_c, 11_c).as_array(), (type{9,7,11}) ); - TTS_EQUAL( kwk::of_size(390_c, 7_c, 11_c).as_array(), (type{390,7,11}) ); + TTS_EQUAL( kwk::of_size(9 , 7 , 11 ).as_array(), (type{9,7,11}) ); + TTS_EQUAL( kwk::of_size(9_c , 7_c, 11_c).as_array(), (type{9,7,11}) ); + TTS_EQUAL( kwk::of_size(390_c, 7_c, 11_c).as_array(), (type{390,7,11}) ); }; TTS_CASE( "Convert a 4D shape to std::array" ) { using namespace kwk::literals; - TTS_EQUAL( kwk::of_size(9 , 7 , 11 , 32 ).as_array(), (type{9,7,11,32}) ); - TTS_EQUAL( kwk::of_size(9_c , 7_c, 11_c, ' ' ).as_array(), (type{9,7,11,32}) ); - TTS_EQUAL( kwk::of_size(390_c, 7_c, 11_c, short{32} ).as_array(), (type{390,7,11,32})); + TTS_EQUAL( kwk::of_size(9 , 7 , 11 , 32 ).as_array(), (type{9,7,11,32}) ); + TTS_EQUAL( kwk::of_size(9_c , 7_c, 11_c, ' ' ).as_array(), (type{9,7,11,32}) ); + TTS_EQUAL( kwk::of_size(390_c, 7_c, 11_c, short{32} ).as_array(), (type{390,7,11,32})); }; diff --git a/test/container/shape/compare.cpp b/test/utility/shape/compare.cpp similarity index 96% rename from test/container/shape/compare.cpp rename to test/utility/shape/compare.cpp index 3501342c..2f599105 100644 --- a/test/container/shape/compare.cpp +++ b/test/utility/shape/compare.cpp @@ -1,14 +1,12 @@ //================================================================================================== /** KIWAKU - Containers Well Made - Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 **/ //================================================================================================== #include "test.hpp" -#include +#include TTS_CASE( "Equality comparison between shapes" ) { diff --git a/test/container/shape/contain.cpp b/test/utility/shape/contain.cpp similarity index 97% rename from test/container/shape/contain.cpp rename to test/utility/shape/contain.cpp index 0b661bfb..83ddf47f 100644 --- a/test/container/shape/contain.cpp +++ b/test/utility/shape/contain.cpp @@ -1,14 +1,12 @@ //================================================================================================== /* KIWAKU - Containers Well Made - Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 */ //================================================================================================== #include "test.hpp" -#include +#include TTS_CASE( "Does a shape contains another" ) { diff --git a/test/container/shape/convert.cpp b/test/utility/shape/convert.cpp similarity index 56% rename from test/container/shape/convert.cpp rename to test/utility/shape/convert.cpp index 1fd67645..59e2fbbc 100644 --- a/test/container/shape/convert.cpp +++ b/test/utility/shape/convert.cpp @@ -1,24 +1,22 @@ //================================================================================================== -/* +/** KIWAKU - Containers Well Made - Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 -*/ +**/ //================================================================================================== #include "test.hpp" -#include +#include TTS_CASE( "Small shape can be used to construct large shape" ) { auto small = kwk::shape{4,2}; auto large = kwk::shape(small); - TTS_EQUAL( large.get<0>(), small.get<0>() ); - TTS_EQUAL( large.get<1>(), small.get<1>() ); - TTS_EQUAL( large.get<2>(), 1 ); - TTS_EQUAL( large.get<3>(), 1 ); + TTS_EQUAL( large[0], small[0] ); + TTS_EQUAL( large[1], small[1] ); + TTS_EQUAL( large[2], 1 ); + TTS_EQUAL( large[3], 1 ); }; TTS_CASE( "Small shape can be assigned to large shape" ) @@ -28,10 +26,10 @@ TTS_CASE( "Small shape can be assigned to large shape" ) large = small; - TTS_EQUAL( large.get<0>(), small.get<0>() ); - TTS_EQUAL( large.get<1>(), small.get<1>() ); - TTS_EQUAL( large.get<2>(), 1 ); - TTS_EQUAL( large.get<3>(), 1 ); + TTS_EQUAL( large[0], small[0] ); + TTS_EQUAL( large[1], small[1] ); + TTS_EQUAL( large[2], 1 ); + TTS_EQUAL( large[3], 1 ); }; TTS_CASE( "Large shape need to be explicitly converted to small shape" ) @@ -39,8 +37,8 @@ TTS_CASE( "Large shape need to be explicitly converted to small shape" ) auto large = kwk::shape{4,2,6,9}; auto small = kwk::shape{large}; - TTS_EQUAL( small.get<0>(), large.get<0>() ); - TTS_EQUAL( small.get<1>(), large.get<1>()*large.get<2>()*large.get<3>() ); + TTS_EQUAL( small[0], large[0] ); + TTS_EQUAL( small[1], large[1]*large[2]*large[3] ); }; TTS_CASE( "Large shape need to be explicitly assigned to small shape" ) @@ -50,6 +48,6 @@ TTS_CASE( "Large shape need to be explicitly assigned to small shape" ) small = kwk::shape{large}; - TTS_EQUAL( small.get<0>(), large.get<0>() ); - TTS_EQUAL( small.get<1>(), large.get<1>()*large.get<2>()*large.get<3>() ); + TTS_EQUAL( small[0], large[0] ); + TTS_EQUAL( small[1], large[1]*large[2]*large[3] ); }; diff --git a/test/utility/shape/ctor.cpp b/test/utility/shape/ctor.cpp new file mode 100644 index 00000000..51d4dc52 --- /dev/null +++ b/test/utility/shape/ctor.cpp @@ -0,0 +1,25 @@ +//================================================================================================== +/** + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +**/ +//================================================================================================== +#include "test.hpp" +#include +#include "utility/shape/shape.hpp" + +TTS_CASE_TPL( "Building a nD shape with kwk::kwk::shape{a1,...,an}", sizes<10>) +(::tts::type) +{ + auto f = [](std::index_sequence const&) + { + return kwk::shape( 3*static_cast(1+Idx)...); + }; + + auto sh = f(up_to{}); + TTS_EQUAL(sh.order(), T::value ); + + for(int i =0;i +#include "utility/shape/shape.hpp" + +TTS_CASE( "Default constructed shape behavior - Mixed 1D") +{ + kwk::shape shape_d; + kwk::shape shape_s; + + TTS_EQUAL(sizeof(shape_d) , 8UL ); + TTS_EQUAL(sizeof(shape_s) , 1UL ); + + TTS_EQUAL(shape_d.nbdims() , 1 ); + TTS_EQUAL(shape_s.nbdims() , 1 ); + + TTS_EQUAL(shape_d.numel() , 0L ); + TTS_EQUAL(shape_s.numel() , 7L ); + + TTS_EQUAL(shape_d.order() , 1L ); + TTS_EQUAL(shape_s.order() , 1L ); + + TTS_EQUAL(get<0>(shape_d) , 0L ); + TTS_EQUAL(get<0>(shape_s) , 7L ); +}; + +TTS_CASE( "Default constructed shape behavior - Mixed 2D") +{ + kwk::shape shape_dd; + kwk::shape shape_ds; + kwk::shape shape_sd; + kwk::shape shape_ss; + + TTS_EQUAL(sizeof(shape_dd), 16UL); + TTS_EQUAL(sizeof(shape_ds), 8UL); + TTS_EQUAL(sizeof(shape_sd), 8UL); + TTS_EQUAL(sizeof(shape_ss), 1UL); + + TTS_EQUAL(shape_dd.nbdims() , 1L); + TTS_EQUAL(shape_ds.nbdims() , 2L); + TTS_EQUAL(shape_sd.nbdims() , 1L); + TTS_EQUAL(shape_ss.nbdims() , 2L); + + TTS_EQUAL(shape_dd.order(), 2L); + TTS_EQUAL(shape_ds.order(), 2L); + TTS_EQUAL(shape_sd.order(), 2L); + TTS_EQUAL(shape_ss.order(), 2L); + + TTS_EQUAL(get<0>(shape_dd), 0L ); + TTS_EQUAL(get<0>(shape_ds), 0L ); + TTS_EQUAL(get<0>(shape_sd), 7L ); + TTS_EQUAL(get<0>(shape_ss), 7L ); + + TTS_EQUAL(get<1>(shape_dd), 1L ); + TTS_EQUAL(get<1>(shape_ds), 7L ); + TTS_EQUAL(get<1>(shape_sd), 1L ); + TTS_EQUAL(get<1>(shape_ss), 5L ); +}; + +TTS_CASE( "Default constructed shape behavior - Mixed 3D") +{ + kwk::shape shape_ddd; + kwk::shape shape_dds; + kwk::shape shape_dsd; + kwk::shape shape_dss; + kwk::shape shape_sdd; + kwk::shape shape_sds; + kwk::shape shape_ssd; + kwk::shape shape_sss; + + TTS_EQUAL(sizeof(shape_ddd) , 24UL); + TTS_EQUAL(sizeof(shape_dds) , 16UL); + TTS_EQUAL(sizeof(shape_dsd) , 16UL); + TTS_EQUAL(sizeof(shape_dss) , 8UL); + TTS_EQUAL(sizeof(shape_sdd) , 16UL); + TTS_EQUAL(sizeof(shape_sds) , 8UL); + TTS_EQUAL(sizeof(shape_ssd) , 8UL); + TTS_EQUAL(sizeof(shape_sss) , 1UL); + + TTS_EQUAL(shape_ddd.nbdims(), 1L); + TTS_EQUAL(shape_dds.nbdims(), 3L); + TTS_EQUAL(shape_dsd.nbdims(), 2L); + TTS_EQUAL(shape_dss.nbdims(), 3L); + TTS_EQUAL(shape_sdd.nbdims(), 1L); + TTS_EQUAL(shape_sds.nbdims(), 3L); + TTS_EQUAL(shape_ssd.nbdims(), 2L); + TTS_EQUAL(shape_sss.nbdims(), 3L); + + TTS_EQUAL(shape_ddd.order(), 3L); + TTS_EQUAL(shape_dds.order(), 3L); + TTS_EQUAL(shape_dsd.order(), 3L); + TTS_EQUAL(shape_dss.order(), 3L); + TTS_EQUAL(shape_sdd.order(), 3L); + TTS_EQUAL(shape_sds.order(), 3L); + TTS_EQUAL(shape_ssd.order(), 3L); + TTS_EQUAL(shape_sss.order(), 3L); + + TTS_EQUAL(get<0>(shape_ddd), 0L ); + TTS_EQUAL(get<0>(shape_dds), 0L ); + TTS_EQUAL(get<0>(shape_dsd), 0L ); + TTS_EQUAL(get<0>(shape_dss), 0L ); + TTS_EQUAL(get<0>(shape_sdd), 7L ); + TTS_EQUAL(get<0>(shape_sds), 7L ); + TTS_EQUAL(get<0>(shape_ssd), 7L ); + TTS_EQUAL(get<0>(shape_sss), 7L ); + + TTS_EQUAL(get<1>(shape_ddd), 1L ); + TTS_EQUAL(get<1>(shape_dds), 1L ); + TTS_EQUAL(get<1>(shape_dsd), 7L ); + TTS_EQUAL(get<1>(shape_dss), 7L ); + TTS_EQUAL(get<1>(shape_sdd), 1L ); + TTS_EQUAL(get<1>(shape_sds), 1L ); + TTS_EQUAL(get<1>(shape_ssd), 5L ); + TTS_EQUAL(get<1>(shape_sss), 5L ); + + TTS_EQUAL(get<2>(shape_ddd), 1L ); + TTS_EQUAL(get<2>(shape_dds), 7L ); + TTS_EQUAL(get<2>(shape_dsd), 1L ); + TTS_EQUAL(get<2>(shape_dss), 5L ); + TTS_EQUAL(get<2>(shape_sdd), 1L ); + TTS_EQUAL(get<2>(shape_sds), 5L ); + TTS_EQUAL(get<2>(shape_ssd), 1L ); + TTS_EQUAL(get<2>(shape_sss), 3L ); +}; + + +TTS_CASE( "Default constructed shape behavior - Mixed 4D") +{ + kwk::shape shape_dddd; + kwk::shape shape_ddds; + kwk::shape shape_ddsd; + kwk::shape shape_ddss; + kwk::shape shape_dsdd; + kwk::shape shape_dsds; + kwk::shape shape_dssd; + kwk::shape shape_dsss; + kwk::shape shape_sddd; + kwk::shape shape_sdds; + kwk::shape shape_sdsd; + kwk::shape shape_sdss; + kwk::shape shape_ssdd; + kwk::shape shape_ssds; + kwk::shape shape_sssd; + kwk::shape shape_ssss; + + TTS_EQUAL(sizeof(shape_dddd) , 32UL ); + TTS_EQUAL(sizeof(shape_ddds) , 24UL ); + TTS_EQUAL(sizeof(shape_ddsd) , 24UL ); + TTS_EQUAL(sizeof(shape_ddss) , 16UL ); + TTS_EQUAL(sizeof(shape_dsdd) , 24UL ); + TTS_EQUAL(sizeof(shape_dsds) , 16UL ); + TTS_EQUAL(sizeof(shape_dssd) , 16UL ); + TTS_EQUAL(sizeof(shape_dsss) , 8UL ); + TTS_EQUAL(sizeof(shape_sddd) , 24UL ); + TTS_EQUAL(sizeof(shape_sdds) , 16UL ); + TTS_EQUAL(sizeof(shape_sdsd) , 16UL ); + TTS_EQUAL(sizeof(shape_sdss) , 8UL ); + TTS_EQUAL(sizeof(shape_ssdd) , 16UL ); + TTS_EQUAL(sizeof(shape_ssds) , 8UL ); + TTS_EQUAL(sizeof(shape_sssd) , 8UL ); + TTS_EQUAL(sizeof(shape_ssss) , 1UL ); + + TTS_EQUAL(shape_dddd.nbdims(), 1L); + TTS_EQUAL(shape_ddds.nbdims(), 4L); + TTS_EQUAL(shape_ddsd.nbdims(), 3L); + TTS_EQUAL(shape_ddss.nbdims(), 4L); + TTS_EQUAL(shape_dsdd.nbdims(), 2L); + TTS_EQUAL(shape_dsds.nbdims(), 4L); + TTS_EQUAL(shape_dssd.nbdims(), 3L); + TTS_EQUAL(shape_dsss.nbdims(), 4L); + TTS_EQUAL(shape_sddd.nbdims(), 1L); + TTS_EQUAL(shape_sdds.nbdims(), 4L); + TTS_EQUAL(shape_sdsd.nbdims(), 3L); + TTS_EQUAL(shape_sdss.nbdims(), 4L); + TTS_EQUAL(shape_ssdd.nbdims(), 2L); + TTS_EQUAL(shape_ssds.nbdims(), 4L); + TTS_EQUAL(shape_sssd.nbdims(), 3L); + TTS_EQUAL(shape_ssss.nbdims(), 4L); + + TTS_EQUAL(shape_dddd.order(), 4L); + TTS_EQUAL(shape_ddds.order(), 4L); + TTS_EQUAL(shape_ddsd.order(), 4L); + TTS_EQUAL(shape_ddss.order(), 4L); + TTS_EQUAL(shape_dsdd.order(), 4L); + TTS_EQUAL(shape_dsds.order(), 4L); + TTS_EQUAL(shape_dssd.order(), 4L); + TTS_EQUAL(shape_dsss.order(), 4L); + TTS_EQUAL(shape_sddd.order(), 4L); + TTS_EQUAL(shape_sdds.order(), 4L); + TTS_EQUAL(shape_sdsd.order(), 4L); + TTS_EQUAL(shape_sdss.order(), 4L); + TTS_EQUAL(shape_ssdd.order(), 4L); + TTS_EQUAL(shape_ssds.order(), 4L); + TTS_EQUAL(shape_sssd.order(), 4L); + TTS_EQUAL(shape_ssss.order(), 4L); + + TTS_EQUAL(get<0>(shape_dddd), 0L ); + TTS_EQUAL(get<0>(shape_ddds), 0L ); + TTS_EQUAL(get<0>(shape_ddsd), 0L ); + TTS_EQUAL(get<0>(shape_ddss), 0L ); + TTS_EQUAL(get<0>(shape_dsdd), 0L ); + TTS_EQUAL(get<0>(shape_dsds), 0L ); + TTS_EQUAL(get<0>(shape_dssd), 0L ); + TTS_EQUAL(get<0>(shape_dsss), 0L ); + TTS_EQUAL(get<0>(shape_sddd), 9L ); + TTS_EQUAL(get<0>(shape_sdds), 9L ); + TTS_EQUAL(get<0>(shape_sdsd), 9L ); + TTS_EQUAL(get<0>(shape_sdss), 9L ); + TTS_EQUAL(get<0>(shape_ssdd), 9L ); + TTS_EQUAL(get<0>(shape_ssds), 9L ); + TTS_EQUAL(get<0>(shape_sssd), 9L ); + TTS_EQUAL(get<0>(shape_ssss), 9L ); + + TTS_EQUAL(get<1>(shape_dddd), 1L ); + TTS_EQUAL(get<1>(shape_ddds), 1L ); + TTS_EQUAL(get<1>(shape_ddsd), 1L ); + TTS_EQUAL(get<1>(shape_ddss), 1L ); + TTS_EQUAL(get<1>(shape_dsdd), 7L ); + TTS_EQUAL(get<1>(shape_dsds), 7L ); + TTS_EQUAL(get<1>(shape_dssd), 7L ); + TTS_EQUAL(get<1>(shape_dsss), 7L ); + TTS_EQUAL(get<1>(shape_sddd), 1L ); + TTS_EQUAL(get<1>(shape_sdds), 1L ); + TTS_EQUAL(get<1>(shape_sdsd), 1L ); + TTS_EQUAL(get<1>(shape_sdss), 1L ); + TTS_EQUAL(get<1>(shape_ssdd), 7L ); + TTS_EQUAL(get<1>(shape_ssds), 7L ); + TTS_EQUAL(get<1>(shape_sssd), 7L ); + TTS_EQUAL(get<1>(shape_ssss), 7L ); + + TTS_EQUAL(get<2>(shape_dddd), 1L ); + TTS_EQUAL(get<2>(shape_ddds), 1L ); + TTS_EQUAL(get<2>(shape_ddsd), 7L ); + TTS_EQUAL(get<2>(shape_ddss), 7L ); + TTS_EQUAL(get<2>(shape_dsdd), 1L ); + TTS_EQUAL(get<2>(shape_dsds), 1L ); + TTS_EQUAL(get<2>(shape_dssd), 5L ); + TTS_EQUAL(get<2>(shape_dsss), 5L ); + TTS_EQUAL(get<2>(shape_sddd), 1L ); + TTS_EQUAL(get<2>(shape_sdds), 1L ); + TTS_EQUAL(get<2>(shape_sdsd), 7L ); + TTS_EQUAL(get<2>(shape_sdss), 7L ); + TTS_EQUAL(get<2>(shape_ssdd), 1L ); + TTS_EQUAL(get<2>(shape_ssds), 1L ); + TTS_EQUAL(get<2>(shape_sssd), 5L ); + TTS_EQUAL(get<2>(shape_ssss), 5L ); + + TTS_EQUAL(get<3>(shape_dddd), 1L ); + TTS_EQUAL(get<3>(shape_ddds), 7L ); + TTS_EQUAL(get<3>(shape_ddsd), 1L ); + TTS_EQUAL(get<3>(shape_ddss), 5L ); + TTS_EQUAL(get<3>(shape_dsdd), 1L ); + TTS_EQUAL(get<3>(shape_dsds), 5L ); + TTS_EQUAL(get<3>(shape_dssd), 1L ); + TTS_EQUAL(get<3>(shape_dsss), 3L ); + TTS_EQUAL(get<2>(shape_ssss), 5L ); + TTS_EQUAL(get<3>(shape_sddd), 1L ); + TTS_EQUAL(get<3>(shape_sdds), 7L ); + TTS_EQUAL(get<3>(shape_sdsd), 1L ); + TTS_EQUAL(get<3>(shape_sdss), 5L ); + TTS_EQUAL(get<3>(shape_ssdd), 1L ); + TTS_EQUAL(get<3>(shape_ssds), 5L ); + TTS_EQUAL(get<3>(shape_sssd), 1L ); + TTS_EQUAL(get<3>(shape_ssss), 3L ); +}; + +TTS_CASE_TPL( "Default constructed shape behavior - Dynamic 5D -> 10D", sizes<5>) +(::tts::type) +{ + constexpr auto dims = 5+T::value; + kwk::shape> sh; + + TTS_EQUAL(sizeof(sh) , dims*sizeof(std::ptrdiff_t) ); + TTS_EQUAL(sh.nbdims() , 1 ); + TTS_EQUAL(sh.numel() , 0 ); + TTS_EQUAL(sh.order() , dims); + + TTS_EQUAL(get<0>(sh) , 0); + for(int i = 1;i -#include +#include +#include TTS_CASE( "1D shape constructor with joker indexes" ) { @@ -42,7 +40,7 @@ void test_sizes(auto computed, auto expected) { auto comp = kwk::of_size(get<0>(e)); auto ref = kwk::of_size(get<1>(e)); - TTS_EQUAL(comp, ref); + TTS_EQUAL(comp, ref) << "From:\n" << get<0>(e) << "\nand:\n" << get<1>(e); } , kumi::zip(computed,expected) ); diff --git a/test/container/shape/mixed.cpp b/test/utility/shape/mixed.cpp similarity index 78% rename from test/container/shape/mixed.cpp rename to test/utility/shape/mixed.cpp index 9bfe9030..c3cf9c44 100644 --- a/test/container/shape/mixed.cpp +++ b/test/utility/shape/mixed.cpp @@ -1,15 +1,13 @@ //================================================================================================== -/* +/** KIWAKU - Containers Well Made - Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 -*/ +**/ //================================================================================================== #include "test.hpp" -#include -#include +#include +#include TTS_CASE( "1D mixed shape constructor" ) { @@ -17,13 +15,13 @@ TTS_CASE( "1D mixed shape constructor" ) auto s1 = kwk::of_size(7); TTS_CONSTEXPR_EQUAL(sizeof(s1), sizeof(int) ); - TTS_EQUAL(s1.order() , 1 ); + TTS_EQUAL(s1.order() , 1 ); TTS_EQUAL(s1.numel() , 7 ); TTS_EQUAL(get<0>(s1) , 7 ); auto s2 = kwk::of_size(33); TTS_CONSTEXPR_EQUAL(sizeof(s2), sizeof(std::int16_t)); - TTS_EQUAL(s2.order() , 1 ); + TTS_EQUAL(s2.order() , 1 ); TTS_EQUAL(s2.numel() , 33 ); TTS_EQUAL(get<0>(s2) , 33 ); @@ -31,32 +29,32 @@ TTS_CASE( "1D mixed shape constructor" ) TTS_CONSTEXPR_EQUAL(sizeof(ss2) , sizeof(std::int16_t)); TTS_EQUAL(ss2.order() , 1 ); TTS_EQUAL(ss2.numel() , 33 ); - TTS_EQUAL(get<0>(ss2) , 33 ); + TTS_EQUAL(get<0>(ss2) , 33 ); auto s2d = kwk::of_size(std::int16_t{33}); TTS_CONSTEXPR_EQUAL(sizeof(s2d), sizeof(std::int16_t) ); - TTS_EQUAL(s2d.order() , 1 ); + TTS_EQUAL(s2d.order() , 1 ); TTS_EQUAL(s2d.numel() , 33 ); TTS_EQUAL(get<0>(s2d) , 33 ); auto s3 = kwk::of_size(kwk::fixed<9>); TTS_CONSTEXPR_EQUAL(sizeof(s3) , 1ULL); - TTS_CONSTEXPR_EQUAL(sizeof(get<0>(s3)), 1ULL); - TTS_EQUAL(s3.order() , 1 ); - TTS_EQUAL(s3.numel() , 9 ); - TTS_EQUAL(get<0>(s3) , 9 ); + TTS_CONSTEXPR_EQUAL(sizeof(get<0>(s3)), 4ULL); + TTS_EQUAL(s3.order() , 1 ); + TTS_EQUAL(s3.numel() , 9 ); + TTS_EQUAL(get<0>(s3) , 9 ); auto s3d = kwk::of_size(kwk::fixed<390>); - TTS_CONSTEXPR_EQUAL(sizeof(s3d) , 1ULL); - TTS_CONSTEXPR_EQUAL(sizeof(get<0>(s3d)) , 2ULL); - TTS_EQUAL(s3d.order() , 1 ); - TTS_EQUAL(s3d.numel() , 390 ); - TTS_EQUAL(get<0>(s3d) , 390 ); + TTS_CONSTEXPR_EQUAL(sizeof(s3d) , 1ULL ); + TTS_CONSTEXPR_EQUAL(sizeof(get<0>(s3d)) , 4ULL ); + TTS_EQUAL(s3d.order() , 1 ); + TTS_EQUAL(s3d.numel() , 390 ); + TTS_EQUAL(get<0>(s3d) , 390 ); auto s4 = kwk::of_size(11_c); TTS_CONSTEXPR_EQUAL(sizeof(s4) , 1ULL); TTS_CONSTEXPR_EQUAL(sizeof(get<0>(s4)), 1ULL); - TTS_EQUAL(s4.order() , 1 ); + TTS_EQUAL(s4.order() , 1 ); TTS_EQUAL(s4.numel() , 11 ); TTS_EQUAL(get<0>(s4) , 11 ); }; @@ -68,7 +66,7 @@ TTS_CASE( "2D partial shape constructor" ) auto s1 = kwk::of_size(7,9); TTS_CONSTEXPR_EQUAL(sizeof(s1), 2*sizeof(7) ); - TTS_EQUAL(s1.order() , 2 ); + TTS_EQUAL(s1.order() , 2 ); TTS_EQUAL(s1.numel() , 63 ); TTS_EQUAL(get<0>(s1) , 7 ); TTS_EQUAL(get<1>(s1) , 9 ); @@ -76,7 +74,7 @@ TTS_CASE( "2D partial shape constructor" ) auto s2 = kwk::of_size(9,3); TTS_CONSTEXPR_EQUAL(sizeof(s2), 2*sizeof(std::int16_t) ); - TTS_EQUAL(s2.order() , 2 ); + TTS_EQUAL(s2.order() , 2 ); TTS_EQUAL(s2.numel() , 27 ); TTS_EQUAL(get<0>(s2) , 9 ); TTS_EQUAL(get<1>(s2) , 3 ); @@ -84,7 +82,7 @@ TTS_CASE( "2D partial shape constructor" ) auto s3 = kwk::of_size(5_c, 8); TTS_CONSTEXPR_EQUAL(sizeof(s3), sizeof(int) ); - TTS_EQUAL(s3.order() , 2 ); + TTS_EQUAL(s3.order() , 2 ); TTS_EQUAL(s3.numel() , 40 ); TTS_EQUAL(get<0>(s3) , 5 ); TTS_EQUAL(get<1>(s3) , 8 ); @@ -92,7 +90,7 @@ TTS_CASE( "2D partial shape constructor" ) auto s4 = kwk::of_size(5, 9_c); TTS_CONSTEXPR_EQUAL(sizeof(s4), sizeof(std::int16_t) ); - TTS_EQUAL(s4.order() , 2 ); + TTS_EQUAL(s4.order() , 2 ); TTS_EQUAL(s4.numel() , 45 ); TTS_EQUAL(get<0>(s4) , 5 ); TTS_EQUAL(get<1>(s4) , 9 ); @@ -100,7 +98,7 @@ TTS_CASE( "2D partial shape constructor" ) auto s5 = kwk::of_size(7_c, 9_c); TTS_CONSTEXPR_EQUAL(sizeof(s5), 1ULL); - TTS_EQUAL(s5.order() , 2 ); + TTS_EQUAL(s5.order() , 2 ); TTS_EQUAL(s5.numel() , 63 ); TTS_EQUAL(get<0>(s5) , 7 ); TTS_EQUAL(get<1>(s5) , 9 ); @@ -122,7 +120,7 @@ TTS_CASE( "3D partial shape constructor" ) auto s2 = kwk::of_size(9,3,7); TTS_CONSTEXPR_EQUAL(sizeof(s2), 3*sizeof(std::int16_t) ); - TTS_EQUAL(s2.order() , 3 ); + TTS_EQUAL(s2.order() , 3 ); TTS_EQUAL(s2.numel() , 189 ); TTS_EQUAL(get<0>(s2) , 9 ); TTS_EQUAL(get<1>(s2) , 3 ); @@ -131,7 +129,7 @@ TTS_CASE( "3D partial shape constructor" ) auto s3 = kwk::of_size(7_c,9,11); TTS_CONSTEXPR_EQUAL(sizeof(s3), 2*sizeof(int) ); - TTS_EQUAL(s3.order() , 3 ); + TTS_EQUAL(s3.order() , 3 ); TTS_EQUAL(s3.numel() , 693 ); TTS_EQUAL(get<0>(s3) , 7 ); TTS_EQUAL(get<1>(s3) , 9 ); @@ -140,7 +138,7 @@ TTS_CASE( "3D partial shape constructor" ) auto s4 = kwk::of_size(7,9_c,11); TTS_CONSTEXPR_EQUAL(sizeof(s4), 2*sizeof(int) ); - TTS_EQUAL(s4.order() , 3 ); + TTS_EQUAL(s4.order() , 3 ); TTS_EQUAL(s4.numel() , 693 ); TTS_EQUAL(get<0>(s4) , 7 ); TTS_EQUAL(get<1>(s4) , 9 ); @@ -149,7 +147,7 @@ TTS_CASE( "3D partial shape constructor" ) auto s5 = kwk::of_size(7,9,11_c); TTS_CONSTEXPR_EQUAL(sizeof(s5), 2*sizeof(int) ); - TTS_EQUAL(s5.order() , 3 ); + TTS_EQUAL(s5.order() , 3 ); TTS_EQUAL(s5.numel() , 693 ); TTS_EQUAL(get<0>(s5) , 7 ); TTS_EQUAL(get<1>(s5) , 9 ); @@ -158,7 +156,7 @@ TTS_CASE( "3D partial shape constructor" ) auto s6 = kwk::of_size(7_c,9_c,11); TTS_CONSTEXPR_EQUAL(sizeof(s6), sizeof(int) ); - TTS_EQUAL(s6.order() , 3 ); + TTS_EQUAL(s6.order() , 3 ); TTS_EQUAL(s6.numel() , 693 ); TTS_EQUAL(get<0>(s6) , 7 ); TTS_EQUAL(get<1>(s6) , 9 ); @@ -167,7 +165,7 @@ TTS_CASE( "3D partial shape constructor" ) auto s7 = kwk::of_size(7,9_c,11_c); TTS_CONSTEXPR_EQUAL(sizeof(s7), sizeof(int) ); - TTS_EQUAL(s7.order() , 3 ); + TTS_EQUAL(s7.order() , 3 ); TTS_EQUAL(s7.numel() , 693 ); TTS_EQUAL(get<0>(s7) , 7 ); TTS_EQUAL(get<1>(s7) , 9 ); @@ -176,7 +174,7 @@ TTS_CASE( "3D partial shape constructor" ) auto s8 = kwk::of_size(7_c,9,11_c); TTS_CONSTEXPR_EQUAL(sizeof(s8), sizeof(std::int16_t) ); - TTS_EQUAL(s8.order() , 3 ); + TTS_EQUAL(s8.order() , 3 ); TTS_EQUAL(s8.numel() , 693 ); TTS_EQUAL(get<0>(s8) , 7 ); TTS_EQUAL(get<1>(s8) , 9 ); @@ -185,7 +183,7 @@ TTS_CASE( "3D partial shape constructor" ) auto s9 = kwk::of_size(7_c,9_c,11_c); TTS_CONSTEXPR_EQUAL(sizeof(s9), 1ULL ); - TTS_EQUAL(s9.order() , 3 ); + TTS_EQUAL(s9.order() , 3 ); TTS_EQUAL(s9.numel() , 693 ); TTS_EQUAL(get<0>(s9) , 7 ); TTS_EQUAL(get<1>(s9) , 9 ); diff --git a/test/container/shape/of_shape.cpp b/test/utility/shape/of_size.cpp similarity index 75% rename from test/container/shape/of_shape.cpp rename to test/utility/shape/of_size.cpp index 6d6e9c26..cba8e2fe 100644 --- a/test/container/shape/of_shape.cpp +++ b/test/utility/shape/of_size.cpp @@ -1,15 +1,14 @@ //================================================================================================== /** KIWAKU - Containers Well Made - Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 **/ //================================================================================================== #include "test.hpp" -#include "container/shape/shape.hpp" +#include +#include "utility/shape/shape.hpp" TTS_CASE_TPL( "Building a nD shape with kwk::of_shape(a1,...,an)", sizes<10>) (::tts::type) @@ -19,5 +18,9 @@ TTS_CASE_TPL( "Building a nD shape with kwk::of_shape(a1,...,an)", sizes<10>) return kwk::of_size( 3*static_cast(1+Idx)...); }; - test_nD(T{}, f(up_to{})); + auto sh = f(up_to{}); + TTS_EQUAL(sh.order(), T::value ); + + for(int i =0;i +#include TTS_CASE( "nbdims behavior on nD shape" ) { - TTS_EXPR_IS( kwk::of_size(4,2,6,9).nbdims() , int ); - TTS_EXPR_IS( kwk::of_size(4,2,6,9).nbdims() , int ); - TTS_EXPR_IS( kwk::of_size(4,2,6,9).nbdims() , int ); - TTS_EXPR_IS( kwk::of_size(4,2,6,9).nbdims() , int ); + TTS_EXPR_IS( kwk::of_size(4,2,6,9).nbdims() , std::ptrdiff_t ); + TTS_EXPR_IS( kwk::of_size(4,2,6,9).nbdims() , std::ptrdiff_t ); + TTS_EXPR_IS( kwk::of_size(4,2,6,9).nbdims() , std::ptrdiff_t ); + TTS_EXPR_IS( kwk::of_size(4,2,6,9).nbdims() , std::ptrdiff_t ); TTS_EQUAL( (kwk::of_size(4,2,6,9).nbdims()), 4); TTS_EQUAL( (kwk::of_size(4,2,6,1).nbdims()), 3); @@ -26,12 +24,12 @@ TTS_CASE( "nbdims behavior on nD shape" ) TTS_CASE( "numel behavior on nD shape" ) { - TTS_EXPR_IS( kwk::of_size(4,2,6,9).numel() , int ); - TTS_EXPR_IS( kwk::of_size(4,2,6,9).numel() , int ); - TTS_EXPR_IS( kwk::of_size(4,2,6,9).numel() , int ); - TTS_EXPR_IS( kwk::of_size(4,2,6,9).numel() , std::uint32_t ); + TTS_EXPR_IS( kwk::of_size(4,2,6,9).numel() , std::ptrdiff_t); + TTS_EXPR_IS( kwk::of_size(4,2,6,9).numel() , std::ptrdiff_t); + TTS_EXPR_IS( kwk::of_size(4,2,6,9).numel() , std::ptrdiff_t); + TTS_EXPR_IS( kwk::of_size(4,2,6,9).numel() , std::ptrdiff_t); TTS_EXPR_IS( kwk::of_size(4,2,6,9).numel(), std::ptrdiff_t); - TTS_EXPR_IS( kwk::of_size(4,2,6,9).numel() , std::size_t ); + TTS_EXPR_IS( kwk::of_size(4,2,6,9).numel() , std::ptrdiff_t); TTS_EQUAL( (kwk::of_size(4,2,6,9).numel()), 432 ); TTS_EQUAL( (kwk::of_size(4,2,6,1).numel()), 48 ); diff --git a/test/container/shape/shape.hpp b/test/utility/shape/shape.hpp similarity index 50% rename from test/container/shape/shape.hpp rename to test/utility/shape/shape.hpp index 793e23eb..3df83da4 100644 --- a/test/container/shape/shape.hpp +++ b/test/utility/shape/shape.hpp @@ -1,15 +1,13 @@ //================================================================================================== /** KIWAKU - Containers Well Made - Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 **/ //================================================================================================== #pragma once -#include +#include template> struct sizes; @@ -18,17 +16,3 @@ template struct sizes> using types_list = tts::types...>; }; -template inline void test_0D(Shape const& sh) -{ - TTS_EQUAL(sh.nbdims() , 0 ); - TTS_EQUAL(sh.numel() , 0 ); - TTS_EQUAL(sh.size() , 0 ); -} - -template inline void test_nD(Size const&, Shape const& sh) -{ - TTS_EQUAL(sh.order(), Size::value ); - - TTS_EQUAL(kwk::get<0>(sh) , 3 ); - TTS_EQUAL(kwk::get(sh), 3*Size::value); -} diff --git a/test/container/shape/strictly_contain.cpp b/test/utility/shape/strictly_contain.cpp similarity index 97% rename from test/container/shape/strictly_contain.cpp rename to test/utility/shape/strictly_contain.cpp index 518bd2fc..336317fd 100644 --- a/test/container/shape/strictly_contain.cpp +++ b/test/utility/shape/strictly_contain.cpp @@ -1,14 +1,12 @@ //================================================================================================== -/* +/** KIWAKU - Containers Well Made - Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 -*/ +**/ //================================================================================================== #include "test.hpp" -#include +#include TTS_CASE( "Does a shape strictly-contains another" ) { diff --git a/test/container/shape/swap.cpp b/test/utility/shape/swap.cpp similarity index 91% rename from test/container/shape/swap.cpp rename to test/utility/shape/swap.cpp index f6df67dc..6684d41f 100644 --- a/test/container/shape/swap.cpp +++ b/test/utility/shape/swap.cpp @@ -1,14 +1,12 @@ //================================================================================================== /** KIWAKU - Containers Well Made - Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 **/ //================================================================================================== #include "test.hpp" -#include +#include TTS_CASE( "swap behavior on 1D shape" ) { diff --git a/test/container/shape/tuple.cpp b/test/utility/shape/tuple.cpp similarity index 57% rename from test/container/shape/tuple.cpp rename to test/utility/shape/tuple.cpp index fb60c85a..810a2a7a 100644 --- a/test/container/shape/tuple.cpp +++ b/test/utility/shape/tuple.cpp @@ -1,25 +1,23 @@ //================================================================================================== /** KIWAKU - Containers Well Made - Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 **/ //================================================================================================== #include "test.hpp" -#include +#include TTS_CASE( "Checks tuple API for kwk::shape - read only access") { auto const _7d = kwk::of_size(3,5,7,9,11,13,69); auto [c70,c71,c72,c73,c74,c75,c76] = _7d; - TTS_EQUAL(c70, _7d.get<0>()); - TTS_EQUAL(c71, _7d.get<1>()); - TTS_EQUAL(c72, _7d.get<2>()); - TTS_EQUAL(c73, _7d.get<3>()); - TTS_EQUAL(c74, _7d.get<4>()); - TTS_EQUAL(c75, _7d.get<5>()); - TTS_EQUAL(c76, _7d.get<6>()); + TTS_EQUAL(c70, get<0>(_7d)); + TTS_EQUAL(c71, get<1>(_7d)); + TTS_EQUAL(c72, get<2>(_7d)); + TTS_EQUAL(c73, get<3>(_7d)); + TTS_EQUAL(c74, get<4>(_7d)); + TTS_EQUAL(c75, get<5>(_7d)); + TTS_EQUAL(c76, get<6>(_7d)); }; diff --git a/test/utility/slicer/CMakeLists.txt b/test/utility/slicer/CMakeLists.txt new file mode 100644 index 00000000..42a5d6fc --- /dev/null +++ b/test/utility/slicer/CMakeLists.txt @@ -0,0 +1,15 @@ +##================================================================================================== +## KIWAKU - Containers Well Made +## Copyright : KIWAKU Contributors & Maintainers +## SPDX-License-Identifier: BSL-1.0 +##================================================================================================== +set ( SOURCES + api.cpp + all.cpp + to.cpp + from.cpp + between.cpp + every.cpp + ) + +make_unit("utility.slicer" ${SOURCES}) diff --git a/test/utility/slicer/all.cpp b/test/utility/slicer/all.cpp new file mode 100644 index 00000000..f91553a9 --- /dev/null +++ b/test/utility/slicer/all.cpp @@ -0,0 +1,47 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include "test.hpp" +#include + +TTS_CASE("Check dynamic slicing for kwk::_") +{ + using namespace kwk::literals; + + auto shp = kwk::of_size(2, 4, 5, 10); + + TTS_EQUAL(shp(kwk::_) , kwk::of_size(400)); + TTS_EQUAL(shp(kwk::_, kwk::_) , kwk::of_size(2, 200)); + TTS_EQUAL(shp(kwk::_, kwk::_, kwk::_) , kwk::of_size(2, 4, 50)); + TTS_EQUAL(shp(kwk::_, kwk::_, kwk::_, kwk::_), shp); +}; + + +TTS_CASE("Check static slicing for kwk::_") +{ + using namespace kwk::literals; + + auto shp = kwk::of_size(2_c, 4_c, 5_c, 10_c); + + TTS_EQUAL(shp(kwk::_) , kwk::of_size(400)); + TTS_EQUAL(shp(kwk::_).extent<0>(), 400); + + TTS_EQUAL(shp(kwk::_, kwk::_) , kwk::of_size(2, 200)); + TTS_EQUAL(shp(kwk::_, kwk::_).extent<0>(), 2); + TTS_EQUAL(shp(kwk::_, kwk::_).extent<1>(), 200); + + TTS_EQUAL(shp(kwk::_, kwk::_, kwk::_) , kwk::of_size(2, 4, 50)); + TTS_EQUAL(shp(kwk::_, kwk::_, kwk::_).extent<0>(), 2); + TTS_EQUAL(shp(kwk::_, kwk::_, kwk::_).extent<1>(), 4); + TTS_EQUAL(shp(kwk::_, kwk::_, kwk::_).extent<2>(), 50); + + TTS_EQUAL(shp(kwk::_, kwk::_, kwk::_, kwk::_) , shp); + TTS_EQUAL(shp(kwk::_, kwk::_, kwk::_, kwk::_).extent<0>(), 2); + TTS_EQUAL(shp(kwk::_, kwk::_, kwk::_, kwk::_).extent<1>(), 4); + TTS_EQUAL(shp(kwk::_, kwk::_, kwk::_, kwk::_).extent<2>(), 5); + TTS_EQUAL(shp(kwk::_, kwk::_, kwk::_, kwk::_).extent<3>(), 10); +}; diff --git a/test/utility/slicer/api.cpp b/test/utility/slicer/api.cpp new file mode 100644 index 00000000..a0c736ea --- /dev/null +++ b/test/utility/slicer/api.cpp @@ -0,0 +1,147 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include "test.hpp" +#include + +namespace kwk_test +{ + template + struct slicer + { + T dim; + constexpr slicer(T dim_): dim(dim_) { } + }; + + template + constexpr auto reshape( kwk::shape const& sh + , slicer s + , kumi::index_t const& + ) noexcept + { + + if constexpr (requires{ T::value; }) + { + return kwk::fixed; + } + else + { + return get(sh) + 10 * s.dim; + } + } +} + +TTS_CASE("Check that slicing keeps dynamic values") +{ + auto shp1 = kwk::of_size(7); + auto shp2 = kwk::of_size(7, 3); + auto shp3 = kwk::of_size(7, 3, 5); + auto shp4 = kwk::of_size(7, 3, 5, 2); + auto shp7 = kwk::of_size(7, 3, 5, 2, 6, 8, 4); + + auto sl1 = kwk_test::slicer(1); + auto sl2 = kwk_test::slicer(2); + auto sl3 = kwk_test::slicer(3); + auto sl4 = kwk_test::slicer(4); + auto sl5 = kwk_test::slicer(5); + auto sl6 = kwk_test::slicer(6); + auto sl7 = kwk_test::slicer(7); + + auto res1 = shp1(sl1); + auto res2 = shp2(sl1, sl2); + auto res3 = shp3(sl1, sl2, sl3); + auto res4 = shp4(sl1, sl2, sl3, sl4); + auto res7 = shp7(sl1, sl2, sl3, sl4, sl5, sl6, sl7); + + TTS_EQUAL(get<0>(res1), 17); + TTS_EQUAL(get<0>(res2), 17); + TTS_EQUAL(get<0>(res3), 17); + TTS_EQUAL(get<0>(res4), 17); + TTS_EQUAL(get<0>(res7), 17); + + TTS_EQUAL(get<1>(res2), 23); + TTS_EQUAL(get<1>(res3), 23); + TTS_EQUAL(get<1>(res4), 23); + TTS_EQUAL(get<1>(res7), 23); + + TTS_EQUAL(get<2>(res3), 35); + TTS_EQUAL(get<2>(res4), 35); + TTS_EQUAL(get<2>(res7), 35); + + TTS_EQUAL(get<3>(res4), 42); + TTS_EQUAL(get<3>(res7), 42); + + TTS_EQUAL(get<4>(res7), 56); + TTS_EQUAL(get<5>(res7), 68); + TTS_EQUAL(get<6>(res7), 74); + +}; + +TTS_CASE("Check that slicing keeps static values") +{ + using namespace kwk::literals; + + auto shp1 = kwk::of_size(7); + auto shp2 = kwk::of_size(7, 3); + auto shp3 = kwk::of_size(7, 3, 5); + auto shp4 = kwk::of_size(7, 3, 5, 2); + auto shp7 = kwk::of_size(7, 3, 5, 2, 6, 8, 4); + + auto sl1 = kwk_test::slicer(1_c); + auto sl2 = kwk_test::slicer(2_c); + auto sl3 = kwk_test::slicer(3_c); + auto sl4 = kwk_test::slicer(4_c); + auto sl5 = kwk_test::slicer(5_c); + auto sl6 = kwk_test::slicer(6_c); + auto sl7 = kwk_test::slicer(7_c); + + auto res1 = shp1(sl1); + auto res2 = shp2(sl1, sl2); + auto res3 = shp3(sl1, sl2, sl3); + auto res4 = shp4(sl1, sl2, sl3, sl4); + auto res7 = shp7(sl1, sl2, sl3, sl4, sl5, sl6, sl7); + + // 0 + 1 * 10 + TTS_EQUAL(get<0>(res1), 10U); + TTS_EQUAL(get<0>(res2), 10U); + TTS_EQUAL(get<0>(res3), 10U); + TTS_EQUAL(get<0>(res4), 10U); + TTS_EQUAL(get<0>(res7), 10U); + TTS_EQUAL(res1.extent<0>(), 10U); + TTS_EQUAL(res2.extent<0>(), 10U); + TTS_EQUAL(res3.extent<0>(), 10U); + TTS_EQUAL(res4.extent<0>(), 10U); + TTS_EQUAL(res7.extent<0>(), 10U); + // 1 + 2 * 10 + TTS_EQUAL(get<1>(res2), 21U); + TTS_EQUAL(get<1>(res3), 21U); + TTS_EQUAL(get<1>(res4), 21U); + TTS_EQUAL(get<1>(res7), 21U); + TTS_EQUAL(res2.extent<1>(), 21U); + TTS_EQUAL(res3.extent<1>(), 21U); + TTS_EQUAL(res4.extent<1>(), 21U); + TTS_EQUAL(res7.extent<1>(), 21U); + // 2 + 3 * 10 + TTS_EQUAL(get<2>(res3), 32U); + TTS_EQUAL(get<2>(res4), 32U); + TTS_EQUAL(get<2>(res7), 32U); + TTS_EQUAL(res3.extent<2>(), 32U); + TTS_EQUAL(res4.extent<2>(), 32U); + TTS_EQUAL(res7.extent<2>(), 32U); + + TTS_EQUAL(get<3>(res4), 43U); + TTS_EQUAL(get<3>(res7), 43U); + TTS_EQUAL(res4.extent<3>(), 43U); + TTS_EQUAL(res7.extent<3>(), 43U); + + TTS_EQUAL(get<4>(res7) , 54U); + TTS_EQUAL(res7.extent<4>(), 54U); + TTS_EQUAL(get<5>(res7) , 65U); + TTS_EQUAL(res7.extent<5>(), 65U); + TTS_EQUAL(get<6>(res7) , 76U); + TTS_EQUAL(res7.extent<6>(), 76U); +}; \ No newline at end of file diff --git a/test/utility/slicer/between.cpp b/test/utility/slicer/between.cpp new file mode 100644 index 00000000..6bce9b24 --- /dev/null +++ b/test/utility/slicer/between.cpp @@ -0,0 +1,102 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include "test.hpp" +#include + +TTS_CASE("Check dynamic slicing for kwk::between") +{ + using namespace kwk::literals; + using kwk::between; + using kwk::fixed; + using kwk::of_size; + + int d0 = 13, d1 = 15, d2 = 47, d3 = 27; + auto shp = kwk::of_size(d0, d1, d2, d3); + + constexpr unsigned int v0 = 1, v1 = 4, v2 = 8, v3 = 9, v4 = 11; + + auto b0 = between(v0, v1); auto c0 = between(fixed, fixed); + auto b1 = between(v1, v2); auto c1 = between(fixed, fixed); + auto b2 = between(v2, v3); auto c2 = between(fixed, fixed); + auto b3 = between(v3, v4); auto c3 = between(fixed, fixed); + + TTS_EQUAL ( shp(b0) , of_size(v1 - v0)); + TTS_EQUAL ( shp(b0, b1) , of_size(v1 - v0, v2 - v1)); + TTS_EQUAL ( shp(b0, b1, b2) , of_size(v1 - v0, v2 - v1, v3 - v2)); + TTS_EQUAL ( shp(b0, b1, b2, b3) , of_size(v1 - v0, v2 - v1, v3 - v2, v4 - v3)); + + TTS_EQUAL ( shp(c0) , of_size(v1 - v0)); + TTS_EQUAL ( shp(c0, c1) , of_size(v1 - v0, v2 - v1)); + TTS_EQUAL ( shp(c0, c1, c2) , of_size(v1 - v0, v2 - v1, v3 - v2)); + TTS_EQUAL ( shp(c0, c1, c2, c3) , of_size(v1 - v0, v2 - v1, v3 - v2, v4 - v3)); + + // TTS_EXPR_IS(shp(b0).extent<0>(), kwk::joker); already tested in API.exe + TTS_EQUAL(shp(c0).extent<0>() , v1 - v0); + TTS_EQUAL(shp(c0, c1).extent<0>() , v1 - v0); + TTS_EQUAL(shp(c0, c1).extent<1>() , v2 - v1); + + TTS_EQUAL(shp(c0, c1, c2).extent<0>() , v1 - v0); + TTS_EQUAL(shp(c0, c1, c2).extent<1>() , v2 - v1); + TTS_EQUAL(shp(c0, c1, c2).extent<2>() , v3 - v2); + + TTS_EQUAL(shp(c0, c1, c2, c3).extent<0>() , v1 - v0); + TTS_EQUAL(shp(c0, c1, c2, c3).extent<1>() , v2 - v1); + TTS_EQUAL(shp(c0, c1, c2, c3).extent<2>() , v3 - v2); + TTS_EQUAL(shp(c0, c1, c2, c3).extent<3>() , v4 - v3); +}; + +TTS_CASE("Check static slicing for kwk::between") +{ + using namespace kwk::literals; + using kwk::between; + using kwk::fixed; + using kwk::of_size; + + auto d0 = 13_c; + auto d1 = 15_c; + auto d2 = 47_c; + auto d3 = 27_c; + + auto shp = kwk::of_size(d0, d1, d2, d3); + + constexpr unsigned int v0 = 1, v1 = 4, v2 = 8, v3 = 9, v4 = 11; + + auto b0 = between(v0, v1); auto c0 = between(fixed, fixed); + auto b1 = between(v1, v2); auto c1 = between(fixed, fixed); + auto b2 = between(v2, v3); auto c2 = between(fixed, fixed); + auto b3 = between(v3, v4); auto c3 = between(fixed, fixed); + + TTS_EQUAL ( shp(b0) , of_size(v1 - v0)); + TTS_EQUAL ( shp(b0, b1) , of_size(v1 - v0, v2 - v1)); + TTS_EQUAL ( shp(b0, b1, b2) , of_size(v1 - v0, v2 - v1, v3 - v2)); + TTS_EQUAL ( shp(b0, b1, b2, b3) , of_size(v1 - v0, v2 - v1, v3 - v2, v4 - v3)); + + TTS_EXPECT ( shp(b0).is_fully_dynamic); + TTS_EXPECT ( shp(b0, b1).is_fully_dynamic); + TTS_EXPECT ( shp(b0, b1, b2).is_fully_dynamic); + TTS_EXPECT ( shp(b0, b1, b2, b3).is_fully_dynamic); + + TTS_EQUAL ( shp(c0) , of_size(v1 - v0)); + TTS_EQUAL ( shp(c0, c1) , of_size(v1 - v0, v2 - v1)); + TTS_EQUAL ( shp(c0, c1, c2) , of_size(v1 - v0, v2 - v1, v3 - v2)); + TTS_EQUAL ( shp(c0, c1, c2, c3) , of_size(v1 - v0, v2 - v1, v3 - v2, v4 - v3)); + + // TTS_EXPR_IS(shp(b0).extent<0>(), kwk::joker); already tested in API.exe + TTS_EQUAL(shp(c0).extent<0>() , v1 - v0); + TTS_EQUAL(shp(c0, c1).extent<0>() , v1 - v0); + TTS_EQUAL(shp(c0, c1).extent<1>() , v2 - v1); + + TTS_EQUAL(shp(c0, c1, c2).extent<0>() , v1 - v0); + TTS_EQUAL(shp(c0, c1, c2).extent<1>() , v2 - v1); + TTS_EQUAL(shp(c0, c1, c2).extent<2>() , v3 - v2); + + TTS_EQUAL(shp(c0, c1, c2, c3).extent<0>() , v1 - v0); + TTS_EQUAL(shp(c0, c1, c2, c3).extent<1>() , v2 - v1); + TTS_EQUAL(shp(c0, c1, c2, c3).extent<2>() , v3 - v2); + TTS_EQUAL(shp(c0, c1, c2, c3).extent<3>() , v4 - v3); +}; diff --git a/test/utility/slicer/every.cpp b/test/utility/slicer/every.cpp new file mode 100644 index 00000000..ccc23262 --- /dev/null +++ b/test/utility/slicer/every.cpp @@ -0,0 +1,97 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include "test.hpp" +#include + +std::uint32_t sz(auto s, auto d) { return 1 + s/d; } + +TTS_CASE("Check kwk::every special cases") +{ + using namespace kwk::literals; + using kwk::every; + using kwk::fixed; + using kwk::of_size; + + auto shp = of_size(2, 2, 3_c, 3_c); + auto shp0 = of_size(0, 0, 0_c, 0_c); + + constexpr std::ptrdiff_t unit = 1, zero = 0; + + TTS_EQUAL( shp(every(4), every(5_c), every(6), every(7_c)), of_size(1,1,1,1)); + TTS_EQUAL( shp0(every(4), every(5_c), every(6), every(7_c)), of_size(0,0,0,0)); + + TTS_TYPED_EQUAL(shp(every(4), every(5_c), every(6), every(7_c)).extent<0>(), unit); + TTS_TYPED_EQUAL(shp(every(4), every(5_c), every(6), every(7_c)).extent<1>(), unit); + TTS_TYPED_EQUAL(shp(every(4), every(5_c), every(6), every(7_c)).extent<2>(), unit); + TTS_TYPED_EQUAL(shp(every(4), every(5_c), every(6), every(7_c)).extent<3>(), fixed); + + TTS_TYPED_EQUAL(shp0(every(4), every(5_c), every(6), every(7_c)).extent<0>(), zero); + TTS_TYPED_EQUAL(shp0(every(4), every(5_c), every(6), every(7_c)).extent<1>(), zero); + TTS_TYPED_EQUAL(shp0(every(4), every(5_c), every(6), every(7_c)).extent<2>(), zero); + TTS_TYPED_EQUAL(shp0(every(4), every(5_c), every(6), every(7_c)).extent<3>(), fixed); +}; + +TTS_CASE("Check slicing for kwk::every") +{ + using namespace kwk::literals; + using kwk::every; + using kwk::fixed; + using kwk::of_size; + + constexpr std::ptrdiff_t d0 = 17, d1 = 29; + auto d2 = fixed<23>; + auto d3 = fixed<97>; + + auto shp = of_size(d0, d1, d2, d3); + + constexpr std::ptrdiff_t v0 = 4, v2 = 6, one = 1; + auto v1 = fixed<5>; + auto v3 = fixed<7>; + + auto e0 = every(v0); + auto e1 = every(v1); + auto e2 = every(v2); + auto e3 = every(v3); + + TTS_EQUAL( shp(e0, e1, e2, e3), of_size(d0/v0+1, d1/v1+1, d2/v2+1, d3/v3+1)); + + TTS_TYPED_EQUAL(shp(e0, e1, e2, e3).extent<0>(), d0/v0+one); + TTS_TYPED_EQUAL(shp(e0, e1, e2, e3).extent<1>(), d1/v1+one); + TTS_TYPED_EQUAL(shp(e0, e1, e2, e3).extent<2>(), d2/v2+one); + TTS_TYPED_EQUAL(shp(e0, e1, e2, e3).extent<3>(), d3/v3+fixed); +}; + +TTS_CASE("Check exact slicing for kwk::every") +{ + using namespace kwk::literals; + using kwk::every; + using kwk::fixed; + using kwk::of_size; + + constexpr std::ptrdiff_t d0 = 33, d1 = 99; + auto d2 = fixed<100>; + auto d3 = fixed<1000>; + + auto shp = of_size(d0, d1, d2, d3); + + constexpr std::ptrdiff_t v0 = 3, v2 = 10; + auto v1 = fixed; + auto v3 = fixed; + + auto e0 = every(v0); + auto e1 = every(v1); + auto e2 = every(v2); + auto e3 = every(v3); + + TTS_EQUAL( shp(e0, e1, e2, e3), of_size(d0/v0, d1/v1, d2/v2, d3/v3)); + + TTS_TYPED_EQUAL(shp(e0, e1, e2, e3).extent<0>(), d0/v0); + TTS_TYPED_EQUAL(shp(e0, e1, e2, e3).extent<1>(), d1/v1); + TTS_TYPED_EQUAL(shp(e0, e1, e2, e3).extent<2>(), d2/v2); + TTS_TYPED_EQUAL(shp(e0, e1, e2, e3).extent<3>(), d3/v3); +}; diff --git a/test/utility/slicer/from.cpp b/test/utility/slicer/from.cpp new file mode 100644 index 00000000..278bf615 --- /dev/null +++ b/test/utility/slicer/from.cpp @@ -0,0 +1,241 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include "test.hpp" +#include + +TTS_CASE("Check basic slicing for kwk::from") +{ + using namespace kwk::literals; + using kwk::from; + using kwk::fixed; + + constexpr std::size_t d0 = 1, d1 = 2, d2 = 3, d3 = 5; + auto s2 = kwk::fixed; + auto s3 = kwk::fixed; + + constexpr std::size_t f = 1; + + auto t0 = from(f); + auto t1 = from(fixed); + auto t2 = from(f); + auto t3 = from(fixed); + + auto shp = kwk::of_size(d0, d1, s2, s3); + + TTS_EQUAL( shp(t0, t1, t2, t3) , kwk::of_size(d0-f, d1-f, d2-f, d3-f)); + + TTS_TYPED_EQUAL(shp(t0, t1, t2, t3).extent<0>(), d0-f); + TTS_TYPED_EQUAL(shp(t0, t1, t2, t3).extent<1>(), d1-f); + TTS_TYPED_EQUAL(shp(t0, t1, t2, t3).extent<2>(), d2-f); + TTS_TYPED_EQUAL(shp(t0, t1, t2, t3).extent<3>(), fixed); +}; + +TTS_CASE("Check slicing with end for kwk::from") +{ + using namespace kwk::literals; + using kwk::from; + using kwk::fixed; + using kwk::end; + + constexpr std::ptrdiff_t d0 = 1, d1 = 3, zero = 0; + auto s1 = kwk::fixed; + auto t0 = from(end); + + auto shp = kwk::of_size(d0, s1); + + TTS_EQUAL( shp(t0, t0), kwk::of_size(0, 0)); + TTS_TYPED_EQUAL(shp(t0, t0).extent<0>(), zero); + TTS_TYPED_EQUAL(shp(t0, t0).extent<1>(), fixed); +}; + +TTS_CASE("Check slicing with end-n for kwk::from") +{ + using namespace kwk::literals; + using kwk::from; + using kwk::fixed; + using kwk::end; + + + constexpr std::size_t d0 = 1, d1 = 3, d2 = 5, d3 = 7; + auto s1 = kwk::fixed; + auto s3 = kwk::fixed; + + constexpr std::size_t v0 = 1; + auto c0 = fixed; + auto t0 = from(end-v0); + auto t1 = from(end-c0); + + auto shp = kwk::of_size(d0, s1, d2, s3); + + TTS_EQUAL( shp(t0, t0, t1, t1), kwk::of_size(v0, v0, c0, c0)); + + // shape = d s d s + // slicer = d d s s + // expect = d d d s + TTS_TYPED_EQUAL(shp(t0, t0, t1, t1).extent<0>(), v0); + TTS_TYPED_EQUAL(shp(t0, t0, t1, t1).extent<1>(), v0); + TTS_TYPED_EQUAL(shp(t0, t0, t1, t1).extent<2>(), v0); + TTS_TYPED_EQUAL(shp(t0, t0, t1, t1).extent<3>(), c0); +}; + +TTS_CASE("Check slicing with end/n for kwk::from") +{ + using namespace kwk::literals; + using kwk::from; + using kwk::fixed; + using kwk::end; + + constexpr std::size_t d0 = 3, d1 = 5, d2 = 7, d3 = 9; + auto s1 = kwk::fixed; + auto s3 = kwk::fixed; + + constexpr std::size_t v0 = 2; + auto c0 = fixed; + auto t0 = from(end/v0); + auto t1 = from(end/c0); + + auto shp = kwk::of_size(d0, s1, d2, s3); + + TTS_EQUAL( shp(t0, t0, t1, t1), kwk::of_size(d0 - d0/v0, d1 - d1/v0, d2 - d2/c0, d3 - d3/c0)); + + // shape = d s d s + // slicer = d d s s + // expect = d d d s + TTS_TYPED_EQUAL(shp(t0,t0, t1, t1).extent<0>(), d0 - d0/v0); + TTS_TYPED_EQUAL(shp(t0, t0, t1, t1).extent<1>(), d1 - d1/v0); + TTS_TYPED_EQUAL(shp(t0, t0, t1, t1).extent<2>(), d2 - d2/c0); + TTS_TYPED_EQUAL(shp(t0, t0, t1, t1).extent<3>(), fixed); +}; + +TTS_CASE("Check slicing with (k * end / q) for kwk::from") +{ + using namespace kwk::literals; + using kwk::from; + using kwk::fixed; + using kwk::end; + + constexpr std::size_t d0 = 3, d1 = 5, d2 = 7, d3 = 9, d4 = 11, d5 = 13, d6 = 15, d7 = 17; + auto s4 = kwk::fixed; + auto s5 = kwk::fixed; + auto s6 = kwk::fixed; + auto s7 = kwk::fixed; + + constexpr std::size_t f = 2; + constexpr std::size_t d = 5; + auto fc = fixed; + auto dc = fixed; + + auto tdd = from(end*f/d); + auto tdc = from(end*f/dc); + auto tcd = from(end*fc/d); + auto tcc = from(end*fc/dc); + + auto shp = kwk::of_size(d0, d1, d2, d3, s4, s5, s6, s7); + + auto sliced = shp(tdd, tdc, tcd, tcc, tdd, tdc, tcd, tcc); + TTS_EQUAL ( sliced + , kwk::of_size( d0-d0*f/d, d1-d1*f/d, d2-d2*f/d, d3-d3*f/d + , d4-d4*f/d, d5-d5*f/d, d6-d6*f/d, d7-d7*f/d) + ); + + // shape = d d d d s s s s + // slicer = d d d s d d d s + // expect = d d d d d d d s + TTS_TYPED_EQUAL(sliced.extent<0>(), d0-d0*f/d); + TTS_TYPED_EQUAL(sliced.extent<1>(), d1-d1*f/d); + TTS_TYPED_EQUAL(sliced.extent<2>(), d2-d2*f/d); + TTS_TYPED_EQUAL(sliced.extent<3>(), d3-d3*f/d); + TTS_TYPED_EQUAL(sliced.extent<4>(), d4-d4*f/d); + TTS_TYPED_EQUAL(sliced.extent<5>(), d5-d5*f/d); + TTS_TYPED_EQUAL(sliced.extent<6>(), d6-d6*f/d); + TTS_TYPED_EQUAL(sliced.extent<7>(), fixed); +}; + +TTS_CASE("Check slicing with (k * end / q + dynamic_offset) for kwk::from") +{ + using namespace kwk::literals; + using kwk::from; + using kwk::fixed; + using kwk::end; + + constexpr std::size_t od = 2; + constexpr std::size_t d0 = 5, d1 = 7, d2 = 9, d3 = 11, d4 = 13, d5 = 15, d6 = 17, d7 = 19; + auto s4 = kwk::fixed; + auto s5 = kwk::fixed; + auto s6 = kwk::fixed; + auto s7 = kwk::fixed; + + constexpr std::size_t f = 2; + constexpr std::size_t d = 5; + auto fc = fixed; + auto dc = fixed; + + auto tdd = from(end*f /d + od); + auto tdc = from(end*f /dc + od); + auto tcd = from(end*fc/d + od); + auto tcc = from(end*fc/dc + od); + + auto shp = kwk::of_size(d0, d1, d2, d3, s4, s5, s6, s7); + + auto sliced = shp(tdd, tdc, tcd, tcc, tdd, tdc, tcd, tcc); + TTS_EQUAL ( sliced + , kwk::of_size(d0-d0*f/d-od, d1-d1*f/d-od, d2-d2*f/d-od + , d3-d3*f/d-od, d4-d4*f/d-od, d5-d5*f/d-od, d6-d6*f/d-od, d7-d7*f/d-od) + ); + + TTS_TYPED_EQUAL(sliced.extent<0>(), d0-d0*f/d-od); + TTS_TYPED_EQUAL(sliced.extent<1>(), d1-d1*f/d-od); + TTS_TYPED_EQUAL(sliced.extent<2>(), d2-d2*f/d-od); + TTS_TYPED_EQUAL(sliced.extent<3>(), d3-d3*f/d-od); + TTS_TYPED_EQUAL(sliced.extent<4>(), d4-d4*f/d-od); + TTS_TYPED_EQUAL(sliced.extent<5>(), d5-d5*f/d-od); + TTS_TYPED_EQUAL(sliced.extent<6>(), d6-d6*f/d-od); + TTS_TYPED_EQUAL(sliced.extent<7>(), d7-d7*f/d-od); +}; + +TTS_CASE("Check slicing with (k * end / q + static_offset) for kwk::from") +{ + using namespace kwk::literals; + using kwk::from; + using kwk::fixed; + using kwk::end; + + auto oc = fixed<2UL>; + constexpr std::size_t d0 = 5, d1 = 7, d2 = 9, d3 = 11, d4 = 13, d5 = 15, d6 = 17, d7 = 19; + auto s4 = kwk::fixed; + auto s5 = kwk::fixed; + auto s6 = kwk::fixed; + auto s7 = kwk::fixed; + + constexpr std::size_t f = 2; + constexpr std::size_t d = 5; + auto fc = fixed; + auto dc = fixed; + + auto tdd = from(end*f /d + oc); + auto tdc = from(end*f /dc + oc); + auto tcd = from(end*fc/d + oc); + auto tcc = from(end*fc/dc + oc); + + auto shp = kwk::of_size(d0, d1, d2, d3, s4, s5, s6, s7); + + auto sliced = shp(tdd, tdc, tcd, tcc, tdd, tdc, tcd, tcc); + TTS_EQUAL ( sliced + , kwk::of_size(d0-d0*f/d-oc, d1-d1*f/d-oc, d2-d2*f/d-oc + , d3-d3*f/d-oc, d4-d4*f/d-oc, d5-d5*f/d-oc, d6-d6*f/d-oc, d7-d7*f/d-oc) + ); + + TTS_TYPED_EQUAL(sliced.extent<0>(), d0-d0*f/d-oc); + TTS_TYPED_EQUAL(sliced.extent<1>(), d1-d1*f/d-oc); + TTS_TYPED_EQUAL(sliced.extent<2>(), d2-d2*f/d-oc); + TTS_TYPED_EQUAL(sliced.extent<3>(), d3-d3*f/d-oc); + TTS_TYPED_EQUAL(sliced.extent<4>(), d4-d4*f/d-oc); + TTS_TYPED_EQUAL(sliced.extent<5>(), d5-d5*f/d-oc); + TTS_TYPED_EQUAL(sliced.extent<6>(), d6-d6*f/d-oc); + TTS_TYPED_EQUAL(sliced.extent<7>(), fixed); +}; diff --git a/test/utility/slicer/to.cpp b/test/utility/slicer/to.cpp new file mode 100644 index 00000000..f5872676 --- /dev/null +++ b/test/utility/slicer/to.cpp @@ -0,0 +1,232 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include "test.hpp" +#include + +TTS_CASE("Check basic slicing for kwk::to") +{ + using namespace kwk::literals; + using kwk::to; + using kwk::fixed; + + constexpr std::size_t d0 = 1, d1 = 2, d2 = 3, d3 = 5; + auto s2 = kwk::fixed; + auto s3 = kwk::fixed; + + auto t0 = to(d0); + auto t1 = to(fixed); + auto t2 = to(d2); + auto t3 = to(fixed); + + auto shp = kwk::of_size(d0, d1, s2, s3); + + TTS_EQUAL( shp(t0, t1, t2, t3) , kwk::of_size(d0, d1, d2, d3)); + + // It is possible to get the compile-time extent<0> value, since the value + // returned by to is static <=> its argument is static + // (the shape does not have to be static since its value is not part + // of the computation) + TTS_TYPED_EQUAL(shp(t0, t1, t2, t3).extent<0>(), d0); + TTS_TYPED_EQUAL(shp(t0, t1, t2, t3).extent<1>(), fixed); + TTS_TYPED_EQUAL(shp(t0, t1, t2, t3).extent<2>(), d2); + TTS_TYPED_EQUAL(shp(t0, t1, t2, t3).extent<3>(), fixed); +}; + +TTS_CASE("Check slicing with end for kwk::to") +{ + using namespace kwk::literals; + using kwk::to; + using kwk::fixed; + using kwk::end; + + constexpr std::ptrdiff_t d0 = 1, d1 = 3; + auto s1 = kwk::fixed; + auto t0 = to(end); + + auto shp = kwk::of_size(d0, s1); + + TTS_EQUAL( shp(t0, t0), kwk::of_size(d0, s1)); + TTS_TYPED_EQUAL(shp(t0, t0).extent<0>(), d0); + TTS_TYPED_EQUAL(shp(t0, t0).extent<1>(), fixed); +}; + +TTS_CASE("Check slicing with end-n for kwk::to") +{ + using namespace kwk::literals; + using kwk::to; + using kwk::fixed; + using kwk::end; + + constexpr std::size_t d0 = 1, d1 = 3, d2 = 5, d3 = 7; + auto s1 = kwk::fixed; + auto s3 = kwk::fixed; + + constexpr std::size_t v0 = 1; + auto c0 = fixed; + auto t0 = to(end-v0); + auto t1 = to(end-c0); + + auto shp = kwk::of_size(d0, s1, d2, s3); + + TTS_EQUAL( shp(t0, t0, t1, t1), kwk::of_size(d0-v0, d1-v0, d2-c0, d3-c0)); + + TTS_TYPED_EQUAL(shp(t0, t0, t1, t1).extent<0>(), d0-v0); + TTS_TYPED_EQUAL(shp(t0, t0, t1, t1).extent<1>(), d1-v0); + TTS_TYPED_EQUAL(shp(t0, t0, t1, t1).extent<2>(), d2-c0); + TTS_TYPED_EQUAL(shp(t0, t0, t1, t1).extent<3>(), fixed); +}; + +TTS_CASE("Check slicing with end/n for kwk::to") +{ + using namespace kwk::literals; + using kwk::to; + using kwk::fixed; + using kwk::end; + + constexpr std::size_t d0 = 3, d1 = 5, d2 = 7, d3 = 9; + auto s1 = kwk::fixed; + auto s3 = kwk::fixed; + + constexpr std::size_t v0 = 2; + auto c0 = fixed; + auto t0 = to(end/v0); + auto t1 = to(end/c0); + + auto shp = kwk::of_size(d0, s1, d2, s3); + + TTS_EQUAL( shp(t0, t0, t1, t1), kwk::of_size(d0/v0, d1/v0, d2/c0, d3/c0)); + + TTS_TYPED_EQUAL(shp(t0, t0, t1, t1).extent<0>(), d0/v0); + TTS_TYPED_EQUAL(shp(t0, t0, t1, t1).extent<1>(), d1/v0); + TTS_TYPED_EQUAL(shp(t0, t0, t1, t1).extent<2>(), d2/c0); + TTS_TYPED_EQUAL(shp(t0, t0, t1, t1).extent<3>(), fixed); +}; + +TTS_CASE("Check slicing with (k * end / q) for kwk::to") +{ + using namespace kwk::literals; + using kwk::to; + using kwk::fixed; + using kwk::end; + + constexpr std::size_t d0 = 3, d1 = 5, d2 = 7, d3 = 9, d4 = 11, d5 = 13, d6 = 15, d7 = 17; + auto s4 = kwk::fixed; + auto s5 = kwk::fixed; + auto s6 = kwk::fixed; + auto s7 = kwk::fixed; + + constexpr std::size_t f = 2; + constexpr std::size_t d = 5; + auto fc = fixed; + auto dc = fixed; + + auto tdd = to(end*f/d); + auto tdc = to(end*f/dc); + auto tcd = to(end*fc/d); + auto tcc = to(end*fc/dc); + + auto shp = kwk::of_size(d0, d1, d2, d3, s4, s5, s6, s7); + + auto sliced = shp(tdd, tdc, tcd, tcc, tdd, tdc, tcd, tcc); + TTS_EQUAL ( sliced + , kwk::of_size(d0*f/d, d1*f/d, d2*f/d, d3*f/d, d4*f/d, d5*f/d, d6*f/d, d7*f/d) + ); + + TTS_TYPED_EQUAL(sliced.extent<0>(), d0*f/d); + TTS_TYPED_EQUAL(sliced.extent<1>(), d1*f/d); + TTS_TYPED_EQUAL(sliced.extent<2>(), d2*f/d); + TTS_TYPED_EQUAL(sliced.extent<3>(), d3*f/d); + TTS_TYPED_EQUAL(sliced.extent<4>(), d4*f/d); + TTS_TYPED_EQUAL(sliced.extent<5>(), d5*f/d); + TTS_TYPED_EQUAL(sliced.extent<6>(), d6*f/d); + TTS_TYPED_EQUAL(sliced.extent<7>(), fixed); +}; + +TTS_CASE("Check slicing with (k * end / q + dynamic_offset) for kwk::to") +{ + using namespace kwk::literals; + using kwk::to; + using kwk::fixed; + using kwk::end; + + constexpr std::size_t od = 2; + constexpr std::size_t d0 = 5, d1 = 7, d2 = 9, d3 = 11, d4 = 13, d5 = 15, d6 = 17, d7 = 19; + auto s4 = kwk::fixed; + auto s5 = kwk::fixed; + auto s6 = kwk::fixed; + auto s7 = kwk::fixed; + + constexpr std::size_t f = 2; + constexpr std::size_t d = 5; + auto fc = fixed; + auto dc = fixed; + + auto tdd = to(end*f /d + od); + auto tdc = to(end*f /dc + od); + auto tcd = to(end*fc/d + od); + auto tcc = to(end*fc/dc + od); + + auto shp = kwk::of_size(d0, d1, d2, d3, s4, s5, s6, s7); + + auto sliced = shp(tdd, tdc, tcd, tcc, tdd, tdc, tcd, tcc); + TTS_EQUAL ( sliced + , kwk::of_size(d0*f/d+od, d1*f/d+od, d2*f/d+od + , d3*f/d+od, d4*f/d+od, d5*f/d+od, d6*f/d+od, d7*f/d+od) + ); + + TTS_TYPED_EQUAL(sliced.extent<0>(), d0*f/d+od); + TTS_TYPED_EQUAL(sliced.extent<1>(), d1*f/d+od); + TTS_TYPED_EQUAL(sliced.extent<2>(), d2*f/d+od); + TTS_TYPED_EQUAL(sliced.extent<3>(), d3*f/d+od); + TTS_TYPED_EQUAL(sliced.extent<4>(), d4*f/d+od); + TTS_TYPED_EQUAL(sliced.extent<5>(), d5*f/d+od); + TTS_TYPED_EQUAL(sliced.extent<6>(), d6*f/d+od); + TTS_TYPED_EQUAL(sliced.extent<7>(), d7*f/d+od); +}; + +TTS_CASE("Check slicing with (k * end / q + static_offset) for kwk::to") +{ + using namespace kwk::literals; + using kwk::to; + using kwk::fixed; + using kwk::end; + + auto oc = fixed<2UL>; + constexpr std::size_t d0 = 5, d1 = 7, d2 = 9, d3 = 11, d4 = 13, d5 = 15, d6 = 17, d7 = 19; + auto s4 = kwk::fixed; + auto s5 = kwk::fixed; + auto s6 = kwk::fixed; + auto s7 = kwk::fixed; + + constexpr std::size_t f = 2; + constexpr std::size_t d = 5; + auto fc = fixed; + auto dc = fixed; + + auto tdd = to(end*f /d + oc); + auto tdc = to(end*f /dc + oc); + auto tcd = to(end*fc/d + oc); + auto tcc = to(end*fc/dc + oc); + + auto shp = kwk::of_size(d0, d1, d2, d3, s4, s5, s6, s7); + + auto sliced = shp(tdd, tdc, tcd, tcc, tdd, tdc, tcd, tcc); + TTS_EQUAL ( sliced + , kwk::of_size(d0*f/d+oc, d1*f/d+oc, d2*f/d+oc + , d3*f/d+oc, d4*f/d+oc, d5*f/d+oc, d6*f/d+oc, d7*f/d+oc) + ); + + TTS_TYPED_EQUAL(sliced.extent<0>(), d0*f/d+oc); + TTS_TYPED_EQUAL(sliced.extent<1>(), d1*f/d+oc); + TTS_TYPED_EQUAL(sliced.extent<2>(), d2*f/d+oc); + TTS_TYPED_EQUAL(sliced.extent<3>(), d3*f/d+oc); + TTS_TYPED_EQUAL(sliced.extent<4>(), d4*f/d+oc); + TTS_TYPED_EQUAL(sliced.extent<5>(), d5*f/d+oc); + TTS_TYPED_EQUAL(sliced.extent<6>(), d6*f/d+oc); + TTS_TYPED_EQUAL(sliced.extent<7>(), fixed); +}; diff --git a/test/utility/stride/CMakeLists.txt b/test/utility/stride/CMakeLists.txt new file mode 100644 index 00000000..0249c25e --- /dev/null +++ b/test/utility/stride/CMakeLists.txt @@ -0,0 +1,12 @@ +##================================================================================================== +## KIWAKU - Containers Well Made +## Copyright : KIWAKU Contributors & Maintainers +## SPDX-License-Identifier: BSL-1.0 +##================================================================================================== +set ( SOURCES + as_stride.cpp + with_strides.cpp + linear_index.cpp + ) + +make_unit("utility.stride" ${SOURCES}) diff --git a/test/utility/stride/as_stride.cpp b/test/utility/stride/as_stride.cpp new file mode 100644 index 00000000..ec74bed9 --- /dev/null +++ b/test/utility/stride/as_stride.cpp @@ -0,0 +1,26 @@ +//================================================================================================== +/* + KIWAKU - Containers Well Made + Copyright : KIWAKU Contributors & Maintainers + SPDX-License-Identifier: BSL-1.0 +*/ +//================================================================================================== +#include "test.hpp" +#include +#include + +TTS_CASE( "Convert a shapes to strides" ) +{ + using namespace kwk::literals; + TTS_EQUAL( kwk::as_stride(kwk::shape(9)), kwk::with_strides(1_c) ); + TTS_EQUAL( kwk::as_stride(kwk::shape(9)).is_unit, true ); + + TTS_EQUAL( kwk::as_stride(kwk::shape(3,4)), kwk::with_strides(1_c, 3) ); + TTS_EQUAL( kwk::as_stride(kwk::shape(3,4)).is_unit, true ); + + TTS_EQUAL( kwk::as_stride(kwk::shape(3,5,7)), kwk::with_strides(1_c, 3, 15) ); + TTS_EQUAL( kwk::as_stride(kwk::shape(3,5,7)).is_unit, true ); + + TTS_EQUAL( kwk::as_stride(kwk::shape(2,4,6,8)), kwk::with_strides(1_c, 2, 8, 48) ); + TTS_EQUAL( kwk::as_stride(kwk::shape(2,4,6,8)).is_unit, true ); +}; diff --git a/test/container/utility/linear_index.cpp b/test/utility/stride/linear_index.cpp similarity index 93% rename from test/container/utility/linear_index.cpp rename to test/utility/stride/linear_index.cpp index 0b960069..8614a3e7 100644 --- a/test/container/utility/linear_index.cpp +++ b/test/utility/stride/linear_index.cpp @@ -2,13 +2,11 @@ /** KIWAKU - Containers Well Made Copyright : KIWAKU Contributors & Maintainers - SPDX-License-Identifier: KIWAKU - Containers Well Made - Copyright : KIWAKU Project Contributors SPDX-License-Identifier: BSL-1.0 **/ //================================================================================================== #include "test.hpp" -#include +#include #include TTS_CASE( "1D behavior of linear_index" ) diff --git a/test/utility/stride/with_strides.cpp b/test/utility/stride/with_strides.cpp new file mode 100644 index 00000000..3247faf4 --- /dev/null +++ b/test/utility/stride/with_strides.cpp @@ -0,0 +1,55 @@ +//================================================================================================== +/** + KIWAKU - Containers Well Made + Copyright : KIWAKU Project Contributors + SPDX-License-Identifier: BSL-1.0 +**/ +//================================================================================================== +#include "test.hpp" +#include +#include + +using namespace kwk::literals; +auto in = kumi::tuple{1_c,2_c,9}; + +void test_strides(auto values) +{ + kumi::for_each( [](auto m) + { + auto the_stride = kwk::with_strides(m); + TTS_EQUAL(the_stride.size(), m.size()); + + kumi::for_each( [&](auto o, auto e) { TTS_EQUAL(o,e); }, the_stride, m ); + + if constexpr( std::same_as>) + TTS_CONSTEXPR_EXPECT( the_stride.is_unit ); + else + TTS_CONSTEXPR_EXPECT_NOT( the_stride.is_unit ); + } + , values + ); +} + +TTS_CASE( "Building a 1D stride using with_strides" ) +{ + auto values = kumi::cartesian_product(in); + test_strides(values); +}; + +TTS_CASE( "Building a 2D stride using with_strides" ) +{ + auto values = kumi::cartesian_product(in,in); + test_strides(values); +}; + +TTS_CASE( "Building a 3D stride using with_strides" ) +{ + auto values = kumi::cartesian_product(in,in,in); + test_strides(values); +}; + +TTS_CASE( "Building a 4D stride using with_strides" ) +{ + auto values = kumi::cartesian_product(in,in,in,in); + test_strides(values); +};