diff options
author | Maxim Yurchuk <maxim-yurchuk@ydb.tech> | 2024-11-20 17:37:57 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-11-20 17:37:57 +0000 |
commit | f76323e9b295c15751e51e3443aa47a36bee8023 (patch) | |
tree | 4113c8cad473a33e0f746966e0cf087252fa1d7a /library/cpp/yt/string/format_analyser.h | |
parent | 753ecb8d410a4cb459c26f3a0082fb2d1724fe63 (diff) | |
parent | a7b9a6afea2a9d7a7bfac4c5eb4c1a8e60adb9e6 (diff) | |
download | ydb-f76323e9b295c15751e51e3443aa47a36bee8023.tar.gz |
Merge pull request #11788 from ydb-platform/mergelibs-241120-1113
Library import 241120-1113
Diffstat (limited to 'library/cpp/yt/string/format_analyser.h')
-rw-r--r-- | library/cpp/yt/string/format_analyser.h | 42 |
1 files changed, 33 insertions, 9 deletions
diff --git a/library/cpp/yt/string/format_analyser.h b/library/cpp/yt/string/format_analyser.h index 20eee60580..9f194144dc 100644 --- a/library/cpp/yt/string/format_analyser.h +++ b/library/cpp/yt/string/format_analyser.h @@ -4,6 +4,7 @@ #include <util/generic/strbuf.h> +#include <algorithm> #include <array> #include <string_view> @@ -14,13 +15,26 @@ namespace NYT::NDetail { struct TFormatAnalyser { public: + using TMarkerLocation = std::tuple<int, int>; + // NB(arkady-e1ppa): Location is considered invalid (e.g. not filled) + // if get<0> == get<1> == 0. + template <class... TArgs> + using TMarkerLocations = std::array<TMarkerLocation, sizeof...(TArgs)>; + // NB(arkady-e1ppa): We can't cover all of them since that would require + // dynamic storage for their coordinates and we do not have + // constexpr context large enough to deallocate dynamic memory at the + // correct time. Thus we store first 5 position and scanning afterwards + // is pessimized. |-1| is for no position at all. + // |-2| is used to imply runtime format. + using TEscapeLocations = std::array<int, 5>; + // TODO(arkady-e1ppa): Until clang-19 consteval functions // defined out of line produce symbols in rare cases // causing linker to crash. template <class... TArgs> - static consteval void ValidateFormat(std::string_view fmt) + static consteval auto AnalyzeFormat(std::string_view fmt) { - DoValidateFormat<TArgs...>(fmt); + return DoAnalyzeFormat<TArgs...>(fmt); } private: @@ -51,11 +65,16 @@ private: static constexpr char IntroductorySymbol = '%'; template <class... TArgs> - static consteval void DoValidateFormat(std::string_view format) + static consteval auto DoAnalyzeFormat(std::string_view format) { - std::array<std::string_view, sizeof...(TArgs)> markers = {}; std::array<TSpecifiers, sizeof...(TArgs)> specifiers{GetSpecifiers<TArgs>()...}; + TMarkerLocations<TArgs...> markerLocations = {}; + TEscapeLocations escapeLocations = {}; + std::ranges::fill(escapeLocations, -1); + + int escapesCount = 0; + int markerCount = 0; int currentMarkerStart = -1; @@ -81,12 +100,17 @@ private: throw "You may not terminate flag sequence other than %% with \'%\' symbol"; } // '%%' detected --- skip + if (escapesCount < std::ssize(escapeLocations)) { + escapeLocations[escapesCount] = currentMarkerStart; + ++escapesCount; + } + currentMarkerStart = -1; continue; } // We are inside of marker. - if (markerCount == std::ssize(markers)) { + if (markerCount == std::ssize(markerLocations)) { // Too many markers throw "Number of arguments supplied to format is smaller than the number of flag sequences"; } @@ -94,8 +118,8 @@ private: if (Contains(specifiers[markerCount].Conversion, symbol)) { // Marker has finished. - markers[markerCount] - = std::string_view(format.begin() + currentMarkerStart, index - currentMarkerStart + 1); + markerLocations[markerCount] + = std::tuple{currentMarkerStart, index + 1}; currentMarkerStart = -1; ++markerCount; @@ -110,16 +134,16 @@ private: if (currentMarkerStart != -1) { // Runaway marker. throw "Unterminated flag sequence detected; Use \'%%\' to type plain %"; - return; } - if (markerCount < std::ssize(markers)) { + if (markerCount < std::ssize(markerLocations)) { // Missing markers. throw "Number of arguments supplied to format is greater than the number of flag sequences"; } // TODO(arkady-e1ppa): Consider per-type verification // of markers. + return std::tuple(markerLocations, escapeLocations); } }; |