#include "swift/Basic/OptionSet.h" #include "swift/Basic/ValueEnumerator.h" #include "gtest/gtest.h" using namespace swift; TEST(OptionSet, contains) { enum class Flags { A = 1 << 0, B = 1 << 1, C = 1 << 2 }; OptionSet emptySet; OptionSet aSet = Flags::A; OptionSet abSet = aSet | Flags::B; OptionSet abcSet = abSet | Flags::C; OptionSet bcSet = abcSet - Flags::A; OptionSet cSet = bcSet - Flags::B; EXPECT_TRUE(emptySet.contains(emptySet)); EXPECT_FALSE(emptySet.contains(aSet)); EXPECT_FALSE(emptySet.contains(abSet)); EXPECT_FALSE(emptySet.contains(abcSet)); EXPECT_FALSE(emptySet.contains(bcSet)); EXPECT_FALSE(emptySet.contains(cSet)); EXPECT_TRUE(aSet.contains(emptySet)); EXPECT_TRUE(aSet.contains(aSet)); EXPECT_FALSE(aSet.contains(abSet)); EXPECT_FALSE(aSet.contains(abcSet)); EXPECT_FALSE(aSet.contains(bcSet)); EXPECT_FALSE(aSet.contains(cSet)); EXPECT_TRUE(abSet.contains(emptySet)); EXPECT_TRUE(abSet.contains(aSet)); EXPECT_TRUE(abSet.contains(abSet)); EXPECT_FALSE(abSet.contains(abcSet)); EXPECT_FALSE(abSet.contains(bcSet)); EXPECT_FALSE(abSet.contains(cSet)); EXPECT_TRUE(abcSet.contains(emptySet)); EXPECT_TRUE(abcSet.contains(aSet)); EXPECT_TRUE(abcSet.contains(abSet)); EXPECT_TRUE(abcSet.contains(abcSet)); EXPECT_TRUE(abcSet.contains(bcSet)); EXPECT_TRUE(abcSet.contains(cSet)); } TEST(OptionSet, intptr_t) { enum class Small : int8_t { A = 1 << 0 }; OptionSet small = Small::A; EXPECT_EQ(static_cast(Small::A), static_cast(small)); enum class UPtr : uintptr_t { A = std::numeric_limits::max() }; OptionSet uptr = UPtr::A; EXPECT_EQ(static_cast(UPtr::A), static_cast(uptr)); enum class Ptr : intptr_t { A = std::numeric_limits::min() }; OptionSet ptr = Ptr::A; EXPECT_EQ(static_cast(Ptr::A), static_cast(ptr)); } TEST(OptionSet, intptr_t_isConstructible) { // First check that std::is_constructible counts explicit conversion // operators. class AlwaysConvertible { public: explicit operator intptr_t () const { return 0; } }; if (!std::is_constructible::value) { // std::is_constructible doesn't test what we want it to. Just exit early. return; } enum class LongLong : unsigned long long { A = 1 }; bool isConvertible = std::is_constructible>::value; if (sizeof(intptr_t) < sizeof(long long)) { EXPECT_FALSE(isConvertible); } else { EXPECT_TRUE(isConvertible); } } TEST(ValueEnumerator, basic) { { ValueEnumerator Trans; // Check that indexing is persistent. EXPECT_EQ(Trans.getIndex(99), Trans.getIndex(99)); EXPECT_EQ(Trans.getIndex(100), Trans.getIndex(100)); // Check that we don't have collisions. bool SameIndex = Trans.getIndex(82) == Trans.getIndex(73); EXPECT_FALSE(SameIndex); // Check that invalidation works. // After invalidation the old index must not be equal to the new index. size_t oldIndex = Trans.getIndex(99); Trans.invalidateValue(99); size_t newIndex = Trans.getIndex(99); EXPECT_FALSE(newIndex == oldIndex); } { const char *string_1 = "hello"; const char *string_2 = "goodbye"; const char *string_3 = ":-)"; ValueEnumerator Trans; EXPECT_EQ(Trans.getIndex(nullptr), Trans.getIndex(nullptr)); EXPECT_EQ(Trans.getIndex(string_1), Trans.getIndex(string_1)); EXPECT_EQ(Trans.getIndex(string_2), Trans.getIndex(string_2)); // Check that invalidation works. size_t oldIndex = Trans.getIndex(string_3); Trans.invalidateValue(string_3); size_t newIndex = Trans.getIndex(string_3); EXPECT_FALSE(newIndex == oldIndex); // Check that different values don't give the same index. EXPECT_FALSE(Trans.getIndex(string_2) == Trans.getIndex(string_3)); } { ValueEnumerator Trans; // Check a bunch of integers. for (int i = 1; i < 10000; i++) { EXPECT_TRUE(Trans.getIndex(0) != Trans.getIndex(i)); } // Check that there are no accidental collisions. for (int i = 0; i < 10000; i++) { for (int j = 1; j < 10; j++) { EXPECT_TRUE(Trans.getIndex(i) != Trans.getIndex(i + j)); } } // Check that indexing is still persistent. EXPECT_EQ(Trans.getIndex(100), Trans.getIndex(100)); } }