ContinuousRangeMap.h 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. #pragma once
  2. #ifdef __GNUC__
  3. #pragma GCC diagnostic push
  4. #pragma GCC diagnostic ignored "-Wunused-parameter"
  5. #endif
  6. //===- ContinuousRangeMap.h - Map with int range as key ---------*- C++ -*-===//
  7. //
  8. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  9. // See https://llvm.org/LICENSE.txt for license information.
  10. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  11. //
  12. //===----------------------------------------------------------------------===//
  13. //
  14. // This file defines the ContinuousRangeMap class, which is a highly
  15. // specialized container used by serialization.
  16. //
  17. //===----------------------------------------------------------------------===//
  18. #ifndef LLVM_CLANG_SERIALIZATION_CONTINUOUSRANGEMAP_H
  19. #define LLVM_CLANG_SERIALIZATION_CONTINUOUSRANGEMAP_H
  20. #include "clang/Basic/LLVM.h"
  21. #include "llvm/ADT/STLExtras.h"
  22. #include "llvm/ADT/SmallVector.h"
  23. #include <algorithm>
  24. #include <cassert>
  25. #include <utility>
  26. namespace clang {
  27. /// A map from continuous integer ranges to some value, with a very
  28. /// specialized interface.
  29. ///
  30. /// CRM maps from integer ranges to values. The ranges are continuous, i.e.
  31. /// where one ends, the next one begins. So if the map contains the stops I0-3,
  32. /// the first range is from I0 to I1, the second from I1 to I2, the third from
  33. /// I2 to I3 and the last from I3 to infinity.
  34. ///
  35. /// Ranges must be inserted in order. Inserting a new stop I4 into the map will
  36. /// shrink the fourth range to I3 to I4 and add the new range I4 to inf.
  37. template <typename Int, typename V, unsigned InitialCapacity>
  38. class ContinuousRangeMap {
  39. public:
  40. using value_type = std::pair<Int, V>;
  41. using reference = value_type &;
  42. using const_reference = const value_type &;
  43. using pointer = value_type *;
  44. using const_pointer = const value_type *;
  45. private:
  46. using Representation = SmallVector<value_type, InitialCapacity>;
  47. Representation Rep;
  48. struct Compare {
  49. bool operator ()(const_reference L, Int R) const {
  50. return L.first < R;
  51. }
  52. bool operator ()(Int L, const_reference R) const {
  53. return L < R.first;
  54. }
  55. bool operator ()(Int L, Int R) const {
  56. return L < R;
  57. }
  58. bool operator ()(const_reference L, const_reference R) const {
  59. return L.first < R.first;
  60. }
  61. };
  62. public:
  63. void insert(const value_type &Val) {
  64. if (!Rep.empty() && Rep.back() == Val)
  65. return;
  66. assert((Rep.empty() || Rep.back().first < Val.first) &&
  67. "Must insert keys in order.");
  68. Rep.push_back(Val);
  69. }
  70. void insertOrReplace(const value_type &Val) {
  71. iterator I = llvm::lower_bound(Rep, Val, Compare());
  72. if (I != Rep.end() && I->first == Val.first) {
  73. I->second = Val.second;
  74. return;
  75. }
  76. Rep.insert(I, Val);
  77. }
  78. using iterator = typename Representation::iterator;
  79. using const_iterator = typename Representation::const_iterator;
  80. iterator begin() { return Rep.begin(); }
  81. iterator end() { return Rep.end(); }
  82. const_iterator begin() const { return Rep.begin(); }
  83. const_iterator end() const { return Rep.end(); }
  84. iterator find(Int K) {
  85. iterator I = llvm::upper_bound(Rep, K, Compare());
  86. // I points to the first entry with a key > K, which is the range that
  87. // follows the one containing K.
  88. if (I == Rep.begin())
  89. return Rep.end();
  90. --I;
  91. return I;
  92. }
  93. const_iterator find(Int K) const {
  94. return const_cast<ContinuousRangeMap*>(this)->find(K);
  95. }
  96. reference back() { return Rep.back(); }
  97. const_reference back() const { return Rep.back(); }
  98. /// An object that helps properly build a continuous range map
  99. /// from a set of values.
  100. class Builder {
  101. ContinuousRangeMap &Self;
  102. public:
  103. explicit Builder(ContinuousRangeMap &Self) : Self(Self) {}
  104. Builder(const Builder&) = delete;
  105. Builder &operator=(const Builder&) = delete;
  106. ~Builder() {
  107. llvm::sort(Self.Rep, Compare());
  108. Self.Rep.erase(
  109. std::unique(
  110. Self.Rep.begin(), Self.Rep.end(),
  111. [](const_reference A, const_reference B) {
  112. // FIXME: we should not allow any duplicate keys, but there are
  113. // a lot of duplicate 0 -> 0 mappings to remove first.
  114. assert((A == B || A.first != B.first) &&
  115. "ContinuousRangeMap::Builder given non-unique keys");
  116. return A == B;
  117. }),
  118. Self.Rep.end());
  119. }
  120. void insert(const value_type &Val) {
  121. Self.Rep.push_back(Val);
  122. }
  123. };
  124. friend class Builder;
  125. };
  126. } // namespace clang
  127. #endif // LLVM_CLANG_SERIALIZATION_CONTINUOUSRANGEMAP_H
  128. #ifdef __GNUC__
  129. #pragma GCC diagnostic pop
  130. #endif