SPIRV-Tools/test/enum_set_test.cpp
Nathan Gauër 17d9669d51
enumset: add iterator based constructor/insert (#5344)
Expanding a bit the EnumSet API to have iterator-based
insert and constructors (like the STL).
This is also a pre-requisite from the capability-trimming pass as
it allows to build a const set from a constexpr std::array easily.

Signed-off-by: Nathan Gauër <brioche@google.com>
2023-07-20 17:54:50 +00:00

902 lines
29 KiB
C++

// Copyright (c) 2016 Google Inc.
//
// 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 "source/enum_set.h"
#include <algorithm>
#include <array>
#include <random>
#include <utility>
#include <vector>
#include "gmock/gmock.h"
#include "test/unit_spirv.h"
namespace spvtools {
namespace {
using spvtest::ElementsIn;
using ::testing::Eq;
using ::testing::Values;
using ::testing::ValuesIn;
enum class TestEnum : uint32_t {
ZERO = 0,
ONE = 1,
TWO = 2,
THREE = 3,
FOUR = 4,
FIVE = 5,
EIGHT = 8,
TWENTY = 20,
TWENTY_FOUR = 24,
THIRTY = 30,
ONE_HUNDRED = 100,
ONE_HUNDRED_FIFTY = 150,
TWO_HUNDRED = 200,
THREE_HUNDRED = 300,
FOUR_HUNDRED = 400,
FIVE_HUNDRED = 500,
SIX_HUNDRED = 600,
};
constexpr std::array kCapabilities{
spv::Capability::Matrix,
spv::Capability::Shader,
spv::Capability::Geometry,
spv::Capability::Tessellation,
spv::Capability::Addresses,
spv::Capability::Linkage,
spv::Capability::Kernel,
spv::Capability::Vector16,
spv::Capability::Float16Buffer,
spv::Capability::Float16,
spv::Capability::Float64,
spv::Capability::Int64,
spv::Capability::Int64Atomics,
spv::Capability::ImageBasic,
spv::Capability::ImageReadWrite,
spv::Capability::ImageMipmap,
spv::Capability::Pipes,
spv::Capability::Groups,
spv::Capability::DeviceEnqueue,
spv::Capability::LiteralSampler,
spv::Capability::AtomicStorage,
spv::Capability::Int16,
spv::Capability::TessellationPointSize,
spv::Capability::GeometryPointSize,
spv::Capability::ImageGatherExtended,
spv::Capability::StorageImageMultisample,
spv::Capability::UniformBufferArrayDynamicIndexing,
spv::Capability::SampledImageArrayDynamicIndexing,
spv::Capability::StorageBufferArrayDynamicIndexing,
spv::Capability::StorageImageArrayDynamicIndexing,
spv::Capability::ClipDistance,
spv::Capability::CullDistance,
spv::Capability::ImageCubeArray,
spv::Capability::SampleRateShading,
spv::Capability::ImageRect,
spv::Capability::SampledRect,
spv::Capability::GenericPointer,
spv::Capability::Int8,
spv::Capability::InputAttachment,
spv::Capability::SparseResidency,
spv::Capability::MinLod,
spv::Capability::Sampled1D,
spv::Capability::Image1D,
spv::Capability::SampledCubeArray,
spv::Capability::SampledBuffer,
spv::Capability::ImageBuffer,
spv::Capability::ImageMSArray,
spv::Capability::StorageImageExtendedFormats,
spv::Capability::ImageQuery,
spv::Capability::DerivativeControl,
spv::Capability::InterpolationFunction,
spv::Capability::TransformFeedback,
spv::Capability::GeometryStreams,
spv::Capability::StorageImageReadWithoutFormat,
spv::Capability::StorageImageWriteWithoutFormat,
spv::Capability::MultiViewport,
spv::Capability::SubgroupDispatch,
spv::Capability::NamedBarrier,
spv::Capability::PipeStorage,
spv::Capability::GroupNonUniform,
spv::Capability::GroupNonUniformVote,
spv::Capability::GroupNonUniformArithmetic,
spv::Capability::GroupNonUniformBallot,
spv::Capability::GroupNonUniformShuffle,
spv::Capability::GroupNonUniformShuffleRelative,
spv::Capability::GroupNonUniformClustered,
spv::Capability::GroupNonUniformQuad,
spv::Capability::ShaderLayer,
spv::Capability::ShaderViewportIndex,
spv::Capability::UniformDecoration,
spv::Capability::CoreBuiltinsARM,
spv::Capability::FragmentShadingRateKHR,
spv::Capability::SubgroupBallotKHR,
spv::Capability::DrawParameters,
spv::Capability::WorkgroupMemoryExplicitLayoutKHR,
spv::Capability::WorkgroupMemoryExplicitLayout8BitAccessKHR,
spv::Capability::WorkgroupMemoryExplicitLayout16BitAccessKHR,
spv::Capability::SubgroupVoteKHR,
spv::Capability::StorageBuffer16BitAccess,
spv::Capability::StorageUniformBufferBlock16,
spv::Capability::StorageUniform16,
spv::Capability::UniformAndStorageBuffer16BitAccess,
spv::Capability::StoragePushConstant16,
spv::Capability::StorageInputOutput16,
spv::Capability::DeviceGroup,
spv::Capability::MultiView,
spv::Capability::VariablePointersStorageBuffer,
spv::Capability::VariablePointers,
spv::Capability::AtomicStorageOps,
spv::Capability::SampleMaskPostDepthCoverage,
spv::Capability::StorageBuffer8BitAccess,
spv::Capability::UniformAndStorageBuffer8BitAccess,
spv::Capability::StoragePushConstant8,
spv::Capability::DenormPreserve,
spv::Capability::DenormFlushToZero,
spv::Capability::SignedZeroInfNanPreserve,
spv::Capability::RoundingModeRTE,
spv::Capability::RoundingModeRTZ,
spv::Capability::RayQueryProvisionalKHR,
spv::Capability::RayQueryKHR,
spv::Capability::RayTraversalPrimitiveCullingKHR,
spv::Capability::RayTracingKHR,
spv::Capability::Float16ImageAMD,
spv::Capability::ImageGatherBiasLodAMD,
spv::Capability::FragmentMaskAMD,
spv::Capability::StencilExportEXT,
spv::Capability::ImageReadWriteLodAMD,
spv::Capability::Int64ImageEXT,
spv::Capability::ShaderClockKHR,
spv::Capability::SampleMaskOverrideCoverageNV,
spv::Capability::GeometryShaderPassthroughNV,
spv::Capability::ShaderViewportIndexLayerEXT,
spv::Capability::ShaderViewportIndexLayerNV,
spv::Capability::ShaderViewportMaskNV,
spv::Capability::ShaderStereoViewNV,
spv::Capability::PerViewAttributesNV,
spv::Capability::FragmentFullyCoveredEXT,
spv::Capability::MeshShadingNV,
spv::Capability::ImageFootprintNV,
spv::Capability::MeshShadingEXT,
spv::Capability::FragmentBarycentricKHR,
spv::Capability::FragmentBarycentricNV,
spv::Capability::ComputeDerivativeGroupQuadsNV,
spv::Capability::FragmentDensityEXT,
spv::Capability::ShadingRateNV,
spv::Capability::GroupNonUniformPartitionedNV,
spv::Capability::ShaderNonUniform,
spv::Capability::ShaderNonUniformEXT,
spv::Capability::RuntimeDescriptorArray,
spv::Capability::RuntimeDescriptorArrayEXT,
spv::Capability::InputAttachmentArrayDynamicIndexing,
spv::Capability::InputAttachmentArrayDynamicIndexingEXT,
spv::Capability::UniformTexelBufferArrayDynamicIndexing,
spv::Capability::UniformTexelBufferArrayDynamicIndexingEXT,
spv::Capability::StorageTexelBufferArrayDynamicIndexing,
spv::Capability::StorageTexelBufferArrayDynamicIndexingEXT,
spv::Capability::UniformBufferArrayNonUniformIndexing,
spv::Capability::UniformBufferArrayNonUniformIndexingEXT,
spv::Capability::SampledImageArrayNonUniformIndexing,
spv::Capability::SampledImageArrayNonUniformIndexingEXT,
spv::Capability::StorageBufferArrayNonUniformIndexing,
spv::Capability::StorageBufferArrayNonUniformIndexingEXT,
spv::Capability::StorageImageArrayNonUniformIndexing,
spv::Capability::StorageImageArrayNonUniformIndexingEXT,
spv::Capability::InputAttachmentArrayNonUniformIndexing,
spv::Capability::InputAttachmentArrayNonUniformIndexingEXT,
spv::Capability::UniformTexelBufferArrayNonUniformIndexing,
spv::Capability::UniformTexelBufferArrayNonUniformIndexingEXT,
spv::Capability::StorageTexelBufferArrayNonUniformIndexing,
spv::Capability::StorageTexelBufferArrayNonUniformIndexingEXT,
spv::Capability::RayTracingNV,
spv::Capability::RayTracingMotionBlurNV,
spv::Capability::VulkanMemoryModel,
spv::Capability::VulkanMemoryModelKHR,
spv::Capability::VulkanMemoryModelDeviceScope,
spv::Capability::VulkanMemoryModelDeviceScopeKHR,
spv::Capability::PhysicalStorageBufferAddresses,
spv::Capability::PhysicalStorageBufferAddressesEXT,
spv::Capability::ComputeDerivativeGroupLinearNV,
spv::Capability::RayTracingProvisionalKHR,
spv::Capability::CooperativeMatrixNV,
spv::Capability::FragmentShaderSampleInterlockEXT,
spv::Capability::FragmentShaderShadingRateInterlockEXT,
spv::Capability::ShaderSMBuiltinsNV,
spv::Capability::FragmentShaderPixelInterlockEXT,
spv::Capability::DemoteToHelperInvocation,
spv::Capability::DemoteToHelperInvocationEXT,
spv::Capability::RayTracingOpacityMicromapEXT,
spv::Capability::ShaderInvocationReorderNV,
spv::Capability::BindlessTextureNV,
spv::Capability::SubgroupShuffleINTEL,
spv::Capability::SubgroupBufferBlockIOINTEL,
spv::Capability::SubgroupImageBlockIOINTEL,
spv::Capability::SubgroupImageMediaBlockIOINTEL,
spv::Capability::RoundToInfinityINTEL,
spv::Capability::FloatingPointModeINTEL,
spv::Capability::IntegerFunctions2INTEL,
spv::Capability::FunctionPointersINTEL,
spv::Capability::IndirectReferencesINTEL,
spv::Capability::AsmINTEL,
spv::Capability::AtomicFloat32MinMaxEXT,
spv::Capability::AtomicFloat64MinMaxEXT,
spv::Capability::AtomicFloat16MinMaxEXT,
spv::Capability::VectorComputeINTEL,
spv::Capability::VectorAnyINTEL,
spv::Capability::ExpectAssumeKHR,
spv::Capability::SubgroupAvcMotionEstimationINTEL,
spv::Capability::SubgroupAvcMotionEstimationIntraINTEL,
spv::Capability::SubgroupAvcMotionEstimationChromaINTEL,
spv::Capability::VariableLengthArrayINTEL,
spv::Capability::FunctionFloatControlINTEL,
spv::Capability::FPGAMemoryAttributesINTEL,
spv::Capability::FPFastMathModeINTEL,
spv::Capability::ArbitraryPrecisionIntegersINTEL,
spv::Capability::ArbitraryPrecisionFloatingPointINTEL,
spv::Capability::UnstructuredLoopControlsINTEL,
spv::Capability::FPGALoopControlsINTEL,
spv::Capability::KernelAttributesINTEL,
spv::Capability::FPGAKernelAttributesINTEL,
spv::Capability::FPGAMemoryAccessesINTEL,
spv::Capability::FPGAClusterAttributesINTEL,
spv::Capability::LoopFuseINTEL,
spv::Capability::FPGADSPControlINTEL,
spv::Capability::MemoryAccessAliasingINTEL,
spv::Capability::FPGAInvocationPipeliningAttributesINTEL,
spv::Capability::FPGABufferLocationINTEL,
spv::Capability::ArbitraryPrecisionFixedPointINTEL,
spv::Capability::USMStorageClassesINTEL,
spv::Capability::RuntimeAlignedAttributeINTEL,
spv::Capability::IOPipesINTEL,
spv::Capability::BlockingPipesINTEL,
spv::Capability::FPGARegINTEL,
spv::Capability::DotProductInputAll,
spv::Capability::DotProductInputAllKHR,
spv::Capability::DotProductInput4x8Bit,
spv::Capability::DotProductInput4x8BitKHR,
spv::Capability::DotProductInput4x8BitPacked,
spv::Capability::DotProductInput4x8BitPackedKHR,
spv::Capability::DotProduct,
spv::Capability::DotProductKHR,
spv::Capability::RayCullMaskKHR,
spv::Capability::BitInstructions,
spv::Capability::GroupNonUniformRotateKHR,
spv::Capability::AtomicFloat32AddEXT,
spv::Capability::AtomicFloat64AddEXT,
spv::Capability::LongConstantCompositeINTEL,
spv::Capability::OptNoneINTEL,
spv::Capability::AtomicFloat16AddEXT,
spv::Capability::DebugInfoModuleINTEL,
spv::Capability::SplitBarrierINTEL,
spv::Capability::GroupUniformArithmeticKHR,
spv::Capability::Max,
};
namespace {
std::vector<TestEnum> enumerateValuesFromToWithStep(size_t start, size_t end,
size_t step) {
assert(end > start && "end > start");
std::vector<TestEnum> orderedValues;
for (size_t i = start; i < end; i += step) {
orderedValues.push_back(static_cast<TestEnum>(i));
}
return orderedValues;
}
EnumSet<TestEnum> createSetUnorderedInsertion(
const std::vector<TestEnum>& values) {
std::vector shuffledValues(values.cbegin(), values.cend());
std::mt19937 rng(0);
std::shuffle(shuffledValues.begin(), shuffledValues.end(), rng);
EnumSet<TestEnum> set;
for (auto value : shuffledValues) {
set.insert(value);
}
return set;
}
} // namespace
TEST(EnumSet, IsEmpty1) {
EnumSet<TestEnum> set;
EXPECT_TRUE(set.empty());
set.insert(TestEnum::ZERO);
EXPECT_FALSE(set.empty());
}
TEST(EnumSet, IsEmpty2) {
EnumSet<TestEnum> set;
EXPECT_TRUE(set.empty());
set.insert(TestEnum::ONE_HUNDRED_FIFTY);
EXPECT_FALSE(set.empty());
}
TEST(EnumSet, IsEmpty3) {
EnumSet<TestEnum> set(TestEnum::FOUR);
EXPECT_FALSE(set.empty());
}
TEST(EnumSet, IsEmpty4) {
EnumSet<TestEnum> set(TestEnum::THREE_HUNDRED);
EXPECT_FALSE(set.empty());
}
TEST(EnumSetHasAnyOf, EmptySetEmptyQuery) {
const EnumSet<TestEnum> set;
const EnumSet<TestEnum> empty;
EXPECT_TRUE(set.HasAnyOf(empty));
EXPECT_TRUE(EnumSet<TestEnum>().HasAnyOf(EnumSet<TestEnum>()));
}
TEST(EnumSetHasAnyOf, MaskSetEmptyQuery) {
EnumSet<TestEnum> set;
const EnumSet<TestEnum> empty;
set.insert(TestEnum::FIVE);
set.insert(TestEnum::EIGHT);
EXPECT_TRUE(set.HasAnyOf(empty));
}
TEST(EnumSetHasAnyOf, OverflowSetEmptyQuery) {
EnumSet<TestEnum> set;
const EnumSet<TestEnum> empty;
set.insert(TestEnum::TWO_HUNDRED);
set.insert(TestEnum::THREE_HUNDRED);
EXPECT_TRUE(set.HasAnyOf(empty));
}
TEST(EnumSetHasAnyOf, EmptyQuery) {
EnumSet<TestEnum> set;
const EnumSet<TestEnum> empty;
set.insert(TestEnum::FIVE);
set.insert(TestEnum::EIGHT);
set.insert(TestEnum::TWO_HUNDRED);
set.insert(TestEnum::THREE_HUNDRED);
EXPECT_TRUE(set.HasAnyOf(empty));
}
TEST(EnumSetHasAnyOf, EmptyQueryAlwaysTrue) {
EnumSet<TestEnum> set;
const EnumSet<TestEnum> empty;
EXPECT_TRUE(set.HasAnyOf(empty));
set.insert(TestEnum::FIVE);
EXPECT_TRUE(set.HasAnyOf(empty));
EXPECT_TRUE(
EnumSet<TestEnum>(TestEnum::ONE_HUNDRED).HasAnyOf(EnumSet<TestEnum>()));
}
TEST(EnumSetHasAnyOf, ReflexiveMask) {
EnumSet<TestEnum> set(TestEnum::THREE);
set.insert(TestEnum::TWENTY_FOUR);
set.insert(TestEnum::THIRTY);
EXPECT_TRUE(set.HasAnyOf(set));
}
TEST(EnumSetHasAnyOf, ReflexiveOverflow) {
EnumSet<TestEnum> set(TestEnum::TWO_HUNDRED);
set.insert(TestEnum::TWO_HUNDRED);
set.insert(TestEnum::FOUR_HUNDRED);
EXPECT_TRUE(set.HasAnyOf(set));
}
TEST(EnumSetHasAnyOf, Reflexive) {
EnumSet<TestEnum> set(TestEnum::THREE);
set.insert(TestEnum::TWENTY_FOUR);
set.insert(TestEnum::THREE_HUNDRED);
set.insert(TestEnum::FOUR_HUNDRED);
EXPECT_TRUE(set.HasAnyOf(set));
}
TEST(EnumSetHasAnyOf, EmptySetHasNone) {
EnumSet<TestEnum> set;
EnumSet<TestEnum> items;
for (uint32_t i = 0; i < 200; ++i) {
TestEnum enumValue = static_cast<TestEnum>(i);
items.insert(enumValue);
EXPECT_FALSE(set.HasAnyOf(items));
EXPECT_FALSE(set.HasAnyOf(EnumSet<TestEnum>(enumValue)));
}
}
TEST(EnumSetHasAnyOf, MaskSetMaskQuery) {
EnumSet<TestEnum> set(TestEnum::ZERO);
EnumSet<TestEnum> items(TestEnum::ONE);
EXPECT_FALSE(set.HasAnyOf(items));
set.insert(TestEnum::TWO);
items.insert(TestEnum::THREE);
EXPECT_FALSE(set.HasAnyOf(items));
set.insert(TestEnum::THREE);
EXPECT_TRUE(set.HasAnyOf(items));
set.insert(TestEnum::FOUR);
EXPECT_TRUE(set.HasAnyOf(items));
}
TEST(EnumSetHasAnyOf, OverflowSetOverflowQuery) {
EnumSet<TestEnum> set(TestEnum::ONE_HUNDRED);
EnumSet<TestEnum> items(TestEnum::TWO_HUNDRED);
EXPECT_FALSE(set.HasAnyOf(items));
set.insert(TestEnum::THREE_HUNDRED);
items.insert(TestEnum::FOUR_HUNDRED);
EXPECT_FALSE(set.HasAnyOf(items));
set.insert(TestEnum::TWO_HUNDRED);
EXPECT_TRUE(set.HasAnyOf(items));
set.insert(TestEnum::FIVE_HUNDRED);
EXPECT_TRUE(set.HasAnyOf(items));
}
TEST(EnumSetHasAnyOf, GeneralCase) {
EnumSet<TestEnum> set(TestEnum::ZERO);
EnumSet<TestEnum> items(TestEnum::ONE_HUNDRED);
EXPECT_FALSE(set.HasAnyOf(items));
set.insert(TestEnum::THREE_HUNDRED);
items.insert(TestEnum::FOUR);
EXPECT_FALSE(set.HasAnyOf(items));
set.insert(TestEnum::FIVE);
items.insert(TestEnum::FIVE_HUNDRED);
EXPECT_FALSE(set.HasAnyOf(items));
set.insert(TestEnum::FIVE_HUNDRED);
EXPECT_TRUE(set.HasAnyOf(items));
EXPECT_FALSE(set.HasAnyOf(EnumSet<TestEnum>(TestEnum::TWENTY)));
EXPECT_FALSE(set.HasAnyOf(EnumSet<TestEnum>(TestEnum::SIX_HUNDRED)));
EXPECT_TRUE(set.HasAnyOf(EnumSet<TestEnum>(TestEnum::FIVE)));
EXPECT_TRUE(set.HasAnyOf(EnumSet<TestEnum>(TestEnum::THREE_HUNDRED)));
EXPECT_TRUE(set.HasAnyOf(EnumSet<TestEnum>(TestEnum::ZERO)));
}
TEST(EnumSet, DefaultIsEmpty) {
EnumSet<TestEnum> set;
for (uint32_t i = 0; i < 1000; ++i) {
EXPECT_FALSE(set.contains(static_cast<TestEnum>(i)));
}
}
TEST(EnumSet, EqualityCompareEmpty) {
EnumSet<TestEnum> set1;
EnumSet<TestEnum> set2;
EXPECT_TRUE(set1 == set2);
EXPECT_FALSE(set1 != set2);
}
TEST(EnumSet, EqualityCompareSame) {
EnumSet<TestEnum> set1;
EnumSet<TestEnum> set2;
set1.insert(TestEnum::ONE);
set1.insert(TestEnum::TWENTY);
set2.insert(TestEnum::TWENTY);
set2.insert(TestEnum::ONE);
EXPECT_TRUE(set1 == set2);
EXPECT_FALSE(set1 != set2);
}
TEST(EnumSet, EqualityCompareDifferent) {
EnumSet<TestEnum> set1;
EnumSet<TestEnum> set2;
set1.insert(TestEnum::ONE);
set1.insert(TestEnum::TWENTY);
set2.insert(TestEnum::FIVE);
set2.insert(TestEnum::ONE);
EXPECT_FALSE(set1 == set2);
EXPECT_TRUE(set1 != set2);
}
TEST(EnumSet, ConstructFromIterators) {
auto orderedValues = enumerateValuesFromToWithStep(0, 2, /* step= */ 1);
EnumSet<TestEnum> set1 = createSetUnorderedInsertion(orderedValues);
EnumSet<TestEnum> set2(orderedValues.cbegin(), orderedValues.cend());
EXPECT_EQ(set1, set2);
}
TEST(EnumSet, InsertUsingIteratorRange) {
auto orderedValues = enumerateValuesFromToWithStep(0, 2, /* step= */ 1);
EnumSet<TestEnum> set1 = createSetUnorderedInsertion(orderedValues);
EnumSet<TestEnum> set2;
set2.insert(orderedValues.cbegin(), orderedValues.cend());
EXPECT_EQ(set1, set2);
}
TEST(CapabilitySet, RangeBasedLoopOrderIsEnumOrder) {
auto orderedValues = enumerateValuesFromToWithStep(0, 2, /* step= */ 1);
auto set = createSetUnorderedInsertion(orderedValues);
size_t index = 0;
for (auto value : set) {
ASSERT_THAT(value, Eq(orderedValues[index]));
index++;
}
}
TEST(CapabilitySet, ConstructSingleMemberMatrix) {
CapabilitySet s(spv::Capability::Matrix);
EXPECT_TRUE(s.contains(spv::Capability::Matrix));
EXPECT_FALSE(s.contains(spv::Capability::Shader));
EXPECT_FALSE(s.contains(static_cast<spv::Capability>(1000)));
}
TEST(CapabilitySet, ConstructSingleMemberMaxInMask) {
CapabilitySet s(static_cast<spv::Capability>(63));
EXPECT_FALSE(s.contains(spv::Capability::Matrix));
EXPECT_FALSE(s.contains(spv::Capability::Shader));
EXPECT_TRUE(s.contains(static_cast<spv::Capability>(63)));
EXPECT_FALSE(s.contains(static_cast<spv::Capability>(64)));
EXPECT_FALSE(s.contains(static_cast<spv::Capability>(1000)));
}
TEST(CapabilitySet, ConstructSingleMemberMinOverflow) {
// Check the first one that forces overflow beyond the mask.
CapabilitySet s(static_cast<spv::Capability>(64));
EXPECT_FALSE(s.contains(spv::Capability::Matrix));
EXPECT_FALSE(s.contains(spv::Capability::Shader));
EXPECT_FALSE(s.contains(static_cast<spv::Capability>(63)));
EXPECT_TRUE(s.contains(static_cast<spv::Capability>(64)));
EXPECT_FALSE(s.contains(static_cast<spv::Capability>(1000)));
}
TEST(CapabilitySet, ConstructSingleMemberMaxOverflow) {
// Check the max 32-bit signed int.
CapabilitySet s(static_cast<spv::Capability>(0x7fffffffu));
EXPECT_FALSE(s.contains(spv::Capability::Matrix));
EXPECT_FALSE(s.contains(spv::Capability::Shader));
EXPECT_FALSE(s.contains(static_cast<spv::Capability>(1000)));
EXPECT_TRUE(s.contains(static_cast<spv::Capability>(0x7fffffffu)));
}
TEST(CapabilitySet, AddEnum) {
CapabilitySet s(spv::Capability::Shader);
s.insert(spv::Capability::Kernel);
s.insert(static_cast<spv::Capability>(42));
EXPECT_FALSE(s.contains(spv::Capability::Matrix));
EXPECT_TRUE(s.contains(spv::Capability::Shader));
EXPECT_TRUE(s.contains(spv::Capability::Kernel));
EXPECT_TRUE(s.contains(static_cast<spv::Capability>(42)));
}
TEST(CapabilitySet, InsertReturnsIteratorToInserted) {
CapabilitySet set;
auto[it, inserted] = set.insert(spv::Capability::Kernel);
EXPECT_TRUE(inserted);
EXPECT_EQ(*it, spv::Capability::Kernel);
}
TEST(CapabilitySet, InsertReturnsIteratorToElementOnDoubleInsertion) {
CapabilitySet set;
EXPECT_FALSE(set.contains(spv::Capability::Shader));
{
auto[it, inserted] = set.insert(spv::Capability::Shader);
EXPECT_TRUE(inserted);
EXPECT_EQ(*it, spv::Capability::Shader);
}
EXPECT_TRUE(set.contains(spv::Capability::Shader));
auto[it, inserted] = set.insert(spv::Capability::Shader);
EXPECT_FALSE(inserted);
EXPECT_EQ(*it, spv::Capability::Shader);
EXPECT_TRUE(set.contains(spv::Capability::Shader));
}
TEST(CapabilitySet, InsertWithHintWorks) {
CapabilitySet set;
EXPECT_FALSE(set.contains(spv::Capability::Shader));
auto it = set.insert(set.begin(), spv::Capability::Shader);
EXPECT_EQ(*it, spv::Capability::Shader);
EXPECT_TRUE(set.contains(spv::Capability::Shader));
}
TEST(CapabilitySet, InsertWithEndHintWorks) {
CapabilitySet set;
EXPECT_FALSE(set.contains(spv::Capability::Shader));
auto it = set.insert(set.end(), spv::Capability::Shader);
EXPECT_EQ(*it, spv::Capability::Shader);
EXPECT_TRUE(set.contains(spv::Capability::Shader));
}
TEST(CapabilitySet, IteratorCanBeCopied) {
CapabilitySet set;
set.insert(spv::Capability::Matrix);
set.insert(spv::Capability::Shader);
set.insert(spv::Capability::Geometry);
set.insert(spv::Capability::Float64);
set.insert(spv::Capability::Float16);
auto a = set.begin();
++a;
auto b = a;
EXPECT_EQ(*b, *a);
++b;
EXPECT_NE(*b, *a);
++a;
EXPECT_EQ(*b, *a);
++a;
EXPECT_NE(*b, *a);
}
TEST(CapabilitySet, IteratorBeginToEndPostfix) {
auto orderedValues = enumerateValuesFromToWithStep(0, 100, /* step= */ 1);
auto set = createSetUnorderedInsertion(orderedValues);
size_t index = 0;
for (auto it = set.cbegin(); it != set.cend(); it++, index++) {
EXPECT_EQ(*it, orderedValues[index]);
}
}
TEST(CapabilitySet, IteratorBeginToEndPrefix) {
auto orderedValues = enumerateValuesFromToWithStep(0, 100, /* step= */ 1);
auto set = createSetUnorderedInsertion(orderedValues);
size_t index = 0;
for (auto it = set.cbegin(); it != set.cend(); ++it, index++) {
EXPECT_EQ(*it, orderedValues[index]);
}
}
TEST(CapabilitySet, IteratorBeginToEndPrefixStep) {
auto orderedValues = enumerateValuesFromToWithStep(0, 100, /* step= */ 8);
auto set = createSetUnorderedInsertion(orderedValues);
size_t index = 0;
for (auto it = set.cbegin(); it != set.cend(); ++it, index++) {
ASSERT_EQ(*it, orderedValues[index]);
}
}
TEST(CapabilitySet, IteratorBeginOnEmpty) {
CapabilitySet set;
auto begin = set.begin();
auto end = set.end();
ASSERT_EQ(begin, end);
}
TEST(CapabilitySet, IteratorBeginOnSingleNonZeroValue) {
CapabilitySet set;
set.insert(spv::Capability::Shader);
auto begin = set.begin();
auto end = set.end();
ASSERT_NE(begin, end);
ASSERT_EQ(*begin, spv::Capability::Shader);
}
TEST(CapabilitySet, IteratorForLoopNonZeroValue) {
CapabilitySet set;
set.insert(spv::Capability::Shader);
set.insert(spv::Capability::Tessellation);
auto begin = set.begin();
auto end = set.end();
ASSERT_NE(begin, end);
ASSERT_EQ(*begin, spv::Capability::Shader);
begin++;
ASSERT_NE(begin, end);
ASSERT_EQ(*begin, spv::Capability::Tessellation);
begin++;
ASSERT_EQ(begin, end);
}
TEST(CapabilitySet, IteratorPastEnd) {
CapabilitySet set;
set.insert(spv::Capability::Shader);
auto begin = set.begin();
auto end = set.end();
ASSERT_NE(begin, end);
ASSERT_EQ(*begin, spv::Capability::Shader);
begin++;
ASSERT_EQ(begin, end);
begin++;
ASSERT_EQ(begin, end);
}
TEST(CapabilitySet, CompatibleWithSTLFind) {
CapabilitySet set;
set.insert(spv::Capability::Matrix);
set.insert(spv::Capability::Shader);
set.insert(spv::Capability::Geometry);
set.insert(spv::Capability::Tessellation);
set.insert(spv::Capability::Addresses);
set.insert(spv::Capability::Linkage);
set.insert(spv::Capability::Kernel);
set.insert(spv::Capability::Vector16);
set.insert(spv::Capability::Float16Buffer);
set.insert(spv::Capability::Float64);
{
auto it = std::find(set.cbegin(), set.cend(), spv::Capability::Vector16);
ASSERT_NE(it, set.end());
ASSERT_EQ(*it, spv::Capability::Vector16);
}
{
auto it = std::find(set.cbegin(), set.cend(), spv::Capability::Float16);
ASSERT_EQ(it, set.end());
}
}
TEST(CapabilitySet, CompatibleWithSTLForEach) {
auto orderedValues = enumerateValuesFromToWithStep(0, 100, /* step= */ 15);
auto set = createSetUnorderedInsertion(orderedValues);
size_t index = 0;
std::for_each(set.cbegin(), set.cend(), [&](auto item) {
ASSERT_EQ(item, orderedValues[index]);
index++;
});
}
TEST(CapabilitySet, InitializerListEmpty) {
CapabilitySet s{};
for (uint32_t i = 0; i < 1000; i++) {
EXPECT_FALSE(s.contains(static_cast<spv::Capability>(i)));
}
}
TEST(CapabilitySet, LargeSetHasInsertedElements) {
CapabilitySet set;
for (auto c : kCapabilities) {
EXPECT_FALSE(set.contains(c));
}
for (auto c : kCapabilities) {
set.insert(c);
EXPECT_TRUE(set.contains(c));
}
for (auto c : kCapabilities) {
EXPECT_TRUE(set.contains(c));
}
}
TEST(CapabilitySet, LargeSetHasUnsortedInsertedElements) {
std::vector shuffledCapabilities(kCapabilities.cbegin(),
kCapabilities.cend());
std::mt19937 rng(0);
std::shuffle(shuffledCapabilities.begin(), shuffledCapabilities.end(), rng);
CapabilitySet set;
for (auto c : shuffledCapabilities) {
EXPECT_FALSE(set.contains(c));
}
for (auto c : shuffledCapabilities) {
set.insert(c);
EXPECT_TRUE(set.contains(c));
}
for (auto c : shuffledCapabilities) {
EXPECT_TRUE(set.contains(c));
}
}
TEST(CapabilitySet, LargeSetHasUnsortedRemovedElement) {
std::vector shuffledCapabilities(kCapabilities.cbegin(),
kCapabilities.cend());
std::mt19937 rng(0);
std::shuffle(shuffledCapabilities.begin(), shuffledCapabilities.end(), rng);
CapabilitySet set;
for (auto c : shuffledCapabilities) {
set.insert(c);
EXPECT_TRUE(set.contains(c));
}
for (auto c : kCapabilities) {
set.erase(c);
}
for (auto c : shuffledCapabilities) {
EXPECT_FALSE(set.contains(c));
}
}
struct ForEachCase {
CapabilitySet capabilities;
std::vector<spv::Capability> expected;
};
using CapabilitySetForEachTest = ::testing::TestWithParam<ForEachCase>;
TEST_P(CapabilitySetForEachTest, CallsAsExpected) {
EXPECT_THAT(ElementsIn(GetParam().capabilities), Eq(GetParam().expected));
}
TEST_P(CapabilitySetForEachTest, CopyConstructor) {
CapabilitySet copy(GetParam().capabilities);
EXPECT_THAT(ElementsIn(copy), Eq(GetParam().expected));
}
TEST_P(CapabilitySetForEachTest, MoveConstructor) {
// We need a writable copy to move from.
CapabilitySet copy(GetParam().capabilities);
CapabilitySet moved(std::move(copy));
EXPECT_THAT(ElementsIn(moved), Eq(GetParam().expected));
// The moved-from set is empty.
EXPECT_THAT(ElementsIn(copy), Eq(std::vector<spv::Capability>{}));
}
TEST_P(CapabilitySetForEachTest, OperatorEquals) {
CapabilitySet assigned = GetParam().capabilities;
EXPECT_THAT(ElementsIn(assigned), Eq(GetParam().expected));
}
TEST_P(CapabilitySetForEachTest, OperatorEqualsSelfAssign) {
CapabilitySet assigned{GetParam().capabilities};
assigned = assigned;
EXPECT_THAT(ElementsIn(assigned), Eq(GetParam().expected));
}
INSTANTIATE_TEST_SUITE_P(
Samples, CapabilitySetForEachTest,
ValuesIn(std::vector<ForEachCase>{
{{}, {}},
{{spv::Capability::Matrix}, {spv::Capability::Matrix}},
{{spv::Capability::Kernel, spv::Capability::Shader},
{spv::Capability::Shader, spv::Capability::Kernel}},
{{static_cast<spv::Capability>(999)},
{static_cast<spv::Capability>(999)}},
{{static_cast<spv::Capability>(0x7fffffff)},
{static_cast<spv::Capability>(0x7fffffff)}},
// Mixture and out of order
{{static_cast<spv::Capability>(0x7fffffff),
static_cast<spv::Capability>(100), spv::Capability::Shader,
spv::Capability::Matrix},
{spv::Capability::Matrix, spv::Capability::Shader,
static_cast<spv::Capability>(100),
static_cast<spv::Capability>(0x7fffffff)}},
}));
using BoundaryTestWithParam = ::testing::TestWithParam<spv::Capability>;
TEST_P(BoundaryTestWithParam, InsertedContains) {
CapabilitySet set;
set.insert(GetParam());
EXPECT_TRUE(set.contains(GetParam()));
}
INSTANTIATE_TEST_SUITE_P(
Samples, BoundaryTestWithParam,
Values(static_cast<spv::Capability>(0), static_cast<spv::Capability>(63),
static_cast<spv::Capability>(64), static_cast<spv::Capability>(65),
static_cast<spv::Capability>(127), static_cast<spv::Capability>(128),
static_cast<spv::Capability>(129)));
} // namespace
} // namespace spvtools