diff --git a/coding/coding.pro b/coding/coding.pro index 71f257ffba..11b8a19e5e 100644 --- a/coding/coding.pro +++ b/coding/coding.pro @@ -76,3 +76,4 @@ HEADERS += \ bit_shift.hpp \ base64.hpp \ sha2.hpp \ + value_opt_string.hpp \ diff --git a/coding/coding_tests/coding_tests.pro b/coding/coding_tests/coding_tests.pro index ea22eaab3c..05072e9c7b 100644 --- a/coding/coding_tests/coding_tests.pro +++ b/coding/coding_tests/coding_tests.pro @@ -33,7 +33,8 @@ SOURCES += ../../testing/testingmain.cpp \ coder_util_test.cpp \ bit_shift_test.cpp \ base64_test.cpp \ - sha2_test.cpp + sha2_test.cpp \ + value_opt_string_test.cpp \ HEADERS += \ reader_test.hpp \ diff --git a/coding/coding_tests/value_opt_string_test.cpp b/coding/coding_tests/value_opt_string_test.cpp new file mode 100644 index 0000000000..d25d4b37a1 --- /dev/null +++ b/coding/coding_tests/value_opt_string_test.cpp @@ -0,0 +1,61 @@ +#include "../../testing/testing.hpp" + +#include "../value_opt_string.hpp" + +#include "../reader.hpp" +#include "../writer.hpp" + + +namespace +{ + template + void TestStringCodingT(T const * arr, size_t count, size_t maxSize) + { + for (size_t i = 0; i < count; ++i) + { + StringNumericOptimal s; + s.Set(arr[i]); + + vector buffer; + MemWriter > w(buffer); + + s.Write(w); + + size_t const sz = buffer.size(); + TEST_GREATER(sz, 0, ()); + TEST_LESS_OR_EQUAL(sz, maxSize, ()); + + MemReader r(&buffer[0], sz); + ReaderSource src(r); + s.Read(src); + + TEST_EQUAL(utils::to_string(arr[i]), s.Get(), ()); + } + } +} + +UNIT_TEST(StringNumericOptimal_IntCoding1) +{ + int arr[] = { 0, 1, 2, 666, 0x0FFFFFFF, 0x7FFFFFFF-1, 0x7FFFFFFF }; + TestStringCodingT(arr, ARRAY_SIZE(arr), 5); // should be coded as VarUint +} + +UNIT_TEST(StringNumericOptimal_IntCoding2) +{ + int arr[] = { -1, -2, -666666, 0xFFFFFFFE, 0xFFFFFFFF }; + TestStringCodingT(arr, ARRAY_SIZE(arr), 12); // should be coded as String +} + +UNIT_TEST(StringNumericOptimal_StringCoding) +{ + char const * arr[] = { "xxx", "yyy", "a", "0xFFFFFF", "123456UL" }; + TestStringCodingT(arr, ARRAY_SIZE(arr), 12); // should be coded as String +} + +UNIT_TEST(StringNumericOptimal_LargeStringCoding) +{ + string s; + std::fill_n(back_inserter(s), 10000, 'x'); + + TestStringCodingT(&s, 1, 10006); +} diff --git a/coding/strutil.hpp b/coding/strutil.hpp index ccbe109e58..e643b076ff 100644 --- a/coding/strutil.hpp +++ b/coding/strutil.hpp @@ -12,15 +12,15 @@ #include "../base/start_mem_debug.hpp" -typedef basic_string byte_string; - -inline byte_string StringToByteString(string const & str) -{ - byte_string result; - result.resize(str.size()); - memcpy(&result[0], &str[0], str.size()); - return result; -} +//typedef basic_string byte_string; +// +//inline byte_string StringToByteString(string const & str) +//{ +// byte_string result; +// result.resize(str.size()); +// memcpy(&result[0], &str[0], str.size()); +// return result; +//} inline string ToUtf8(wstring const & wstr) { diff --git a/coding/value_opt_string.hpp b/coding/value_opt_string.hpp new file mode 100644 index 0000000000..7bbdf5cd24 --- /dev/null +++ b/coding/value_opt_string.hpp @@ -0,0 +1,64 @@ +#pragma once + +#include "varint.hpp" + +#include "../base/string_utils.hpp" +#include "../base/assert.hpp" + +#include "../std/string.hpp" + + +class StringNumericOptimal +{ + string m_s; + + static const uint8_t numeric_bit = 1; + +public: + inline void Set(string const & s) + { + CHECK ( !s.empty(), () ); + m_s = s; + } + inline void Set(char const * p) + { + m_s = p; + CHECK ( !m_s.empty(), () ); + } + template void Set(T const & s) + { + m_s = utils::to_string(s); + CHECK ( !m_s.empty(), () ); + } + + inline string Get() const { return m_s; } + + template void Write(TSink & sink) + { + int n; + if (utils::to_int(m_s, n) && n >= 0) + WriteVarUint(sink, static_cast((n << 1) | numeric_bit)); + else + { + size_t const sz = m_s.size(); + ASSERT_GREATER ( sz, 0, () ); + + WriteVarUint(sink, static_cast((sz-1) << 1)); + sink.Write(m_s.c_str(), sz); + } + } + + template void Read(TSource & src) + { + uint32_t sz = ReadVarUint(src); + + if ((sz & numeric_bit) != 0) + m_s = utils::to_string(sz >> 1); + else + { + sz = (sz >> 1) + 1; + m_s.resize(sz); + src.Read(&m_s[0], sz); + } + } +};