diff options
author | Devtools Arcadia <arcadia-devtools@yandex-team.ru> | 2022-02-07 18:08:42 +0300 |
---|---|---|
committer | Devtools Arcadia <arcadia-devtools@mous.vla.yp-c.yandex.net> | 2022-02-07 18:08:42 +0300 |
commit | 1110808a9d39d4b808aef724c861a2e1a38d2a69 (patch) | |
tree | e26c9fed0de5d9873cce7e00bc214573dc2195b7 /util/generic/guid.cpp | |
download | ydb-1110808a9d39d4b808aef724c861a2e1a38d2a69.tar.gz |
intermediate changes
ref:cde9a383711a11544ce7e107a78147fb96cc4029
Diffstat (limited to 'util/generic/guid.cpp')
-rw-r--r-- | util/generic/guid.cpp | 186 |
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(); +} |