Amit Hilbuch | c63ddb2 | 2019-01-02 18:13:58 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2018 The WebRTC project authors. All Rights Reserved. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license |
| 5 | * that can be found in the LICENSE file in the root of the source |
| 6 | * tree. An additional intellectual property rights grant can be found |
| 7 | * in the file PATENTS. All contributing project authors may |
| 8 | * be found in the AUTHORS file in the root of the source tree. |
| 9 | */ |
| 10 | |
Amit Hilbuch | dbb49df | 2019-01-23 22:54:24 | [diff] [blame] | 11 | #ifndef RTC_BASE_UNIQUE_ID_GENERATOR_H_ |
| 12 | #define RTC_BASE_UNIQUE_ID_GENERATOR_H_ |
Amit Hilbuch | c63ddb2 | 2019-01-02 18:13:58 | [diff] [blame] | 13 | |
| 14 | #include <limits> |
| 15 | #include <set> |
| 16 | #include <string> |
| 17 | |
| 18 | #include "api/array_view.h" |
Tomas Gunnarsson | 64099bc | 2021-04-09 07:51:37 | [diff] [blame] | 19 | #include "api/sequence_checker.h" |
| 20 | #include "rtc_base/synchronization/mutex.h" |
| 21 | #include "rtc_base/system/no_unique_address.h" |
Amit Hilbuch | c63ddb2 | 2019-01-02 18:13:58 | [diff] [blame] | 22 | |
Amit Hilbuch | dbb49df | 2019-01-23 22:54:24 | [diff] [blame] | 23 | namespace rtc { |
Amit Hilbuch | c63ddb2 | 2019-01-02 18:13:58 | [diff] [blame] | 24 | |
| 25 | // This class will generate numbers. A common use case is for identifiers. |
| 26 | // The generated numbers will be unique, in the local scope of the generator. |
| 27 | // This means that a generator will never generate the same number twice. |
| 28 | // The generator can also be initialized with a sequence of known ids. |
| 29 | // In such a case, it will never generate an id from that list. |
| 30 | // Recommendedations: |
| 31 | // * Prefer unsigned types. |
| 32 | // * Prefer larger types (uint8_t will run out quickly). |
| 33 | template <typename TIntegral> |
| 34 | class UniqueNumberGenerator { |
| 35 | public: |
| 36 | typedef TIntegral value_type; |
| 37 | UniqueNumberGenerator(); |
| 38 | // Creates a generator that will never return any value from the given list. |
Amit Hilbuch | dbb49df | 2019-01-23 22:54:24 | [diff] [blame] | 39 | explicit UniqueNumberGenerator(ArrayView<TIntegral> known_ids); |
Amit Hilbuch | c63ddb2 | 2019-01-02 18:13:58 | [diff] [blame] | 40 | ~UniqueNumberGenerator(); |
| 41 | |
| 42 | // Generates a number that this generator has never produced before. |
| 43 | // If there are no available numbers to generate, this method will fail |
Artem Titov | 96e3b99 | 2021-07-26 14:03:14 | [diff] [blame] | 44 | // with an `RTC_CHECK`. |
Amit Hilbuch | c63ddb2 | 2019-01-02 18:13:58 | [diff] [blame] | 45 | TIntegral GenerateNumber(); |
| 46 | TIntegral operator()() { return GenerateNumber(); } |
| 47 | |
Amit Hilbuch | ae3df54 | 2019-01-07 20:13:08 | [diff] [blame] | 48 | // Adds an id that this generator should no longer generate. |
Elad Alon | efc9a14 | 2019-02-08 22:35:59 | [diff] [blame] | 49 | // Return value indicates whether the ID was hitherto unknown. |
| 50 | bool AddKnownId(TIntegral value); |
Amit Hilbuch | ae3df54 | 2019-01-07 20:13:08 | [diff] [blame] | 51 | |
Amit Hilbuch | c63ddb2 | 2019-01-02 18:13:58 | [diff] [blame] | 52 | private: |
Tomas Gunnarsson | 64099bc | 2021-04-09 07:51:37 | [diff] [blame] | 53 | RTC_NO_UNIQUE_ADDRESS webrtc::SequenceChecker sequence_checker_; |
Amit Hilbuch | c63ddb2 | 2019-01-02 18:13:58 | [diff] [blame] | 54 | static_assert(std::is_integral<TIntegral>::value, "Must be integral type."); |
Tomas Gunnarsson | 64099bc | 2021-04-09 07:51:37 | [diff] [blame] | 55 | TIntegral counter_ RTC_GUARDED_BY(sequence_checker_); |
| 56 | std::set<TIntegral> known_ids_ RTC_GUARDED_BY(sequence_checker_); |
Amit Hilbuch | c63ddb2 | 2019-01-02 18:13:58 | [diff] [blame] | 57 | }; |
| 58 | |
| 59 | // This class will generate unique ids. Ids are 32 bit unsigned integers. |
| 60 | // The generated ids will be unique, in the local scope of the generator. |
| 61 | // This means that a generator will never generate the same id twice. |
| 62 | // The generator can also be initialized with a sequence of known ids. |
| 63 | // In such a case, it will never generate an id from that list. |
| 64 | class UniqueRandomIdGenerator { |
| 65 | public: |
| 66 | typedef uint32_t value_type; |
| 67 | UniqueRandomIdGenerator(); |
| 68 | // Create a generator that will never return any value from the given list. |
Amit Hilbuch | dbb49df | 2019-01-23 22:54:24 | [diff] [blame] | 69 | explicit UniqueRandomIdGenerator(ArrayView<uint32_t> known_ids); |
Amit Hilbuch | c63ddb2 | 2019-01-02 18:13:58 | [diff] [blame] | 70 | ~UniqueRandomIdGenerator(); |
| 71 | |
| 72 | // Generates a random id that this generator has never produced before. |
| 73 | // This method becomes more expensive with each use, as the probability of |
| 74 | // collision for the randomly generated numbers increases. |
| 75 | uint32_t GenerateId(); |
| 76 | uint32_t operator()() { return GenerateId(); } |
| 77 | |
Amit Hilbuch | ae3df54 | 2019-01-07 20:13:08 | [diff] [blame] | 78 | // Adds an id that this generator should no longer generate. |
Elad Alon | efc9a14 | 2019-02-08 22:35:59 | [diff] [blame] | 79 | // Return value indicates whether the ID was hitherto unknown. |
| 80 | bool AddKnownId(uint32_t value); |
Amit Hilbuch | ae3df54 | 2019-01-07 20:13:08 | [diff] [blame] | 81 | |
Amit Hilbuch | c63ddb2 | 2019-01-02 18:13:58 | [diff] [blame] | 82 | private: |
Tomas Gunnarsson | 64099bc | 2021-04-09 07:51:37 | [diff] [blame] | 83 | // TODO(bugs.webrtc.org/12666): This lock is needed due to an instance in |
| 84 | // SdpOfferAnswerHandler being shared between threads. |
| 85 | webrtc::Mutex mutex_; |
| 86 | std::set<uint32_t> known_ids_ RTC_GUARDED_BY(&mutex_); |
Amit Hilbuch | c63ddb2 | 2019-01-02 18:13:58 | [diff] [blame] | 87 | }; |
| 88 | |
| 89 | // This class will generate strings. A common use case is for identifiers. |
| 90 | // The generated strings will be unique, in the local scope of the generator. |
| 91 | // This means that a generator will never generate the same string twice. |
| 92 | // The generator can also be initialized with a sequence of known ids. |
| 93 | // In such a case, it will never generate an id from that list. |
| 94 | class UniqueStringGenerator { |
| 95 | public: |
| 96 | typedef std::string value_type; |
| 97 | UniqueStringGenerator(); |
Amit Hilbuch | dbb49df | 2019-01-23 22:54:24 | [diff] [blame] | 98 | explicit UniqueStringGenerator(ArrayView<std::string> known_ids); |
Amit Hilbuch | c63ddb2 | 2019-01-02 18:13:58 | [diff] [blame] | 99 | ~UniqueStringGenerator(); |
| 100 | |
| 101 | std::string GenerateString(); |
| 102 | std::string operator()() { return GenerateString(); } |
| 103 | |
Amit Hilbuch | ae3df54 | 2019-01-07 20:13:08 | [diff] [blame] | 104 | // Adds an id that this generator should no longer generate. |
Elad Alon | efc9a14 | 2019-02-08 22:35:59 | [diff] [blame] | 105 | // Return value indicates whether the ID was hitherto unknown. |
| 106 | bool AddKnownId(const std::string& value); |
Amit Hilbuch | ae3df54 | 2019-01-07 20:13:08 | [diff] [blame] | 107 | |
Amit Hilbuch | c63ddb2 | 2019-01-02 18:13:58 | [diff] [blame] | 108 | private: |
| 109 | // This implementation will be simple and will generate "0", "1", ... |
| 110 | UniqueNumberGenerator<uint32_t> unique_number_generator_; |
| 111 | }; |
| 112 | |
| 113 | template <typename TIntegral> |
Tomas Gunnarsson | 64099bc | 2021-04-09 07:51:37 | [diff] [blame] | 114 | UniqueNumberGenerator<TIntegral>::UniqueNumberGenerator() : counter_(0) { |
| 115 | sequence_checker_.Detach(); |
| 116 | } |
Amit Hilbuch | c63ddb2 | 2019-01-02 18:13:58 | [diff] [blame] | 117 | |
| 118 | template <typename TIntegral> |
| 119 | UniqueNumberGenerator<TIntegral>::UniqueNumberGenerator( |
Amit Hilbuch | dbb49df | 2019-01-23 22:54:24 | [diff] [blame] | 120 | ArrayView<TIntegral> known_ids) |
Tomas Gunnarsson | 64099bc | 2021-04-09 07:51:37 | [diff] [blame] | 121 | : counter_(0), known_ids_(known_ids.begin(), known_ids.end()) { |
| 122 | sequence_checker_.Detach(); |
| 123 | } |
Amit Hilbuch | c63ddb2 | 2019-01-02 18:13:58 | [diff] [blame] | 124 | |
| 125 | template <typename TIntegral> |
| 126 | UniqueNumberGenerator<TIntegral>::~UniqueNumberGenerator() {} |
| 127 | |
| 128 | template <typename TIntegral> |
| 129 | TIntegral UniqueNumberGenerator<TIntegral>::GenerateNumber() { |
Tomas Gunnarsson | 64099bc | 2021-04-09 07:51:37 | [diff] [blame] | 130 | RTC_DCHECK_RUN_ON(&sequence_checker_); |
Amit Hilbuch | c63ddb2 | 2019-01-02 18:13:58 | [diff] [blame] | 131 | while (true) { |
| 132 | RTC_CHECK_LT(counter_, std::numeric_limits<TIntegral>::max()); |
| 133 | auto pair = known_ids_.insert(counter_++); |
| 134 | if (pair.second) { |
| 135 | return *pair.first; |
| 136 | } |
| 137 | } |
| 138 | } |
| 139 | |
Amit Hilbuch | ae3df54 | 2019-01-07 20:13:08 | [diff] [blame] | 140 | template <typename TIntegral> |
Elad Alon | efc9a14 | 2019-02-08 22:35:59 | [diff] [blame] | 141 | bool UniqueNumberGenerator<TIntegral>::AddKnownId(TIntegral value) { |
Tomas Gunnarsson | 64099bc | 2021-04-09 07:51:37 | [diff] [blame] | 142 | RTC_DCHECK_RUN_ON(&sequence_checker_); |
Elad Alon | efc9a14 | 2019-02-08 22:35:59 | [diff] [blame] | 143 | return known_ids_.insert(value).second; |
Amit Hilbuch | ae3df54 | 2019-01-07 20:13:08 | [diff] [blame] | 144 | } |
Amit Hilbuch | dbb49df | 2019-01-23 22:54:24 | [diff] [blame] | 145 | } // namespace rtc |
Amit Hilbuch | c63ddb2 | 2019-01-02 18:13:58 | [diff] [blame] | 146 | |
Amit Hilbuch | dbb49df | 2019-01-23 22:54:24 | [diff] [blame] | 147 | #endif // RTC_BASE_UNIQUE_ID_GENERATOR_H_ |