Abseil Common Libraries (C++) (grcp 依赖)
https://abseil.io/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1565 lines
58 KiB
1565 lines
58 KiB
// 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; |
|
} |
|
|
|
// Helper classes to test different size and alignments. |
|
struct alignas(8) Int128 { |
|
uint64_t a, b; |
|
friend bool operator==(Int128 lhs, Int128 rhs) { |
|
return std::tie(lhs.a, lhs.b) == std::tie(rhs.a, rhs.b); |
|
} |
|
|
|
static std::string Name() { |
|
return internal_layout::adl_barrier::TypeName<Int128>(); |
|
} |
|
}; |
|
|
|
// int64_t is *not* 8-byte aligned on all platforms! |
|
struct alignas(8) Int64 { |
|
int64_t a; |
|
friend bool operator==(Int64 lhs, Int64 rhs) { |
|
return lhs.a == rhs.a; |
|
} |
|
}; |
|
|
|
// 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(Int64) == 8, ""); |
|
static_assert(alignof(Int64) == 8, ""); |
|
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>::Alignment() == 8, ""); |
|
static_assert(Layout<Aligned<int8_t, 64>>::Alignment() == 64, ""); |
|
static_assert(Layout<int8_t, int32_t, Int64>::Alignment() == 8, ""); |
|
static_assert(Layout<int8_t, Int64, int32_t>::Alignment() == 8, ""); |
|
static_assert(Layout<int32_t, int8_t, Int64>::Alignment() == 8, ""); |
|
static_assert(Layout<int32_t, Int64, int8_t>::Alignment() == 8, ""); |
|
static_assert(Layout<Int64, int8_t, int32_t>::Alignment() == 8, ""); |
|
static_assert(Layout<Int64, 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, 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) { |
|
{ |
|
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" + |
|
Int128::Name() + "(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" + |
|
Int128::Name() + "(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" + |
|
Int128::Name() + "(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
|
|
|