From 0fafe92173197288defadaf753a5e0871409fe5c Mon Sep 17 00:00:00 2001 From: Andrew Lumsdaine Date: Thu, 6 Jun 2024 00:02:01 -0700 Subject: [PATCH] Add simplified C++23 `chunk_view` (#5035) This PR adds a class to provide a subset of the functionality of the C++23 `std::ranges::chunk_view`. This view divides an underlying view into a range of equal-sized chunks (the last one may be shorter than the others). A complete description of `chunk_view` can be found on cppreference.com, which also includes "exposition only" aspects that point to particular implementation approaches. We did not adopt those approaches in most cases, though the public API of the class matches the spec, for the functions that we did implement. This view will be used to partition the original input data from the user query into, well, chunks that will be individually sorted and then written to a TileDB array as a data block. Data blocks are of fixed and uniform byte size that will contain a chunk smaller than or equal to its byte limit. * The class assumes a` random_access_range`, which is what we have in our buffers that we are chunking, so I didn't try to generalize any further than that. * The class provides a complete iterator interface via `iterator_facade` as well as a complete view interface via `view_interface`. Aspects of those interfaces that rely on C++23 are pended. * Unit tests validate that `chunk_view` and its iterator meet the expected `std::ranges` concepts. * The unit tests do not yet test composition of this view with other views (our custom views as well as other C++20 views). This will be fairly extensive and the subject of its own PR. * One todo would be to create a variable chunk class view that chunks up the underlying view into variable-sized pieces, the better to fit into the data blocks. However, the data blocks will be fairly large, so there should not be too much internal fragmentation. We can always manage internal fragmentation by making the chunks some fraction of the block size, so even if there is some variation in chunk size, they can be well-packed into the data blocks. --- TYPE: IMPROVEMENT DESC: Implementation of a `chunk_view` class to provide a subset of C++23 chunk_view, suitable for supporting external sort. --------- Co-authored-by: Luc Rancourt --- .../tiledb/common/dag/utility/range_join.h | 2 +- .../dag/utility/test/compile_utils_main.cc | 2 +- tiledb/common/util/CMakeLists.txt | 1 + tiledb/common/util/alt_var_length_view.h | 4 +- tiledb/common/util/block_view.h | 43 ++ tiledb/common/util/detail/CMakeLists.txt | 30 ++ tiledb/common/util/{ => detail}/arrow_proxy.h | 2 +- .../util/{ => detail}/iterator_facade.h | 4 +- tiledb/common/util/detail/test/CMakeLists.txt | 33 ++ .../{ => detail}/test/unit_iterator_facade.cc | 2 +- tiledb/common/util/permutation_view.h | 4 +- tiledb/common/util/print_types.h | 47 ++- tiledb/common/util/proxy_sort.h | 2 +- tiledb/common/util/test/CMakeLists.txt | 53 ++- .../util/test/unit_alt_var_length_view.cc | 2 +- tiledb/common/util/test/unit_block_view.cc | 38 ++ .../common/util/test/unit_permutation_sort.cc | 10 +- .../common/util/test/unit_permutation_view.cc | 4 +- tiledb/common/util/test/unit_proxy_sort.cc | 2 +- tiledb/common/util/test/unit_sort_zip.cc | 6 +- .../common/util/test/unit_var_length_util.cc | 2 +- .../common/util/test/unit_var_length_view.cc | 2 +- tiledb/common/util/var_length_util.h | 2 +- tiledb/common/util/var_length_view.h | 4 +- tiledb/stdx/CMakeLists.txt | 1 + tiledb/stdx/DIRECTORY.md | 11 + tiledb/stdx/__ranges/CMakeLists.txt | 30 ++ tiledb/stdx/__ranges/chunk_view.h | 282 +++++++++++++ tiledb/stdx/__ranges/test/CMakeLists.txt | 39 ++ tiledb/stdx/__ranges/test/unit_chunk_view.cc | 389 ++++++++++++++++++ .../__ranges}/test/unit_zip_view.cc | 15 +- .../{common/util => stdx/__ranges}/zip_view.h | 21 +- tiledb/stdx/ranges | 47 +++ 33 files changed, 1064 insertions(+), 72 deletions(-) create mode 100644 tiledb/common/util/block_view.h create mode 100644 tiledb/common/util/detail/CMakeLists.txt rename tiledb/common/util/{ => detail}/arrow_proxy.h (97%) rename tiledb/common/util/{ => detail}/iterator_facade.h (99%) create mode 100644 tiledb/common/util/detail/test/CMakeLists.txt rename tiledb/common/util/{ => detail}/test/unit_iterator_facade.cc (99%) create mode 100644 tiledb/common/util/test/unit_block_view.cc create mode 100644 tiledb/stdx/DIRECTORY.md create mode 100644 tiledb/stdx/__ranges/CMakeLists.txt create mode 100644 tiledb/stdx/__ranges/chunk_view.h create mode 100644 tiledb/stdx/__ranges/test/CMakeLists.txt create mode 100644 tiledb/stdx/__ranges/test/unit_chunk_view.cc rename tiledb/{common/util => stdx/__ranges}/test/unit_zip_view.cc (96%) rename tiledb/{common/util => stdx/__ranges}/zip_view.h (96%) create mode 100644 tiledb/stdx/ranges diff --git a/experimental/tiledb/common/dag/utility/range_join.h b/experimental/tiledb/common/dag/utility/range_join.h index 5c0411d76fc..ba6166dd789 100644 --- a/experimental/tiledb/common/dag/utility/range_join.h +++ b/experimental/tiledb/common/dag/utility/range_join.h @@ -73,7 +73,7 @@ #include #include #include -#include "tiledb/common/util/arrow_proxy.h" +#include "tiledb/common/util/detail/arrow_proxy.h" #include "external/include/span/span.hpp" diff --git a/experimental/tiledb/common/dag/utility/test/compile_utils_main.cc b/experimental/tiledb/common/dag/utility/test/compile_utils_main.cc index 3b57acf679d..eafc4322116 100644 --- a/experimental/tiledb/common/dag/utility/test/compile_utils_main.cc +++ b/experimental/tiledb/common/dag/utility/test/compile_utils_main.cc @@ -31,7 +31,7 @@ #include "../range_join.h" #include "../spinlock.h" #include "../traits.h" -#include "tiledb/common/util/arrow_proxy.h" +#include "tiledb/common/util/detail/arrow_proxy.h" int main() { } diff --git a/tiledb/common/util/CMakeLists.txt b/tiledb/common/util/CMakeLists.txt index 15d75d4b447..f37bd2951d4 100644 --- a/tiledb/common/util/CMakeLists.txt +++ b/tiledb/common/util/CMakeLists.txt @@ -27,4 +27,5 @@ include(common NO_POLICY_SCOPE) include(object_library) +add_subdirectory(detail) add_test_subdirectory() diff --git a/tiledb/common/util/alt_var_length_view.h b/tiledb/common/util/alt_var_length_view.h index bb16b7d4160..b80a80f957f 100644 --- a/tiledb/common/util/alt_var_length_view.h +++ b/tiledb/common/util/alt_var_length_view.h @@ -1,5 +1,5 @@ /** - * @file alt_alt_var_length_view.h + * @file tiledb/common/util/alt_var_length_view.h * * @section LICENSE * @@ -56,7 +56,7 @@ #include -#include "iterator_facade.h" +#include "tiledb/common/util/detail/iterator_facade.h" /** * A view that splits a view into subranges of variable length, as delimited by diff --git a/tiledb/common/util/block_view.h b/tiledb/common/util/block_view.h new file mode 100644 index 00000000000..f4d9383af16 --- /dev/null +++ b/tiledb/common/util/block_view.h @@ -0,0 +1,43 @@ +/** + * @file tiledb/common/util/block_view.h + * + * @section LICENSE + * + * The MIT License + * + * @copyright Copyright (c) 2024 TileDB, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + * This file implements a zip view for zipping together a set of ranges. + * It is intended to implement the zip view as defined for C++23. From + * https://en.cppreference.com/w/cpp/ranges/zip_view: + * 1) A zip_view is a range adaptor that takes one or more views, and produces + * a view whose ith element is a tuple-like value consisting of the ith elements + * of all views. The size of produced view is the minimum of sizes of all + * adapted views. 2) zip is a customization point object that constructs a + * zip_view. + * + */ + +#ifndef TILEDB_BLOCK_VIEW_H +#define TILEDB_BLOCK_VIEW_H +#endif // TILEDB_BLOCK_VIEW_H diff --git a/tiledb/common/util/detail/CMakeLists.txt b/tiledb/common/util/detail/CMakeLists.txt new file mode 100644 index 00000000000..87855c545e9 --- /dev/null +++ b/tiledb/common/util/detail/CMakeLists.txt @@ -0,0 +1,30 @@ +# +# tiledb/util/detail/CMakeLists.txt +# +# The MIT License +# +# Copyright (c) 2024 TileDB, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + +include(common NO_POLICY_SCOPE) +include(object_library) + +add_test_subdirectory() \ No newline at end of file diff --git a/tiledb/common/util/arrow_proxy.h b/tiledb/common/util/detail/arrow_proxy.h similarity index 97% rename from tiledb/common/util/arrow_proxy.h rename to tiledb/common/util/detail/arrow_proxy.h index 1591b2555b9..c38129bbe80 100644 --- a/tiledb/common/util/arrow_proxy.h +++ b/tiledb/common/util/detail/arrow_proxy.h @@ -1,5 +1,5 @@ /** - * @file arrow_proxy.hpp + * @file tiledb/common/util/arrow_proxy.hpp * * @section LICENSE * diff --git a/tiledb/common/util/iterator_facade.h b/tiledb/common/util/detail/iterator_facade.h similarity index 99% rename from tiledb/common/util/iterator_facade.h rename to tiledb/common/util/detail/iterator_facade.h index 5131b7f3b5f..a6334034e7e 100644 --- a/tiledb/common/util/iterator_facade.h +++ b/tiledb/common/util/detail/iterator_facade.h @@ -1,5 +1,5 @@ /** - * @file iterator_facade.h + * @file tiledb/common/util/iterator_facade.h * * @section LICENSE * @@ -42,7 +42,7 @@ #include #include -#include "arrow_proxy.h" +#include "tiledb/common/util/detail/arrow_proxy.h" namespace detail { diff --git a/tiledb/common/util/detail/test/CMakeLists.txt b/tiledb/common/util/detail/test/CMakeLists.txt new file mode 100644 index 00000000000..c815cd54a4a --- /dev/null +++ b/tiledb/common/util/detail/test/CMakeLists.txt @@ -0,0 +1,33 @@ +# +# tiledb/util/detail/test/CMakeLists.txt +# +# The MIT License +# +# Copyright (c) 2024 TileDB, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + +include(unit_test) + +commence(unit_test iterator_facade) + this_target_sources( + unit_iterator_facade.cc +) +conclude(unit_test) diff --git a/tiledb/common/util/test/unit_iterator_facade.cc b/tiledb/common/util/detail/test/unit_iterator_facade.cc similarity index 99% rename from tiledb/common/util/test/unit_iterator_facade.cc rename to tiledb/common/util/detail/test/unit_iterator_facade.cc index 4ceafc0e88d..cd0f4e0b553 100644 --- a/tiledb/common/util/test/unit_iterator_facade.cc +++ b/tiledb/common/util/detail/test/unit_iterator_facade.cc @@ -40,7 +40,7 @@ #include #include #include -#include "../iterator_facade.h" +#include "tiledb/common/util/detail/iterator_facade.h" TEST_CASE("iterator_facade: Null test", "[iterator_facade][null_test]") { REQUIRE(true); diff --git a/tiledb/common/util/permutation_view.h b/tiledb/common/util/permutation_view.h index 9fa2274c940..44ef010486d 100644 --- a/tiledb/common/util/permutation_view.h +++ b/tiledb/common/util/permutation_view.h @@ -1,5 +1,5 @@ /** - * @file permutation_view.h + * @file tiledb/common/util/permutation_view.h * * @section LICENSE * @@ -50,8 +50,8 @@ #include #include -#include "iterator_facade.h" #include "proxy_sort.h" +#include "tiledb/common/util/detail/iterator_facade.h" /** * A view that creates a permutation of the underlying view, as determined by diff --git a/tiledb/common/util/print_types.h b/tiledb/common/util/print_types.h index e7d2161800e..6222aa6ab2c 100644 --- a/tiledb/common/util/print_types.h +++ b/tiledb/common/util/print_types.h @@ -1,5 +1,5 @@ /** - * @file print_types.h + * @file tiledb/common/util/print_types.h * * @section LICENSE * @@ -28,9 +28,50 @@ * @section DESCRIPTION * * This file implements a compile-time debugging utility for investigating - * the specific types of objects. + * the specific types of objects. It is the equivalent of a compile-time + * `printf`, but for types and is useful for debugging compile-time issues + * related to templates. It is intended for development use only and should + * not be included in production code. * - * Based on utility from NWGraph. Author Luke D'Alessandro. + * As a compile-time "printf" for types, it will generate a compiler error + * whose message will contain the expanded types of the variables passed to it. + * Note that the `print_types` takes *variable* as argument, not actual types + * or template parameters. The programmer will need to inspect the error + * message to determine the types of the variables. + * + * @example + * + * // See https://godbolt.org/z/3q341cs57 for running example + * #include + * #include "tiledb/common/util/print_types.h" + * + * template + * void foo(const S& s, const T& t) { + * // Note we pass s and t, not S and T + * print_types(s, t); + * } + * + * int main() { + * foo(1.0, std::vector>{{1, 2}, {3, 4}}); + * } + * + * This will produce an error message like the following (gcc 12.1): + * :18:31: error: invalid use of incomplete type 'struct + * print_types_t >, + * std::allocator > > > >' 18 | return + * print_types_t{}; + * + * Or like the following (clang 16.0): + * :18:10: error: implicit instantiation of undefined template + * 'print_types_t>>' return + * print_types_t{}; + * + * The types of the variable `s` and `t` are contained in the template + * arguments shown for `print_types`. In this case they are respectively + * `double` and `std::vector>`. + * + * This file is based on the `print_types` utility from NWGraph. + * Author Luke D'Alessandro. */ #ifndef TILEDB_PRINT_TYPES_H diff --git a/tiledb/common/util/proxy_sort.h b/tiledb/common/util/proxy_sort.h index 01fa5b240bb..397df531c18 100644 --- a/tiledb/common/util/proxy_sort.h +++ b/tiledb/common/util/proxy_sort.h @@ -1,5 +1,5 @@ /** - * @file proxy_sort.h + * @file tiledb/common/util/proxy_sort.h * * @section LICENSE * diff --git a/tiledb/common/util/test/CMakeLists.txt b/tiledb/common/util/test/CMakeLists.txt index 471ad68ac89..9b00d92d26a 100644 --- a/tiledb/common/util/test/CMakeLists.txt +++ b/tiledb/common/util/test/CMakeLists.txt @@ -26,56 +26,51 @@ include(unit_test) -commence(unit_test unit_alt_var_length_view) -this_target_sources( - unit_alt_var_length_view.cc +commence(unit_test alt_var_length_view) + this_target_sources( + unit_alt_var_length_view.cc ) conclude(unit_test) -commence(unit_test unit_iterator_facade) -this_target_sources( - unit_iterator_facade.cc +commence(unit_test permutation_sort) + this_target_sources( + unit_permutation_sort.cc ) conclude(unit_test) -commence(unit_test unit_permutation_sort) -this_target_sources( - unit_permutation_sort.cc +commence(unit_test permutation_view) + this_target_sources( + unit_permutation_view.cc ) conclude(unit_test) -commence(unit_test unit_permutation_view) -this_target_sources( - unit_permutation_view.cc +commence(unit_test proxy_sort) + this_target_sources( + unit_proxy_sort.cc ) conclude(unit_test) -commence(unit_test unit_proxy_sort) -this_target_sources( - unit_proxy_sort.cc +commence(unit_test sort_zip) + this_target_sources( + unit_sort_zip.cc ) conclude(unit_test) -commence(unit_test unit_sort_zip) -this_target_sources( - unit_sort_zip.cc +commence(unit_test var_length_util) + this_target_sources( + unit_var_length_util.cc ) conclude(unit_test) -commence(unit_test unit_var_length_util) -this_target_sources( - unit_var_length_util.cc -) -conclude(unit_test) - -commence(unit_test unit_var_length_view) -this_target_sources( +commence(unit_test var_length_view) + this_target_sources( unit_var_length_view.cc ) conclude(unit_test) -commence(unit_test unit_zip_view) -this_target_sources( - unit_zip_view.cc +commence(unit_test block_view) + this_target_sources( + unit_block_view.cc ) conclude(unit_test) + diff --git a/tiledb/common/util/test/unit_alt_var_length_view.cc b/tiledb/common/util/test/unit_alt_var_length_view.cc index dd0d75a37b3..50164071e2e 100644 --- a/tiledb/common/util/test/unit_alt_var_length_view.cc +++ b/tiledb/common/util/test/unit_alt_var_length_view.cc @@ -33,7 +33,7 @@ #include #include #include -#include "../alt_var_length_view.h" +#include "tiledb/common/util/alt_var_length_view.h" TEST_CASE( "alt_var_length_view: Null test", "[alt_var_length_view][null_test]") { diff --git a/tiledb/common/util/test/unit_block_view.cc b/tiledb/common/util/test/unit_block_view.cc new file mode 100644 index 00000000000..dd800ee96c8 --- /dev/null +++ b/tiledb/common/util/test/unit_block_view.cc @@ -0,0 +1,38 @@ +/** + * @file unit_block_view.cc + * + * @section LICENSE + * + * The MIT License + * + * @copyright Copyright (c) 2024 TileDB, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + * This file implements unit tests for the block_view class. + */ + +#include +#include "tiledb/common/util/block_view.h" + +TEST_CASE("block_view: null test", "[block_view][null test]") { + REQUIRE(true); +} diff --git a/tiledb/common/util/test/unit_permutation_sort.cc b/tiledb/common/util/test/unit_permutation_sort.cc index 41b37456290..23bf78abf15 100644 --- a/tiledb/common/util/test/unit_permutation_sort.cc +++ b/tiledb/common/util/test/unit_permutation_sort.cc @@ -36,11 +36,11 @@ #include #include #include -#include "../alt_var_length_view.h" -#include "../permutation_view.h" -#include "../proxy_sort.h" -#include "../var_length_view.h" -#include "../zip_view.h" +#include "tiledb/common/util/alt_var_length_view.h" +#include "tiledb/common/util/permutation_view.h" +#include "tiledb/common/util/proxy_sort.h" +#include "tiledb/common/util/var_length_view.h" +#include "tiledb/stdx/__ranges/zip_view.h" TEST_CASE("permutation_sort: Null test", "[permutation_sort][null_test]") { REQUIRE(true); diff --git a/tiledb/common/util/test/unit_permutation_view.cc b/tiledb/common/util/test/unit_permutation_view.cc index bead37c8705..00a9b38805a 100644 --- a/tiledb/common/util/test/unit_permutation_view.cc +++ b/tiledb/common/util/test/unit_permutation_view.cc @@ -33,8 +33,8 @@ #include #include #include -#include "../permutation_view.h" -#include "../var_length_view.h" +#include "tiledb/common/util/permutation_view.h" +#include "tiledb/common/util/var_length_view.h" TEST_CASE("permutation_view: Null test", "[permutation_view][null_test]") { REQUIRE(true); diff --git a/tiledb/common/util/test/unit_proxy_sort.cc b/tiledb/common/util/test/unit_proxy_sort.cc index 1704d7d0e9b..8ddbbc24a68 100644 --- a/tiledb/common/util/test/unit_proxy_sort.cc +++ b/tiledb/common/util/test/unit_proxy_sort.cc @@ -35,7 +35,7 @@ #include #include #include -#include "../proxy_sort.h" +#include "tiledb/common/util/proxy_sort.h" TEST_CASE("proxy_sort: Null test", "[proxy_sort][null_test]") { REQUIRE(true); diff --git a/tiledb/common/util/test/unit_sort_zip.cc b/tiledb/common/util/test/unit_sort_zip.cc index cc5f6718720..2f1c829be7a 100644 --- a/tiledb/common/util/test/unit_sort_zip.cc +++ b/tiledb/common/util/test/unit_sort_zip.cc @@ -33,8 +33,8 @@ #include #include #include -#include "../alt_var_length_view.h" -#include "../zip_view.h" +#include "tiledb/common/util/alt_var_length_view.h" +#include "tiledb/stdx/__ranges/zip_view.h" TEST_CASE("sort_zip: Null test", "[zip_view][null_test]") { REQUIRE(true); @@ -207,7 +207,7 @@ TEST_CASE("sort_zip: mini sort zip view", "[zip_view]") { TEST_CASE("sort_zip: range sort zip view concepts", "[zip_view]") { using VI = std::ranges::iterator_t>; - using ZI = std::ranges::iterator_t>>; + using ZI = std::ranges::iterator_t>>; CHECK(std::forward_iterator); CHECK(std::indirectly_movable_storable); diff --git a/tiledb/common/util/test/unit_var_length_util.cc b/tiledb/common/util/test/unit_var_length_util.cc index a9489292c03..fe54dee1947 100644 --- a/tiledb/common/util/test/unit_var_length_util.cc +++ b/tiledb/common/util/test/unit_var_length_util.cc @@ -33,7 +33,7 @@ #include #include #include -#include "../var_length_util.h" +#include "tiledb/common/util/var_length_util.h" TEST_CASE("var_length_uti: Null test", "[var_length_util][null_test]") { REQUIRE(true); diff --git a/tiledb/common/util/test/unit_var_length_view.cc b/tiledb/common/util/test/unit_var_length_view.cc index e0d0e2026ae..77bdb7780eb 100644 --- a/tiledb/common/util/test/unit_var_length_view.cc +++ b/tiledb/common/util/test/unit_var_length_view.cc @@ -33,7 +33,7 @@ #include #include #include -#include "../var_length_view.h" +#include "tiledb/common/util/var_length_view.h" TEST_CASE("var_length_view: Null test", "[var_length_view][null_test]") { REQUIRE(true); diff --git a/tiledb/common/util/var_length_util.h b/tiledb/common/util/var_length_util.h index e53f0acad00..1e08e25f5f7 100644 --- a/tiledb/common/util/var_length_util.h +++ b/tiledb/common/util/var_length_util.h @@ -1,5 +1,5 @@ /** - * @file var_length_util.h + * @file tiledb/common/util/var_length_util.h * * @section LICENSE * diff --git a/tiledb/common/util/var_length_view.h b/tiledb/common/util/var_length_view.h index 2054f1ef68b..3dc2ce108ec 100644 --- a/tiledb/common/util/var_length_view.h +++ b/tiledb/common/util/var_length_view.h @@ -1,5 +1,5 @@ /** - * @file var_length_view.h + * @file tiledb/common/util/var_length_view.h * * @section LICENSE * @@ -47,7 +47,7 @@ #include -#include "iterator_facade.h" +#include "tiledb/common/util/detail/iterator_facade.h" /** * A view that splits a view into subranges of variable length, as delimited by diff --git a/tiledb/stdx/CMakeLists.txt b/tiledb/stdx/CMakeLists.txt index b5bc6bca475..31080528e4a 100644 --- a/tiledb/stdx/CMakeLists.txt +++ b/tiledb/stdx/CMakeLists.txt @@ -28,3 +28,4 @@ include(common NO_POLICY_SCOPE) add_test_subdirectory() add_subdirectory(synchronized_optional) +add_subdirectory(__ranges) diff --git a/tiledb/stdx/DIRECTORY.md b/tiledb/stdx/DIRECTORY.md new file mode 100644 index 00000000000..8b0a8141bcf --- /dev/null +++ b/tiledb/stdx/DIRECTORY.md @@ -0,0 +1,11 @@ +## stdx + +This directory contains local implementations of C++ standard library components that have been introduced in recent versions of the standard, but that are not included in the standard library shipping with one or more of the compilers supported by libtiledb. + +### `ranges` + +There are two views standardized as part of C++23 that we provide a subset for: `zip_view` and `chunk_view`. The file `tiledb/stdx/ranges` is an include file (mimicking "`ranges`" in the standard library) that provides these two views. The implementations of these views are included in the `__ranges` subdirectory. (This naming convention mirrors that of LLVM.) The include directives for the implementations are surrounded by the appropriate `version` preprocessor directives so that once `zip_view` and/or `chunk_view` are available for a given compiler, the standard implementation will be used instead of our local implementation. + +### `thread` and `stop_token` + +These are copies of Josuttis's model implementation. \ No newline at end of file diff --git a/tiledb/stdx/__ranges/CMakeLists.txt b/tiledb/stdx/__ranges/CMakeLists.txt new file mode 100644 index 00000000000..14947b9244e --- /dev/null +++ b/tiledb/stdx/__ranges/CMakeLists.txt @@ -0,0 +1,30 @@ +# +# tiledb/stdx/__ranges/CMakeLists.txt +# +# The MIT License +# +# Copyright (c) 2024 TileDB, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + +include(common NO_POLICY_SCOPE) +include(object_library) + +add_test_subdirectory() \ No newline at end of file diff --git a/tiledb/stdx/__ranges/chunk_view.h b/tiledb/stdx/__ranges/chunk_view.h new file mode 100644 index 00000000000..ba892d95b7b --- /dev/null +++ b/tiledb/stdx/__ranges/chunk_view.h @@ -0,0 +1,282 @@ +/** + * @file tiledb/stdx/__ranges/chunk_view.h + * + * @section LICENSE + * + * The MIT License + * + * @copyright Copyright (c) 2024 TileDB, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + * Simplified implementation of a chunk view for C++23. This is a view + * that splits a view into subranges of uniform length, as given by the + * constructor argument `chunk_size`. The size of the last chunk may be less + * than or equal to `chunk_size`. The number of chunks is determined by + * `detail::div_ceil`. + * + * @todo Implement the full C++23 chunk view (or wait for C++23 or reference + * implementation without GPL) + */ + +#ifndef TILEDB_CHUNK_VIEW_H +#define TILEDB_CHUNK_VIEW_H + +#include +#include +#include "tiledb/common/util/detail/iterator_facade.h" + +namespace stdx::ranges { + +namespace detail { + +/** Helper template, API from cppreference, sans "__" prefix */ +template +constexpr I div_ceil(I num, I denom) { + // In cppreference: + // I r = num / denom; + // if (num % denom) + // ++r; + // return r; + return (num + denom - 1) / denom; // This should be a little faster +} +} // namespace detail + +/** + * A view that splits a view into subranges of uniform length, as delimited by + * a chunk size value. The resulting view is a range of subranges, each of which + * is a view into the original data range. The iterator over the chunk_view + * is a random_access_iterator that dereferences to a subrange of the data + * range. + * + * @tparam R Type of the data range, assumed to be a random access range. + * + * @todo R could be a view rather than a range. + */ +template +class chunk_view : public std::ranges::view_interface> { + // Forward reference of the iterator over the data range data + template + struct private_iterator; + + /** The type of the iterator over the chunked data range */ + using data_iterator_type = std::ranges::iterator_t; + + /** The type that can index into the chunked data range */ + using data_index_type = std::ranges::range_difference_t; + + /** The type dereferenced by the iterator is a subrange */ + using chunk_type = std::ranges::subrange; + + /** The type of the iterator over the chunk view */ + using chunk_iterator = private_iterator; + + /** The type of the iterator over the chunk view */ + using chunk_const_iterator = private_iterator; + + public: + /** Default constructor */ + chunk_view() = default; + chunk_view(const chunk_view&) = default; + chunk_view(chunk_view&&) = default; + chunk_view& operator=(const chunk_view&) = default; + chunk_view& operator=(chunk_view&&) = default; + + /** + * Constructor taking ranges for the data range, along with size of the + * chunks. This is the signature from cppreference, but having an argument + * type for `chunk_size` that could be negative does not seem right. + */ + chunk_view(R& data, std::ranges::range_difference_t chunk_size) + : data_begin_(std::ranges::begin(data)) + , data_end_(std::ranges::end(data)) + , chunk_size_(chunk_size) { + } + + /* + * Define the necessary members for view_interface. + */ + + /** Return iterator to the beginning of the chunk view */ + constexpr auto begin() { + return chunk_iterator(data_begin_, data_end_, chunk_size_); + } + + /** Return iterator to the end of the chunk view */ + constexpr auto end() { + return chunk_iterator(data_end_, data_end_, chunk_size_); + } + + /** Return const iterator to the beginning of the chunk view */ + constexpr auto begin() const { + return chunk_const_iterator(data_begin_, data_end_, chunk_size_); + } + + /** Return const iterator to the end of the chunk view */ + constexpr auto end() const { + return chunk_const_iterator(data_end_, data_end_, chunk_size_); + } + + /** Return const iterator to the beginning of the chunk view */ + constexpr auto cbegin() const { + return chunk_const_iterator(data_begin_, data_end_, chunk_size_); + } + + /** Return const iterator to the end of the chunk view */ + constexpr auto cend() const { + return chunk_const_iterator(data_end_, data_end_, chunk_size_); + } + + /** Return the number of chunks in the chunk view */ + constexpr auto size() const { + return detail::div_ceil(data_end_ - data_begin_, chunk_size_); + } + + private: + template + struct private_iterator : public iterator_facade> { + using value_type = V; + using reference_type = V&; + + /** Default constructor */ + private_iterator() = default; + private_iterator(const private_iterator&) = default; + private_iterator(private_iterator&&) = default; + private_iterator& operator=(const private_iterator&) = default; + private_iterator& operator=(private_iterator&&) = default; + + /** Primary constructor */ + private_iterator( + data_iterator_type data_begin, + data_iterator_type data_end, + data_index_type chunk_size) + : data_begin_(data_begin) + , data_end_(data_end) + , current_(data_begin) + , chunk_size_(chunk_size) { + } + + /************************************************************************* + * Functions needed for iterator_facade + * Here we just supply the minimum needed to make the iterator work + *************************************************************************/ + + /* + * The critical function for defining the iterator as it determines the + * value type, etc and also does the dereference. In the case of the + * chunk_view, the value type is a subrange of the data range, and + * the subrage return value must be a proxy object, which we return by + * value. This is fine, since we can't assign a subrange to another. + * We do, however, want to be able to modify the contents of the subrange. + */ + constexpr value_type dereference() const { + if (data_end_ - current_ < chunk_size_) { + return {current_, data_end_}; + } else { + return {current_, current_ + chunk_size_}; + } + } + + /** + * Advance the iterator by n. Note that we don't move past the end of the + * data range. + */ + constexpr auto& advance(data_index_type n) { + if (data_end_ - current_ < n * chunk_size_) { + current_ = data_end_; + } else { + current_ += n * chunk_size_; + } + return *this; + } + + /** Return the distance to another iterator */ + constexpr auto distance_to(const private_iterator& other) const { + return other.current_ - current_; + } + + /** Compare two iterators for equality */ + constexpr bool operator==(const private_iterator& other) const { + return chunk_size_ == other.chunk_size_ && current_ == other.current_; + } + + /** Flag to indicate that the iterator is not a single pass iterator */ + static const bool single_pass_iterator = false; + + /** + * Iterator to the beginning of the data range. This is a copy of the + * parent data_begin_. We maintain the copy to avoid an indirection through + * the parent pointer. + */ + data_iterator_type data_begin_; + + /** + * Iterator to the end of the data range. A copy of the parent + * data_end_. + */ + data_iterator_type data_end_; + + /** The current location of the iterator */ + data_iterator_type current_; + + /** The chunk size. Also cached from parent. */ + data_index_type chunk_size_; + }; + + /** The beginning of the data range */ + std::ranges::iterator_t data_begin_; + + /** The end of the data range */ + std::ranges::iterator_t data_end_; + + /** The number of chunks in the chunk_range */ + std::ranges::range_difference_t chunk_size_; +}; + +/** Deduction guide for chunk_view */ +template +chunk_view(R, I) -> chunk_view>; +} // namespace stdx::ranges +/** + * Define "chunk()" cpo for creating chunk views + */ +namespace _chunk { +struct _fn { + // @todo Should this take a viewable range? + // template + template + constexpr auto operator()(T&& t, I i) const { + return stdx::ranges::chunk_view{std::forward(t), i}; + } +}; +} // namespace _chunk +inline namespace _cpo { +inline constexpr auto chunk = _chunk::_fn{}; +} // namespace _cpo + +namespace stdx::views { +using _cpo::chunk; +} // namespace stdx::views + +namespace stdx::ranges::views { +using _cpo::chunk; +} // namespace stdx::ranges::views +#endif // TILEDB_CHUNK_VIEW_H diff --git a/tiledb/stdx/__ranges/test/CMakeLists.txt b/tiledb/stdx/__ranges/test/CMakeLists.txt new file mode 100644 index 00000000000..554e291c37a --- /dev/null +++ b/tiledb/stdx/__ranges/test/CMakeLists.txt @@ -0,0 +1,39 @@ +# +# tiledb/stdx/__ranges/test/CMakeLists.txt +# +# The MIT License +# +# Copyright (c) 2024 TileDB, Inc. +# +# Permission is hereby granted, free of charge, to any person obtaining a copy +# of this software and associated documentation files (the "Software"), to deal +# in the Software without restriction, including without limitation the rights +# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +# copies of the Software, and to permit persons to whom the Software is +# furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +# THE SOFTWARE. +# + +include(unit_test) + +commence(unit_test chunk_view) +this_target_sources( + unit_chunk_view.cc +) +conclude(unit_test) + +commence(unit_test zip_view) +this_target_sources( + unit_zip_view.cc +) +conclude(unit_test) \ No newline at end of file diff --git a/tiledb/stdx/__ranges/test/unit_chunk_view.cc b/tiledb/stdx/__ranges/test/unit_chunk_view.cc new file mode 100644 index 00000000000..35afb0fe28f --- /dev/null +++ b/tiledb/stdx/__ranges/test/unit_chunk_view.cc @@ -0,0 +1,389 @@ +/** + * @file tiledb/stdx/__ranges/test/unit_chunk_view.cc + * + * @section LICENSE + * + * The MIT License + * + * @copyright Copyright (c) 2024 TileDB, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + * This file implements unit tests for the chunk_view class. + */ + +#include +#include "tiledb/stdx/__ranges/chunk_view.h" + +TEST_CASE("chunk_view: null test", "[chunk_view][null test]") { + REQUIRE(true); +} + +// Test that the chunk_view satisfies the expected concepts +TEST_CASE("chunk_view: Range concepts", "[chunk_view][concepts]") { + using test_type = stdx::ranges::chunk_view>; + + CHECK(std::ranges::range); + CHECK(!std::ranges::borrowed_range); + CHECK(std::ranges::sized_range); + CHECK(std::ranges::view); + CHECK(std::ranges::input_range); + CHECK(!std::ranges:: + output_range>); + CHECK(std::ranges::forward_range); + CHECK(std::ranges::bidirectional_range); + CHECK(std::ranges::random_access_range); + CHECK(!std::ranges::contiguous_range); + CHECK(std::ranges::common_range); + CHECK(std::ranges::viewable_range); + + CHECK(std::ranges::view); +} + +// Test that the chunk_view iterators satisfy the expected concepts +TEST_CASE("chunk_view: Iterator concepts", "[chunk_view][concepts]") { + using test_type = stdx::ranges::chunk_view>; + using test_type_iterator = std::ranges::iterator_t; + using test_type_const_iterator = std::ranges::iterator_t; + + CHECK(std::input_or_output_iterator); + CHECK(std::input_or_output_iterator); + CHECK(std::input_iterator); + CHECK(std::input_iterator); + CHECK(!std::output_iterator< + test_type_iterator, + std::ranges::range_value_t>); + CHECK(!std::output_iterator< + test_type_const_iterator, + std::ranges::range_value_t>); + CHECK(std::forward_iterator); + CHECK(std::forward_iterator); + CHECK(std::bidirectional_iterator); + CHECK(std::bidirectional_iterator); + CHECK(std::random_access_iterator); + CHECK(std::random_access_iterator); +} + +// Test that the chunk_view value_type satisfies the expected concepts +TEST_CASE("chunk_view: value_type concepts", "[chunk_view][concepts]") { + using test_type = stdx::ranges::chunk_view>; + CHECK(std::ranges::range); + + using test_iterator_type = std::ranges::iterator_t; + using test_iterator_value_type = std::iter_value_t; + using test_iterator_reference_type = + std::iter_reference_t; + + using range_value_type = std::ranges::range_value_t; + using range_reference_type = std::ranges::range_reference_t; + + CHECK(std::is_same_v); + CHECK(std::is_same_v); +} + +std::vector v10 = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0}; +std::vector v11 = { + 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0}; +std::vector v12 = { + 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0}; +std::vector v13 = { + 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0}; +std::vector v14 = { + 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0}; +std::vector v15 = { + 1.0, + 2.0, + 3.0, + 4.0, + 5.0, + 6.0, + 7.0, + 8.0, + 9.0, + 10.0, + 11.0, + 12.0, + 13.0, + 14.0, + 15.0}; +std::vector v16 = { + 1.0, + 2.0, + 3.0, + 4.0, + 5.0, + 6.0, + 7.0, + 8.0, + 9.0, + 10.0, + 11.0, + 12.0, + 13.0, + 14.0, + 15.0, + 16.0}; + +// Simple test that a chunk_view can be constructed +TEST_CASE("chunk_view: Constructor", "[chunk_view]") { + [[maybe_unused]] auto c = _cpo::chunk(v10, 2); + [[maybe_unused]] auto d = _cpo::chunk(v10, 3); + [[maybe_unused]] auto e = _cpo::chunk(v11, 2); + [[maybe_unused]] auto f = _cpo::chunk(v11, 3); +} + +TEST_CASE("chunk_view: Constructor + size", "[chunk_view]") { + auto c = _cpo::chunk(v10, 2); + CHECK(c.size() == 5); + auto d = _cpo::chunk(v10, 3); + CHECK(d.size() == 4); + auto e = _cpo::chunk(v11, 2); // 2, 2, 2, 2, 2, 1 + CHECK(e.size() == 6); + auto f = _cpo::chunk(v11, 3); // 3, 3, 3, 2 + CHECK(f.size() == 4); + auto g = _cpo::chunk(v12, 2); + CHECK(g.size() == 6); + auto h = _cpo::chunk(v12, 3); + CHECK(h.size() == 4); + auto i = _cpo::chunk(v12, 4); + CHECK(i.size() == 3); +} + +TEST_CASE("chunk_view: Iterators begin and end", "[chunk_view]") { + for (auto&& v : {v10, v11, v12, v13, v14, v15, v16}) { + auto a = _cpo::chunk(v, 2); + auto b = a.begin(); + auto c = a.end(); + auto d = a.begin(); + auto e = a.end(); + CHECK(b != c); + CHECK(d != e); + CHECK(b == d); + CHECK(c == e); + } + + for (auto&& v : {v11, v12}) { + auto a = _cpo::chunk(v, 2); + auto b = a.begin(); + CHECK(b == a.begin()); + CHECK(b != a.end()); + + ++b; + CHECK(b != a.begin()); + CHECK(b != a.end()); + + ++b; + CHECK(b != a.begin()); + CHECK(b != a.end()); + + ++b; + CHECK(b != a.begin()); + CHECK(b != a.end()); + + ++b; + CHECK(b != a.begin()); + CHECK(b != a.end()); + + ++b; + CHECK(b != a.begin()); + CHECK(b != a.end()); + + ++b; + CHECK(b != a.begin()); + CHECK(b == a.end()); + } +} + +TEST_CASE("chunk_view: Iterators ++ and --", "[chunk_view]") { + for (auto&& v : {v10, v11, v12, v13, v14, v15, v16}) { + auto a = _cpo::chunk(v, 2); + auto b = a.begin(); + [[maybe_unused]] auto c = a.end(); + auto d = a.begin(); + auto e = a.end(); + while (b != e) { + ++b; + d++; + CHECK(b == d); + } + } + + for (auto&& v : {v10, v11, v12, v13, v14, v15, v16}) { + auto a = _cpo::chunk(v, 2); + auto b = a.begin(); + [[maybe_unused]] auto c = a.end(); + auto d = a.begin(); + auto e = a.end(); + while (b != e) { + ++b; + --b; + b++; + d++; + d--; + ++d; + CHECK(b == d); + } + } +} + +TEST_CASE("chunk_view: Iterators + 1", "[chunk_view]") { + for (auto ch : {2, 3, 4, 9, 10, 11}) { + for (auto&& v : {v10, v11, v12, v13, v14, v15, v16}) { + auto a = _cpo::chunk(v, ch); + auto b = a.begin(); + [[maybe_unused]] auto c = a.end(); + auto d = a.begin(); + auto e = a.end(); + + while (b != e) { + auto x = b; + b += 1; + if (b == e) { + break; + } + CHECK(b != d); + CHECK(b == d + 1); + CHECK(b != d + 2); + d++; + CHECK(b == d); + CHECK(b == (x + 1)); + } + } + } +} + +TEST_CASE("chunk_view: Iterators - 1 - 1", "[chunk_view]") { + auto a = _cpo::chunk(v11, 3); + auto b = a.begin(); + auto c = b; + auto d = a.begin(); + auto e = a.end(); + + CHECK(b == c); + CHECK(c == b); + CHECK(b == d); + CHECK(d == b); + CHECK(c == d); + CHECK(c == c); + CHECK(d == c); + CHECK(c == a.begin()); + CHECK(b != e); + CHECK(b == c); + CHECK(c == b); + + auto x = b; + ++b; + auto y = b; + + CHECK(c != b); + CHECK(c == (b - 1)); + CHECK(b == (c + 1)); + CHECK(c == x); + CHECK(c == y - 1); + CHECK(y == (c + 1)); + CHECK(y == ((b - 1) + 1)); + + --b; + x = b; + + CHECK(c == x); + CHECK(x == b); + CHECK(c == b); + CHECK(b == c); + CHECK(b == a.begin()); +} + +TEST_CASE("chunk_view: Iterators - 1", "[chunk_view]") { + for (auto ch : {2, 3, 4, 9, 10, 11}) { + for (auto&& vx : {v10, v11, v12, v13, v14, v15, v16}) { + auto a = _cpo::chunk(vx, ch); + auto b = a.begin(); + [[maybe_unused]] auto c = a.end(); + auto d = a.begin(); + auto e = a.end(); + + { + auto dh = 9; + auto a = _cpo::chunk(vx, dh); + auto bb = a.begin(); + auto dd = a.begin(); + CHECK(bb == dd); + + ++bb; + + if (bb == e) { + break; + } + --bb; + if (!(bb == a.begin())) { + [[maybe_unused]] auto asdf = 1; // to allow debugging breakpoint + } + CHECK(bb == a.begin()); + } + + while (b != e) { + CHECK(b == d); + + ++b; + if (b == e) { + break; + } + --b; + + // CHECK(b == d); + b++; + d++; + CHECK(b == d); + } + } + } +} + +TEST_CASE("chunk_view: Iterators", "[chunk_view]") { + for (auto&& v : {v10, v11, v12, v13, v14, v15, v16}) { + for (size_t i = 1; i <= v.size(); ++i) { + auto a = _cpo::chunk(v, (long)i); + auto b = a.begin(); + CHECK(b->size() == (unsigned)i); + } + } +} + +TEST_CASE("chunk_view: Iterators values", "[chunk_view]") { + auto a = _cpo::chunk(v10, 5); + auto b = a.begin(); + + CHECK(b->size() == 5); + CHECK((*b)[0] == 1.0); + CHECK((*b)[1] == 2.0); + CHECK((*b)[2] == 3.0); + CHECK((*b)[3] == 4.0); + CHECK((*b)[4] == 5.0); + ++b; + CHECK(b->size() == 5); + CHECK((*b)[0] == 6.0); + CHECK((*b)[1] == 7.0); + CHECK((*b)[2] == 8.0); + CHECK((*b)[3] == 9.0); + CHECK((*b)[4] == 10.0); + ++b; + CHECK(b == a.end()); +} diff --git a/tiledb/common/util/test/unit_zip_view.cc b/tiledb/stdx/__ranges/test/unit_zip_view.cc similarity index 96% rename from tiledb/common/util/test/unit_zip_view.cc rename to tiledb/stdx/__ranges/test/unit_zip_view.cc index 6abc6b8d099..b0148d001aa 100644 --- a/tiledb/common/util/test/unit_zip_view.cc +++ b/tiledb/stdx/__ranges/test/unit_zip_view.cc @@ -1,5 +1,5 @@ /** - * @file unit_zip_view.cc + * @file tiledb/stdx/__ranges/test/unit_zip_view.cc * * @section LICENSE * @@ -34,8 +34,8 @@ #include #include #include -#include "../alt_var_length_view.h" -#include "../zip_view.h" +#include "tiledb/common/util/alt_var_length_view.h" +#include "tiledb/stdx/__ranges/zip_view.h" TEST_CASE("zip_view: Null test", "[zip_view][null_test]") { REQUIRE(true); @@ -66,7 +66,8 @@ TEST_CASE("zip_view: Should not copy", "[zip_view]") { /** Test that the zip_view type satisfies the expected range concepts */ TEST_CASE("zip_view: Range concepts", "[zip_view][concepts]") { - using test_type = zip_view, std::vector>; + using test_type = + stdx::ranges::zip_view, std::vector>; CHECK(std::ranges::range); CHECK(!std::ranges::borrowed_range); @@ -86,7 +87,8 @@ TEST_CASE("zip_view: Range concepts", "[zip_view][concepts]") { /** Test that the zip_view iterator satisfies the expected concepts */ TEST_CASE("zip_view: Iterator concepts", "[zip_view][concepts]") { - using test_type = zip_view, std::vector>; + using test_type = + stdx::ranges::zip_view, std::vector>; using test_type_iterator = std::ranges::iterator_t; using test_type_const_iterator = std::ranges::iterator_t; // using test_type_const_iterator = decltype((const test_type){}.begin()); @@ -152,7 +154,8 @@ TEST_CASE("zip_view: Iterator concepts", "[zip_view][concepts]") { // Test that the zip_view value_type satisfies the expected concepts TEST_CASE("zip_view: value_type concepts", "[zip_view][concepts]") { - using test_type = zip_view, std::vector>; + using test_type = + stdx::ranges::zip_view, std::vector>; CHECK(std::ranges::range); using test_iterator_type = std::ranges::iterator_t; diff --git a/tiledb/common/util/zip_view.h b/tiledb/stdx/__ranges/zip_view.h similarity index 96% rename from tiledb/common/util/zip_view.h rename to tiledb/stdx/__ranges/zip_view.h index c2f453a7be8..de1272820c3 100644 --- a/tiledb/common/util/zip_view.h +++ b/tiledb/stdx/__ranges/zip_view.h @@ -1,5 +1,5 @@ /** - * @file zip_view.h + * @file tiledb/stdx/__ranges/zip_view.h * * @section LICENSE * @@ -58,8 +58,8 @@ #define TILEDB_ZIP_VIEW_H #include -#include "iterator_facade.h" - +#include "tiledb/common/util/detail/iterator_facade.h" +namespace stdx::ranges { /* * @todo Should this take viewable ranges? E.g., * template @@ -239,7 +239,7 @@ class zip_view : public std::ranges::view_interface> { /** * Dereference the iterator -- the critical function for defining the - * iterator sinc the facade bases many type aliases and other functions + * iterator since the facade bases many type aliases and other functions * based on it and its signature */ reference dereference() const { @@ -323,7 +323,7 @@ class zip_view : public std::ranges::view_interface> { /** The ranges being zipped */ std::tuple ranges_; }; - +} // namespace stdx::ranges /** * Define "zip()" cpo for creating zip views */ @@ -333,14 +333,23 @@ struct _fn { // template template auto constexpr operator()(T&&... t) const { - return zip_view{std::forward(t)...}; + return stdx::ranges::zip_view{std::forward(t)...}; } }; } // namespace _zip + inline namespace _cpo { inline constexpr auto zip = _zip::_fn{}; } // namespace _cpo +namespace stdx::views { +using _cpo::zip; +} // namespace stdx::views + +namespace stdx::ranges::views { +using _cpo::zip; +} // namespace stdx::ranges::views + /** * Define "swap()" for tuples of references * diff --git a/tiledb/stdx/ranges b/tiledb/stdx/ranges new file mode 100644 index 00000000000..949b11b363c --- /dev/null +++ b/tiledb/stdx/ranges @@ -0,0 +1,47 @@ +/** + * @file tiledb/stdx/ranges + * + * @section LICENSE + * + * The MIT License + * + * @copyright Copyright (c) 2024 TileDB, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @section DESCRIPTION + * + * This file provides a single header for ranges / views that we have + * implemented in anticipation of their availability in C++23. + */ + +#ifndef TILEDB_STDX_RANGES +#define TILEDB_STDX_RANGES + +#include + +#if !defined(__cpp_lib_ranges_chunk) || __cpp_lib_ranges_chunk < 202202L +#include "tiledb/stdx/__ranges/chunk_view.h" +#endif + +#if !defined(__cpp_lib_ranges_zip) || __cpp_lib_ranges_zip < 202110L +#include "tiledb/stdx/__ranges/zip_view.h" +#endif + +#endif // TILEDB_STDX_RANGES