// 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 #include #include #include #include #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::LongCompositesINTEL, spv::Capability::OptNoneINTEL, spv::Capability::AtomicFloat16AddEXT, spv::Capability::DebugInfoModuleINTEL, spv::Capability::SplitBarrierINTEL, spv::Capability::GroupUniformArithmeticKHR, spv::Capability::Max, }; namespace { std::vector enumerateValuesFromToWithStep(size_t start, size_t end, size_t step) { assert(end > start && "end > start"); std::vector orderedValues; for (size_t i = start; i < end; i += step) { orderedValues.push_back(static_cast(i)); } return orderedValues; } EnumSet createSetUnorderedInsertion( const std::vector& values) { std::vector shuffledValues(values.cbegin(), values.cend()); std::mt19937 rng(0); std::shuffle(shuffledValues.begin(), shuffledValues.end(), rng); EnumSet set; for (auto value : shuffledValues) { set.insert(value); } return set; } } // namespace TEST(EnumSet, IsEmpty1) { EnumSet set; EXPECT_TRUE(set.empty()); set.insert(TestEnum::ZERO); EXPECT_FALSE(set.empty()); } TEST(EnumSet, IsEmpty2) { EnumSet set; EXPECT_TRUE(set.empty()); set.insert(TestEnum::ONE_HUNDRED_FIFTY); EXPECT_FALSE(set.empty()); } TEST(EnumSet, IsEmpty3) { EnumSet set(TestEnum::FOUR); EXPECT_FALSE(set.empty()); } TEST(EnumSet, IsEmpty4) { EnumSet set(TestEnum::THREE_HUNDRED); EXPECT_FALSE(set.empty()); } TEST(EnumSetHasAnyOf, EmptySetEmptyQuery) { const EnumSet set; const EnumSet empty; EXPECT_TRUE(set.HasAnyOf(empty)); EXPECT_TRUE(EnumSet().HasAnyOf(EnumSet())); } TEST(EnumSetHasAnyOf, MaskSetEmptyQuery) { EnumSet set; const EnumSet empty; set.insert(TestEnum::FIVE); set.insert(TestEnum::EIGHT); EXPECT_TRUE(set.HasAnyOf(empty)); } TEST(EnumSetHasAnyOf, OverflowSetEmptyQuery) { EnumSet set; const EnumSet empty; set.insert(TestEnum::TWO_HUNDRED); set.insert(TestEnum::THREE_HUNDRED); EXPECT_TRUE(set.HasAnyOf(empty)); } TEST(EnumSetHasAnyOf, EmptyQuery) { EnumSet set; const EnumSet 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 set; const EnumSet empty; EXPECT_TRUE(set.HasAnyOf(empty)); set.insert(TestEnum::FIVE); EXPECT_TRUE(set.HasAnyOf(empty)); EXPECT_TRUE( EnumSet(TestEnum::ONE_HUNDRED).HasAnyOf(EnumSet())); } TEST(EnumSetHasAnyOf, ReflexiveMask) { EnumSet set(TestEnum::THREE); set.insert(TestEnum::TWENTY_FOUR); set.insert(TestEnum::THIRTY); EXPECT_TRUE(set.HasAnyOf(set)); } TEST(EnumSetHasAnyOf, ReflexiveOverflow) { EnumSet set(TestEnum::TWO_HUNDRED); set.insert(TestEnum::TWO_HUNDRED); set.insert(TestEnum::FOUR_HUNDRED); EXPECT_TRUE(set.HasAnyOf(set)); } TEST(EnumSetHasAnyOf, Reflexive) { EnumSet 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 set; EnumSet items; for (uint32_t i = 0; i < 200; ++i) { TestEnum enumValue = static_cast(i); items.insert(enumValue); EXPECT_FALSE(set.HasAnyOf(items)); EXPECT_FALSE(set.HasAnyOf(EnumSet(enumValue))); } } TEST(EnumSetHasAnyOf, MaskSetMaskQuery) { EnumSet set(TestEnum::ZERO); EnumSet 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 set(TestEnum::ONE_HUNDRED); EnumSet 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 set(TestEnum::ZERO); EnumSet 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::TWENTY))); EXPECT_FALSE(set.HasAnyOf(EnumSet(TestEnum::SIX_HUNDRED))); EXPECT_TRUE(set.HasAnyOf(EnumSet(TestEnum::FIVE))); EXPECT_TRUE(set.HasAnyOf(EnumSet(TestEnum::THREE_HUNDRED))); EXPECT_TRUE(set.HasAnyOf(EnumSet(TestEnum::ZERO))); } TEST(EnumSet, DefaultIsEmpty) { EnumSet set; for (uint32_t i = 0; i < 1000; ++i) { EXPECT_FALSE(set.contains(static_cast(i))); } } TEST(EnumSet, EqualityCompareEmpty) { EnumSet set1; EnumSet set2; EXPECT_TRUE(set1 == set2); EXPECT_FALSE(set1 != set2); } TEST(EnumSet, EqualityCompareSame) { EnumSet set1; EnumSet 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 set1; EnumSet 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 set1 = createSetUnorderedInsertion(orderedValues); EnumSet set2(orderedValues.cbegin(), orderedValues.cend()); EXPECT_EQ(set1, set2); } TEST(EnumSet, InsertUsingIteratorRange) { auto orderedValues = enumerateValuesFromToWithStep(0, 2, /* step= */ 1); EnumSet set1 = createSetUnorderedInsertion(orderedValues); EnumSet 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(1000))); } TEST(CapabilitySet, ConstructSingleMemberMaxInMask) { CapabilitySet s(static_cast(63)); EXPECT_FALSE(s.contains(spv::Capability::Matrix)); EXPECT_FALSE(s.contains(spv::Capability::Shader)); EXPECT_TRUE(s.contains(static_cast(63))); EXPECT_FALSE(s.contains(static_cast(64))); EXPECT_FALSE(s.contains(static_cast(1000))); } TEST(CapabilitySet, ConstructSingleMemberMinOverflow) { // Check the first one that forces overflow beyond the mask. CapabilitySet s(static_cast(64)); EXPECT_FALSE(s.contains(spv::Capability::Matrix)); EXPECT_FALSE(s.contains(spv::Capability::Shader)); EXPECT_FALSE(s.contains(static_cast(63))); EXPECT_TRUE(s.contains(static_cast(64))); EXPECT_FALSE(s.contains(static_cast(1000))); } TEST(CapabilitySet, ConstructSingleMemberMaxOverflow) { // Check the max 32-bit signed int. CapabilitySet s(static_cast(0x7fffffffu)); EXPECT_FALSE(s.contains(spv::Capability::Matrix)); EXPECT_FALSE(s.contains(spv::Capability::Shader)); EXPECT_FALSE(s.contains(static_cast(1000))); EXPECT_TRUE(s.contains(static_cast(0x7fffffffu))); } TEST(CapabilitySet, AddEnum) { CapabilitySet s(spv::Capability::Shader); s.insert(spv::Capability::Kernel); s.insert(static_cast(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(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(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 expected; }; using CapabilitySetForEachTest = ::testing::TestWithParam; 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{})); } 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{ {{}, {}}, {{spv::Capability::Matrix}, {spv::Capability::Matrix}}, {{spv::Capability::Kernel, spv::Capability::Shader}, {spv::Capability::Shader, spv::Capability::Kernel}}, {{static_cast(999)}, {static_cast(999)}}, {{static_cast(0x7fffffff)}, {static_cast(0x7fffffff)}}, // Mixture and out of order {{static_cast(0x7fffffff), static_cast(100), spv::Capability::Shader, spv::Capability::Matrix}, {spv::Capability::Matrix, spv::Capability::Shader, static_cast(100), static_cast(0x7fffffff)}}, })); using BoundaryTestWithParam = ::testing::TestWithParam; TEST_P(BoundaryTestWithParam, InsertedContains) { CapabilitySet set; set.insert(GetParam()); EXPECT_TRUE(set.contains(GetParam())); } INSTANTIATE_TEST_SUITE_P( Samples, BoundaryTestWithParam, Values(static_cast(0), static_cast(63), static_cast(64), static_cast(65), static_cast(127), static_cast(128), static_cast(129))); } // namespace } // namespace spvtools