Skip to content

Commit dd7f780

Browse files
committed
[multimapcache] Change multi-map cache to use a std::function instead of CRTP.
This makes it so one uses a passed in std::function, instead of an impl class to map a key to a list of values to be cached.
1 parent 061c6d0 commit dd7f780

File tree

2 files changed

+52
-32
lines changed

2 files changed

+52
-32
lines changed

include/swift/Basic/MultiMapCache.h

Lines changed: 12 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -18,40 +18,35 @@
1818

1919
namespace swift {
2020

21-
/// A CRTP write-once multi-map cache that can be small. It uses a DenseMap
21+
/// A write-once multi-map cache that can be small. It uses a DenseMap
2222
/// internally, so it can be used as a cache without needing to be frozen like
23-
/// FrozenMultiMap (which uses only a vector internally). The Impl class
24-
/// implements the method constructValuesForKey that is used to compute the
25-
/// actual cache value.
26-
///
27-
/// NOTE: constructValuesForKeys is assumed to take a KeyTy and a
28-
/// SmallVectorImpl<ValueTy>. It must append all results to that accumulator and
29-
/// not read any contents of the accumulator.
23+
/// FrozenMultiMap (which uses only a vector internally). The cached value is
24+
/// computed by a passed in std::function. The std::function is able to map
25+
/// multiple values to a specific key via the out array.
3026
///
3127
/// NOTE: We store the (size, length) of each ArrayRef<ValueTy> instead of
3228
/// storing the ArrayRef to avoid data invalidation issues caused by SmallVector
3329
/// switching from small to large representations.
3430
///
3531
/// For an example of a subclass implementation see:
3632
/// unittests/Basic/MultiMapCacheTest.cpp.
37-
template <typename ImplType, typename KeyTy, typename ValueTy,
33+
template <typename KeyTy, typename ValueTy,
3834
typename MapTy =
3935
llvm::DenseMap<KeyTy, Optional<std::tuple<unsigned, unsigned>>>,
4036
typename VectorTy = std::vector<ValueTy>,
4137
typename VectorTyImpl = VectorTy>
4238
class MultiMapCache {
39+
std::function<bool(const KeyTy &, VectorTyImpl &)> function;
4340
MapTy valueToDataOffsetIndexMap;
4441
VectorTy data;
4542

4643
constexpr static unsigned ArrayStartOffset = 0;
4744
constexpr static unsigned ArrayLengthOffset = 1;
4845

49-
constexpr ImplType &asImpl() const {
50-
auto *self = const_cast<MultiMapCache *>(this);
51-
return reinterpret_cast<ImplType &>(*self);
52-
}
53-
5446
public:
47+
MultiMapCache(std::function<bool(const KeyTy &, VectorTyImpl &)> function)
48+
: function(function) {}
49+
5550
void clear() {
5651
valueToDataOffsetIndexMap.clear();
5752
data.clear();
@@ -81,7 +76,7 @@ class MultiMapCache {
8176

8277
// We assume that constructValuesForKey /only/ inserts to the end of data
8378
// and does not inspect any other values in the data array.
84-
if (!asImpl().constructValuesForKey(key, data)) {
79+
if (!function(key, data)) {
8580
return None;
8681
}
8782

@@ -94,9 +89,9 @@ class MultiMapCache {
9489
}
9590
};
9691

97-
template <typename ImplType, typename KeyTy, typename ValueTy>
92+
template <typename KeyTy, typename ValueTy>
9893
using SmallMultiMapCache = MultiMapCache<
99-
ImplType, KeyTy, ValueTy,
94+
KeyTy, ValueTy,
10095
llvm::SmallDenseMap<KeyTy, Optional<std::tuple<unsigned, unsigned>>, 8>,
10196
SmallVector<ValueTy, 32>, SmallVectorImpl<ValueTy>>;
10297

unittests/Basic/MultiMapCacheTest.cpp

Lines changed: 40 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,49 @@
1717

1818
using namespace swift;
1919

20-
namespace {
21-
22-
/// A multimap cache that caches the initial 4 powers of each key.
23-
struct PowerMultiMapCache
24-
: public MultiMapCache<PowerMultiMapCache, unsigned, unsigned> {
25-
bool constructValuesForKey(unsigned key, std::vector<unsigned> &data) {
26-
// Construct the first 3 powers of key.
27-
data.push_back(key);
28-
data.push_back(key * key);
29-
data.push_back(key * key * key);
30-
return true;
20+
TEST(MultiMapCache, powersTest) {
21+
std::function<bool(unsigned, std::vector<unsigned> &)> cacheCompute =
22+
[&](unsigned key, std::vector<unsigned> &outArray) {
23+
outArray.push_back(key);
24+
outArray.push_back(key * key);
25+
outArray.push_back(key * key * key);
26+
return true;
27+
};
28+
MultiMapCache<unsigned, unsigned> cache(cacheCompute);
29+
30+
EXPECT_TRUE(cache.empty());
31+
EXPECT_EQ(cache.size(), 0u);
32+
for (unsigned index : range(1, 256)) {
33+
auto array = *cache.get(index);
34+
for (unsigned power : array) {
35+
EXPECT_EQ(power % index, 0);
36+
}
37+
}
38+
EXPECT_FALSE(cache.empty());
39+
EXPECT_EQ(cache.size(), 255);
40+
for (unsigned index : range(1, 256)) {
41+
auto array = *cache.get(index);
42+
for (unsigned power : array) {
43+
EXPECT_EQ(power % index, 0);
44+
}
3145
}
32-
};
46+
EXPECT_FALSE(cache.empty());
47+
EXPECT_EQ(cache.size(), 255);
3348

34-
} // end anonymous namespace
49+
cache.clear();
50+
EXPECT_TRUE(cache.empty());
51+
EXPECT_EQ(cache.size(), 0);
52+
}
3553

36-
TEST(MultiMapCache, powersTest) {
37-
PowerMultiMapCache cache;
54+
TEST(MultiMapCache, smallTest) {
55+
std::function<bool(unsigned, SmallVectorImpl<unsigned> &)> cacheCompute =
56+
[&](unsigned key, SmallVectorImpl<unsigned> &outArray) {
57+
outArray.push_back(key);
58+
outArray.push_back(key * key);
59+
outArray.push_back(key * key * key);
60+
return true;
61+
};
62+
SmallMultiMapCache<unsigned, unsigned> cache(cacheCompute);
3863

3964
EXPECT_TRUE(cache.empty());
4065
EXPECT_EQ(cache.size(), 0u);

0 commit comments

Comments
 (0)