mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
`AvailabilityRange` is now being used as a currency type in more of the compiler, and some of those uses are in permanent `ASTContext` allocations. The class wraps the `VersionRange` utility, which is itself a wrapper around `llvm::VersionTuple` with some additional storage for representing sentinel values. Even though the two sentinel values can be be represented with just a single bit of additional storage on top of the 16 bytes required to represent `VersionTuple`, because of alignment requirements the sentinel values end up bloating the layout of `VersionRange` by many bytes. To make `AvailabilityRange` and `VersionRange` more efficient to store, we can instead reserve two unlikely `llvm::VersionTuple` bit patterns as the sentinel values instead. The values chosen are the same ones LLVM uses to represent version tuple tombstones and empty keys in a `DenseMap`.
134 lines
4.6 KiB
C++
134 lines
4.6 KiB
C++
#include "swift/AST/AvailabilityRange.h"
|
|
#include "gtest/gtest.h"
|
|
|
|
using namespace swift;
|
|
|
|
// A test fixture with version ranges
|
|
class VersionRangeLattice : public ::testing::Test {
|
|
public:
|
|
VersionRange All = VersionRange::all();
|
|
|
|
VersionRange GreaterThanEqual10_10 =
|
|
VersionRange::allGTE(llvm::VersionTuple(10, 10));
|
|
|
|
VersionRange GreaterThanEqual10_9 =
|
|
VersionRange::allGTE(llvm::VersionTuple(10, 9));
|
|
|
|
VersionRange Empty = VersionRange::empty();
|
|
|
|
VersionRange intersectRanges(VersionRange A, VersionRange B) {
|
|
A.intersectWith(B);
|
|
return A;
|
|
}
|
|
|
|
VersionRange unionRanges(VersionRange A, VersionRange B) {
|
|
A.unionWith(B);
|
|
return A;
|
|
}
|
|
|
|
bool equals(VersionRange A, VersionRange B) {
|
|
return A.isContainedIn(B) && B.isContainedIn(A);
|
|
}
|
|
|
|
bool intersectEquals(VersionRange A, VersionRange B, VersionRange Expected) {
|
|
VersionRange AMeetB = intersectRanges(A, B);
|
|
VersionRange BMeetA = intersectRanges(A, B);
|
|
|
|
return equals(AMeetB, Expected) && equals(BMeetA, Expected);
|
|
}
|
|
|
|
bool unionEquals(VersionRange A, VersionRange B, VersionRange Expected) {
|
|
VersionRange AJoinB = unionRanges(A, B);
|
|
VersionRange BJoinA = unionRanges(A, B);
|
|
|
|
return equals(AJoinB, Expected) && equals(BJoinA, Expected);
|
|
}
|
|
};
|
|
|
|
// Test that All acts like the top element in the lattice with respect to
|
|
// containment.
|
|
TEST_F(VersionRangeLattice, AllIsTopElement) {
|
|
EXPECT_TRUE(All.isContainedIn(All));
|
|
|
|
EXPECT_TRUE(GreaterThanEqual10_10.isContainedIn(All));
|
|
EXPECT_TRUE(Empty.isContainedIn(All));
|
|
|
|
EXPECT_FALSE(All.isContainedIn(GreaterThanEqual10_10));
|
|
EXPECT_FALSE(All.isContainedIn(Empty));
|
|
}
|
|
|
|
// Test that Empty acts like the bottom element in the lattice with respect to
|
|
// containment.
|
|
TEST_F(VersionRangeLattice, EmptyIsBottomElement) {
|
|
EXPECT_TRUE(Empty.isContainedIn(Empty));
|
|
|
|
EXPECT_TRUE(Empty.isContainedIn(All));
|
|
EXPECT_TRUE(Empty.isContainedIn(GreaterThanEqual10_10));
|
|
|
|
EXPECT_FALSE(GreaterThanEqual10_10.isContainedIn(Empty));
|
|
EXPECT_FALSE(GreaterThanEqual10_10.isContainedIn(Empty));
|
|
}
|
|
|
|
// Test containment for ranges with lower end points.
|
|
TEST_F(VersionRangeLattice, ContainmentClosedEndedPositiveInfinity) {
|
|
EXPECT_TRUE(GreaterThanEqual10_10.isContainedIn(GreaterThanEqual10_10));
|
|
|
|
EXPECT_TRUE(GreaterThanEqual10_10.isContainedIn(GreaterThanEqual10_9));
|
|
EXPECT_TRUE(Empty.isContainedIn(GreaterThanEqual10_9));
|
|
|
|
EXPECT_FALSE(GreaterThanEqual10_9.isContainedIn(GreaterThanEqual10_10));
|
|
}
|
|
|
|
// Test that All acts like the top element in the lattice with respect to
|
|
// intersection.
|
|
TEST_F(VersionRangeLattice, MeetWithAll) {
|
|
EXPECT_TRUE(intersectEquals(All, All, All));
|
|
EXPECT_TRUE(intersectEquals(GreaterThanEqual10_10, All,
|
|
GreaterThanEqual10_10));
|
|
EXPECT_TRUE(intersectEquals(Empty, All, Empty));
|
|
}
|
|
|
|
// Test that All acts like the top element in the lattice with respect to
|
|
// union.
|
|
TEST_F(VersionRangeLattice, JoinWithAll) {
|
|
EXPECT_TRUE(unionEquals(All, All, All));
|
|
EXPECT_TRUE(unionEquals(GreaterThanEqual10_10, All, All));
|
|
EXPECT_TRUE(unionEquals(Empty, All, All));
|
|
}
|
|
|
|
// Test that Empty acts like the bottom element in the lattice with respect to
|
|
// intersection.
|
|
TEST_F(VersionRangeLattice, MeetWithEmpty) {
|
|
EXPECT_TRUE(intersectEquals(GreaterThanEqual10_10, Empty, Empty));
|
|
EXPECT_TRUE(intersectEquals(Empty, Empty, Empty));
|
|
}
|
|
|
|
// Test that Empty acts like the bottom element in the lattice with respect to
|
|
// union.
|
|
TEST_F(VersionRangeLattice, JoinWithEmpty) {
|
|
EXPECT_TRUE(unionEquals(GreaterThanEqual10_10, Empty, GreaterThanEqual10_10));
|
|
EXPECT_TRUE(unionEquals(Empty, Empty, Empty));
|
|
}
|
|
|
|
// Test intersection for ranges with lower end points.
|
|
TEST_F(VersionRangeLattice, MeetWithClosedEndedPositiveInfinity) {
|
|
EXPECT_TRUE(intersectEquals(GreaterThanEqual10_10, GreaterThanEqual10_10,
|
|
GreaterThanEqual10_10));
|
|
EXPECT_TRUE(intersectEquals(GreaterThanEqual10_10, GreaterThanEqual10_9,
|
|
GreaterThanEqual10_10));
|
|
}
|
|
|
|
// Test union for ranges with lower end points.
|
|
TEST_F(VersionRangeLattice, JoinWithClosedEndedPositiveInfinity) {
|
|
EXPECT_TRUE(unionEquals(GreaterThanEqual10_10, GreaterThanEqual10_10,
|
|
GreaterThanEqual10_10));
|
|
EXPECT_TRUE(unionEquals(GreaterThanEqual10_10, GreaterThanEqual10_9,
|
|
GreaterThanEqual10_9));
|
|
}
|
|
|
|
TEST_F(VersionRangeLattice, ValidVersionTuples) {
|
|
EXPECT_TRUE(VersionRange::isValidVersion(llvm::VersionTuple()));
|
|
EXPECT_FALSE(VersionRange::isValidVersion(llvm::VersionTuple(0x7FFFFFFE)));
|
|
EXPECT_FALSE(VersionRange::isValidVersion(llvm::VersionTuple(0x7FFFFFFF)));
|
|
}
|