simdtest.cpp 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  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. #elif defined(__ARM_NEON)
  23. # define RAPIDJSON_NEON
  24. #endif
  25. #define RAPIDJSON_NAMESPACE rapidjson_simd
  26. #include "unittest.h"
  27. #include "rapidjson/reader.h"
  28. #include "rapidjson/writer.h"
  29. #ifdef __GNUC__
  30. RAPIDJSON_DIAG_PUSH
  31. RAPIDJSON_DIAG_OFF(effc++)
  32. #endif
  33. using namespace rapidjson_simd;
  34. #ifdef RAPIDJSON_SSE2
  35. #define SIMD_SUFFIX(name) name##_SSE2
  36. #elif defined(RAPIDJSON_SSE42)
  37. #define SIMD_SUFFIX(name) name##_SSE42
  38. #elif defined(RAPIDJSON_NEON)
  39. #define SIMD_SUFFIX(name) name##_NEON
  40. #else
  41. #define SIMD_SUFFIX(name) name
  42. #endif
  43. template <typename StreamType>
  44. void TestSkipWhitespace() {
  45. for (size_t step = 1; step < 32; step++) {
  46. char buffer[1025];
  47. for (size_t i = 0; i < 1024; i++)
  48. buffer[i] = " \t\r\n"[i % 4];
  49. for (size_t i = 0; i < 1024; i += step)
  50. buffer[i] = 'X';
  51. buffer[1024] = '\0';
  52. StreamType s(buffer);
  53. size_t i = 0;
  54. for (;;) {
  55. SkipWhitespace(s);
  56. if (s.Peek() == '\0')
  57. break;
  58. EXPECT_EQ(i, s.Tell());
  59. EXPECT_EQ('X', s.Take());
  60. i += step;
  61. }
  62. }
  63. }
  64. TEST(SIMD, SIMD_SUFFIX(SkipWhitespace)) {
  65. TestSkipWhitespace<StringStream>();
  66. TestSkipWhitespace<InsituStringStream>();
  67. }
  68. TEST(SIMD, SIMD_SUFFIX(SkipWhitespace_EncodedMemoryStream)) {
  69. for (size_t step = 1; step < 32; step++) {
  70. char buffer[1024];
  71. for (size_t i = 0; i < 1024; i++)
  72. buffer[i] = " \t\r\n"[i % 4];
  73. for (size_t i = 0; i < 1024; i += step)
  74. buffer[i] = 'X';
  75. MemoryStream ms(buffer, 1024);
  76. EncodedInputStream<UTF8<>, MemoryStream> s(ms);
  77. size_t i = 0;
  78. for (;;) {
  79. SkipWhitespace(s);
  80. if (s.Peek() == '\0')
  81. break;
  82. //EXPECT_EQ(i, s.Tell());
  83. EXPECT_EQ('X', s.Take());
  84. i += step;
  85. }
  86. }
  87. }
  88. struct ScanCopyUnescapedStringHandler : BaseReaderHandler<UTF8<>, ScanCopyUnescapedStringHandler> {
  89. bool String(const char* str, size_t length, bool) {
  90. memcpy(buffer, str, length + 1);
  91. return true;
  92. }
  93. char buffer[1024 + 5 + 32];
  94. };
  95. template <unsigned parseFlags, typename StreamType>
  96. void TestScanCopyUnescapedString() {
  97. char buffer[1024u + 5 + 32];
  98. char backup[1024u + 5 + 32];
  99. // Test "ABCDABCD...\\"
  100. for (size_t offset = 0; offset < 32; offset++) {
  101. for (size_t step = 0; step < 1024; step++) {
  102. char* json = buffer + offset;
  103. char *p = json;
  104. *p++ = '\"';
  105. for (size_t i = 0; i < step; i++)
  106. *p++ = "ABCD"[i % 4];
  107. *p++ = '\\';
  108. *p++ = '\\';
  109. *p++ = '\"';
  110. *p++ = '\0';
  111. strcpy(backup, json); // insitu parsing will overwrite buffer, so need to backup first
  112. StreamType s(json);
  113. Reader reader;
  114. ScanCopyUnescapedStringHandler h;
  115. reader.Parse<parseFlags>(s, h);
  116. EXPECT_TRUE(memcmp(h.buffer, backup + 1, step) == 0);
  117. EXPECT_EQ('\\', h.buffer[step]); // escaped
  118. EXPECT_EQ('\0', h.buffer[step + 1]);
  119. }
  120. }
  121. // Test "\\ABCDABCD..."
  122. for (size_t offset = 0; offset < 32; offset++) {
  123. for (size_t step = 0; step < 1024; step++) {
  124. char* json = buffer + offset;
  125. char *p = json;
  126. *p++ = '\"';
  127. *p++ = '\\';
  128. *p++ = '\\';
  129. for (size_t i = 0; i < step; i++)
  130. *p++ = "ABCD"[i % 4];
  131. *p++ = '\"';
  132. *p++ = '\0';
  133. strcpy(backup, json); // insitu parsing will overwrite buffer, so need to backup first
  134. StreamType s(json);
  135. Reader reader;
  136. ScanCopyUnescapedStringHandler h;
  137. reader.Parse<parseFlags>(s, h);
  138. EXPECT_TRUE(memcmp(h.buffer + 1, backup + 3, step) == 0);
  139. EXPECT_EQ('\\', h.buffer[0]); // escaped
  140. EXPECT_EQ('\0', h.buffer[step + 1]);
  141. }
  142. }
  143. }
  144. TEST(SIMD, SIMD_SUFFIX(ScanCopyUnescapedString)) {
  145. TestScanCopyUnescapedString<kParseDefaultFlags, StringStream>();
  146. TestScanCopyUnescapedString<kParseInsituFlag, InsituStringStream>();
  147. }
  148. TEST(SIMD, SIMD_SUFFIX(ScanWriteUnescapedString)) {
  149. char buffer[2048 + 1 + 32];
  150. for (size_t offset = 0; offset < 32; offset++) {
  151. for (size_t step = 0; step < 1024; step++) {
  152. char* s = buffer + offset;
  153. char* p = s;
  154. for (size_t i = 0; i < step; i++)
  155. *p++ = "ABCD"[i % 4];
  156. char escape = "\0\n\\\""[step % 4];
  157. *p++ = escape;
  158. for (size_t i = 0; i < step; i++)
  159. *p++ = "ABCD"[i % 4];
  160. StringBuffer sb;
  161. Writer<StringBuffer> writer(sb);
  162. writer.String(s, SizeType(step * 2 + 1));
  163. const char* q = sb.GetString();
  164. EXPECT_EQ('\"', *q++);
  165. for (size_t i = 0; i < step; i++)
  166. EXPECT_EQ("ABCD"[i % 4], *q++);
  167. if (escape == '\0') {
  168. EXPECT_EQ('\\', *q++);
  169. EXPECT_EQ('u', *q++);
  170. EXPECT_EQ('0', *q++);
  171. EXPECT_EQ('0', *q++);
  172. EXPECT_EQ('0', *q++);
  173. EXPECT_EQ('0', *q++);
  174. }
  175. else if (escape == '\n') {
  176. EXPECT_EQ('\\', *q++);
  177. EXPECT_EQ('n', *q++);
  178. }
  179. else if (escape == '\\') {
  180. EXPECT_EQ('\\', *q++);
  181. EXPECT_EQ('\\', *q++);
  182. }
  183. else if (escape == '\"') {
  184. EXPECT_EQ('\\', *q++);
  185. EXPECT_EQ('\"', *q++);
  186. }
  187. for (size_t i = 0; i < step; i++)
  188. EXPECT_EQ("ABCD"[i % 4], *q++);
  189. EXPECT_EQ('\"', *q++);
  190. EXPECT_EQ('\0', *q++);
  191. }
  192. }
  193. }
  194. #ifdef __GNUC__
  195. RAPIDJSON_DIAG_POP
  196. #endif