My Project
StorageUniquer.h
Go to the documentation of this file.
1 //===- StorageUniquer.h - Common Storage Class Uniquer ----------*- C++ -*-===//
2 //
3 // Part of the MLIR Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef MLIR_SUPPORT_STORAGEUNIQUER_H
10 #define MLIR_SUPPORT_STORAGEUNIQUER_H
11 
12 #include "mlir/Support/STLExtras.h"
13 #include "llvm/ADT/DenseMap.h"
14 #include "llvm/ADT/DenseSet.h"
15 #include "llvm/Support/Allocator.h"
16 
17 namespace mlir {
18 namespace detail {
19 struct StorageUniquerImpl;
20 
22 template <typename ImplTy, typename... Args>
23 using has_impltype_getkey_t = decltype(ImplTy::getKey(std::declval<Args>()...));
24 
26 template <typename ImplTy, typename T>
27 using has_impltype_hash_t = decltype(ImplTy::hashKey(std::declval<T>()));
28 } // namespace detail
29 
65 public:
67  ~StorageUniquer();
68 
71  class BaseStorage {
72  public:
74  unsigned getKind() const { return kind; }
75 
76  protected:
77  BaseStorage() : kind(0) {}
78 
79  private:
82 
84  unsigned kind;
85  };
86 
90  public:
93  template <typename T> ArrayRef<T> copyInto(ArrayRef<T> elements) {
94  if (elements.empty())
95  return llvm::None;
96  auto result = allocator.Allocate<T>(elements.size());
97  std::uninitialized_copy(elements.begin(), elements.end(), result);
98  return ArrayRef<T>(result, elements.size());
99  }
100 
103  StringRef copyInto(StringRef str) {
104  auto result = copyInto(ArrayRef<char>(str.data(), str.size()));
105  return StringRef(result.data(), str.size());
106  }
107 
109  template <typename T> T *allocate() { return allocator.Allocate<T>(); }
110 
112  void *allocate(size_t size, size_t alignment) {
113  return allocator.Allocate(size, alignment);
114  }
115 
116  private:
118  llvm::BumpPtrAllocator allocator;
119  };
120 
125  template <typename Storage, typename Arg, typename... Args>
126  Storage *get(std::function<void(Storage *)> initFn, unsigned kind, Arg &&arg,
127  Args &&... args) {
128  // Construct a value of the derived key type.
129  auto derivedKey =
130  getKey<Storage>(std::forward<Arg>(arg), std::forward<Args>(args)...);
131 
132  // Create a hash of the kind and the derived key.
133  unsigned hashValue = getHash<Storage>(kind, derivedKey);
134 
135  // Generate an equality function for the derived storage.
136  std::function<bool(const BaseStorage *)> isEqual =
137  [&derivedKey](const BaseStorage *existing) {
138  return static_cast<const Storage &>(*existing) == derivedKey;
139  };
140 
141  // Generate a constructor function for the derived storage.
142  std::function<BaseStorage *(StorageAllocator &)> ctorFn =
143  [&](StorageAllocator &allocator) {
144  auto *storage = Storage::construct(allocator, derivedKey);
145  if (initFn)
146  initFn(storage);
147  return storage;
148  };
149 
150  // Get an instance for the derived storage.
151  return static_cast<Storage *>(getImpl(kind, hashValue, isEqual, ctorFn));
152  }
153 
158  template <typename Storage>
159  Storage *get(std::function<void(Storage *)> initFn, unsigned kind) {
160  auto ctorFn = [&](StorageAllocator &allocator) {
161  auto *storage = new (allocator.allocate<Storage>()) Storage();
162  if (initFn)
163  initFn(storage);
164  return storage;
165  };
166  return static_cast<Storage *>(getImpl(kind, ctorFn));
167  }
168 
171  template <typename Storage, typename Arg, typename... Args>
172  void erase(unsigned kind, Arg &&arg, Args &&... args) {
173  // Construct a value of the derived key type.
174  auto derivedKey =
175  getKey<Storage>(std::forward<Arg>(arg), std::forward<Args>(args)...);
176 
177  // Create a hash of the kind and the derived key.
178  unsigned hashValue = getHash<Storage>(kind, derivedKey);
179 
180  // Generate an equality function for the derived storage.
181  std::function<bool(const BaseStorage *)> isEqual =
182  [&derivedKey](const BaseStorage *existing) {
183  return static_cast<const Storage &>(*existing) == derivedKey;
184  };
185 
186  // Attempt to erase the storage instance.
187  eraseImpl(kind, hashValue, isEqual, [](BaseStorage *storage) {
188  static_cast<Storage *>(storage)->cleanup();
189  });
190  }
191 
192 private:
195  BaseStorage *getImpl(unsigned kind, unsigned hashValue,
196  function_ref<bool(const BaseStorage *)> isEqual,
197  std::function<BaseStorage *(StorageAllocator &)> ctorFn);
198 
201  BaseStorage *getImpl(unsigned kind,
202  std::function<BaseStorage *(StorageAllocator &)> ctorFn);
203 
206  void eraseImpl(unsigned kind, unsigned hashValue,
207  function_ref<bool(const BaseStorage *)> isEqual,
208  std::function<void(BaseStorage *)> cleanupFn);
209 
211  std::unique_ptr<detail::StorageUniquerImpl> impl;
212 
213  //===--------------------------------------------------------------------===//
214  // Key Construction
215  //===--------------------------------------------------------------------===//
216 
219  template <typename ImplTy, typename... Args>
220  static typename std::enable_if<
221  is_detected<detail::has_impltype_getkey_t, ImplTy, Args...>::value,
222  typename ImplTy::KeyTy>::type
223  getKey(Args &&... args) {
224  return ImplTy::getKey(args...);
225  }
228  template <typename ImplTy, typename... Args>
229  static typename std::enable_if<
230  !is_detected<detail::has_impltype_getkey_t, ImplTy, Args...>::value,
231  typename ImplTy::KeyTy>::type
232  getKey(Args &&... args) {
233  return typename ImplTy::KeyTy(args...);
234  }
235 
236  //===--------------------------------------------------------------------===//
237  // Key and Kind Hashing
238  //===--------------------------------------------------------------------===//
239 
242  template <typename ImplTy, typename DerivedKey>
243  static typename std::enable_if<
245  ::llvm::hash_code>::type
246  getHash(unsigned kind, const DerivedKey &derivedKey) {
247  return llvm::hash_combine(kind, ImplTy::hashKey(derivedKey));
248  }
251  template <typename ImplTy, typename DerivedKey>
252  static typename std::enable_if<
253  !is_detected<detail::has_impltype_hash_t, ImplTy, DerivedKey>::value,
254  ::llvm::hash_code>::type
255  getHash(unsigned kind, const DerivedKey &derivedKey) {
256  return llvm::hash_combine(
257  kind, DenseMapInfo<DerivedKey>::getHashValue(derivedKey));
258  }
259 };
260 } // end namespace mlir
261 
262 #endif
Definition: InferTypeOpInterface.cpp:20
decltype(ImplTy::hashKey(std::declval< T >())) has_impltype_hash_t
Trait to check if ImplTy provides a &#39;hashKey&#39; method for &#39;T&#39;.
Definition: StorageUniquer.h:27
This is the implementation of the StorageUniquer class.
Definition: StorageUniquer.cpp:20
StringRef copyInto(StringRef str)
Definition: StorageUniquer.h:103
Definition: LLVM.h:45
Definition: LLVM.h:49
Definition: StorageUniquer.h:89
T * allocate()
Allocate an instance of the provided type.
Definition: StorageUniquer.h:109
Definition: LLVM.h:37
typename detail::detector< void, Op, Args... >::value_t is_detected
Definition: STLExtras.h:125
BaseStorage()
Definition: StorageUniquer.h:77
Definition: StorageUniquer.h:64
void erase(unsigned kind, Arg &&arg, Args &&... args)
Definition: StorageUniquer.h:172
Definition: StorageUniquer.h:71
unsigned getKind() const
Get the kind classification of this storage.
Definition: StorageUniquer.h:74
decltype(ImplTy::getKey(std::declval< Args >()...)) has_impltype_getkey_t
Trait to check if ImplTy provides a &#39;getKey&#39; method with types &#39;Args&#39;.
Definition: StorageUniquer.h:23
Definition: StandardTypes.h:63
ArrayRef< T > copyInto(ArrayRef< T > elements)
Definition: StorageUniquer.h:93
void * allocate(size_t size, size_t alignment)
Allocate &#39;size&#39; bytes of &#39;alignment&#39; aligned memory.
Definition: StorageUniquer.h:112