simdtest.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. // Tencent is pleased to support the open source community by making RapidJSON available.
  2. //
  3. // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
  4. //
  5. // Licensed under the MIT License (the "License"); you may not use this file except
  6. // in compliance with the License. You may obtain a copy of the License at
  7. //
  8. // http://opensource.org/licenses/MIT
  9. //
  10. // Unless required by applicable law or agreed to in writing, software distributed
  11. // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  12. // CONDITIONS OF ANY KIND, either express or implied. See the License for the
  13. // specific language governing permissions and limitations under the License.
  14. // Since Travis CI installs old Valgrind 3.7.0, which fails with some SSE4.2
  15. // The unit tests prefix with SIMD should be skipped by Valgrind test
  16. // __SSE2__ and __SSE4_2__ are recognized by gcc, clang, and the Intel compiler.
  17. // We use -march=native with gmake to enable -msse2 and -msse4.2, if supported.
  18. #if defined(__SSE4_2__)
  19. # define RAPIDJSON_SSE42
  20. #elif defined(__SSE2__)
  21. # define RAPIDJSON_SSE2
  22. #endif
  23. #define RAPIDJSON_NAMESPACE rapidjson_simd
  24. #include "unittest.h"
  25. #include "rapidjson/reader.h"
  26. #include "rapidjson/writer.h"
  27. #ifdef __GNUC__
  28. RAPIDJSON_DIAG_PUSH
  29. RAPIDJSON_DIAG_OFF(effc++)
  30. #endif
  31. using namespace rapidjson_simd;
  32. #ifdef RAPIDJSON_SSE2
  33. #define SIMD_SUFFIX(name) name##_SSE2
  34. #elif defined(RAPIDJSON_SSE42)
  35. #define SIMD_SUFFIX(name) name##_SSE42
  36. #else
  37. #define SIMD_SUFFIX(name) name
  38. #endif
  39. template <typename StreamType>
  40. void TestSkipWhitespace() {
  41. for (size_t step = 1; step < 32; step++) {
  42. char buffer[1025];
  43. for (size_t i = 0; i < 1024; i++)
  44. buffer[i] = " \t\r\n"[i % 4];
  45. for (size_t i = 0; i < 1024; i += step)
  46. buffer[i] = 'X';
  47. buffer[1024] = '\0';
  48. StreamType s(buffer);
  49. size_t i = 0;
  50. for (;;) {
  51. SkipWhitespace(s);
  52. if (s.Peek() == '\0')
  53. break;
  54. EXPECT_EQ(i, s.Tell());
  55. EXPECT_EQ('X', s.Take());
  56. i += step;
  57. }
  58. }
  59. }
  60. TEST(SIMD, SIMD_SUFFIX(SkipWhitespace)) {
  61. TestSkipWhitespace<StringStream>();
  62. TestSkipWhitespace<InsituStringStream>();
  63. }
  64. TEST(SIMD, SIMD_SUFFIX(SkipWhitespace_EncodedMemoryStream)) {
  65. for (size_t step = 1; step < 32; step++) {
  66. char buffer[1024];
  67. for (size_t i = 0; i < 1024; i++)
  68. buffer[i] = " \t\r\n"[i % 4];
  69. for (size_t i = 0; i < 1024; i += step)
  70. buffer[i] = 'X';
  71. MemoryStream ms(buffer, 1024);
  72. EncodedInputStream<UTF8<>, MemoryStream> s(ms);
  73. size_t i = 0;
  74. for (;;) {
  75. SkipWhitespace(s);
  76. if (s.Peek() == '\0')
  77. break;
  78. //EXPECT_EQ(i, s.Tell());
  79. EXPECT_EQ('X', s.Take());
  80. i += step;
  81. }
  82. }
  83. }
  84. struct ScanCopyUnescapedStringHandler : BaseReaderHandler<UTF8<>, ScanCopyUnescapedStringHandler> {
  85. bool String(const char* str, size_t length, bool) {
  86. memcpy(buffer, str, length + 1);
  87. return true;
  88. }
  89. char buffer[1024 + 5 + 32];
  90. };
  91. template <unsigned parseFlags, typename StreamType>
  92. void TestScanCopyUnescapedString() {
  93. char buffer[1024 + 5 + 32];
  94. char backup[1024 + 5 + 32];
  95. // Test "ABCDABCD...\\"
  96. for (size_t offset = 0; offset < 32; offset++) {
  97. for (size_t step = 0; step < 1024; step++) {
  98. char* json = buffer + offset;
  99. char *p = json;
  100. *p++ = '\"';
  101. for (size_t i = 0; i < step; i++)
  102. *p++ = "ABCD"[i % 4];
  103. *p++ = '\\';
  104. *p++ = '\\';
  105. *p++ = '\"';
  106. *p++ = '\0';
  107. strcpy(backup, json); // insitu parsing will overwrite buffer, so need to backup first
  108. StreamType s(json);
  109. Reader reader;
  110. ScanCopyUnescapedStringHandler h;
  111. reader.Parse<parseFlags>(s, h);
  112. EXPECT_TRUE(memcmp(h.buffer, backup + 1, step) == 0);
  113. EXPECT_EQ('\\', h.buffer[step]); // escaped
  114. EXPECT_EQ('\0', h.buffer[step + 1]);
  115. }
  116. }
  117. // Test "\\ABCDABCD..."
  118. for (size_t offset = 0; offset < 32; offset++) {
  119. for (size_t step = 0; step < 1024; step++) {
  120. char* json = buffer + offset;
  121. char *p = json;
  122. *p++ = '\"';
  123. *p++ = '\\';
  124. *p++ = '\\';
  125. for (size_t i = 0; i < step; i++)
  126. *p++ = "ABCD"[i % 4];
  127. *p++ = '\"';
  128. *p++ = '\0';
  129. strcpy(backup, json); // insitu parsing will overwrite buffer, so need to backup first
  130. StreamType s(json);
  131. Reader reader;
  132. ScanCopyUnescapedStringHandler h;
  133. reader.Parse<parseFlags>(s, h);
  134. EXPECT_TRUE(memcmp(h.buffer + 1, backup + 3, step) == 0);
  135. EXPECT_EQ('\\', h.buffer[0]); // escaped
  136. EXPECT_EQ('\0', h.buffer[step + 1]);
  137. }
  138. }
  139. }
  140. TEST(SIMD, SIMD_SUFFIX(ScanCopyUnescapedString)) {
  141. TestScanCopyUnescapedString<kParseDefaultFlags, StringStream>();
  142. TestScanCopyUnescapedString<kParseInsituFlag, InsituStringStream>();
  143. }
  144. TEST(SIMD, SIMD_SUFFIX(ScanWriteUnescapedString)) {
  145. char buffer[2048 + 1 + 32];
  146. for (size_t offset = 0; offset < 32; offset++) {
  147. for (size_t step = 0; step < 1024; step++) {
  148. char* s = buffer + offset;
  149. char* p = s;
  150. for (size_t i = 0; i < step; i++)
  151. *p++ = "ABCD"[i % 4];
  152. char escape = "\0\n\\\""[step % 4];
  153. *p++ = escape;
  154. for (size_t i = 0; i < step; i++)
  155. *p++ = "ABCD"[i % 4];
  156. StringBuffer sb;
  157. Writer<StringBuffer> writer(sb);
  158. writer.String(s, SizeType(step * 2 + 1));
  159. const char* q = sb.GetString();
  160. EXPECT_EQ('\"', *q++);
  161. for (size_t i = 0; i < step; i++)
  162. EXPECT_EQ("ABCD"[i % 4], *q++);
  163. if (escape == '\0') {
  164. EXPECT_EQ('\\', *q++);
  165. EXPECT_EQ('u', *q++);
  166. EXPECT_EQ('0', *q++);
  167. EXPECT_EQ('0', *q++);
  168. EXPECT_EQ('0', *q++);
  169. EXPECT_EQ('0', *q++);
  170. }
  171. else if (escape == '\n') {
  172. EXPECT_EQ('\\', *q++);
  173. EXPECT_EQ('n', *q++);
  174. }
  175. else if (escape == '\\') {
  176. EXPECT_EQ('\\', *q++);
  177. EXPECT_EQ('\\', *q++);
  178. }
  179. else if (escape == '\"') {
  180. EXPECT_EQ('\\', *q++);
  181. EXPECT_EQ('\"', *q++);
  182. }
  183. for (size_t i = 0; i < step; i++)
  184. EXPECT_EQ("ABCD"[i % 4], *q++);
  185. EXPECT_EQ('\"', *q++);
  186. EXPECT_EQ('\0', *q++);
  187. }
  188. }
  189. }
  190. #ifdef __GNUC__
  191. RAPIDJSON_DIAG_POP
  192. #endif