1 // 2 // Copyright (c) 2016-2019 Vinnie Falco (vinnie dot falco at gmail dot com) 3 // 4 // Distributed under the Boost Software License, Version 1.0. (See accompanying 5 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) 6 // 7 // Official repository: https://github.com/boostorg/beast 8 // 9 10 #include <boost/beast/websocket/detail/utf8_checker.hpp> 11 #include <boost/beast/_experimental/unit_test/suite.hpp> 12 #include <chrono> 13 #include <random> 14 15 #ifndef BEAST_USE_BOOST_LOCALE_BENCHMARK 16 #define BEAST_USE_BOOST_LOCALE_BENCHMARK 0 17 #endif 18 19 #if BEAST_USE_BOOST_LOCALE_BENCHMARK 20 #include <boost/locale.hpp> 21 #endif 22 23 namespace boost { 24 namespace beast { 25 26 class utf8_checker_test : public beast::unit_test::suite 27 { 28 std::mt19937 rng_; 29 30 public: 31 using size_type = std::uint64_t; 32 33 class timer 34 { 35 public: 36 using clock_type = 37 std::chrono::system_clock; 38 39 private: 40 clock_type::time_point when_; 41 42 public: 43 using duration = 44 clock_type::duration; 45 timer()46 timer() 47 : when_(clock_type::now()) 48 { 49 } 50 51 duration elapsed() const52 elapsed() const 53 { 54 return clock_type::now() - when_; 55 } 56 }; 57 58 template<class UInt = std::size_t> 59 UInt rand(std::size_t n)60 rand(std::size_t n) 61 { 62 return static_cast<UInt>( 63 std::uniform_int_distribution< 64 std::size_t>{0, n-1}(rng_)); 65 } 66 67 static 68 inline 69 size_type throughput(std::chrono::duration<double> const & elapsed,size_type items)70 throughput(std::chrono::duration< 71 double> const& elapsed, size_type items) 72 { 73 using namespace std::chrono; 74 return static_cast<size_type>( 75 1 / (elapsed/items).count()); 76 } 77 78 std::string corpus(std::size_t n)79 corpus(std::size_t n) 80 { 81 std::string s; 82 s.reserve(n); 83 while(n--) 84 s.push_back(static_cast<char>( 85 ' ' + rand(95))); 86 return s; 87 } 88 89 void checkBeast(std::string const & s)90 checkBeast(std::string const& s) 91 { 92 beast::websocket::detail::check_utf8( 93 s.data(), s.size()); 94 } 95 96 #if BEAST_USE_BOOST_LOCALE_BENCHMARK 97 void checkLocale(std::string const & s)98 checkLocale(std::string const& s) 99 { 100 using namespace boost::locale; 101 auto p = s.begin(); 102 auto const e = s.end(); 103 while(p != e) 104 { 105 auto cp = utf::utf_traits<char>::decode(p, e); 106 if(cp == utf::illegal) 107 break; 108 } 109 } 110 #endif 111 112 template<class F> 113 typename timer::clock_type::duration test(F const & f)114 test(F const& f) 115 { 116 timer t; 117 f(); 118 return t.elapsed(); 119 } 120 121 void run()122 run() override 123 { 124 auto const s = corpus(32 * 1024 * 1024); 125 for(int i = 0; i < 5; ++ i) 126 { 127 auto const elapsed = test([&]{ 128 checkBeast(s); 129 checkBeast(s); 130 checkBeast(s); 131 checkBeast(s); 132 checkBeast(s); 133 }); 134 log << "beast: " << throughput(elapsed, s.size()) << " char/s" << std::endl; 135 } 136 #if BEAST_USE_BOOST_LOCALE_BENCHMARK 137 for(int i = 0; i < 5; ++ i) 138 { 139 auto const elapsed = test([&]{ 140 checkLocale(s); 141 checkLocale(s); 142 checkLocale(s); 143 checkLocale(s); 144 checkLocale(s); 145 }); 146 log << "locale: " << throughput(elapsed, s.size()) << " char/s" << std::endl; 147 } 148 #endif 149 pass(); 150 } 151 }; 152 153 BEAST_DEFINE_TESTSUITE(beast,benchmarks,utf8_checker); 154 155 } // beast 156 } // boost 157 158