From 0c73ac5fea0e1e14a890fec4e3826120a88b2b00 Mon Sep 17 00:00:00 2001 From: Arsentiy Milchakov Date: Wed, 27 May 2020 12:00:53 +0300 Subject: [PATCH] [base] id generator is added --- base/CMakeLists.txt | 1 + base/base_tests/CMakeLists.txt | 1 + base/base_tests/id_generator_tests.cpp | 33 ++++++++++++ base/id_generator.hpp | 69 ++++++++++++++++++++++++++ 4 files changed, 104 insertions(+) create mode 100644 base/base_tests/id_generator_tests.cpp create mode 100644 base/id_generator.hpp diff --git a/base/CMakeLists.txt b/base/CMakeLists.txt index 53856cdc92..bfbacb116e 100644 --- a/base/CMakeLists.txt +++ b/base/CMakeLists.txt @@ -33,6 +33,7 @@ set( get_time.hpp gmtime.cpp gmtime.hpp + id_generator.hpp internal/message.cpp internal/message.hpp levenshtein_dfa.cpp diff --git a/base/base_tests/CMakeLists.txt b/base/base_tests/CMakeLists.txt index f3d7bdd061..072d3f7849 100644 --- a/base/base_tests/CMakeLists.txt +++ b/base/base_tests/CMakeLists.txt @@ -17,6 +17,7 @@ set( condition_test.cpp containers_test.cpp control_flow_tests.cpp + id_generator_tests.cpp fifo_cache_test.cpp file_name_utils_tests.cpp geo_object_id_tests.cpp diff --git a/base/base_tests/id_generator_tests.cpp b/base/base_tests/id_generator_tests.cpp new file mode 100644 index 0000000000..e557dcc84e --- /dev/null +++ b/base/base_tests/id_generator_tests.cpp @@ -0,0 +1,33 @@ +#include "testing/testing.hpp" + +#include "base/id_generator.hpp" + +#include +#include +#include + +UNIT_TEST(IdGenerator_Smoke) +{ + auto const initial = base::IdGenerator::GetInitialId(); + TEST_EQUAL(initial, "1", ()); + + auto constexpr kOverflowCount = 5; + auto constexpr kItemsCount = std::numeric_limits::max(); + + auto id = initial; + auto i = 2; + for (auto k = 0; k < kOverflowCount; ++k) + { + for (; i <= kItemsCount; ++i) + { + std::string target; + for (auto j = 0; j < k; ++j) + target += std::to_string(kItemsCount); + + target += std::to_string(i); + id = base::IdGenerator::GetNextId(id); + TEST_EQUAL(target, id, ()); + } + i = 1; + } +} diff --git a/base/id_generator.hpp b/base/id_generator.hpp new file mode 100644 index 0000000000..7043868198 --- /dev/null +++ b/base/id_generator.hpp @@ -0,0 +1,69 @@ +#pragma once + +#include "base/string_utils.hpp" + +#include +#include +#include + +namespace base +{ +// Simple id generator which increments received value and concatenates when +// BaseIntegralUnsigned max value is reached. +template +class IdGenerator +{ +public: + static_assert(std::is_integral::value, "Integral types is supported only"); + static_assert(std::is_unsigned::value, "Unsigned types is supported only"); + + using Id = std::string; + + static Id GetInitialId() + { + return std::to_string(kMinIdInternal); + } + + static Id GetNextId(Id const & id) + { + std::vector idParts; + auto first = id.begin(); + auto last = id.end(); + while (last - first > kMaxSymbolsIdInternal) + { + idParts.emplace_back(first, first + kMaxSymbolsIdInternal); + first += kMaxSymbolsIdInternal; + } + idParts.emplace_back(first, last); + + IdInternal internalId; + if (!strings::to_any(idParts.back(), internalId)) + return {}; + + auto const newId = MakeNextInternalId(internalId); + + if (newId < internalId) + idParts.emplace_back(std::to_string(newId)); + else + idParts.back() = std::to_string(newId); + + return strings::JoinAny(idParts, ""); + } + +private: + using IdInternal = BaseIntegralUnsigned; + + static IdInternal constexpr kIncorrectId = 0; + static IdInternal constexpr kMinIdInternal = 1; + static IdInternal constexpr kMaxIdInternal = std::numeric_limits::max(); + static auto constexpr kMaxSymbolsIdInternal = std::numeric_limits::digits10 + 1; + + static constexpr IdInternal MakeNextInternalId(IdInternal id) + { + if (id == kMaxIdInternal) + return kMinIdInternal; + + return ++id; + } +}; +} // namespace base