| // Copyright 2026 Google LLC | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // https://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| // | |
| // A Uuid is an identifier, that is unique over all space and time. The default | |
| // implementation is based on UUID (DCE version), which uses the Ethernet MAC | |
| // address of the machine, and a timestamp (which we replace with a sequence | |
| // number). | |
| // | |
| // http://en.wikipedia.org/wiki/Universally_unique_identifier | |
| // http://tools.ietf.org/html/rfc4122.html | |
| // | |
| // The reason to use DCE is that it is based on the physical | |
| // address, which may aid debugging. | |
| #ifndef THIRD_PARTY_CREDENTIO_UUID_UUID_H_ | |
| #define THIRD_PARTY_CREDENTIO_UUID_UUID_H_ | |
| #include <cstdint> | |
| #include <ostream> | |
| #include <string> | |
| #include "absl/log/check.h" | |
| #include "absl/numeric/int128.h" | |
| #include "absl/status/statusor.h" | |
| #include "absl/strings/string_view.h" | |
| namespace credentio { | |
| // Uuid is the type of unique identifiers. | |
| class Uuid { | |
| public: | |
| // In addition to the following constructors, the default copy constructor and | |
| // assignment operator are also allowed. | |
| // Uuids are not POD, because the default constructor initializes them to | |
| // kInvalid. However, the Google Style Guide allows static Uuid constants | |
| // because Uuid constructors are all constexpr, and the type has no | |
| // destructors. | |
| constexpr Uuid() : high_(0), low_(InvalidMinLo()) {} // equal to kInvalid | |
| explicit constexpr Uuid(uint64_t low) : high_(0), low_(low) {} | |
| constexpr Uuid(uint64_t high, uint64_t low) : high_(high), low_(low) {} | |
| constexpr explicit Uuid(absl::uint128 raw) | |
| : Uuid(absl::Uint128High64(raw), absl::Uint128Low64(raw)) {} | |
| bool IsValid() const; | |
| // Conversion to/from the ASCII form xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. The | |
| // format uses the following ABNF, where each numerical component is | |
| // represented in hex, with leading zeros (although the FromString variants | |
| // will accept input without leading zeros). The 'x's above show the maximum | |
| // length of each of those components. | |
| // | |
| // UUID = time-low "-" time-mid "-" time-high-and-version "-" | |
| // clock-seq-and-reserved clock-seq-low "-" node | |
| // | |
| // FromString returns INVALID_ARGUMENT, and FromStringOrDie CHECK-fails if | |
| // there is a syntax error. | |
| std::string ToString() const; | |
| static absl::StatusOr<Uuid> FromString(absl::string_view s); | |
| static constexpr Uuid FromStringOrDie(absl::string_view s) { | |
| Uuid uuid; | |
| CHECK(Uuid::ParseFromString(s, &uuid)) | |
| << "Syntax error: string '" << s << "' is not a Uuid"; | |
| return uuid; | |
| } | |
| absl::uint128 ToRawNumber() const { return absl::MakeUint128(high_, low_); } | |
| uint64_t high64() const { return high_; } | |
| uint64_t low64() const { return low_; } | |
| // Conversion to/from 16-byte binary strings. Layout and byte order | |
| // are specified by RFC 4122. | |
| std::string ToProtoBytes() const; | |
| void ToProtoBytes(std::string* s) const; | |
| // Convert proto string to Uuid. Returns INVALID_ARGUMENT if the Uuid could | |
| // not be parsed correctly. | |
| static absl::StatusOr<Uuid> FromProtoBytes(absl::string_view bytes); | |
| // Canonical Uuids | |
| static const Uuid kInvalid; // Represents errors. | |
| static constexpr absl::string_view kInvalidRepr = | |
| "Uid::kInvalid"; // String representation of kInvalid. | |
| // We reserve 999 in invalid Uuids (in addition to kInvalid) that can be | |
| // used as special sentinel values that will be different from any id returned | |
| // by a Uuid generator. Magic values can be declared as static compile-time | |
| // constants. | |
| template <uint64_t k> | |
| static constexpr Uuid Magic() { | |
| static_assert(k < ValidMinLo(), "Argument too large"); | |
| static_assert(k > InvalidMinLo(), "Argument too small"); | |
| return Uuid(k); | |
| } | |
| bool IsMagic() const; | |
| // Range of valid Uuids | |
| static const Uuid kValidMin; | |
| static const Uuid kValidMax; | |
| template <typename H> | |
| friend H AbslHashValue(H h, const Uuid& uuid) { | |
| return H::combine(std::move(h), uuid.high_, uuid.low_); | |
| } | |
| private: | |
| // Underlying parsing function for ASCII form conversions. | |
| static constexpr bool ParseFromString(absl::string_view s, Uuid* uuid) { | |
| auto consume_hex = [](int max_chars, absl::string_view* input, | |
| uint64_t* res) { | |
| *res = 0; | |
| int count = 0; | |
| while (count < max_chars && !input->empty()) { | |
| char c = input->front(); | |
| uint32_t v = 0; | |
| if (c >= '0' && c <= '9') { | |
| v = c - '0'; | |
| } else if (c >= 'a' && c <= 'f') { | |
| v = c - 'a' + 10; | |
| } else if (c >= 'A' && c <= 'F') { | |
| v = c - 'A' + 10; | |
| } else { | |
| break; | |
| } | |
| *res = (*res << 4) + v; | |
| input->remove_prefix(1); | |
| ++count; | |
| } | |
| return count > 0; | |
| }; | |
| auto consume_char = [](char check_char, absl::string_view* input) { | |
| if (input->empty() || input->front() != check_char) return false; | |
| input->remove_prefix(1); | |
| return true; | |
| }; | |
| if (s == kInvalidRepr) { | |
| // Equal to kInvalid (canonical value cannot be used here due to constexpr | |
| // restrictions). | |
| *uuid = Uuid(); | |
| return true; | |
| } | |
| absl::string_view input(s); | |
| uint64_t time_low = 0, time_mid = 0, time_high = 0, sequence = 0, node = 0; | |
| bool valid = true; | |
| valid &= consume_hex(8, &input, &time_low); | |
| valid &= consume_char('-', &input); | |
| valid &= consume_hex(4, &input, &time_mid); | |
| valid &= consume_char('-', &input); | |
| valid &= consume_hex(4, &input, &time_high); | |
| valid &= consume_char('-', &input); | |
| valid &= consume_hex(4, &input, &sequence); | |
| valid &= consume_char('-', &input); | |
| valid &= consume_hex(12, &input, &node); | |
| valid &= input.empty(); | |
| if (!valid) { | |
| return false; | |
| } | |
| const uint64_t high64 = | |
| ((node & 0xffffffffffffULL) << 16) | (sequence & 0xffffULL); | |
| const uint64_t low64 = ((time_high & 0xffffULL) << 48) | | |
| ((time_mid & 0xffffULL) << 32) | | |
| (time_low & 0xffffffffULL); | |
| *uuid = Uuid(high64, low64); | |
| return true; | |
| } | |
| // We reserve the node 00:00:00:00:00:00, time [0, 999] for invalid | |
| // Uuids (constants) | |
| static constexpr uint64_t ValidMinLo() { return 1000; } | |
| static constexpr uint64_t InvalidMinLo() { return 0; } | |
| uint64_t high_{0}; | |
| uint64_t low_{0}; | |
| }; | |
| // Comparison operators. | |
| inline bool operator==(Uuid a, Uuid b) { | |
| return a.high64() == b.high64() && a.low64() == b.low64(); | |
| } | |
| inline bool operator!=(Uuid a, Uuid b) { return !(a == b); } | |
| inline bool operator<(Uuid a, Uuid b) { | |
| return a.high64() < b.high64() || | |
| (a.high64() == b.high64() && a.low64() < b.low64()); | |
| } | |
| inline bool operator<=(Uuid a, Uuid b) { | |
| return a.high64() < b.high64() || | |
| (a.high64() == b.high64() && a.low64() <= b.low64()); | |
| } | |
| // Formatting. | |
| inline std::ostream& operator<<(std::ostream& o, Uuid id) { | |
| return o << id.ToString(); | |
| } | |
| class UuidGenerator { | |
| public: | |
| virtual ~UuidGenerator() = default; | |
| virtual Uuid Generate() const = 0; | |
| // Generates a V4 UUID as documented in | |
| // https://tools.ietf.org/html/rfc4122#section-4.4 | |
| static const UuidGenerator& Default(); | |
| }; | |
| } // namespace credentio | |
| #endif // THIRD_PARTY_CREDENTIO_UUID_UUID_H_ |