diff options
| -rw-r--r-- | src/test-performance.cpp | 80 | 
1 files changed, 46 insertions, 34 deletions
| diff --git a/src/test-performance.cpp b/src/test-performance.cpp index 629aadd..64535c6 100644 --- a/src/test-performance.cpp +++ b/src/test-performance.cpp @@ -19,7 +19,6 @@  #include <limits>  #include <list>  #include <locale> -#include <random>  #include <string>  #include <tuple>  #include <type_traits> @@ -34,49 +33,68 @@ using namespace std::string_literals;  typedef std::tuple<std::basic_string<utf8_t>, std::basic_string<char16_t>, std::basic_string<char32_t>> types_collection_type; -struct random_context { - random_context(int max_value = 0x10FFFF - 0x800): code_point_distribution(0, max_value) {} - std::random_device rd;  // OS random number engine to seed RNG (below) - std::mt19937 gen{rd()}; - std::uniform_int_distribution<size_t> sequence_length{0, 100000}; // length of sequence: 0 ... 100000 code units - std::uniform_int_distribution<unsigned long> code_point_distribution; -}; +// LCG for generating deterministic mixed data, see also https://arxiv.org/pdf/2001.05304.pdf +uint8_t generate_byte() +{ + static uint64_t x{1}; + const static uint32_t a{0x915f77f5}; + const static uint32_t c{12345}; + const static uint32_t m_mask{0xFFFFFFFF}; + + x = (x * a + c) & m_mask; + + return (x >> 16) & 0xFF; +} + +// max is inclusive +template<typename T> +T generate_value(T max = std::numeric_limits<T>::max()) +{ + uint64_t max_modulo{ static_cast<uint64_t>(0x100000000ULL) - (0x100000000ULL % (max + 1))}; + + uint32_t value{}; + do { +  for (int i = 0; i < sizeof(value); ++i) { +   value = (value << 8) | generate_byte(); +  } + } while (static_cast<uint64_t>(value) >= max_modulo); + + return static_cast<T>(value % (max + 1)); +}  // generates valid and invalid strings of different type  template<typename T> -T generate_random_invalid(random_context& rc, size_t length) +T generate_string_invalid(size_t length)  { - // Using unsigned long for std::uniform_int_distribution<> because it needs to be basic type according to MSVC - std::uniform_int_distribution<unsigned long> code_unit{0, std::numeric_limits<typename T::value_type>::max()}; // code unit value   T result; - std::generate_n(std::back_inserter(result), length, [&](){return static_cast<typename T::value_type>(code_unit(rc.gen));}); + std::generate_n(std::back_inserter(result), length, [&](){return generate_value<typename T::value_type>();});   return result;  } -char32_t generate_random_char(random_context& rc) +char32_t generate_char(char32_t max = 0x10FFFF - 0x800)  { - auto result {rc.code_point_distribution(rc.gen)}; + char32_t result {generate_value<char32_t>(max)};   if (result >= 0xD800)    result += 0x800;   return static_cast<char32_t>(result);  } -std::u32string generate_random_string(random_context& rc, size_t length) +std::u32string generate_string(char32_t max, size_t length)  {   std::u32string result; - std::generate_n(std::back_inserter(result), length, [&](){return generate_random_char(rc);}); + std::generate_n(std::back_inserter(result), length, [&](){return generate_char(max);});   return result;  }  template<typename From, typename ToTypesCollectionType, size_t i = 0> -void test_random_invalid(random_context& rc, size_t length) +void test_string_invalid(size_t length)  {   //std::cerr << "LENGTH: " << length << std::endl;   typedef typename std::tuple_element<i,ToTypesCollectionType>::type To; - From r {static_cast<From>(generate_random_invalid<From>(rc, length))}; + From r {static_cast<From>(generate_string_invalid<From>(length))};   // base type interface   try { @@ -125,15 +143,13 @@ void test_random_invalid(random_context& rc, size_t length)   // iterate over remaining To types   if constexpr (i + 1 < std::tuple_size<ToTypesCollectionType>::value) -  test_random_invalid<From, ToTypesCollectionType, i + 1>(rc, length); +  test_string_invalid<From, ToTypesCollectionType, i + 1>(length);  } -BOOST_AUTO_TEST_CASE_TEMPLATE(random_sequences_invalid, T, types_collection_type) +BOOST_AUTO_TEST_CASE_TEMPLATE(sequences_invalid, T, types_collection_type)  { - random_context rc; -   for (int i = 0; i < 10; i++) { -  test_random_invalid<T,types_collection_type>(rc, rc.sequence_length(rc.gen)); +  test_string_invalid<T,types_collection_type>(generate_value<size_t>(100000));   }  } @@ -166,13 +182,13 @@ private:  };  template<typename From, typename ToTypesCollectionType, size_t index = 0> -void test_random_valid(random_context& rc, size_t length, const std::string& description) +void test_string_valid(char32_t max, size_t length, const std::string& description)  {   typedef typename std::tuple_element<index,ToTypesCollectionType>::type To;   // Fill UTF-32 data list: source for tests   std::vector<std::u32string> u32list; - std::generate_n(std::back_inserter(u32list), 1000, [&](){return generate_random_string(rc, rc.sequence_length(rc.gen));}); + std::generate_n(std::back_inserter(u32list), 1000, [&](){return generate_string(max, generate_value<size_t>(100000));});   // Fill From data list   std::vector<From> list; @@ -211,20 +227,16 @@ void test_random_valid(random_context& rc, size_t length, const std::string& des   // iterate over remaining To types   if constexpr (index + 1 < std::tuple_size<ToTypesCollectionType>::value) -  test_random_valid<From, ToTypesCollectionType, index + 1>(rc, length, description); +  test_string_valid<From, ToTypesCollectionType, index + 1>(max, length, description);  } -BOOST_AUTO_TEST_CASE_TEMPLATE(random_sequences_valid_ascii, T, types_collection_type) +BOOST_AUTO_TEST_CASE_TEMPLATE(sequences_valid_ascii, T, types_collection_type)  { - random_context rc{127}; - - test_random_valid<T,types_collection_type>(rc, rc.sequence_length(rc.gen), "ASCII only strings"); + test_string_valid<T,types_collection_type>(127, generate_value<size_t>(100000), "ASCII only strings");  } -BOOST_AUTO_TEST_CASE_TEMPLATE(random_sequences_valid_all_unicode, T, types_collection_type) +BOOST_AUTO_TEST_CASE_TEMPLATE(sequences_valid_all_unicode, T, types_collection_type)  { - random_context rc; - - test_random_valid<T,types_collection_type>(rc, rc.sequence_length(rc.gen), "All Unicode strings"); + test_string_valid<T,types_collection_type>(0x10FFFF - 0x800, generate_value<size_t>(100000), "All Unicode strings");  } | 
