aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/yt/string/format_analyser.h
diff options
context:
space:
mode:
authorAlexander Smirnov <alex@ydb.tech>2024-11-20 11:14:58 +0000
committerAlexander Smirnov <alex@ydb.tech>2024-11-20 11:14:58 +0000
commit31773f157bf8164364649b5f470f52dece0a4317 (patch)
tree33d0f7eef45303ab68cf08ab381ce5e5e36c5240 /library/cpp/yt/string/format_analyser.h
parent2c7938962d8689e175574fc1e817c05049f27905 (diff)
parenteff600952d5dfe17942f38f510a8ac2b203bb3a5 (diff)
downloadydb-31773f157bf8164364649b5f470f52dece0a4317.tar.gz
Merge branch 'rightlib' into mergelibs-241120-1113
Diffstat (limited to 'library/cpp/yt/string/format_analyser.h')
-rw-r--r--library/cpp/yt/string/format_analyser.h42
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);
}
};