aboutsummaryrefslogtreecommitdiffstats
path: root/util/generic/guid.cpp
diff options
context:
space:
mode:
authorDevtools Arcadia <arcadia-devtools@yandex-team.ru>2022-02-07 18:08:42 +0300
committerDevtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net>2022-02-07 18:08:42 +0300
commit1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch)
treee26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/generic/guid.cpp
downloadydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/generic/guid.cpp')
-rw-r--r--util/generic/guid.cpp186
1 files changed, 186 insertions, 0 deletions
diff --git a/util/generic/guid.cpp b/util/generic/guid.cpp
new file mode 100644
index 0000000000..8b907457bc
--- /dev/null
+++ b/util/generic/guid.cpp
@@ -0,0 +1,186 @@
+#include "guid.h"
+#include "ylimits.h"
+#include "string.h"
+
+#include <util/string/ascii.h>
+#include <util/string/builder.h>
+#include <util/stream/format.h>
+#include <util/system/unaligned_mem.h>
+#include <util/random/easy.h>
+
+namespace {
+ inline void LowerCaseHex(TString& s) {
+ for (auto&& c : s) {
+ c = AsciiToLower(c);
+ }
+ }
+}
+
+TString TGUID::AsGuidString() const {
+ TStringBuilder s;
+ s.reserve(50);
+ s << Hex(dw[0], 0) << '-' << Hex(dw[1], 0) << '-' << Hex(dw[2], 0) << '-' << Hex(dw[3], 0);
+ LowerCaseHex(s);
+ return std::move(s);
+}
+
+TString TGUID::AsUuidString() const {
+ TStringBuilder s;
+ s.reserve(50);
+ s << Hex(dw[0], HF_FULL) << '-';
+ s << Hex(static_cast<ui16>(dw[1] >> 16), HF_FULL) << '-' << Hex(static_cast<ui16>(dw[1]), HF_FULL) << '-';
+ s << Hex(static_cast<ui16>(dw[2] >> 16), HF_FULL) << '-' << Hex(static_cast<ui16>(dw[2]), HF_FULL);
+ s << Hex(dw[3], HF_FULL);
+ LowerCaseHex(s);
+ return std::move(s);
+}
+
+TGUID TGUID::Create() {
+ TGUID result;
+ CreateGuid(&result);
+ return result;
+}
+
+void CreateGuid(TGUID* res) {
+ ui64* dw = reinterpret_cast<ui64*>(res->dw);
+
+ WriteUnaligned<ui64>(&dw[0], RandomNumber<ui64>());
+ WriteUnaligned<ui64>(&dw[1], RandomNumber<ui64>());
+}
+
+TGUID TGUID::CreateTimebased() {
+ TGUID result;
+ // GUID_EPOCH_OFFSET is the number of 100-ns intervals between the
+ // UUID epoch 1582-10-15 00:00:00 and the Unix epoch 1970-01-01 00:00:00.
+ constexpr ui64 GUID_EPOCH_OFFSET = 0x01b21dd213814000;
+ const ui64 timestamp = Now().NanoSeconds() / 100 + GUID_EPOCH_OFFSET;
+ result.dw[0] = ui32(timestamp & 0xffffffff); // time low
+ const ui32 timeMid = ui32((timestamp >> 32) & 0xffff);
+ constexpr ui32 UUID_VERSION = 1;
+ const ui32 timeHighAndVersion = ui16((timestamp >> 48) & 0x0fff) | (UUID_VERSION << 12);
+ result.dw[1] = (timeMid << 16) | timeHighAndVersion;
+ const ui32 clockSeq = RandomNumber<ui32>(0x3fff) | 0x8000;
+ result.dw[2] = (clockSeq << 16) | RandomNumber<ui16>();
+ result.dw[3] = RandomNumber<ui32>() | (1 << 24);
+ return result;
+}
+
+TString GetGuidAsString(const TGUID& g) {
+ return g.AsGuidString();
+}
+
+TString CreateGuidAsString() {
+ return TGUID::Create().AsGuidString();
+}
+
+static bool GetDigit(const char c, ui32& digit) {
+ digit = 0;
+ if ('0' <= c && c <= '9') {
+ digit = c - '0';
+ } else if ('a' <= c && c <= 'f') {
+ digit = c - 'a' + 10;
+ } else if ('A' <= c && c <= 'F') {
+ digit = c - 'A' + 10;
+ } else {
+ return false; // non-hex character
+ }
+ return true;
+}
+
+bool GetGuid(const TStringBuf s, TGUID& result) {
+ size_t partId = 0;
+ ui64 partValue = 0;
+ bool isEmptyPart = true;
+
+ for (size_t i = 0; i != s.size(); ++i) {
+ const char c = s[i];
+
+ if (c == '-') {
+ if (isEmptyPart || partId == 3) { // x-y--z, -x-y-z or x-y-z-m-...
+ return false;
+ }
+ result.dw[partId] = static_cast<ui32>(partValue);
+ ++partId;
+ partValue = 0;
+ isEmptyPart = true;
+ continue;
+ }
+
+ ui32 digit = 0;
+ if (!GetDigit(c, digit)) {
+ return false;
+ }
+
+ partValue = partValue * 16 + digit;
+ isEmptyPart = false;
+
+ // overflow check
+ if (partValue > Max<ui32>()) {
+ return false;
+ }
+ }
+
+ if (partId != 3 || isEmptyPart) { // x-y or x-y-z-
+ return false;
+ }
+ result.dw[partId] = static_cast<ui32>(partValue);
+ return true;
+}
+
+// Parses GUID from s and checks that it's valid.
+// In case of error returns TGUID().
+TGUID GetGuid(const TStringBuf s) {
+ TGUID result;
+
+ if (GetGuid(s, result)) {
+ return result;
+ }
+
+ return TGUID();
+}
+
+bool GetUuid(const TStringBuf s, TGUID& result) {
+ if (s.size() != 36) {
+ return false;
+ }
+
+ size_t partId = 0;
+ ui64 partValue = 0;
+ size_t digitCount = 0;
+
+ for (size_t i = 0; i < s.size(); ++i) {
+ const char c = s[i];
+
+ if (c == '-') {
+ if (i != 8 && i != 13 && i != 18 && i != 23) {
+ return false;
+ }
+ continue;
+ }
+
+ ui32 digit = 0;
+ if (!GetDigit(c, digit)) {
+ return false;
+ }
+
+ partValue = partValue * 16 + digit;
+
+ if (++digitCount == 8) {
+ result.dw[partId++] = partValue;
+ digitCount = 0;
+ }
+ }
+ return true;
+}
+
+// Parses GUID from uuid and checks that it's valid.
+// In case of error returns TGUID().
+TGUID GetUuid(const TStringBuf s) {
+ TGUID result;
+
+ if (GetUuid(s, result)) {
+ return result;
+ }
+
+ return TGUID();
+}