Caffe2 - C++ API
A deep learning, cross platform ML framework
ordered_dict.h
1 #pragma once
2 
3 #include <c10/util/Exception.h>
4 
5 #include <cstdint>
6 #include <functional>
7 #include <initializer_list>
8 #include <string>
9 #include <unordered_map>
10 #include <utility>
11 #include <vector>
12 
13 namespace torch {
15 template <typename Key, typename Value>
16 class OrderedDict {
17  public:
19  class Item;
20 
21  // The lifetime of an iterator is bound to the lifetime of the `OrderedDict`.
22  // Further, any `insert()` operation may invalidate all iterators
23  // pointing into the vector.
24  using Iterator = typename std::vector<Item>::iterator;
25  using ConstIterator = typename std::vector<Item>::const_iterator;
26 
30  explicit OrderedDict(std::string key_description = "Key");
31 
33  OrderedDict(const OrderedDict& other);
34 
36  OrderedDict& operator=(const OrderedDict& other);
37 
38  // NB: Move works by default, because you can move-construct vectors of const
39  // values. I tried to make this noexcept (conditional on the move constructors
40  // of index_ and items_ being noexcept) but the obvious spelling didn't
41  // compile on Windows.
42  OrderedDict(OrderedDict&& other) = default;
43  OrderedDict& operator=(OrderedDict&& other) = default;
44 
45  ~OrderedDict() = default;
46 
49  /*implicit */ OrderedDict(std::initializer_list<Item> initializer_list);
50 
52  const std::string& key_description() const noexcept;
53 
54  // Element Access
55 
58  Item& front();
59 
62  const Item& front() const;
63 
66  Item& back();
67 
70  const Item& back() const;
71 
74  Item& operator[](size_t index);
75 
78  const Item& operator[](size_t index) const;
79 
83  Value& operator[](const Key& key);
84 
88  const Value& operator[](const Key& key) const;
89 
90  // Lookup
91 
94  Value* find(const Key& key) noexcept;
95 
98  const Value* find(const Key& key) const noexcept;
99 
101  bool contains(const Key& key) const noexcept;
102 
103  // Iterators
104 
107  Iterator begin();
108 
111  ConstIterator begin() const;
112 
114  Iterator end();
115 
117  ConstIterator end() const;
118 
119  // Capacity
120 
122  size_t size() const noexcept;
123 
125  bool is_empty() const noexcept;
126 
129  void reserve(size_t requested_capacity);
130 
131  // Modifiers
132 
136  template <typename K, typename V>
137  Value& insert(K&& key, V&& value);
138 
142  Value& insert(Key key, Value&& value);
143 
146  void update(OrderedDict&& other);
147 
150  void update(const OrderedDict& other);
151 
153  void clear();
154 
155  // Observers
156 
158  const std::vector<Item>& items() const noexcept;
159 
162  ::std::vector<Key> keys() const;
163 
166  ::std::vector<Value> values() const;
167 
170  ::std::vector<std::pair<Key, Value>> pairs() const;
171 
172  private:
174  ::std::unordered_map<Key, size_t> index_;
175 
177  ::std::vector<Item> items_;
178 
180  ::std::string key_description_{"Key"};
181 };
182 
183 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ OrderedDict::Item ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
184 
185 template <typename Key, typename Value>
186 class OrderedDict<Key, Value>::Item {
187  public:
189  Item(Key key, Value value) : pair_(std::move(key), std::move(value)) {}
190 
192  Value& operator*() {
193  return value();
194  }
195 
197  const Value& operator*() const {
198  return value();
199  }
200 
202  Value* operator->() {
203  return &value();
204  }
205 
207  const Value* operator->() const {
208  return &value();
209  }
210 
212  const Key& key() const noexcept {
213  return pair_.first;
214  }
215 
217  Value& value() noexcept {
218  return pair_.second;
219  }
220 
222  const Value& value() const noexcept {
223  return pair_.second;
224  }
225 
227  const std::pair<const Key, Value>& pair() const noexcept {
228  return pair_;
229  }
230 
231  private:
234  ::std::pair<const Key, Value> pair_;
235 };
236 
237 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ OrderedDict ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
238 
239 template <typename Key, typename Value>
241  : key_description_(std::move(key_description)) {}
242 
243 template <typename Key, typename Value>
245  : index_(other.index_), key_description_(other.key_description_) {
246  // Copy we have to do ourselves, because items' keys are const, so we have to
247  // re-insert the items.
248  for (const auto& item : other.items_) {
249  items_.push_back(item);
250  }
251 }
252 
253 template <typename Key, typename Value>
255  const OrderedDict& other) {
256  index_ = other.index_;
257  items_.clear();
258  for (auto& item : other.items_) {
259  items_.push_back(item);
260  }
261  key_description_ = other.key_description_;
262  return *this;
263 }
264 
265 template <typename Key, typename Value>
267  std::initializer_list<Item> initializer_list)
268  : OrderedDict("Key") {
269  items_.reserve(initializer_list.size());
270  for (auto& item : initializer_list) {
271  // Copy the key here and move it into the index.
272  items_.emplace_back(item.key(), std::move(item.value()));
273  index_.emplace(std::move(item.key()), size() - 1);
274  }
275 }
276 
277 template <typename Key, typename Value>
278 typename OrderedDict<Key, Value>::Iterator OrderedDict<Key, Value>::begin() {
279  return items_.begin();
280 }
281 
282 template <typename Key, typename Value>
283 typename OrderedDict<Key, Value>::ConstIterator OrderedDict<Key, Value>::begin()
284  const {
285  return items_.begin();
286 }
287 
288 template <typename Key, typename Value>
289 typename OrderedDict<Key, Value>::Iterator OrderedDict<Key, Value>::end() {
290  return items_.end();
291 }
292 
293 template <typename Key, typename Value>
294 typename OrderedDict<Key, Value>::ConstIterator OrderedDict<Key, Value>::end()
295  const {
296  return items_.end();
297 }
298 
299 template <typename Key, typename Value>
301  AT_CHECK(!items_.empty(), "Called front() on an empty OrderedDict");
302  return items_.front();
303 }
304 
305 template <typename Key, typename Value>
307  const {
308  AT_CHECK(!items_.empty(), "Called front() on an empty OrderedDict");
309  return items_.front();
310 }
311 
312 template <typename Key, typename Value>
314  AT_CHECK(!items_.empty(), "Called back() on an empty OrderedDict");
315  return items_.back();
316 }
317 
318 template <typename Key, typename Value>
320  const {
321  AT_CHECK(!items_.empty(), "Called back() on an empty OrderedDict");
322  return items_.back();
323 }
324 
325 template <typename Key, typename Value>
327  size_t index) {
328  AT_CHECK(index < items_.size(), "Index ", index, " is out of bounds");
329  return items_[index];
330 }
331 
332 template <typename Key, typename Value>
333 const typename OrderedDict<Key, Value>::
335  AT_CHECK(index < items_.size(), "Index ", index, " is out of bounds");
336  return items_[index];
337 }
338 
339 template <typename Key, typename Value>
340 Value& OrderedDict<Key, Value>::operator[](const Key& key) {
341  if (auto* value = find(key)) {
342  return *value;
343  }
344  AT_ERROR(key_description_, " '", key, "' is not defined");
345 }
346 
347 template <typename Key, typename Value>
348 const Value& OrderedDict<Key, Value>::operator[](const Key& key) const {
349  if (auto* value = find(key)) {
350  return *value;
351  }
352  AT_ERROR(key_description_, " '", key, "' is not defined");
353 }
354 
355 template <typename Key, typename Value>
356 template <typename K, typename V>
357 Value& OrderedDict<Key, Value>::insert(K&& key, V&& value) {
358  AT_CHECK(
359  index_.count(key) == 0, key_description_, " '", key, "' already defined");
360  // Copy `key` here and move it into the index.
361  items_.emplace_back(key, std::forward<V>(value));
362  index_.emplace(std::forward<K>(key), size() - 1);
363  return items_.back().value();
364 }
365 
366 template <typename Key, typename Value>
367 Value& OrderedDict<Key, Value>::insert(Key key, Value&& value) {
368  return insert<Key, Value>(std::move(key), std::move(value));
369 }
370 
371 template <typename Key, typename Value>
373  reserve(size() + other.size());
374  for (auto& item : other) {
375  // We want to call `insert()` to prevent duplicate keys.
376  insert(std::move(item.key()), std::move(item.value()));
377  }
378 }
379 
380 template <typename Key, typename Value>
382  reserve(size() + other.size());
383  for (auto& item : other) {
384  // We want to call `insert()` to prevent duplicate keys.
385  insert(item.key(), item.value());
386  }
387 }
388 
389 template <typename Key, typename Value>
390 Value* OrderedDict<Key, Value>::find(const Key& key) noexcept {
391  auto iterator = index_.find(key);
392  if (iterator == index_.end()) {
393  return nullptr;
394  }
395  return &items_[iterator->second].value();
396 }
397 
398 template <typename Key, typename Value>
399 const Value* OrderedDict<Key, Value>::find(const Key& key) const noexcept {
400  auto iterator = index_.find(key);
401  if (iterator == index_.end()) {
402  return nullptr;
403  }
404  return &items_[iterator->second].value();
405 }
406 
407 template <typename Key, typename Value>
408 bool OrderedDict<Key, Value>::contains(const Key& key) const noexcept {
409  return find(key) != nullptr;
410 }
411 
412 template <typename Key, typename Value>
414  index_.clear();
415  items_.clear();
416 }
417 
418 template <typename Key, typename Value>
419 size_t OrderedDict<Key, Value>::size() const noexcept {
420  return items_.size();
421 }
422 
423 template <typename Key, typename Value>
424 bool OrderedDict<Key, Value>::is_empty() const noexcept {
425  return items_.empty();
426 }
427 
428 template <typename Key, typename Value>
429 const std::string& OrderedDict<Key, Value>::key_description() const noexcept {
430  return key_description_;
431 }
432 
433 template <typename Key, typename Value>
434 const std::vector<typename OrderedDict<Key, Value>::Item>& OrderedDict<
435  Key,
436  Value>::items() const noexcept {
437  return items_;
438 }
439 
440 template <typename Key, typename Value>
441 ::std::vector<Key> OrderedDict<Key, Value>::keys() const {
442  std::vector<Key> keys;
443  keys.reserve(size());
444  for (const auto& item : items_) {
445  keys.push_back(item.key());
446  }
447  return keys;
448 }
449 
450 template <typename Key, typename Value>
451 ::std::vector<Value> OrderedDict<Key, Value>::values() const {
452  std::vector<Value> values;
453  values.reserve(size());
454  for (const auto& item : items_) {
455  values.push_back(item.value());
456  }
457  return values;
458 }
459 
460 template <typename Key, typename Value>
461 ::std::vector<std::pair<Key, Value>> OrderedDict<Key, Value>::pairs() const {
462  std::vector<std::pair<Key, Value>> values;
463  values.reserve(size());
464  for (const auto& item : items_) {
465  values.push_back(item.pair());
466  }
467  return values;
468 }
469 
470 template <typename Key, typename Value>
471 void OrderedDict<Key, Value>::reserve(size_t requested_capacity) {
472  index_.reserve(requested_capacity);
473  items_.reserve(requested_capacity);
474 }
475 
476 } // namespace torch
Item(Key key, Value value)
Constructs a new item.
Definition: ordered_dict.h:189
Item & operator[](size_t index)
Returns the item at the index-th position in the OrderedDict.
Definition: ordered_dict.h:326
Value * operator->()
Allows access to the value using the arrow operator.
Definition: ordered_dict.h:202
::std::vector< Value > values() const
Returns a newly allocated vector and copies all values from this OrderedDict into the vector...
Definition: ordered_dict.h:451
size_t size() const noexcept
Returns the number of items currently stored in the OrderedDict.
Definition: ordered_dict.h:419
Iterator begin()
Returns an iterator to the first item in the OrderedDict.
Definition: ordered_dict.h:278
Iterator end()
Returns an iterator one past the last item in the OrderedDict.
Definition: ordered_dict.h:289
Value & insert(K &&key, V &&value)
Inserts a new (key, value) pair into the OrderedDict.
Definition: ordered_dict.h:357
Value & value() noexcept
Returns a reference to the value.
Definition: ordered_dict.h:217
Value * find(const Key &key) noexcept
Returns a pointer to the value associated with the given key, or a nullptr if no such key is stored i...
Definition: ordered_dict.h:390
bool contains(const Key &key) const noexcept
Returns true if the key is present in the OrderedDict.
Definition: ordered_dict.h:408
bool is_empty() const noexcept
Returns true if the OrderedDict contains no elements.
Definition: ordered_dict.h:424
const Value & value() const noexcept
Returns a reference to the value.
Definition: ordered_dict.h:222
const Key & key() const noexcept
Returns a reference to the key.
Definition: ordered_dict.h:212
void update(OrderedDict &&other)
Inserts all items from other into this OrderedDict.
Definition: ordered_dict.h:372
void reserve(size_t requested_capacity)
Resizes internal storage to fit at least requested_capacity items without requiring reallocation...
Definition: ordered_dict.h:471
const std::string & key_description() const noexcept
Returns the key description string the OrderedDict was constructed with.
Definition: ordered_dict.h:429
const Value & operator*() const
Returns a reference to the value.
Definition: ordered_dict.h:197
Item & back()
Returns the very last item in the OrderedDict and throws an exception if it is empty.
Definition: ordered_dict.h:313
Value & operator*()
Returns a reference to the value.
Definition: ordered_dict.h:192
::std::vector< std::pair< Key, Value > > pairs() const
Returns a newly allocated vector and copies all keys and values from this OrderedDict into a vector o...
Definition: ordered_dict.h:461
Definition: jit_type.h:17
OrderedDict & operator=(const OrderedDict &other)
Assigns items from other to this OrderedDict.
Definition: ordered_dict.h:254
const std::vector< Item > & items() const noexcept
Returns the items stored in the OrderedDict.
Definition: ordered_dict.h:436
::std::vector< Key > keys() const
Returns a newly allocated vector and copies all keys from this OrderedDict into the vector...
Definition: ordered_dict.h:441
const Value * operator->() const
Allows access to the value using the arrow operator.
Definition: ordered_dict.h:207
OrderedDict(std::string key_description="Key")
Constructs the OrderedDict with a short description of the kinds of keys stored in the OrderedDict...
Definition: ordered_dict.h:240
void clear()
Removes all items from this OrderedDict.
Definition: ordered_dict.h:413
An ordered dictionary implementation, akin to Python&#39;s OrderedDict.
Definition: ordered_dict.h:16
Item & front()
Returns the very first item in the OrderedDict and throws an exception if it is empty.
Definition: ordered_dict.h:300
const std::pair< const Key, Value > & pair() const noexcept
Returns a (key, value) pair.
Definition: ordered_dict.h:227