diff options
author | Alexey Salmin <alexey.salmin@gmail.com> | 2022-02-10 16:49:37 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:49:37 +0300 |
commit | 71af077a5dfe7e9f932a508422c2dac81a57ebc0 (patch) | |
tree | 5d5cb817648f650d76cf1076100726fd9b8448e8 /util/string | |
parent | 3c5b1607b38f637d2f3313791ed25c2e080d2647 (diff) | |
download | ydb-71af077a5dfe7e9f932a508422c2dac81a57ebc0.tar.gz |
Restoring authorship annotation for Alexey Salmin <alexey.salmin@gmail.com>. Commit 2 of 2.
Diffstat (limited to 'util/string')
-rw-r--r-- | util/string/benchmark/join/main.cpp | 160 | ||||
-rw-r--r-- | util/string/benchmark/join/metrics/main.py | 8 | ||||
-rw-r--r-- | util/string/benchmark/join/metrics/ya.make | 28 | ||||
-rw-r--r-- | util/string/benchmark/join/ya.make | 22 | ||||
-rw-r--r-- | util/string/benchmark/ya.make | 4 | ||||
-rw-r--r-- | util/string/cast.h | 8 | ||||
-rw-r--r-- | util/string/join.h | 158 | ||||
-rw-r--r-- | util/string/join_ut.cpp | 56 |
8 files changed, 222 insertions, 222 deletions
diff --git a/util/string/benchmark/join/main.cpp b/util/string/benchmark/join/main.cpp index 94466069d4..1a8633d3a8 100644 --- a/util/string/benchmark/join/main.cpp +++ b/util/string/benchmark/join/main.cpp @@ -1,70 +1,70 @@ #include <library/cpp/testing/benchmark/bench.h> - -#include <util/generic/function.h> -#include <util/generic/singleton.h> -#include <util/generic/vector.h> -#include <util/generic/xrange.h> -#include <util/random/fast.h> -#include <util/string/cast.h> -#include <util/string/join.h> - -namespace { - // This class assigns random values to variadic lists of variables of different types. - // It can be used to randomize a tuple via Apply() (arcadia version of std::apply). - class TRandomizer { - public: - TRandomizer(ui64 seed) - : Prng(seed) - { - } - - void Randomize(ui16& i) { - i = static_cast<ui16>(Prng.GenRand()); - } - - void Randomize(ui32& i) { - i = static_cast<ui32>(Prng.GenRand()); - } - - void Randomize(double& d) { - d = Prng.GenRandReal4() + Prng.Uniform(Max<ui16>()); - } - - void Randomize(TString& s) { - s = ::ToString(Prng.GenRand()); - } - + +#include <util/generic/function.h> +#include <util/generic/singleton.h> +#include <util/generic/vector.h> +#include <util/generic/xrange.h> +#include <util/random/fast.h> +#include <util/string/cast.h> +#include <util/string/join.h> + +namespace { + // This class assigns random values to variadic lists of variables of different types. + // It can be used to randomize a tuple via Apply() (arcadia version of std::apply). + class TRandomizer { + public: + TRandomizer(ui64 seed) + : Prng(seed) + { + } + + void Randomize(ui16& i) { + i = static_cast<ui16>(Prng.GenRand()); + } + + void Randomize(ui32& i) { + i = static_cast<ui32>(Prng.GenRand()); + } + + void Randomize(double& d) { + d = Prng.GenRandReal4() + Prng.Uniform(Max<ui16>()); + } + + void Randomize(TString& s) { + s = ::ToString(Prng.GenRand()); + } + template <typename T, typename... TArgs> - void Randomize(T& t, TArgs&... args) { - Randomize(t); - Randomize(args...); - } - - private: - TFastRng<ui64> Prng; - }; - + void Randomize(T& t, TArgs&... args) { + Randomize(t); + Randomize(args...); + } + + private: + TFastRng<ui64> Prng; + }; + template <size_t N, typename... T> - struct TExamplesHolder { + struct TExamplesHolder { using TExamples = TVector<std::tuple<T...>>; - TExamples Examples; - - TExamplesHolder() - : Examples(N) - { - TRandomizer r{N * sizeof(typename TExamples::value_type) * 42}; - for (auto& x : Examples) { + TExamples Examples; + + TExamplesHolder() + : Examples(N) + { + TRandomizer r{N * sizeof(typename TExamples::value_type) * 42}; + for (auto& x : Examples) { Apply([&r](T&... t) { r.Randomize(t...); }, x); - } - } - }; - + } + } + }; + template <typename... TArgs> - TString JoinTuple(std::tuple<TArgs...> t) { - return Apply([](TArgs... x) -> TString { return Join("-", x...); }, t); - } -} - + TString JoinTuple(std::tuple<TArgs...> t) { + return Apply([](TArgs... x) -> TString { return Join("-", x...); }, t); + } +} + #define DEFINE_BENCHMARK(count, types, ...) \ Y_CPU_BENCHMARK(Join_##count##_##types, iface) { \ const auto& examples = Default<TExamplesHolder<count, __VA_ARGS__>>().Examples; \ @@ -74,22 +74,22 @@ namespace { Y_DO_NOT_OPTIMIZE_AWAY(JoinTuple(e)); \ } \ } \ - } - -DEFINE_BENCHMARK(100, SS, TString, TString); -DEFINE_BENCHMARK(100, SSS, TString, TString, TString); -DEFINE_BENCHMARK(100, SSSSS, TString, TString, TString, TString, TString); - -DEFINE_BENCHMARK(100, ss, ui16, ui16); -DEFINE_BENCHMARK(100, SsS, TString, ui16, TString); -DEFINE_BENCHMARK(100, SsSsS, TString, ui16, TString, ui16, TString); - -DEFINE_BENCHMARK(100, ii, ui32, ui32); -DEFINE_BENCHMARK(100, SiS, TString, ui32, TString); -DEFINE_BENCHMARK(100, SiSiS, TString, ui32, TString, ui32, TString); - -DEFINE_BENCHMARK(100, dd, double, double); -DEFINE_BENCHMARK(100, SdS, TString, double, TString); -DEFINE_BENCHMARK(100, SdSdS, TString, double, TString, double, TString); - -#undef DEFINE_BENCHMARK + } + +DEFINE_BENCHMARK(100, SS, TString, TString); +DEFINE_BENCHMARK(100, SSS, TString, TString, TString); +DEFINE_BENCHMARK(100, SSSSS, TString, TString, TString, TString, TString); + +DEFINE_BENCHMARK(100, ss, ui16, ui16); +DEFINE_BENCHMARK(100, SsS, TString, ui16, TString); +DEFINE_BENCHMARK(100, SsSsS, TString, ui16, TString, ui16, TString); + +DEFINE_BENCHMARK(100, ii, ui32, ui32); +DEFINE_BENCHMARK(100, SiS, TString, ui32, TString); +DEFINE_BENCHMARK(100, SiSiS, TString, ui32, TString, ui32, TString); + +DEFINE_BENCHMARK(100, dd, double, double); +DEFINE_BENCHMARK(100, SdS, TString, double, TString); +DEFINE_BENCHMARK(100, SdSdS, TString, double, TString, double, TString); + +#undef DEFINE_BENCHMARK diff --git a/util/string/benchmark/join/metrics/main.py b/util/string/benchmark/join/metrics/main.py index 60eb0e470f..1ed5014808 100644 --- a/util/string/benchmark/join/metrics/main.py +++ b/util/string/benchmark/join/metrics/main.py @@ -1,5 +1,5 @@ -import yatest.common as yc - - -def test_export_metrics(metrics): +import yatest.common as yc + + +def test_export_metrics(metrics): metrics.set_benchmark(yc.execute_benchmark('util/string/benchmark/join/join', threads=8)) diff --git a/util/string/benchmark/join/metrics/ya.make b/util/string/benchmark/join/metrics/ya.make index bdbf806aa2..08ff3a149f 100644 --- a/util/string/benchmark/join/metrics/ya.make +++ b/util/string/benchmark/join/metrics/ya.make @@ -1,21 +1,21 @@ -OWNER( - salmin - g:util -) +OWNER( + salmin + g:util +) SUBSCRIBER(g:util-subscribers) - + PY2TEST() - + SIZE(LARGE) - -TAG( + +TAG( ya:force_sandbox - sb:intel_e5_2660v1 + sb:intel_e5_2660v1 ya:fat -) - +) + TEST_SRCS(main.py) - + DEPENDS(util/string/benchmark/join) - -END() + +END() diff --git a/util/string/benchmark/join/ya.make b/util/string/benchmark/join/ya.make index 6ba2d2dadb..dfcc1d264e 100644 --- a/util/string/benchmark/join/ya.make +++ b/util/string/benchmark/join/ya.make @@ -1,13 +1,13 @@ Y_BENCHMARK() - -OWNER( - salmin - g:util -) + +OWNER( + salmin + g:util +) SUBSCRIBER(g:util-subscribers) - -SRCS( - main.cpp -) - -END() + +SRCS( + main.cpp +) + +END() diff --git a/util/string/benchmark/ya.make b/util/string/benchmark/ya.make index e6ab78b6f6..266b53c7b3 100644 --- a/util/string/benchmark/ya.make +++ b/util/string/benchmark/ya.make @@ -9,8 +9,8 @@ RECURSE( cast float_to_string float_to_string/metrics - join - join/metrics + join + join/metrics subst_global subst_global/metrics ) diff --git a/util/string/cast.h b/util/string/cast.h index 9c230d1095..90e925c194 100644 --- a/util/string/cast.h +++ b/util/string/cast.h @@ -69,10 +69,10 @@ namespace NPrivate { template <class T> struct TToString<T, false> { static inline TString Cvt(const T& t) { - TString s; - TStringOutput o(s); - o << t; - return s; + TString s; + TStringOutput o(s); + o << t; + return s; } }; } diff --git a/util/string/join.h b/util/string/join.h index a49e6dfe50..b166fad1f3 100644 --- a/util/string/join.h +++ b/util/string/join.h @@ -5,31 +5,31 @@ #include <util/string/cast.h> #include "cast.h" -/* - * Default implementation of AppendToString uses a temporary TString object which is inefficient. You can overload it - * for your type to speed up string joins. If you already have an Out() or operator<<() implementation you can simply - * do the following: - * - * inline void AppendToString(TString& dst, const TMyType& t) { - * TStringOutput o(dst); - * o << t; - * } - * - * Unfortunately we can't do this by default because for some types ToString() is defined while Out() is not. - * For standard types (strings of all kinds and arithmetic types) we don't use a temporary TString in AppendToString(). - */ - +/* + * Default implementation of AppendToString uses a temporary TString object which is inefficient. You can overload it + * for your type to speed up string joins. If you already have an Out() or operator<<() implementation you can simply + * do the following: + * + * inline void AppendToString(TString& dst, const TMyType& t) { + * TStringOutput o(dst); + * o << t; + * } + * + * Unfortunately we can't do this by default because for some types ToString() is defined while Out() is not. + * For standard types (strings of all kinds and arithmetic types) we don't use a temporary TString in AppendToString(). + */ + template <typename TCharType, typename T> -inline std::enable_if_t<!std::is_arithmetic<std::remove_cv_t<T>>::value, void> +inline std::enable_if_t<!std::is_arithmetic<std::remove_cv_t<T>>::value, void> AppendToString(TBasicString<TCharType>& dst, const T& t) { dst.AppendNoAlias(ToString(t)); -} +} template <typename TCharType, typename T> -inline std::enable_if_t<std::is_arithmetic<std::remove_cv_t<T>>::value, void> +inline std::enable_if_t<std::is_arithmetic<std::remove_cv_t<T>>::value, void> AppendToString(TBasicString<TCharType>& dst, const T& t) { - char buf[512]; - dst.append(buf, ToString<std::remove_cv_t<T>>(t, buf, sizeof(buf))); + char buf[512]; + dst.append(buf, ToString<std::remove_cv_t<T>>(t, buf, sizeof(buf))); } template <typename TCharType> @@ -42,59 +42,59 @@ inline void AppendToString(TBasicString<TCharType>& dst, TBasicStringBuf<TCharTy dst.append(t); } -namespace NPrivate { - template <typename T> - inline size_t GetLength(const T&) { - // By default don't pre-allocate space when joining and appending non-string types. - // This code can be extended by estimating stringified length for specific types (e.g. 10 for ui32). - return 0; - } - - template <> - inline size_t GetLength(const TString& s) { - return s.length(); - } - - template <> - inline size_t GetLength(const TStringBuf& s) { - return s.length(); - } - - template <> - inline size_t GetLength(const char* const& s) { +namespace NPrivate { + template <typename T> + inline size_t GetLength(const T&) { + // By default don't pre-allocate space when joining and appending non-string types. + // This code can be extended by estimating stringified length for specific types (e.g. 10 for ui32). + return 0; + } + + template <> + inline size_t GetLength(const TString& s) { + return s.length(); + } + + template <> + inline size_t GetLength(const TStringBuf& s) { + return s.length(); + } + + template <> + inline size_t GetLength(const char* const& s) { return (s ? std::char_traits<char>::length(s) : 0); - } - - inline size_t GetAppendLength(const TStringBuf /*delim*/) { - return 0; - } - - template <typename TFirst, typename... TRest> - size_t GetAppendLength(const TStringBuf delim, const TFirst& f, const TRest&... r) { - return delim.length() + ::NPrivate::GetLength(f) + ::NPrivate::GetAppendLength(delim, r...); - } + } + + inline size_t GetAppendLength(const TStringBuf /*delim*/) { + return 0; + } + + template <typename TFirst, typename... TRest> + size_t GetAppendLength(const TStringBuf delim, const TFirst& f, const TRest&... r) { + return delim.length() + ::NPrivate::GetLength(f) + ::NPrivate::GetAppendLength(delim, r...); + } } template <typename TCharType> inline void AppendJoinNoReserve(TBasicString<TCharType>&, TBasicStringBuf<TCharType>) { -} - +} + template <typename TCharType, typename TFirst, typename... TRest> inline void AppendJoinNoReserve(TBasicString<TCharType>& dst, TBasicStringBuf<TCharType> delim, const TFirst& f, const TRest&... r) { AppendToString(dst, delim); AppendToString(dst, f); - AppendJoinNoReserve(dst, delim, r...); + AppendJoinNoReserve(dst, delim, r...); +} + +template <typename... TValues> +inline void AppendJoin(TString& dst, const TStringBuf delim, const TValues&... values) { + const size_t appendLength = ::NPrivate::GetAppendLength(delim, values...); + if (appendLength > 0) { + dst.reserve(dst.length() + appendLength); + } + AppendJoinNoReserve(dst, delim, values...); } -template <typename... TValues> -inline void AppendJoin(TString& dst, const TStringBuf delim, const TValues&... values) { - const size_t appendLength = ::NPrivate::GetAppendLength(delim, values...); - if (appendLength > 0) { - dst.reserve(dst.length() + appendLength); - } - AppendJoinNoReserve(dst, delim, values...); -} - template <typename TFirst, typename... TRest> inline TString Join(const TStringBuf delim, const TFirst& f, const TRest&... r) { TString ret = ToString(f); @@ -127,8 +127,8 @@ namespace NPrivate { for (TIter pos = beg; ++pos != end;) { AppendJoinNoReserve(out, delim, *pos); } - } - + } + return out; } @@ -241,25 +241,25 @@ constexpr auto MakeRangeJoiner(TStringBuf delim, const std::initializer_list<TVa return MakeRangeJoiner(delim, std::cbegin(data), std::cend(data)); } -/* We force (std::initializer_list<TStringBuf>) input type for (TString) and (const char*) types because: - * # When (std::initializer_list<TString>) is used, TString objects are copied into the initializer_list object. - * Storing TStringBufs instead is faster, even with COW-enabled strings. - * # For (const char*) we calculate length only once and store it in TStringBuf. Otherwise strlen scan would be executed - * in both GetAppendLength and AppendToString. For string literals constant lengths get propagated in compile-time. - * - * This way JoinSeq(",", { s1, s2 }) always does the right thing whatever types s1 and s2 have. - * - * If someone needs to join std::initializer_list<TString> -- it still works because of the TContainer template above. -*/ - +/* We force (std::initializer_list<TStringBuf>) input type for (TString) and (const char*) types because: + * # When (std::initializer_list<TString>) is used, TString objects are copied into the initializer_list object. + * Storing TStringBufs instead is faster, even with COW-enabled strings. + * # For (const char*) we calculate length only once and store it in TStringBuf. Otherwise strlen scan would be executed + * in both GetAppendLength and AppendToString. For string literals constant lengths get propagated in compile-time. + * + * This way JoinSeq(",", { s1, s2 }) always does the right thing whatever types s1 and s2 have. + * + * If someone needs to join std::initializer_list<TString> -- it still works because of the TContainer template above. +*/ + template <typename T> inline std::enable_if_t< !std::is_same<std::decay_t<T>, TString>::value && !std::is_same<std::decay_t<T>, const char*>::value, TString> -JoinSeq(const TStringBuf delim, const std::initializer_list<T>& data) { +JoinSeq(const TStringBuf delim, const std::initializer_list<T>& data) { + return JoinRange(delim, data.begin(), data.end()); +} + +inline TString JoinSeq(const TStringBuf delim, const std::initializer_list<TStringBuf>& data) { return JoinRange(delim, data.begin(), data.end()); } - -inline TString JoinSeq(const TStringBuf delim, const std::initializer_list<TStringBuf>& data) { - return JoinRange(delim, data.begin(), data.end()); -} diff --git a/util/string/join_ut.cpp b/util/string/join_ut.cpp index 74ff515da9..3ed2b2459c 100644 --- a/util/string/join_ut.cpp +++ b/util/string/join_ut.cpp @@ -39,18 +39,18 @@ Y_UNIT_TEST_SUITE(JoinStringTest) { } Y_UNIT_TEST(StrContainerItems) { - // try various overloads and template type arguments - static const char* const result = "1 22 333"; - static const char* const v[] = {"1", "22", "333"}; + // try various overloads and template type arguments + static const char* const result = "1 22 333"; + static const char* const v[] = {"1", "22", "333"}; TVector<const char*> vchar(v, v + sizeof(v) / sizeof(v[0])); TVector<TStringBuf> vbuf(v, v + sizeof(v) / sizeof(v[0])); TVector<TString> vstring(v, v + sizeof(v) / sizeof(v[0])); - - // ranges - UNIT_ASSERT_EQUAL(JoinRange(" ", v, v + 3), result); - UNIT_ASSERT_EQUAL(JoinRange(" ", vchar.begin(), vchar.end()), result); - UNIT_ASSERT_EQUAL(JoinRange(" ", vbuf.begin(), vbuf.end()), result); - UNIT_ASSERT_EQUAL(JoinRange(" ", vstring.begin(), vstring.end()), result); + + // ranges + UNIT_ASSERT_EQUAL(JoinRange(" ", v, v + 3), result); + UNIT_ASSERT_EQUAL(JoinRange(" ", vchar.begin(), vchar.end()), result); + UNIT_ASSERT_EQUAL(JoinRange(" ", vbuf.begin(), vbuf.end()), result); + UNIT_ASSERT_EQUAL(JoinRange(" ", vstring.begin(), vstring.end()), result); { TStringStream stream; stream << MakeRangeJoiner(" ", v, v + 3); @@ -71,11 +71,11 @@ Y_UNIT_TEST_SUITE(JoinStringTest) { stream << MakeRangeJoiner(" ", vstring.begin(), vstring.end()); UNIT_ASSERT_EQUAL(stream.Str(), result); } - - // vectors - UNIT_ASSERT_EQUAL(JoinSeq(" ", vchar), result); - UNIT_ASSERT_EQUAL(JoinSeq(" ", vbuf), result); - UNIT_ASSERT_EQUAL(JoinSeq(" ", vstring), result); + + // vectors + UNIT_ASSERT_EQUAL(JoinSeq(" ", vchar), result); + UNIT_ASSERT_EQUAL(JoinSeq(" ", vbuf), result); + UNIT_ASSERT_EQUAL(JoinSeq(" ", vstring), result); { TStringStream stream; stream << MakeRangeJoiner(" ", vchar); @@ -91,12 +91,12 @@ Y_UNIT_TEST_SUITE(JoinStringTest) { stream << MakeRangeJoiner(" ", vstring); UNIT_ASSERT_EQUAL(stream.Str(), result); } - - // initializer lists with type deduction - UNIT_ASSERT_EQUAL(JoinSeq(" ", {v[0], v[1], v[2]}), result); - UNIT_ASSERT_EQUAL(JoinSeq(" ", {vchar[0], vchar[1], vchar[2]}), result); - UNIT_ASSERT_EQUAL(JoinSeq(" ", {vbuf[0], vbuf[1], vbuf[2]}), result); - UNIT_ASSERT_EQUAL(JoinSeq(" ", {vstring[0], vstring[1], vstring[2]}), result); + + // initializer lists with type deduction + UNIT_ASSERT_EQUAL(JoinSeq(" ", {v[0], v[1], v[2]}), result); + UNIT_ASSERT_EQUAL(JoinSeq(" ", {vchar[0], vchar[1], vchar[2]}), result); + UNIT_ASSERT_EQUAL(JoinSeq(" ", {vbuf[0], vbuf[1], vbuf[2]}), result); + UNIT_ASSERT_EQUAL(JoinSeq(" ", {vstring[0], vstring[1], vstring[2]}), result); { TStringStream stream; stream << MakeRangeJoiner(" ", {v[0], v[1], v[2]}); @@ -117,12 +117,12 @@ Y_UNIT_TEST_SUITE(JoinStringTest) { stream << MakeRangeJoiner(" ", {vstring[0], vstring[1], vstring[2]}); UNIT_ASSERT_EQUAL(stream.Str(), result); } - - // initializer lists with explicit types - UNIT_ASSERT_EQUAL(JoinSeq(" ", std::initializer_list<const char*>{v[0], v[1], v[2]}), result); - UNIT_ASSERT_EQUAL(JoinSeq(" ", std::initializer_list<const char*>{vchar[0], vchar[1], vchar[2]}), result); - UNIT_ASSERT_EQUAL(JoinSeq(" ", std::initializer_list<TStringBuf>{vbuf[0], vbuf[1], vbuf[2]}), result); - UNIT_ASSERT_EQUAL(JoinSeq(" ", std::initializer_list<TString>{vstring[0], vstring[1], vstring[2]}), result); + + // initializer lists with explicit types + UNIT_ASSERT_EQUAL(JoinSeq(" ", std::initializer_list<const char*>{v[0], v[1], v[2]}), result); + UNIT_ASSERT_EQUAL(JoinSeq(" ", std::initializer_list<const char*>{vchar[0], vchar[1], vchar[2]}), result); + UNIT_ASSERT_EQUAL(JoinSeq(" ", std::initializer_list<TStringBuf>{vbuf[0], vbuf[1], vbuf[2]}), result); + UNIT_ASSERT_EQUAL(JoinSeq(" ", std::initializer_list<TString>{vstring[0], vstring[1], vstring[2]}), result); { TStringStream stream; stream << MakeRangeJoiner(" ", std::initializer_list<const char*>{v[0], v[1], v[2]}); @@ -146,8 +146,8 @@ Y_UNIT_TEST_SUITE(JoinStringTest) { // c-style array UNIT_ASSERT_VALUES_EQUAL(JoinSeq(" ", v), result); - } - + } + Y_UNIT_TEST(CustomToString) { TCustomData d1{{1, 2, 3, 4, 5}}; TCustomData d2{{0, -1, -2}}; |