diff options
author | Abseil Team <absl-team@google.com> | 2018-09-27 12:24:54 -0700 |
---|---|---|
committer | Derek Mauro <dmauro@google.com> | 2018-09-27 15:28:12 -0400 |
commit | 48cd2c3f351ff188bc85684b84a91b6e6d17d896 (patch) | |
tree | 6f92b0cbb0f8282b7df1cd567cb66406fbbb6f80 /absl/container/internal/layout_test.cc | |
parent | e291c279e458761e77a69b09b129d3d1e81f1e80 (diff) |
Export of internal Abseil changes.
--
4eacae3ff1b14b1d309e8092185bc10e8a6203cf by Derek Mauro <dmauro@google.com>:
Release SwissTable - a fast, efficient, cache-friendly hash table.
https://www.youtube.com/watch?v=ncHmEUmJZf4
PiperOrigin-RevId: 214816527
--
df8c3dfab3cfb2f4365909a84d0683b193cfbb11 by Derek Mauro <dmauro@google.com>:
Internal change
PiperOrigin-RevId: 214785288
--
1eabd5266bbcebc33eecc91e5309b751856a75c8 by Abseil Team <absl-team@google.com>:
Internal change
PiperOrigin-RevId: 214722931
--
2ebbfac950f83146b46253038e7dd7dcde9f2951 by Derek Mauro <dmauro@google.com>:
Internal change
PiperOrigin-RevId: 214701684
GitOrigin-RevId: 4eacae3ff1b14b1d309e8092185bc10e8a6203cf
Change-Id: I9ba64e395b22ad7863213d157b8019b082adc19d
Diffstat (limited to 'absl/container/internal/layout_test.cc')
-rw-r--r-- | absl/container/internal/layout_test.cc | 1552 |
1 files changed, 1552 insertions, 0 deletions
diff --git a/absl/container/internal/layout_test.cc b/absl/container/internal/layout_test.cc new file mode 100644 index 00000000..f35157a3 --- /dev/null +++ b/absl/container/internal/layout_test.cc @@ -0,0 +1,1552 @@ +// Copyright 2018 The Abseil Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#include "absl/container/internal/layout.h" + +// We need ::max_align_t because some libstdc++ versions don't provide +// std::max_align_t +#include <stddef.h> +#include <cstdint> +#include <memory> +#include <sstream> +#include <type_traits> + +#include "gmock/gmock.h" +#include "gtest/gtest.h" +#include "absl/base/internal/raw_logging.h" +#include "absl/types/span.h" + +namespace absl { +namespace container_internal { +namespace { + +using ::absl::Span; +using ::testing::ElementsAre; + +size_t Distance(const void* from, const void* to) { + ABSL_RAW_CHECK(from <= to, "Distance must be non-negative"); + return static_cast<const char*>(to) - static_cast<const char*>(from); +} + +template <class Expected, class Actual> +Expected Type(Actual val) { + static_assert(std::is_same<Expected, Actual>(), ""); + return val; +} + +using Int128 = int64_t[2]; + +// Properties of types that this test relies on. +static_assert(sizeof(int8_t) == 1, ""); +static_assert(alignof(int8_t) == 1, ""); +static_assert(sizeof(int16_t) == 2, ""); +static_assert(alignof(int16_t) == 2, ""); +static_assert(sizeof(int32_t) == 4, ""); +static_assert(alignof(int32_t) == 4, ""); +static_assert(sizeof(Int128) == 16, ""); +static_assert(alignof(Int128) == 8, ""); + +template <class Expected, class Actual> +void SameType() { + static_assert(std::is_same<Expected, Actual>(), ""); +} + +TEST(Layout, ElementType) { + { + using L = Layout<int32_t>; + SameType<int32_t, L::ElementType<0>>(); + SameType<int32_t, decltype(L::Partial())::ElementType<0>>(); + SameType<int32_t, decltype(L::Partial(0))::ElementType<0>>(); + } + { + using L = Layout<int32_t, int32_t>; + SameType<int32_t, L::ElementType<0>>(); + SameType<int32_t, L::ElementType<1>>(); + SameType<int32_t, decltype(L::Partial())::ElementType<0>>(); + SameType<int32_t, decltype(L::Partial())::ElementType<1>>(); + SameType<int32_t, decltype(L::Partial(0))::ElementType<0>>(); + SameType<int32_t, decltype(L::Partial(0))::ElementType<1>>(); + } + { + using L = Layout<int8_t, int32_t, Int128>; + SameType<int8_t, L::ElementType<0>>(); + SameType<int32_t, L::ElementType<1>>(); + SameType<Int128, L::ElementType<2>>(); + SameType<int8_t, decltype(L::Partial())::ElementType<0>>(); + SameType<int8_t, decltype(L::Partial(0))::ElementType<0>>(); + SameType<int32_t, decltype(L::Partial(0))::ElementType<1>>(); + SameType<int8_t, decltype(L::Partial(0, 0))::ElementType<0>>(); + SameType<int32_t, decltype(L::Partial(0, 0))::ElementType<1>>(); + SameType<Int128, decltype(L::Partial(0, 0))::ElementType<2>>(); + SameType<int8_t, decltype(L::Partial(0, 0, 0))::ElementType<0>>(); + SameType<int32_t, decltype(L::Partial(0, 0, 0))::ElementType<1>>(); + SameType<Int128, decltype(L::Partial(0, 0, 0))::ElementType<2>>(); + } +} + +TEST(Layout, ElementTypes) { + { + using L = Layout<int32_t>; + SameType<std::tuple<int32_t>, L::ElementTypes>(); + SameType<std::tuple<int32_t>, decltype(L::Partial())::ElementTypes>(); + SameType<std::tuple<int32_t>, decltype(L::Partial(0))::ElementTypes>(); + } + { + using L = Layout<int32_t, int32_t>; + SameType<std::tuple<int32_t, int32_t>, L::ElementTypes>(); + SameType<std::tuple<int32_t, int32_t>, decltype(L::Partial())::ElementTypes>(); + SameType<std::tuple<int32_t, int32_t>, decltype(L::Partial(0))::ElementTypes>(); + } + { + using L = Layout<int8_t, int32_t, Int128>; + SameType<std::tuple<int8_t, int32_t, Int128>, L::ElementTypes>(); + SameType<std::tuple<int8_t, int32_t, Int128>, + decltype(L::Partial())::ElementTypes>(); + SameType<std::tuple<int8_t, int32_t, Int128>, + decltype(L::Partial(0))::ElementTypes>(); + SameType<std::tuple<int8_t, int32_t, Int128>, + decltype(L::Partial(0, 0))::ElementTypes>(); + SameType<std::tuple<int8_t, int32_t, Int128>, + decltype(L::Partial(0, 0, 0))::ElementTypes>(); + } +} + +TEST(Layout, OffsetByIndex) { + { + using L = Layout<int32_t>; + EXPECT_EQ(0, L::Partial().Offset<0>()); + EXPECT_EQ(0, L::Partial(3).Offset<0>()); + EXPECT_EQ(0, L(3).Offset<0>()); + } + { + using L = Layout<int32_t, int32_t>; + EXPECT_EQ(0, L::Partial().Offset<0>()); + EXPECT_EQ(0, L::Partial(3).Offset<0>()); + EXPECT_EQ(12, L::Partial(3).Offset<1>()); + EXPECT_EQ(0, L::Partial(3, 5).Offset<0>()); + EXPECT_EQ(12, L::Partial(3, 5).Offset<1>()); + EXPECT_EQ(0, L(3, 5).Offset<0>()); + EXPECT_EQ(12, L(3, 5).Offset<1>()); + } + { + using L = Layout<int8_t, int32_t, Int128>; + EXPECT_EQ(0, L::Partial().Offset<0>()); + EXPECT_EQ(0, L::Partial(0).Offset<0>()); + EXPECT_EQ(0, L::Partial(0).Offset<1>()); + EXPECT_EQ(0, L::Partial(1).Offset<0>()); + EXPECT_EQ(4, L::Partial(1).Offset<1>()); + EXPECT_EQ(0, L::Partial(5).Offset<0>()); + EXPECT_EQ(8, L::Partial(5).Offset<1>()); + EXPECT_EQ(0, L::Partial(0, 0).Offset<0>()); + EXPECT_EQ(0, L::Partial(0, 0).Offset<1>()); + EXPECT_EQ(0, L::Partial(0, 0).Offset<2>()); + EXPECT_EQ(0, L::Partial(1, 0).Offset<0>()); + EXPECT_EQ(4, L::Partial(1, 0).Offset<1>()); + EXPECT_EQ(8, L::Partial(1, 0).Offset<2>()); + EXPECT_EQ(0, L::Partial(5, 3).Offset<0>()); + EXPECT_EQ(8, L::Partial(5, 3).Offset<1>()); + EXPECT_EQ(24, L::Partial(5, 3).Offset<2>()); + EXPECT_EQ(0, L::Partial(0, 0, 0).Offset<0>()); + EXPECT_EQ(0, L::Partial(0, 0, 0).Offset<1>()); + EXPECT_EQ(0, L::Partial(0, 0, 0).Offset<2>()); + EXPECT_EQ(0, L::Partial(1, 0, 0).Offset<0>()); + EXPECT_EQ(4, L::Partial(1, 0, 0).Offset<1>()); + EXPECT_EQ(8, L::Partial(1, 0, 0).Offset<2>()); + EXPECT_EQ(0, L::Partial(5, 3, 1).Offset<0>()); + EXPECT_EQ(24, L::Partial(5, 3, 1).Offset<2>()); + EXPECT_EQ(8, L::Partial(5, 3, 1).Offset<1>()); + EXPECT_EQ(0, L(5, 3, 1).Offset<0>()); + EXPECT_EQ(24, L(5, 3, 1).Offset<2>()); + EXPECT_EQ(8, L(5, 3, 1).Offset<1>()); + } +} + +TEST(Layout, OffsetByType) { + { + using L = Layout<int32_t>; + EXPECT_EQ(0, L::Partial().Offset<int32_t>()); + EXPECT_EQ(0, L::Partial(3).Offset<int32_t>()); + EXPECT_EQ(0, L(3).Offset<int32_t>()); + } + { + using L = Layout<int8_t, int32_t, Int128>; + EXPECT_EQ(0, L::Partial().Offset<int8_t>()); + EXPECT_EQ(0, L::Partial(0).Offset<int8_t>()); + EXPECT_EQ(0, L::Partial(0).Offset<int32_t>()); + EXPECT_EQ(0, L::Partial(1).Offset<int8_t>()); + EXPECT_EQ(4, L::Partial(1).Offset<int32_t>()); + EXPECT_EQ(0, L::Partial(5).Offset<int8_t>()); + EXPECT_EQ(8, L::Partial(5).Offset<int32_t>()); + EXPECT_EQ(0, L::Partial(0, 0).Offset<int8_t>()); + EXPECT_EQ(0, L::Partial(0, 0).Offset<int32_t>()); + EXPECT_EQ(0, L::Partial(0, 0).Offset<Int128>()); + EXPECT_EQ(0, L::Partial(1, 0).Offset<int8_t>()); + EXPECT_EQ(4, L::Partial(1, 0).Offset<int32_t>()); + EXPECT_EQ(8, L::Partial(1, 0).Offset<Int128>()); + EXPECT_EQ(0, L::Partial(5, 3).Offset<int8_t>()); + EXPECT_EQ(8, L::Partial(5, 3).Offset<int32_t>()); + EXPECT_EQ(24, L::Partial(5, 3).Offset<Int128>()); + EXPECT_EQ(0, L::Partial(0, 0, 0).Offset<int8_t>()); + EXPECT_EQ(0, L::Partial(0, 0, 0).Offset<int32_t>()); + EXPECT_EQ(0, L::Partial(0, 0, 0).Offset<Int128>()); + EXPECT_EQ(0, L::Partial(1, 0, 0).Offset<int8_t>()); + EXPECT_EQ(4, L::Partial(1, 0, 0).Offset<int32_t>()); + EXPECT_EQ(8, L::Partial(1, 0, 0).Offset<Int128>()); + EXPECT_EQ(0, L::Partial(5, 3, 1).Offset<int8_t>()); + EXPECT_EQ(24, L::Partial(5, 3, 1).Offset<Int128>()); + EXPECT_EQ(8, L::Partial(5, 3, 1).Offset<int32_t>()); + EXPECT_EQ(0, L(5, 3, 1).Offset<int8_t>()); + EXPECT_EQ(24, L(5, 3, 1).Offset<Int128>()); + EXPECT_EQ(8, L(5, 3, 1).Offset<int32_t>()); + } +} + +TEST(Layout, Offsets) { + { + using L = Layout<int32_t>; + EXPECT_THAT(L::Partial().Offsets(), ElementsAre(0)); + EXPECT_THAT(L::Partial(3).Offsets(), ElementsAre(0)); + EXPECT_THAT(L(3).Offsets(), ElementsAre(0)); + } + { + using L = Layout<int32_t, int32_t>; + EXPECT_THAT(L::Partial().Offsets(), ElementsAre(0)); + EXPECT_THAT(L::Partial(3).Offsets(), ElementsAre(0, 12)); + EXPECT_THAT(L::Partial(3, 5).Offsets(), ElementsAre(0, 12)); + EXPECT_THAT(L(3, 5).Offsets(), ElementsAre(0, 12)); + } + { + using L = Layout<int8_t, int32_t, Int128>; + EXPECT_THAT(L::Partial().Offsets(), ElementsAre(0)); + EXPECT_THAT(L::Partial(1).Offsets(), ElementsAre(0, 4)); + EXPECT_THAT(L::Partial(5).Offsets(), ElementsAre(0, 8)); + EXPECT_THAT(L::Partial(0, 0).Offsets(), ElementsAre(0, 0, 0)); + EXPECT_THAT(L::Partial(1, 0).Offsets(), ElementsAre(0, 4, 8)); + EXPECT_THAT(L::Partial(5, 3).Offsets(), ElementsAre(0, 8, 24)); + EXPECT_THAT(L::Partial(0, 0, 0).Offsets(), ElementsAre(0, 0, 0)); + EXPECT_THAT(L::Partial(1, 0, 0).Offsets(), ElementsAre(0, 4, 8)); + EXPECT_THAT(L::Partial(5, 3, 1).Offsets(), ElementsAre(0, 8, 24)); + EXPECT_THAT(L(5, 3, 1).Offsets(), ElementsAre(0, 8, 24)); + } +} + +TEST(Layout, AllocSize) { + { + using L = Layout<int32_t>; + EXPECT_EQ(0, L::Partial(0).AllocSize()); + EXPECT_EQ(12, L::Partial(3).AllocSize()); + EXPECT_EQ(12, L(3).AllocSize()); + } + { + using L = Layout<int32_t, int32_t>; + EXPECT_EQ(32, L::Partial(3, 5).AllocSize()); + EXPECT_EQ(32, L(3, 5).AllocSize()); + } + { + using L = Layout<int8_t, int32_t, Int128>; + EXPECT_EQ(0, L::Partial(0, 0, 0).AllocSize()); + EXPECT_EQ(8, L::Partial(1, 0, 0).AllocSize()); + EXPECT_EQ(8, L::Partial(0, 1, 0).AllocSize()); + EXPECT_EQ(16, L::Partial(0, 0, 1).AllocSize()); + EXPECT_EQ(24, L::Partial(1, 1, 1).AllocSize()); + EXPECT_EQ(136, L::Partial(3, 5, 7).AllocSize()); + EXPECT_EQ(136, L(3, 5, 7).AllocSize()); + } +} + +TEST(Layout, SizeByIndex) { + { + using L = Layout<int32_t>; + EXPECT_EQ(0, L::Partial(0).Size<0>()); + EXPECT_EQ(3, L::Partial(3).Size<0>()); + EXPECT_EQ(3, L(3).Size<0>()); + } + { + using L = Layout<int32_t, int32_t>; + EXPECT_EQ(0, L::Partial(0).Size<0>()); + EXPECT_EQ(3, L::Partial(3).Size<0>()); + EXPECT_EQ(3, L::Partial(3, 5).Size<0>()); + EXPECT_EQ(5, L::Partial(3, 5).Size<1>()); + EXPECT_EQ(3, L(3, 5).Size<0>()); + EXPECT_EQ(5, L(3, 5).Size<1>()); + } + { + using L = Layout<int8_t, int32_t, Int128>; + EXPECT_EQ(3, L::Partial(3).Size<0>()); + EXPECT_EQ(3, L::Partial(3, 5).Size<0>()); + EXPECT_EQ(5, L::Partial(3, 5).Size<1>()); + EXPECT_EQ(3, L::Partial(3, 5, 7).Size<0>()); + EXPECT_EQ(5, L::Partial(3, 5, 7).Size<1>()); + EXPECT_EQ(7, L::Partial(3, 5, 7).Size<2>()); + EXPECT_EQ(3, L(3, 5, 7).Size<0>()); + EXPECT_EQ(5, L(3, 5, 7).Size<1>()); + EXPECT_EQ(7, L(3, 5, 7).Size<2>()); + } +} + +TEST(Layout, SizeByType) { + { + using L = Layout<int32_t>; + EXPECT_EQ(0, L::Partial(0).Size<int32_t>()); + EXPECT_EQ(3, L::Partial(3).Size<int32_t>()); + EXPECT_EQ(3, L(3).Size<int32_t>()); + } + { + using L = Layout<int8_t, int32_t, Int128>; + EXPECT_EQ(3, L::Partial(3).Size<int8_t>()); + EXPECT_EQ(3, L::Partial(3, 5).Size<int8_t>()); + EXPECT_EQ(5, L::Partial(3, 5).Size<int32_t>()); + EXPECT_EQ(3, L::Partial(3, 5, 7).Size<int8_t>()); + EXPECT_EQ(5, L::Partial(3, 5, 7).Size<int32_t>()); + EXPECT_EQ(7, L::Partial(3, 5, 7).Size<Int128>()); + EXPECT_EQ(3, L(3, 5, 7).Size<int8_t>()); + EXPECT_EQ(5, L(3, 5, 7).Size<int32_t>()); + EXPECT_EQ(7, L(3, 5, 7).Size<Int128>()); + } +} + +TEST(Layout, Sizes) { + { + using L = Layout<int32_t>; + EXPECT_THAT(L::Partial().Sizes(), ElementsAre()); + EXPECT_THAT(L::Partial(3).Sizes(), ElementsAre(3)); + EXPECT_THAT(L(3).Sizes(), ElementsAre(3)); + } + { + using L = Layout<int32_t, int32_t>; + EXPECT_THAT(L::Partial().Sizes(), ElementsAre()); + EXPECT_THAT(L::Partial(3).Sizes(), ElementsAre(3)); + EXPECT_THAT(L::Partial(3, 5).Sizes(), ElementsAre(3, 5)); + EXPECT_THAT(L(3, 5).Sizes(), ElementsAre(3, 5)); + } + { + using L = Layout<int8_t, int32_t, Int128>; + EXPECT_THAT(L::Partial().Sizes(), ElementsAre()); + EXPECT_THAT(L::Partial(3).Sizes(), ElementsAre(3)); + EXPECT_THAT(L::Partial(3, 5).Sizes(), ElementsAre(3, 5)); + EXPECT_THAT(L::Partial(3, 5, 7).Sizes(), ElementsAre(3, 5, 7)); + EXPECT_THAT(L(3, 5, 7).Sizes(), ElementsAre(3, 5, 7)); + } +} + +TEST(Layout, PointerByIndex) { + alignas(max_align_t) const unsigned char p[100] = {}; + { + using L = Layout<int32_t>; + EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial().Pointer<0>(p)))); + EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<0>(p)))); + EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L(3).Pointer<0>(p)))); + } + { + using L = Layout<int32_t, int32_t>; + EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial().Pointer<0>(p)))); + EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<0>(p)))); + EXPECT_EQ(12, Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<1>(p)))); + EXPECT_EQ(0, + Distance(p, Type<const int32_t*>(L::Partial(3, 5).Pointer<0>(p)))); + EXPECT_EQ(12, + Distance(p, Type<const int32_t*>(L::Partial(3, 5).Pointer<1>(p)))); + EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L(3, 5).Pointer<0>(p)))); + EXPECT_EQ(12, Distance(p, Type<const int32_t*>(L(3, 5).Pointer<1>(p)))); + } + { + using L = Layout<int8_t, int32_t, Int128>; + EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial().Pointer<0>(p)))); + EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial(0).Pointer<0>(p)))); + EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L::Partial(0).Pointer<1>(p)))); + EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial(1).Pointer<0>(p)))); + EXPECT_EQ(4, Distance(p, Type<const int32_t*>(L::Partial(1).Pointer<1>(p)))); + EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial(5).Pointer<0>(p)))); + EXPECT_EQ(8, Distance(p, Type<const int32_t*>(L::Partial(5).Pointer<1>(p)))); + EXPECT_EQ(0, + Distance(p, Type<const int8_t*>(L::Partial(0, 0).Pointer<0>(p)))); + EXPECT_EQ(0, + Distance(p, Type<const int32_t*>(L::Partial(0, 0).Pointer<1>(p)))); + EXPECT_EQ(0, + Distance(p, Type<const Int128*>(L::Partial(0, 0).Pointer<2>(p)))); + EXPECT_EQ(0, + Distance(p, Type<const int8_t*>(L::Partial(1, 0).Pointer<0>(p)))); + EXPECT_EQ(4, + Distance(p, Type<const int32_t*>(L::Partial(1, 0).Pointer<1>(p)))); + EXPECT_EQ(8, + Distance(p, Type<const Int128*>(L::Partial(1, 0).Pointer<2>(p)))); + EXPECT_EQ(0, + Distance(p, Type<const int8_t*>(L::Partial(5, 3).Pointer<0>(p)))); + EXPECT_EQ(8, + Distance(p, Type<const int32_t*>(L::Partial(5, 3).Pointer<1>(p)))); + EXPECT_EQ(24, + Distance(p, Type<const Int128*>(L::Partial(5, 3).Pointer<2>(p)))); + EXPECT_EQ( + 0, Distance(p, Type<const int8_t*>(L::Partial(0, 0, 0).Pointer<0>(p)))); + EXPECT_EQ( + 0, Distance(p, Type<const int32_t*>(L::Partial(0, 0, 0).Pointer<1>(p)))); + EXPECT_EQ( + 0, Distance(p, Type<const Int128*>(L::Partial(0, 0, 0).Pointer<2>(p)))); + EXPECT_EQ( + 0, Distance(p, Type<const int8_t*>(L::Partial(1, 0, 0).Pointer<0>(p)))); + EXPECT_EQ( + 4, Distance(p, Type<const int32_t*>(L::Partial(1, 0, 0).Pointer<1>(p)))); + EXPECT_EQ( + 8, Distance(p, Type<const Int128*>(L::Partial(1, 0, 0).Pointer<2>(p)))); + EXPECT_EQ( + 0, Distance(p, Type<const int8_t*>(L::Partial(5, 3, 1).Pointer<0>(p)))); + EXPECT_EQ( + 24, + Distance(p, Type<const Int128*>(L::Partial(5, 3, 1).Pointer<2>(p)))); + EXPECT_EQ( + 8, Distance(p, Type<const int32_t*>(L::Partial(5, 3, 1).Pointer<1>(p)))); + EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L(5, 3, 1).Pointer<0>(p)))); + EXPECT_EQ(24, Distance(p, Type<const Int128*>(L(5, 3, 1).Pointer<2>(p)))); + EXPECT_EQ(8, Distance(p, Type<const int32_t*>(L(5, 3, 1).Pointer<1>(p)))); + } +} + +TEST(Layout, PointerByType) { + alignas(max_align_t) const unsigned char p[100] = {}; + { + using L = Layout<int32_t>; + EXPECT_EQ(0, + Distance(p, Type<const int32_t*>(L::Partial().Pointer<int32_t>(p)))); + EXPECT_EQ(0, + Distance(p, Type<const int32_t*>(L::Partial(3).Pointer<int32_t>(p)))); + EXPECT_EQ(0, Distance(p, Type<const int32_t*>(L(3).Pointer<int32_t>(p)))); + } + { + using L = Layout<int8_t, int32_t, Int128>; + EXPECT_EQ(0, Distance(p, Type<const int8_t*>(L::Partial().Pointer<int8_t>(p)))); + EXPECT_EQ(0, + Distance(p, Type<const int8_t*>(L::Partial(0).Pointer<int8_t>(p)))); + EXPECT_EQ(0, + Distance(p, Type<const int32_t*>(L::Partial(0).Pointer<int32_t>(p)))); + EXPECT_EQ(0, + Distance(p, Type<const int8_t*>(L::Partial(1).Pointer<int8_t>(p)))); + EXPECT_EQ(4, + Distance(p, Type<const int32_t*>(L::Partial(1).Pointer<int32_t>(p)))); + EXPECT_EQ(0, + Distance(p, Type<const int8_t*>(L::Partial(5).Pointer<int8_t>(p)))); + EXPECT_EQ(8, + Distance(p, Type<const int32_t*>(L::Partial(5).Pointer<int32_t>(p)))); + EXPECT_EQ( + 0, Distance(p, Type<const int8_t*>(L::Partial(0, 0).Pointer<int8_t>(p)))); + EXPECT_EQ( + 0, Distance(p, Type<const int32_t*>(L::Partial(0, 0).Pointer<int32_t>(p)))); + EXPECT_EQ( + 0, + Distance(p, Type<const Int128*>(L::Partial(0, 0).Pointer<Int128>(p)))); + EXPECT_EQ( + 0, Distance(p, Type<const int8_t*>(L::Partial(1, 0).Pointer<int8_t>(p)))); + EXPECT_EQ( + 4, Distance(p, Type<const int32_t*>(L::Partial(1, 0).Pointer<int32_t>(p)))); + EXPECT_EQ( + 8, + Distance(p, Type<const Int128*>(L::Partial(1, 0).Pointer<Int128>(p)))); + EXPECT_EQ( + 0, Distance(p, Type<const int8_t*>(L::Partial(5, 3).Pointer<int8_t>(p)))); + EXPECT_EQ( + 8, Distance(p, Type<const int32_t*>(L::Partial(5, 3).Pointer<int32_t>(p)))); + EXPECT_EQ( + 24, + Distance(p, Type<const Int128*>(L::Partial(5, 3).Pointer<Int128>(p)))); + EXPECT_EQ( + 0, + Distance(p, Type<const int8_t*>(L::Partial(0, 0, 0).Pointer<int8_t>(p)))); + EXPECT_EQ( + 0, + Distance(p, Type<const int32_t*>(L::Partial(0, 0, 0).Pointer<int32_t>(p)))); + EXPECT_EQ(0, Distance(p, Type<const Int128*>( + L::Partial(0, 0, 0).Pointer<Int128>(p)))); + EXPECT_EQ( + 0, + Distance(p, Type<const int8_t*>(L::Partial(1, 0, 0).Pointer<int8_t>(p)))); + EXPECT_EQ( + 4, + Distance(p, Type<const int32_t*>(L::Partial(1, 0, 0).Pointer<int32_t>(p)))); + EXPECT_EQ(8, Distance(p, Type<const Int128*>( + L::Partial(1, 0, 0).Pointer<Int128>(p)))); + EXPECT_EQ( + 0, + Distance(p, Type<const int8_t*>(L::Partial(5, 3, 1).Pointer<int8_t>(p)))); + EXPECT_EQ(24, Distance(p, Type<const Int128*>( + L::Partial(5, 3, 1).Pointer<Int128>(p)))); + EXPECT_EQ( + 8, + Distance(p, Type<const int32_t*>(L::Partial(5, 3, 1).Pointer<int32_t>(p)))); + EXPECT_EQ(24, + Distance(p, Type<const Int128*>(L(5, 3, 1).Pointer<Int128>(p)))); + EXPECT_EQ(8, Distance(p, Type<const int32_t*>(L(5, 3, 1).Pointer<int32_t>(p)))); + } +} + +TEST(Layout, MutablePointerByIndex) { + alignas(max_align_t) unsigned char p[100]; + { + using L = Layout<int32_t>; + EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial().Pointer<0>(p)))); + EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(3).Pointer<0>(p)))); + EXPECT_EQ(0, Distance(p, Type<int32_t*>(L(3).Pointer<0>(p)))); + } + { + using L = Layout<int32_t, int32_t>; + EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial().Pointer<0>(p)))); + EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(3).Pointer<0>(p)))); + EXPECT_EQ(12, Distance(p, Type<int32_t*>(L::Partial(3).Pointer<1>(p)))); + EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(3, 5).Pointer<0>(p)))); + EXPECT_EQ(12, Distance(p, Type<int32_t*>(L::Partial(3, 5).Pointer<1>(p)))); + EXPECT_EQ(0, Distance(p, Type<int32_t*>(L(3, 5).Pointer<0>(p)))); + EXPECT_EQ(12, Distance(p, Type<int32_t*>(L(3, 5).Pointer<1>(p)))); + } + { + using L = Layout<int8_t, int32_t, Int128>; + EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial().Pointer<0>(p)))); + EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0).Pointer<0>(p)))); + EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(0).Pointer<1>(p)))); + EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1).Pointer<0>(p)))); + EXPECT_EQ(4, Distance(p, Type<int32_t*>(L::Partial(1).Pointer<1>(p)))); + EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5).Pointer<0>(p)))); + EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5).Pointer<1>(p)))); + EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0, 0).Pointer<0>(p)))); + EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(0, 0).Pointer<1>(p)))); + EXPECT_EQ(0, Distance(p, Type<Int128*>(L::Partial(0, 0).Pointer<2>(p)))); + EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1, 0).Pointer<0>(p)))); + EXPECT_EQ(4, Distance(p, Type<int32_t*>(L::Partial(1, 0).Pointer<1>(p)))); + EXPECT_EQ(8, Distance(p, Type<Int128*>(L::Partial(1, 0).Pointer<2>(p)))); + EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5, 3).Pointer<0>(p)))); + EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5, 3).Pointer<1>(p)))); + EXPECT_EQ(24, Distance(p, Type<Int128*>(L::Partial(5, 3).Pointer<2>(p)))); + EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0, 0, 0).Pointer<0>(p)))); + EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(0, 0, 0).Pointer<1>(p)))); + EXPECT_EQ(0, Distance(p, Type<Int128*>(L::Partial(0, 0, 0).Pointer<2>(p)))); + EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1, 0, 0).Pointer<0>(p)))); + EXPECT_EQ(4, Distance(p, Type<int32_t*>(L::Partial(1, 0, 0).Pointer<1>(p)))); + EXPECT_EQ(8, Distance(p, Type<Int128*>(L::Partial(1, 0, 0).Pointer<2>(p)))); + EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5, 3, 1).Pointer<0>(p)))); + EXPECT_EQ(24, + Distance(p, Type<Int128*>(L::Partial(5, 3, 1).Pointer<2>(p)))); + EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5, 3, 1).Pointer<1>(p)))); + EXPECT_EQ(0, Distance(p, Type<int8_t*>(L(5, 3, 1).Pointer<0>(p)))); + EXPECT_EQ(24, Distance(p, Type<Int128*>(L(5, 3, 1).Pointer<2>(p)))); + EXPECT_EQ(8, Distance(p, Type<int32_t*>(L(5, 3, 1).Pointer<1>(p)))); + } +} + +TEST(Layout, MutablePointerByType) { + alignas(max_align_t) unsigned char p[100]; + { + using L = Layout<int32_t>; + EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial().Pointer<int32_t>(p)))); + EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(3).Pointer<int32_t>(p)))); + EXPECT_EQ(0, Distance(p, Type<int32_t*>(L(3).Pointer<int32_t>(p)))); + } + { + using L = Layout<int8_t, int32_t, Int128>; + EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial().Pointer<int8_t>(p)))); + EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0).Pointer<int8_t>(p)))); + EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(0).Pointer<int32_t>(p)))); + EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1).Pointer<int8_t>(p)))); + EXPECT_EQ(4, Distance(p, Type<int32_t*>(L::Partial(1).Pointer<int32_t>(p)))); + EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5).Pointer<int8_t>(p)))); + EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5).Pointer<int32_t>(p)))); + EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(0, 0).Pointer<int8_t>(p)))); + EXPECT_EQ(0, Distance(p, Type<int32_t*>(L::Partial(0, 0).Pointer<int32_t>(p)))); + EXPECT_EQ(0, + Distance(p, Type<Int128*>(L::Partial(0, 0).Pointer<Int128>(p)))); + EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(1, 0).Pointer<int8_t>(p)))); + EXPECT_EQ(4, Distance(p, Type<int32_t*>(L::Partial(1, 0).Pointer<int32_t>(p)))); + EXPECT_EQ(8, + Distance(p, Type<Int128*>(L::Partial(1, 0).Pointer<Int128>(p)))); + EXPECT_EQ(0, Distance(p, Type<int8_t*>(L::Partial(5, 3).Pointer<int8_t>(p)))); + EXPECT_EQ(8, Distance(p, Type<int32_t*>(L::Partial(5, 3).Pointer<int32_t>(p)))); + EXPECT_EQ(24, + Distance(p, Type<Int128*>(L::Partial(5, 3).Pointer<Int128>(p)))); + EXPECT_EQ(0, + Distance(p, Type<int8_t*>(L::Partial(0, 0, 0).Pointer<int8_t>(p)))); + EXPECT_EQ(0, + Distance(p, Type<int32_t*>(L::Partial(0, 0, 0).Pointer<int32_t>(p)))); + EXPECT_EQ( + 0, Distance(p, Type<Int128*>(L::Partial(0, 0, 0).Pointer<Int128>(p)))); + EXPECT_EQ(0, + Distance(p, Type<int8_t*>(L::Partial(1, 0, 0).Pointer<int8_t>(p)))); + EXPECT_EQ(4, + Distance(p, Type<int32_t*>(L::Partial(1, 0, 0).Pointer<int32_t>(p)))); + EXPECT_EQ( + 8, Distance(p, Type<Int128*>(L::Partial(1, 0, 0).Pointer<Int128>(p)))); + EXPECT_EQ(0, + Distance(p, Type<int8_t*>(L::Partial(5, 3, 1).Pointer<int8_t>(p)))); + EXPECT_EQ( + 24, Distance(p, Type<Int128*>(L::Partial(5, 3, 1).Pointer<Int128>(p)))); + EXPECT_EQ(8, + Distance(p, Type<int32_t*>(L::Partial(5, 3, 1).Pointer<int32_t>(p)))); + EXPECT_EQ(0, Distance(p, Type<int8_t*>(L(5, 3, 1).Pointer<int8_t>(p)))); + EXPECT_EQ(24, Distance(p, Type<Int128*>(L(5, 3, 1).Pointer<Int128>(p)))); + EXPECT_EQ(8, Distance(p, Type<int32_t*>(L(5, 3, 1).Pointer<int32_t>(p)))); + } +} + +TEST(Layout, Pointers) { + alignas(max_align_t) const unsigned char p[100] = {}; + using L = Layout<int8_t, int8_t, Int128>; + { + const auto x = L::Partial(); + EXPECT_EQ(std::make_tuple(x.Pointer<0>(p)), + Type<std::tuple<const int8_t*>>(x.Pointers(p))); + } + { + const auto x = L::Partial(1); + EXPECT_EQ(std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p)), + (Type<std::tuple<const int8_t*, const int8_t*>>(x.Pointers(p)))); + } + { + const auto x = L::Partial(1, 2); + EXPECT_EQ( + std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p), x.Pointer<2>(p)), + (Type<std::tuple<const int8_t*, const int8_t*, const Int128*>>( + x.Pointers(p)))); + } + { + const auto x = L::Partial(1, 2, 3); + EXPECT_EQ( + std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p), x.Pointer<2>(p)), + (Type<std::tuple<const int8_t*, const int8_t*, const Int128*>>( + x.Pointers(p)))); + } + { + const L x(1, 2, 3); + EXPECT_EQ( + std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p), x.Pointer<2>(p)), + (Type<std::tuple<const int8_t*, const int8_t*, const Int128*>>( + x.Pointers(p)))); + } +} + +TEST(Layout, MutablePointers) { + alignas(max_align_t) unsigned char p[100]; + using L = Layout<int8_t, int8_t, Int128>; + { + const auto x = L::Partial(); + EXPECT_EQ(std::make_tuple(x.Pointer<0>(p)), + Type<std::tuple<int8_t*>>(x.Pointers(p))); + } + { + const auto x = L::Partial(1); + EXPECT_EQ(std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p)), + (Type<std::tuple<int8_t*, int8_t*>>(x.Pointers(p)))); + } + { + const auto x = L::Partial(1, 2); + EXPECT_EQ( + std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p), x.Pointer<2>(p)), + (Type<std::tuple<int8_t*, int8_t*, Int128*>>(x.Pointers(p)))); + } + { + const auto x = L::Partial(1, 2, 3); + EXPECT_EQ( + std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p), x.Pointer<2>(p)), + (Type<std::tuple<int8_t*, int8_t*, Int128*>>(x.Pointers(p)))); + } + { + const L x(1, 2, 3); + EXPECT_EQ( + std::make_tuple(x.Pointer<0>(p), x.Pointer<1>(p), x.Pointer<2>(p)), + (Type<std::tuple<int8_t*, int8_t*, Int128*>>(x.Pointers(p)))); + } +} + +TEST(Layout, SliceByIndexSize) { + alignas(max_align_t) const unsigned char p[100] = {}; + { + using L = Layout<int32_t>; + EXPECT_EQ(0, L::Partial(0).Slice<0>(p).size()); + EXPECT_EQ(3, L::Partial(3).Slice<0>(p).size()); + EXPECT_EQ(3, L(3).Slice<0>(p).size()); + } + { + using L = Layout<int32_t, int32_t>; + EXPECT_EQ(3, L::Partial(3).Slice<0>(p).size()); + EXPECT_EQ(5, L::Partial(3, 5).Slice<1>(p).size()); + EXPECT_EQ(5, L(3, 5).Slice<1>(p).size()); + } + { + using L = Layout<int8_t, int32_t, Int128>; + EXPECT_EQ(3, L::Partial(3).Slice<0>(p).size()); + EXPECT_EQ(3, L::Partial(3, 5).Slice<0>(p).size()); + EXPECT_EQ(5, L::Partial(3, 5).Slice<1>(p).size()); + EXPECT_EQ(3, L::Partial(3, 5, 7).Slice<0>(p).size()); + EXPECT_EQ(5, L::Partial(3, 5, 7).Slice<1>(p).size()); + EXPECT_EQ(7, L::Partial(3, 5, 7).Slice<2>(p).size()); + EXPECT_EQ(3, L(3, 5, 7).Slice<0>(p).size()); + EXPECT_EQ(5, L(3, 5, 7).Slice<1>(p).size()); + EXPECT_EQ(7, L(3, 5, 7).Slice<2>(p).size()); + } +} + +TEST(Layout, SliceByTypeSize) { + alignas(max_align_t) const unsigned char p[100] = {}; + { + using L = Layout<int32_t>; + EXPECT_EQ(0, L::Partial(0).Slice<int32_t>(p).size()); + EXPECT_EQ(3, L::Partial(3).Slice<int32_t>(p).size()); + EXPECT_EQ(3, L(3).Slice<int32_t>(p).size()); + } + { + using L = Layout<int8_t, int32_t, Int128>; + EXPECT_EQ(3, L::Partial(3).Slice<int8_t>(p).size()); + EXPECT_EQ(3, L::Partial(3, 5).Slice<int8_t>(p).size()); + EXPECT_EQ(5, L::Partial(3, 5).Slice<int32_t>(p).size()); + EXPECT_EQ(3, L::Partial(3, 5, 7).Slice<int8_t>(p).size()); + EXPECT_EQ(5, L::Partial(3, 5, 7).Slice<int32_t>(p).size()); + EXPECT_EQ(7, L::Partial(3, 5, 7).Slice<Int128>(p).size()); + EXPECT_EQ(3, L(3, 5, 7).Slice<int8_t>(p).size()); + EXPECT_EQ(5, L(3, 5, 7).Slice<int32_t>(p).size()); + EXPECT_EQ(7, L(3, 5, 7).Slice<Int128>(p).size()); + } +} + +TEST(Layout, MutableSliceByIndexSize) { + alignas(max_align_t) unsigned char p[100]; + { + using L = Layout<int32_t>; + EXPECT_EQ(0, L::Partial(0).Slice<0>(p).size()); + EXPECT_EQ(3, L::Partial(3).Slice<0>(p).size()); + EXPECT_EQ(3, L(3).Slice<0>(p).size()); + } + { + using L = Layout<int32_t, int32_t>; + EXPECT_EQ(3, L::Partial(3).Slice<0>(p).size()); + EXPECT_EQ(5, L::Partial(3, 5).Slice<1>(p).size()); + EXPECT_EQ(5, L(3, 5).Slice<1>(p).size()); + } + { + using L = Layout<int8_t, int32_t, Int128>; + EXPECT_EQ(3, L::Partial(3).Slice<0>(p).size()); + EXPECT_EQ(3, L::Partial(3, 5).Slice<0>(p).size()); + EXPECT_EQ(5, L::Partial(3, 5).Slice<1>(p).size()); + EXPECT_EQ(3, L::Partial(3, 5, 7).Slice<0>(p).size()); + EXPECT_EQ(5, L::Partial(3, 5, 7).Slice<1>(p).size()); + EXPECT_EQ(7, L::Partial(3, 5, 7).Slice<2>(p).size()); + EXPECT_EQ(3, L(3, 5, 7).Slice<0>(p).size()); + EXPECT_EQ(5, L(3, 5, 7).Slice<1>(p).size()); + EXPECT_EQ(7, L(3, 5, 7).Slice<2>(p).size()); + } +} + +TEST(Layout, MutableSliceByTypeSize) { + alignas(max_align_t) unsigned char p[100]; + { + using L = Layout<int32_t>; + EXPECT_EQ(0, L::Partial(0).Slice<int32_t>(p).size()); + EXPECT_EQ(3, L::Partial(3).Slice<int32_t>(p).size()); + EXPECT_EQ(3, L(3).Slice<int32_t>(p).size()); + } + { + using L = Layout<int8_t, int32_t, Int128>; + EXPECT_EQ(3, L::Partial(3).Slice<int8_t>(p).size()); + EXPECT_EQ(3, L::Partial(3, 5).Slice<int8_t>(p).size()); + EXPECT_EQ(5, L::Partial(3, 5).Slice<int32_t>(p).size()); + EXPECT_EQ(3, L::Partial(3, 5, 7).Slice<int8_t>(p).size()); + EXPECT_EQ(5, L::Partial(3, 5, 7).Slice<int32_t>(p).size()); + EXPECT_EQ(7, L::Partial(3, 5, 7).Slice<Int128>(p).size()); + EXPECT_EQ(3, L(3, 5, 7).Slice<int8_t>(p).size()); + EXPECT_EQ(5, L(3, 5, 7).Slice<int32_t>(p).size()); + EXPECT_EQ(7, L(3, 5, 7).Slice<Int128>(p).size()); + } +} + +TEST(Layout, SliceByIndexData) { + alignas(max_align_t) const unsigned char p[100] = {}; + { + using L = Layout<int32_t>; + EXPECT_EQ( + 0, + Distance(p, Type<Span<const int32_t>>(L::Partial(0).Slice<0>(p)).data())); + EXPECT_EQ( + 0, + Distance(p, Type<Span<const int32_t>>(L::Partial(3).Slice<0>(p)).data())); + EXPECT_EQ(0, Distance(p, Type<Span<const int32_t>>(L(3).Slice<0>(p)).data())); + } + { + using L = Layout<int32_t, int32_t>; + EXPECT_EQ( + 0, + Distance(p, Type<Span<const int32_t>>(L::Partial(3).Slice<0>(p)).data())); + EXPECT_EQ( + 0, + Distance(p, + Type<Span<const int32_t>>(L::Partial(3, 5).Slice<0>(p)).data())); + EXPECT_EQ( + 12, + Distance(p, + Type<Span<const int32_t>>(L::Partial(3, 5).Slice<1>(p)).data())); + EXPECT_EQ(0, + Distance(p, Type<Span<const int32_t>>(L(3, 5).Slice<0>(p)).data())); + EXPECT_EQ(12, + Distance(p, Type<Span<const int32_t>>(L(3, 5).Slice<1>(p)).data())); + } + { + using L = Layout<int8_t, int32_t, Int128>; + EXPECT_EQ( + 0, + Distance(p, Type<Span<const int8_t>>(L::Partial(0).Slice<0>(p)).data())); + EXPECT_EQ( + 0, + Distance(p, Type<Span<const int8_t>>(L::Partial(1).Slice<0>(p)).data())); + EXPECT_EQ( + 0, + Distance(p, Type<Span<const int8_t>>(L::Partial(5).Slice<0>(p)).data())); + EXPECT_EQ( + 0, Distance( + p, Type<Span<const int8_t>>(L::Partial(0, 0).Slice<0>(p)).data())); + EXPECT_EQ( + 0, + Distance(p, + Type<Span<const int32_t>>(L::Partial(0, 0).Slice<1>(p)).data())); + EXPECT_EQ( + 0, Distance( + p, Type<Span<const int8_t>>(L::Partial(1, 0).Slice<0>(p)).data())); + EXPECT_EQ( + 4, + Distance(p, + Type<Span<const int32_t>>(L::Partial(1, 0).Slice<1>(p)).data())); + EXPECT_EQ( + 0, Distance( + p, Type<Span<const int8_t>>(L::Partial(5, 3).Slice<0>(p)).data())); + EXPECT_EQ( + 8, + Distance(p, + Type<Span<const int32_t>>(L::Partial(5, 3).Slice<1>(p)).data())); + EXPECT_EQ( + 0, + Distance( + p, Type<Span<const int8_t>>(L::Partial(0, 0, 0).Slice<0>(p)).data())); + EXPECT_EQ( + 0, + Distance( + p, + Type<Span<const int32_t>>(L::Partial(0, 0, 0).Slice<1>(p)).data())); + EXPECT_EQ( + 0, + Distance( + p, + Type<Span<const Int128>>(L::Partial(0, 0, 0).Slice<2>(p)).data())); + EXPECT_EQ( + 0, + Distance( + p, Type<Span<const int8_t>>(L::Partial(1, 0, 0).Slice<0>(p)).data())); + EXPECT_EQ( + 4, + Distance( + p, + Type<Span<const int32_t>>(L::Partial(1, 0, 0).Slice<1>(p)).data())); + EXPECT_EQ( + 8, + Distance( + p, + Type<Span<const Int128>>(L::Partial(1, 0, 0).Slice<2>(p)).data())); + EXPECT_EQ( + 0, + Distance( + p, Type<Span<const int8_t>>(L::Partial(5, 3, 1).Slice<0>(p)).data())); + EXPECT_EQ( + 24, + Distance( + p, + Type<Span<const Int128>>(L::Partial(5, 3, 1).Slice<2>(p)).data())); + EXPECT_EQ( + 8, + Distance( + p, + Type<Span<const int32_t>>(L::Partial(5, 3, 1).Slice<1>(p)).data())); + EXPECT_EQ( + 0, Distance(p, Type<Span<const int8_t>>(L(5, 3, 1).Slice<0>(p)).data())); + EXPECT_EQ( + 24, + Distance(p, Type<Span<const Int128>>(L(5, 3, 1).Slice<2>(p)).data())); + EXPECT_EQ( + 8, Distance(p, Type<Span<const int32_t>>(L(5, 3, 1).Slice<1>(p)).data())); + } +} + +TEST(Layout, SliceByTypeData) { + alignas(max_align_t) const unsigned char p[100] = {}; + { + using L = Layout<int32_t>; + EXPECT_EQ( + 0, + Distance( + p, Type<Span<const int32_t>>(L::Partial(0).Slice<int32_t>(p)).data())); + EXPECT_EQ( + 0, + Distance( + p, Type<Span<const int32_t>>(L::Partial(3).Slice<int32_t>(p)).data())); + EXPECT_EQ( + 0, Distance(p, Type<Span<const int32_t>>(L(3).Slice<int32_t>(p)).data())); + } + { + using L = Layout<int8_t, int32_t, Int128>; + EXPECT_EQ( + 0, Distance( + p, Type<Span<const int8_t>>(L::Partial(0).Slice<int8_t>(p)).data())); + EXPECT_EQ( + 0, Distance( + p, Type<Span<const int8_t>>(L::Partial(1).Slice<int8_t>(p)).data())); + EXPECT_EQ( + 0, Distance( + p, Type<Span<const int8_t>>(L::Partial(5).Slice<int8_t>(p)).data())); + EXPECT_EQ( + 0, + Distance( + p, Type<Span<const int8_t>>(L::Partial(0, 0).Slice<int8_t>(p)).data())); + EXPECT_EQ( + 0, + Distance( + p, + Type<Span<const int32_t>>(L::Partial(0, 0).Slice<int32_t>(p)).data())); + EXPECT_EQ( + 0, + Distance( + p, Type<Span<const int8_t>>(L::Partial(1, 0).Slice<int8_t>(p)).data())); + EXPECT_EQ( + 4, + Distance( + p, + Type<Span<const int32_t>>(L::Partial(1, 0).Slice<int32_t>(p)).data())); + EXPECT_EQ( + 0, + Distance( + p, Type<Span<const int8_t>>(L::Partial(5, 3).Slice<int8_t>(p)).data())); + EXPECT_EQ( + 8, + Distance( + p, + Type<Span<const int32_t>>(L::Partial(5, 3).Slice<int32_t>(p)).data())); + EXPECT_EQ( + 0, + Distance( + p, + Type<Span<const int8_t>>(L::Partial(0, 0, 0).Slice<int8_t>(p)).data())); + EXPECT_EQ( + 0, + Distance(p, Type<Span<const int32_t>>(L::Partial(0, 0, 0).Slice<int32_t>(p)) + .data())); + EXPECT_EQ(0, Distance(p, Type<Span<const Int128>>( + L::Partial(0, 0, 0).Slice<Int128>(p)) + .data())); + EXPECT_EQ( + 0, + Distance( + p, + Type<Span<const int8_t>>(L::Partial(1, 0, 0).Slice<int8_t>(p)).data())); + EXPECT_EQ( + 4, + Distance(p, Type<Span<const int32_t>>(L::Partial(1, 0, 0).Slice<int32_t>(p)) + .data())); + EXPECT_EQ(8, Distance(p, Type<Span<const Int128>>( + L::Partial(1, 0, 0).Slice<Int128>(p)) + .data())); + EXPECT_EQ( + 0, + Distance( + p, + Type<Span<const int8_t>>(L::Partial(5, 3, 1).Slice<int8_t>(p)).data())); + EXPECT_EQ(24, Distance(p, Type<Span<const Int128>>( + L::Partial(5, 3, 1).Slice<Int128>(p)) + .data())); + EXPECT_EQ( + 8, + Distance(p, Type<Span<const int32_t>>(L::Partial(5, 3, 1).Slice<int32_t>(p)) + .data())); + EXPECT_EQ( + 0, + Distance(p, Type<Span<const int8_t>>(L(5, 3, 1).Slice<int8_t>(p)).data())); + EXPECT_EQ( + 24, + Distance(p, + Type<Span<const Int128>>(L(5, 3, 1).Slice<Int128>(p)).data())); + EXPECT_EQ( + 8, Distance( + p, Type<Span<const int32_t>>(L(5, 3, 1).Slice<int32_t>(p)).data())); + } +} + +TEST(Layout, MutableSliceByIndexData) { + alignas(max_align_t) unsigned char p[100]; + { + using L = Layout<int32_t>; + EXPECT_EQ(0, + Distance(p, Type<Span<int32_t>>(L::Partial(0).Slice<0>(p)).data())); + EXPECT_EQ(0, + Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<0>(p)).data())); + EXPECT_EQ(0, Distance(p, Type<Span<int32_t>>(L(3).Slice<0>(p)).data())); + } + { + using L = Layout<int32_t, int32_t>; + EXPECT_EQ(0, + Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<0>(p)).data())); + EXPECT_EQ( + 0, Distance(p, Type<Span<int32_t>>(L::Partial(3, 5).Slice<0>(p)).data())); + EXPECT_EQ( + 12, + Distance(p, Type<Span<int32_t>>(L::Partial(3, 5).Slice<1>(p)).data())); + EXPECT_EQ(0, Distance(p, Type<Span<int32_t>>(L(3, 5).Slice<0>(p)).data())); + EXPECT_EQ(12, Distance(p, Type<Span<int32_t>>(L(3, 5).Slice<1>(p)).data())); + } + { + using L = Layout<int8_t, int32_t, Int128>; + EXPECT_EQ(0, + Distance(p, Type<Span<int8_t>>(L::Partial(0).Slice<0>(p)).data())); + EXPECT_EQ(0, + Distance(p, Type<Span<int8_t>>(L::Partial(1).Slice<0>(p)).data())); + EXPECT_EQ(0, + Distance(p, Type<Span<int8_t>>(L::Partial(5).Slice<0>(p)).data())); + EXPECT_EQ( + 0, Distance(p, Type<Span<int8_t>>(L::Partial(0, 0).Slice<0>(p)).data())); + EXPECT_EQ( + 0, Distance(p, Type<Span<int32_t>>(L::Partial(0, 0).Slice<1>(p)).data())); + EXPECT_EQ( + 0, Distance(p, Type<Span<int8_t>>(L::Partial(1, 0).Slice<0>(p)).data())); + EXPECT_EQ( + 4, Distance(p, Type<Span<int32_t>>(L::Partial(1, 0).Slice<1>(p)).data())); + EXPECT_EQ( + 0, Distance(p, Type<Span<int8_t>>(L::Partial(5, 3).Slice<0>(p)).data())); + EXPECT_EQ( + 8, Distance(p, Type<Span<int32_t>>(L::Partial(5, 3).Slice<1>(p)).data())); + EXPECT_EQ( + 0, + Distance(p, Type<Span<int8_t>>(L::Partial(0, 0, 0).Slice<0>(p)).data())); + EXPECT_EQ( + 0, + Distance(p, Type<Span<int32_t>>(L::Partial(0, 0, 0).Slice<1>(p)).data())); + EXPECT_EQ( + 0, Distance( + p, Type<Span<Int128>>(L::Partial(0, 0, 0).Slice<2>(p)).data())); + EXPECT_EQ( + 0, + Distance(p, Type<Span<int8_t>>(L::Partial(1, 0, 0).Slice<0>(p)).data())); + EXPECT_EQ( + 4, + Distance(p, Type<Span<int32_t>>(L::Partial(1, 0, 0).Slice<1>(p)).data())); + EXPECT_EQ( + 8, Distance( + p, Type<Span<Int128>>(L::Partial(1, 0, 0).Slice<2>(p)).data())); + EXPECT_EQ( + 0, + Distance(p, Type<Span<int8_t>>(L::Partial(5, 3, 1).Slice<0>(p)).data())); + EXPECT_EQ( + 24, Distance( + p, Type<Span<Int128>>(L::Partial(5, 3, 1).Slice<2>(p)).data())); + EXPECT_EQ( + 8, + Distance(p, Type<Span<int32_t>>(L::Partial(5, 3, 1).Slice<1>(p)).data())); + EXPECT_EQ(0, Distance(p, Type<Span<int8_t>>(L(5, 3, 1).Slice<0>(p)).data())); + EXPECT_EQ(24, + Distance(p, Type<Span<Int128>>(L(5, 3, 1).Slice<2>(p)).data())); + EXPECT_EQ(8, Distance(p, Type<Span<int32_t>>(L(5, 3, 1).Slice<1>(p)).data())); + } +} + +TEST(Layout, MutableSliceByTypeData) { + alignas(max_align_t) unsigned char p[100]; + { + using L = Layout<int32_t>; + EXPECT_EQ( + 0, + Distance(p, Type<Span<int32_t>>(L::Partial(0).Slice<int32_t>(p)).data())); + EXPECT_EQ( + 0, + Distance(p, Type<Span<int32_t>>(L::Partial(3).Slice<int32_t>(p)).data())); + EXPECT_EQ(0, Distance(p, Type<Span<int32_t>>(L(3).Slice<int32_t>(p)).data())); + } + { + using L = Layout<int8_t, int32_t, Int128>; + EXPECT_EQ( + 0, Distance(p, Type<Span<int8_t>>(L::Partial(0).Slice<int8_t>(p)).data())); + EXPECT_EQ( + 0, Distance(p, Type<Span<int8_t>>(L::Partial(1).Slice<int8_t>(p)).data())); + EXPECT_EQ( + 0, Distance(p, Type<Span<int8_t>>(L::Partial(5).Slice<int8_t>(p)).data())); + EXPECT_EQ( + 0, + Distance(p, Type<Span<int8_t>>(L::Partial(0, 0).Slice<int8_t>(p)).data())); + EXPECT_EQ( + 0, Distance( + p, Type<Span<int32_t>>(L::Partial(0, 0).Slice<int32_t>(p)).data())); + EXPECT_EQ( + 0, + Distance(p, Type<Span<int8_t>>(L::Partial(1, 0).Slice<int8_t>(p)).data())); + EXPECT_EQ( + 4, Distance( + p, Type<Span<int32_t>>(L::Partial(1, 0).Slice<int32_t>(p)).data())); + EXPECT_EQ( + 0, + Distance(p, Type<Span<int8_t>>(L::Partial(5, 3).Slice<int8_t>(p)).data())); + EXPECT_EQ( + 8, Distance( + p, Type<Span<int32_t>>(L::Partial(5, 3).Slice<int32_t>(p)).data())); + EXPECT_EQ( + 0, Distance( + p, Type<Span<int8_t>>(L::Partial(0, 0, 0).Slice<int8_t>(p)).data())); + EXPECT_EQ( + 0, + Distance( + p, Type<Span<int32_t>>(L::Partial(0, 0, 0).Slice<int32_t>(p)).data())); + EXPECT_EQ( + 0, + Distance( + p, + Type<Span<Int128>>(L::Partial(0, 0, 0).Slice<Int128>(p)).data())); + EXPECT_EQ( + 0, Distance( + p, Type<Span<int8_t>>(L::Partial(1, 0, 0).Slice<int8_t>(p)).data())); + EXPECT_EQ( + 4, + Distance( + p, Type<Span<int32_t>>(L::Partial(1, 0, 0).Slice<int32_t>(p)).data())); + EXPECT_EQ( + 8, + Distance( + p, + Type<Span<Int128>>(L::Partial(1, 0, 0).Slice<Int128>(p)).data())); + EXPECT_EQ( + 0, Distance( + p, Type<Span<int8_t>>(L::Partial(5, 3, 1).Slice<int8_t>(p)).data())); + EXPECT_EQ( + 24, + Distance( + p, + Type<Span<Int128>>(L::Partial(5, 3, 1).Slice<Int128>(p)).data())); + EXPECT_EQ( + 8, + Distance( + p, Type<Span<int32_t>>(L::Partial(5, 3, 1).Slice<int32_t>(p)).data())); + EXPECT_EQ(0, + Distance(p, Type<Span<int8_t>>(L(5, 3, 1).Slice<int8_t>(p)).data())); + EXPECT_EQ( + 24, + Distance(p, Type<Span<Int128>>(L(5, 3, 1).Slice<Int128>(p)).data())); + EXPECT_EQ( + 8, Distance(p, Type<Span<int32_t>>(L(5, 3, 1).Slice<int32_t>(p)).data())); + } +} + +MATCHER_P(IsSameSlice, slice, "") { + return arg.size() == slice.size() && arg.data() == slice.data(); +} + +template <typename... M> +class TupleMatcher { + public: + explicit TupleMatcher(M... matchers) : matchers_(std::move(matchers)...) {} + + template <typename Tuple> + bool MatchAndExplain(const Tuple& p, + testing::MatchResultListener* /* listener */) const { + static_assert(std::tuple_size<Tuple>::value == sizeof...(M), ""); + return MatchAndExplainImpl( + p, absl::make_index_sequence<std::tuple_size<Tuple>::value>{}); + } + + // For the matcher concept. Left empty as we don't really need the diagnostics + // right now. + void DescribeTo(::std::ostream* os) const {} + void DescribeNegationTo(::std::ostream* os) const {} + + private: + template <typename Tuple, size_t... Is> + bool MatchAndExplainImpl(const Tuple& p, absl::index_sequence<Is...>) const { + // Using std::min as a simple variadic "and". + return std::min( + {true, testing::SafeMatcherCast< + const typename std::tuple_element<Is, Tuple>::type&>( + std::get<Is>(matchers_)) + .Matches(std::get<Is>(p))...}); + } + + std::tuple<M...> matchers_; +}; + +template <typename... M> +testing::PolymorphicMatcher<TupleMatcher<M...>> Tuple(M... matchers) { + return testing::MakePolymorphicMatcher( + TupleMatcher<M...>(std::move(matchers)...)); +} + +TEST(Layout, Slices) { + alignas(max_align_t) const unsigned char p[100] = {}; + using L = Layout<int8_t, int8_t, Int128>; + { + const auto x = L::Partial(); + EXPECT_THAT(Type<std::tuple<>>(x.Slices(p)), Tuple()); + } + { + const auto x = L::Partial(1); + EXPECT_THAT(Type<std::tuple<Span<const int8_t>>>(x.Slices(p)), + Tuple(IsSameSlice(x.Slice<0>(p)))); + } + { + const auto x = L::Partial(1, 2); + EXPECT_THAT( + (Type<std::tuple<Span<const int8_t>, Span<const int8_t>>>(x.Slices(p))), + Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)))); + } + { + const auto x = L::Partial(1, 2, 3); + EXPECT_THAT((Type<std::tuple<Span<const int8_t>, Span<const int8_t>, + Span<const Int128>>>(x.Slices(p))), + Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)), + IsSameSlice(x.Slice<2>(p)))); + } + { + const L x(1, 2, 3); + EXPECT_THAT((Type<std::tuple<Span<const int8_t>, Span<const int8_t>, + Span<const Int128>>>(x.Slices(p))), + Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)), + IsSameSlice(x.Slice<2>(p)))); + } +} + +TEST(Layout, MutableSlices) { + alignas(max_align_t) unsigned char p[100] = {}; + using L = Layout<int8_t, int8_t, Int128>; + { + const auto x = L::Partial(); + EXPECT_THAT(Type<std::tuple<>>(x.Slices(p)), Tuple()); + } + { + const auto x = L::Partial(1); + EXPECT_THAT(Type<std::tuple<Span<int8_t>>>(x.Slices(p)), + Tuple(IsSameSlice(x.Slice<0>(p)))); + } + { + const auto x = L::Partial(1, 2); + EXPECT_THAT((Type<std::tuple<Span<int8_t>, Span<int8_t>>>(x.Slices(p))), + Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)))); + } + { + const auto x = L::Partial(1, 2, 3); + EXPECT_THAT( + (Type<std::tuple<Span<int8_t>, Span<int8_t>, Span<Int128>>>(x.Slices(p))), + Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)), + IsSameSlice(x.Slice<2>(p)))); + } + { + const L x(1, 2, 3); + EXPECT_THAT( + (Type<std::tuple<Span<int8_t>, Span<int8_t>, Span<Int128>>>(x.Slices(p))), + Tuple(IsSameSlice(x.Slice<0>(p)), IsSameSlice(x.Slice<1>(p)), + IsSameSlice(x.Slice<2>(p)))); + } +} + +TEST(Layout, UnalignedTypes) { + constexpr Layout<unsigned char, unsigned char, unsigned char> x(1, 2, 3); + alignas(max_align_t) unsigned char p[x.AllocSize() + 1]; + EXPECT_THAT(x.Pointers(p + 1), Tuple(p + 1, p + 2, p + 4)); +} + +TEST(Layout, CustomAlignment) { + constexpr Layout<unsigned char, Aligned<unsigned char, 8>> x(1, 2); + alignas(max_align_t) unsigned char p[x.AllocSize()]; + EXPECT_EQ(10, x.AllocSize()); + EXPECT_THAT(x.Pointers(p), Tuple(p + 0, p + 8)); +} + +TEST(Layout, OverAligned) { + constexpr size_t M = alignof(max_align_t); + constexpr Layout<unsigned char, Aligned<unsigned char, 2 * M>> x(1, 3); + alignas(2 * M) unsigned char p[x.AllocSize()]; + EXPECT_EQ(2 * M + 3, x.AllocSize()); + EXPECT_THAT(x.Pointers(p), Tuple(p + 0, p + 2 * M)); +} + +TEST(Layout, Alignment) { + static_assert(Layout<int8_t>::Alignment() == 1, ""); + static_assert(Layout<int32_t>::Alignment() == 4, ""); + static_assert(Layout<int64_t>::Alignment() == 8, ""); + static_assert(Layout<Aligned<int8_t, 64>>::Alignment() == 64, ""); + static_assert(Layout<int8_t, int32_t, int64_t>::Alignment() == 8, ""); + static_assert(Layout<int8_t, int64_t, int32_t>::Alignment() == 8, ""); + static_assert(Layout<int32_t, int8_t, int64_t>::Alignment() == 8, ""); + static_assert(Layout<int32_t, int64_t, int8_t>::Alignment() == 8, ""); + static_assert(Layout<int64_t, int8_t, int32_t>::Alignment() == 8, ""); + static_assert(Layout<int64_t, int32_t, int8_t>::Alignment() == 8, ""); +} + +TEST(Layout, ConstexprPartial) { + constexpr size_t M = alignof(max_align_t); + constexpr Layout<unsigned char, Aligned<unsigned char, 2 * M>> x(1, 3); + static_assert(x.Partial(1).template Offset<1>() == 2 * M, ""); +} +// [from, to) +struct Region { + size_t from; + size_t to; +}; + +void ExpectRegionPoisoned(const unsigned char* p, size_t n, bool poisoned) { +#ifdef ADDRESS_SANITIZER + for (size_t i = 0; i != n; ++i) { + EXPECT_EQ(poisoned, __asan_address_is_poisoned(p + i)); + } +#endif +} + +template <size_t N> +void ExpectPoisoned(const unsigned char (&buf)[N], + std::initializer_list<Region> reg) { + size_t prev = 0; + for (const Region& r : reg) { + ExpectRegionPoisoned(buf + prev, r.from - prev, false); + ExpectRegionPoisoned(buf + r.from, r.to - r.from, true); + prev = r.to; + } + ExpectRegionPoisoned(buf + prev, N - prev, false); +} + +TEST(Layout, PoisonPadding) { + using L = Layout<int8_t, int64_t, int32_t, Int128>; + + constexpr size_t n = L::Partial(1, 2, 3, 4).AllocSize(); + { + constexpr auto x = L::Partial(); + alignas(max_align_t) const unsigned char c[n] = {}; + x.PoisonPadding(c); + EXPECT_EQ(x.Slices(c), x.Slices(c)); + ExpectPoisoned(c, {}); + } + { + constexpr auto x = L::Partial(1); + alignas(max_align_t) const unsigned char c[n] = {}; + x.PoisonPadding(c); + EXPECT_EQ(x.Slices(c), x.Slices(c)); + ExpectPoisoned(c, {{1, 8}}); + } + { + constexpr auto x = L::Partial(1, 2); + alignas(max_align_t) const unsigned char c[n] = {}; + x.PoisonPadding(c); + EXPECT_EQ(x.Slices(c), x.Slices(c)); + ExpectPoisoned(c, {{1, 8}}); + } + { + constexpr auto x = L::Partial(1, 2, 3); + alignas(max_align_t) const unsigned char c[n] = {}; + x.PoisonPadding(c); + EXPECT_EQ(x.Slices(c), x.Slices(c)); + ExpectPoisoned(c, {{1, 8}, {36, 40}}); + } + { + constexpr auto x = L::Partial(1, 2, 3, 4); + alignas(max_align_t) const unsigned char c[n] = {}; + x.PoisonPadding(c); + EXPECT_EQ(x.Slices(c), x.Slices(c)); + ExpectPoisoned(c, {{1, 8}, {36, 40}}); + } + { + constexpr L x(1, 2, 3, 4); + alignas(max_align_t) const unsigned char c[n] = {}; + x.PoisonPadding(c); + EXPECT_EQ(x.Slices(c), x.Slices(c)); + ExpectPoisoned(c, {{1, 8}, {36, 40}}); + } +} + +TEST(Layout, DebugString) { + const std::string int64_type = +#ifdef _MSC_VER + "__int64"; +#else // _MSC_VER + std::is_same<int64_t, long long>::value ? "long long" : "long"; // NOLINT +#endif // _MSC_VER + { + constexpr auto x = Layout<int8_t, int32_t, int8_t, Int128>::Partial(); + EXPECT_EQ("@0<signed char>(1)", x.DebugString()); + } + { + constexpr auto x = Layout<int8_t, int32_t, int8_t, Int128>::Partial(1); + EXPECT_EQ("@0<signed char>(1)[1]; @4<int>(4)", x.DebugString()); + } + { + constexpr auto x = Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2); + EXPECT_EQ("@0<signed char>(1)[1]; @4<int>(4)[2]; @12<signed char>(1)", + x.DebugString()); + } + { + constexpr auto x = Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2, 3); + EXPECT_EQ( + "@0<signed char>(1)[1]; @4<int>(4)[2]; @12<signed char>(1)[3]; " + "@16<" + + int64_type + " [2]>(16)", + x.DebugString()); + } + { + constexpr auto x = Layout<int8_t, int32_t, int8_t, Int128>::Partial(1, 2, 3, 4); + EXPECT_EQ( + "@0<signed char>(1)[1]; @4<int>(4)[2]; @12<signed char>(1)[3]; " + "@16<" + + int64_type + " [2]>(16)[4]", + x.DebugString()); + } + { + constexpr Layout<int8_t, int32_t, int8_t, Int128> x(1, 2, 3, 4); + EXPECT_EQ( + "@0<signed char>(1)[1]; @4<int>(4)[2]; @12<signed char>(1)[3]; " + "@16<" + + int64_type + " [2]>(16)[4]", + x.DebugString()); + } +} + +TEST(Layout, CharTypes) { + constexpr Layout<int32_t> x(1); + alignas(max_align_t) char c[x.AllocSize()] = {}; + alignas(max_align_t) unsigned char uc[x.AllocSize()] = {}; + alignas(max_align_t) signed char sc[x.AllocSize()] = {}; + alignas(max_align_t) const char cc[x.AllocSize()] = {}; + alignas(max_align_t) const unsigned char cuc[x.AllocSize()] = {}; + alignas(max_align_t) const signed char csc[x.AllocSize()] = {}; + + Type<int32_t*>(x.Pointer<0>(c)); + Type<int32_t*>(x.Pointer<0>(uc)); + Type<int32_t*>(x.Pointer<0>(sc)); + Type<const int32_t*>(x.Pointer<0>(cc)); + Type<const int32_t*>(x.Pointer<0>(cuc)); + Type<const int32_t*>(x.Pointer<0>(csc)); + + Type<int32_t*>(x.Pointer<int32_t>(c)); + Type<int32_t*>(x.Pointer<int32_t>(uc)); + Type<int32_t*>(x.Pointer<int32_t>(sc)); + Type<const int32_t*>(x.Pointer<int32_t>(cc)); + Type<const int32_t*>(x.Pointer<int32_t>(cuc)); + Type<const int32_t*>(x.Pointer<int32_t>(csc)); + + Type<std::tuple<int32_t*>>(x.Pointers(c)); + Type<std::tuple<int32_t*>>(x.Pointers(uc)); + Type<std::tuple<int32_t*>>(x.Pointers(sc)); + Type<std::tuple<const int32_t*>>(x.Pointers(cc)); + Type<std::tuple<const int32_t*>>(x.Pointers(cuc)); + Type<std::tuple<const int32_t*>>(x.Pointers(csc)); + + Type<Span<int32_t>>(x.Slice<0>(c)); + Type<Span<int32_t>>(x.Slice<0>(uc)); + Type<Span<int32_t>>(x.Slice<0>(sc)); + Type<Span<const int32_t>>(x.Slice<0>(cc)); + Type<Span<const int32_t>>(x.Slice<0>(cuc)); + Type<Span<const int32_t>>(x.Slice<0>(csc)); + + Type<std::tuple<Span<int32_t>>>(x.Slices(c)); + Type<std::tuple<Span<int32_t>>>(x.Slices(uc)); + Type<std::tuple<Span<int32_t>>>(x.Slices(sc)); + Type<std::tuple<Span<const int32_t>>>(x.Slices(cc)); + Type<std::tuple<Span<const int32_t>>>(x.Slices(cuc)); + Type<std::tuple<Span<const int32_t>>>(x.Slices(csc)); +} + +TEST(Layout, ConstElementType) { + constexpr Layout<const int32_t> x(1); + alignas(int32_t) char c[x.AllocSize()] = {}; + const char* cc = c; + const int32_t* p = reinterpret_cast<const int32_t*>(cc); + + EXPECT_EQ(alignof(int32_t), x.Alignment()); + + EXPECT_EQ(0, x.Offset<0>()); + EXPECT_EQ(0, x.Offset<const int32_t>()); + + EXPECT_THAT(x.Offsets(), ElementsAre(0)); + + EXPECT_EQ(1, x.Size<0>()); + EXPECT_EQ(1, x.Size<const int32_t>()); + + EXPECT_THAT(x.Sizes(), ElementsAre(1)); + + EXPECT_EQ(sizeof(int32_t), x.AllocSize()); + + EXPECT_EQ(p, Type<const int32_t*>(x.Pointer<0>(c))); + EXPECT_EQ(p, Type<const int32_t*>(x.Pointer<0>(cc))); + + EXPECT_EQ(p, Type<const int32_t*>(x.Pointer<const int32_t>(c))); + EXPECT_EQ(p, Type<const int32_t*>(x.Pointer<const int32_t>(cc))); + + EXPECT_THAT(Type<std::tuple<const int32_t*>>(x.Pointers(c)), Tuple(p)); + EXPECT_THAT(Type<std::tuple<const int32_t*>>(x.Pointers(cc)), Tuple(p)); + + EXPECT_THAT(Type<Span<const int32_t>>(x.Slice<0>(c)), + IsSameSlice(Span<const int32_t>(p, 1))); + EXPECT_THAT(Type<Span<const int32_t>>(x.Slice<0>(cc)), + IsSameSlice(Span<const int32_t>(p, 1))); + + EXPECT_THAT(Type<Span<const int32_t>>(x.Slice<const int32_t>(c)), + IsSameSlice(Span<const int32_t>(p, 1))); + EXPECT_THAT(Type<Span<const int32_t>>(x.Slice<const int32_t>(cc)), + IsSameSlice(Span<const int32_t>(p, 1))); + + EXPECT_THAT(Type<std::tuple<Span<const int32_t>>>(x.Slices(c)), + Tuple(IsSameSlice(Span<const int32_t>(p, 1)))); + EXPECT_THAT(Type<std::tuple<Span<const int32_t>>>(x.Slices(cc)), + Tuple(IsSameSlice(Span<const int32_t>(p, 1)))); +} + +namespace example { + +// Immutable move-only string with sizeof equal to sizeof(void*). The string +// size and the characters are kept in the same heap allocation. +class CompactString { + public: + CompactString(const char* s = "") { // NOLINT + const size_t size = strlen(s); + // size_t[1], followed by char[size + 1]. + // This statement doesn't allocate memory. + const L layout(1, size + 1); + // AllocSize() tells us how much memory we need to allocate for all our + // data. + p_.reset(new unsigned char[layout.AllocSize()]); + // If running under ASAN, mark the padding bytes, if any, to catch memory + // errors. + layout.PoisonPadding(p_.get()); + // Store the size in the allocation. + // Pointer<size_t>() is a synonym for Pointer<0>(). + *layout.Pointer<size_t>(p_.get()) = size; + // Store the characters in the allocation. + memcpy(layout.Pointer<char>(p_.get()), s, size + 1); + } + + size_t size() const { + // Equivalent to reinterpret_cast<size_t&>(*p). + return *L::Partial().Pointer<size_t>(p_.get()); + } + + const char* c_str() const { + // Equivalent to reinterpret_cast<char*>(p.get() + sizeof(size_t)). + // The argument in Partial(1) specifies that we have size_t[1] in front of + // the + // characters. + return L::Partial(1).Pointer<char>(p_.get()); + } + + private: + // Our heap allocation contains a size_t followed by an array of chars. + using L = Layout<size_t, char>; + std::unique_ptr<unsigned char[]> p_; +}; + +TEST(CompactString, Works) { + CompactString s = "hello"; + EXPECT_EQ(5, s.size()); + EXPECT_STREQ("hello", s.c_str()); +} + +} // namespace example + +} // namespace +} // namespace container_internal +} // namespace absl |