diff --git a/MODULE.bazel.lock b/MODULE.bazel.lock index 21b358e..d62a47c 100644 --- a/MODULE.bazel.lock +++ b/MODULE.bazel.lock @@ -64,20 +64,20 @@ "@@apple_support~//crosstool:setup.bzl%apple_cc_configure_extension": { "general": { "bzlTransitiveDigest": "PjIds3feoYE8SGbbIq2SFTZy3zmxeO2tQevJZNDo7iY=", - "usagesDigest": "aLmqbvowmHkkBPve05yyDNGN7oh7QE9kBADr3QIZTZs=", + "usagesDigest": "+hz7IHWN6A1oVJJWNDB6yZRG+RYhF76wAYItpAeIUIg=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, "generatedRepoSpecs": { - "local_config_apple_cc": { - "bzlFile": "@@apple_support~//crosstool:setup.bzl", - "ruleClassName": "_apple_cc_autoconf", - "attributes": {} - }, "local_config_apple_cc_toolchains": { "bzlFile": "@@apple_support~//crosstool:setup.bzl", "ruleClassName": "_apple_cc_autoconf_toolchains", "attributes": {} + }, + "local_config_apple_cc": { + "bzlFile": "@@apple_support~//crosstool:setup.bzl", + "ruleClassName": "_apple_cc_autoconf", + "attributes": {} } }, "recordedRepoMappingEntries": [ @@ -92,7 +92,7 @@ "@@platforms//host:extension.bzl%host_platform": { "general": { "bzlTransitiveDigest": "xelQcPZH8+tmuOHVjL9vDxMnnQNMlwj0SlvgoqBkm4U=", - "usagesDigest": "meSzxn3DUCcYEhq4HQwExWkWtU4EjriRBQLsZN+Q0SU=", + "usagesDigest": "pCYpDQmqMbmiiPI1p2Kd3VLm5T48rRAht5WdW0X2GlA=", "recordedFileInputs": {}, "recordedDirentsInputs": {}, "envVariables": {}, diff --git a/asl/span.hpp b/asl/span.hpp index efc9eec..5ffcf68 100644 --- a/asl/span.hpp +++ b/asl/span.hpp @@ -13,7 +13,12 @@ static constexpr int64_t dynamic_size = -1; template class span { - static constexpr bool kIsDynamic = kSize < 0; + static constexpr bool is_dynamic(int64_t size) + { + return size < 0; + } + + static constexpr bool kIsDynamic = is_dynamic(kSize); using SizeType = select_t; @@ -21,7 +26,7 @@ class span ASL_NO_UNIQUE_ADDRESS SizeType m_size{}; public: - constexpr span() = default; + constexpr span() requires (kIsDynamic || kSize == 0) = default; constexpr span(T* data, int64_t size) requires kIsDynamic @@ -55,7 +60,7 @@ public: requires ( ( kIsDynamic || - span::kIsDynamic || + is_dynamic(kOtherSize) || kOtherSize == kSize ) && convertible_from ) @@ -92,11 +97,49 @@ public: return m_data[i]; // NOLINT(*-pointer-arithmetic) } - // @Todo subspan, first, last + // @Todo first, last // @Todo as_(mutable_)bytes - template - friend class span; + template + constexpr auto subspan() const + requires ( + kOffset >= 0 && + (kIsDynamic || kOffset <= kSize) && + (kIsDynamic || is_dynamic(kSubSize) || kSubSize <= kSize - kOffset) + ) + { + ASL_ASSERT(kOffset <= size()); + + if constexpr (is_dynamic(kSubSize)) + { + if constexpr (kIsDynamic) + { + return span(data() + kOffset, size() - kOffset); + } + else + { + return span(data() + kOffset, size() - kOffset); + } + } + else + { + ASL_ASSERT(kSubSize <= size() - kOffset); + return span(data() + kOffset, kSubSize); + } + } + + constexpr span subspan(int64_t offset, int64_t sub_size = dynamic_size) const + { + ASL_ASSERT(offset <= size()); + + if (is_dynamic(sub_size)) + { + return span{ data() + offset, size() - offset }; + } + + ASL_ASSERT(sub_size <= size() - offset); + return span{ data() + offset, sub_size }; + } }; } // namespace asl diff --git a/asl/tests/span_tests.cpp b/asl/tests/span_tests.cpp index 11510c6..3ede397 100644 --- a/asl/tests/span_tests.cpp +++ b/asl/tests/span_tests.cpp @@ -38,6 +38,10 @@ ASL_TEST(from_array_dynamic) ASL_TEST_EXPECT(span[2] == 3); } +static_assert(asl::default_constructible>); +static_assert(asl::default_constructible>); +static_assert(!asl::default_constructible>); + static_assert(asl::constructible_from, int32_t(&)[8]>); static_assert(!asl::constructible_from, const int32_t(&)[8]>); static_assert(asl::constructible_from, int32_t(&)[8]>); @@ -89,3 +93,125 @@ ASL_TEST(conversion) ASL_TEST_EXPECT(span4[1] == 2); ASL_TEST_EXPECT(span4[2] == 3); } + +template +[[maybe_unused]] static auto try_static_subspan(int) + -> decltype(asl::declval().template subspan()); + +template +[[maybe_unused]] static auto try_static_subspan(...) -> asl::empty; + +template +concept invalid_subspan = asl::same_as(0)), asl::empty>; + +static_assert(asl::same_as, + decltype(asl::declval>().subspan<0>())>); + +static_assert(asl::same_as, + decltype(asl::declval>().subspan<1>())>); + +static_assert(asl::same_as, + decltype(asl::declval>().subspan<2>())>); + +static_assert(asl::same_as, + decltype(asl::declval>().subspan<3>())>); + +static_assert(asl::same_as, + decltype(asl::declval>().subspan<4>())>); + +static_assert(invalid_subspan, 5>); + +static_assert(asl::same_as, + decltype(asl::declval>().subspan<0>())>); + +static_assert(asl::same_as, + decltype(asl::declval>().subspan<0, 4>())>); + +static_assert(asl::same_as, + decltype(asl::declval>().subspan<0, 4>())>); + +static_assert(asl::same_as, + decltype(asl::declval>().subspan<1, 2>())>); + +static_assert(asl::same_as, + decltype(asl::declval>().subspan<2, 2>())>); + +static_assert(invalid_subspan, 2, 3>); + +ASL_TEST(subspan_static_from_static) +{ + int array[] = {1, 2, 3, 4}; + asl::span span{array}; + + auto s1 = span.subspan<0>(); + ASL_TEST_EXPECT(s1.size() == 4); + ASL_TEST_ASSERT(s1[0] == 1); + ASL_TEST_ASSERT(s1[1] == 2); + ASL_TEST_ASSERT(s1[2] == 3); + ASL_TEST_ASSERT(s1[3] == 4); + + auto s2 = span.subspan<2>(); + ASL_TEST_EXPECT(s2.size() == 2); + ASL_TEST_ASSERT(s2[0] == 3); + ASL_TEST_ASSERT(s2[1] == 4); + + auto s3 = span.subspan<4>(); + ASL_TEST_EXPECT(s3.size() == 0); + + auto s4 = span.subspan<1, 2>(); + ASL_TEST_EXPECT(s4.size() == 2); + ASL_TEST_ASSERT(s4[0] == 2); + ASL_TEST_ASSERT(s4[1] == 3); +} + +ASL_TEST(subspan_static_from_dynamic) +{ + int array[] = {1, 2, 3, 4}; + asl::span span{array}; + + auto s1 = span.subspan<0>(); + ASL_TEST_EXPECT(s1.size() == 4); + ASL_TEST_ASSERT(s1[0] == 1); + ASL_TEST_ASSERT(s1[1] == 2); + ASL_TEST_ASSERT(s1[2] == 3); + ASL_TEST_ASSERT(s1[3] == 4); + + auto s2 = span.subspan<2>(); + ASL_TEST_EXPECT(s2.size() == 2); + ASL_TEST_ASSERT(s2[0] == 3); + ASL_TEST_ASSERT(s2[1] == 4); + + auto s3 = span.subspan<4>(); + ASL_TEST_EXPECT(s3.size() == 0); + + auto s4 = span.subspan<1, 2>(); + ASL_TEST_EXPECT(s4.size() == 2); + ASL_TEST_ASSERT(s4[0] == 2); + ASL_TEST_ASSERT(s4[1] == 3); +} + +ASL_TEST(subspan_dynamic) +{ + int array[] = {1, 2, 3, 4}; + asl::span span{array}; + + auto s1 = span.subspan(0); + ASL_TEST_EXPECT(s1.size() == 4); + ASL_TEST_ASSERT(s1[0] == 1); + ASL_TEST_ASSERT(s1[1] == 2); + ASL_TEST_ASSERT(s1[2] == 3); + ASL_TEST_ASSERT(s1[3] == 4); + + auto s2 = span.subspan(2); + ASL_TEST_EXPECT(s2.size() == 2); + ASL_TEST_ASSERT(s2[0] == 3); + ASL_TEST_ASSERT(s2[1] == 4); + + auto s3 = span.subspan(4); + ASL_TEST_EXPECT(s3.size() == 0); + + auto s4 = span.subspan(1, 2); + ASL_TEST_EXPECT(s4.size() == 2); + ASL_TEST_ASSERT(s4[0] == 2); + ASL_TEST_ASSERT(s4[1] == 3); +}