blob: 570b0836436fea17b761a0566327d01fe9b48228 [file] [log] [blame]
miloyip8d392822015-04-18 21:41:38 +08001// Tencent is pleased to support the open source community by making RapidJSON available.
2//
Silas S. Brownb7734d92020-10-09 10:04:07 +01003// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip.
miloyipa32d8b72015-04-15 18:18:49 +08004//
miloyip8d392822015-04-18 21:41:38 +08005// 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
miloyipa32d8b72015-04-15 18:18:49 +08007//
miloyip8d392822015-04-18 21:41:38 +08008// http://opensource.org/licenses/MIT
miloyipa32d8b72015-04-15 18:18:49 +08009//
miloyip8d392822015-04-18 21:41:38 +080010// 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.
miloyipa32d8b72015-04-15 18:18:49 +080014
15// Since Travis CI installs old Valgrind 3.7.0, which fails with some SSE4.2
16// The unit tests prefix with SIMD should be skipped by Valgrind test
17
18// __SSE2__ and __SSE4_2__ are recognized by gcc, clang, and the Intel compiler.
19// We use -march=native with gmake to enable -msse2 and -msse4.2, if supported.
20#if defined(__SSE4_2__)
21# define RAPIDJSON_SSE42
22#elif defined(__SSE2__)
23# define RAPIDJSON_SSE2
Alejandro Martinez22912582017-04-11 02:02:15 +000024#elif defined(__ARM_NEON)
25# define RAPIDJSON_NEON
miloyipa32d8b72015-04-15 18:18:49 +080026#endif
27
miloyipee505262015-04-15 18:34:18 +080028#define RAPIDJSON_NAMESPACE rapidjson_simd
29
miloyipa32d8b72015-04-15 18:18:49 +080030#include "unittest.h"
31
32#include "rapidjson/reader.h"
Milo Yip6a6d9c72016-02-14 17:37:53 +080033#include "rapidjson/writer.h"
miloyipa32d8b72015-04-15 18:18:49 +080034
Milo Yipcefae772016-02-03 13:29:25 +080035#ifdef __GNUC__
36RAPIDJSON_DIAG_PUSH
37RAPIDJSON_DIAG_OFF(effc++)
38#endif
39
miloyipee505262015-04-15 18:34:18 +080040using namespace rapidjson_simd;
miloyipa32d8b72015-04-15 18:18:49 +080041
42#ifdef RAPIDJSON_SSE2
43#define SIMD_SUFFIX(name) name##_SSE2
44#elif defined(RAPIDJSON_SSE42)
45#define SIMD_SUFFIX(name) name##_SSE42
Alejandro Martinez22912582017-04-11 02:02:15 +000046#elif defined(RAPIDJSON_NEON)
47#define SIMD_SUFFIX(name) name##_NEON
miloyipa32d8b72015-04-15 18:18:49 +080048#else
49#define SIMD_SUFFIX(name) name
50#endif
51
Steve Hanson778dc8b2022-12-01 10:58:43 +000052#define SIMD_SIZE_ALIGN(n) ((size_t(n) + 15) & ~size_t(15))
53
Milo Yip0571a212015-04-15 22:36:00 +080054template <typename StreamType>
55void TestSkipWhitespace() {
Milo Yip74c8dcf2015-12-18 18:34:04 +080056 for (size_t step = 1; step < 32; step++) {
Steve Hanson778dc8b2022-12-01 10:58:43 +000057 char buffer[SIMD_SIZE_ALIGN(1025)];
Milo Yip4d3c64a2015-04-15 21:07:30 +080058 for (size_t i = 0; i < 1024; i++)
59 buffer[i] = " \t\r\n"[i % 4];
60 for (size_t i = 0; i < 1024; i += step)
61 buffer[i] = 'X';
62 buffer[1024] = '\0';
miloyipa32d8b72015-04-15 18:18:49 +080063
Milo Yip0571a212015-04-15 22:36:00 +080064 StreamType s(buffer);
Milo Yip4d3c64a2015-04-15 21:07:30 +080065 size_t i = 0;
66 for (;;) {
67 SkipWhitespace(s);
68 if (s.Peek() == '\0')
69 break;
70 EXPECT_EQ(i, s.Tell());
71 EXPECT_EQ('X', s.Take());
72 i += step;
73 }
miloyipa32d8b72015-04-15 18:18:49 +080074 }
75}
Milo Yip0571a212015-04-15 22:36:00 +080076
77TEST(SIMD, SIMD_SUFFIX(SkipWhitespace)) {
78 TestSkipWhitespace<StringStream>();
79 TestSkipWhitespace<InsituStringStream>();
80}
Milo Yipd258f592016-02-03 12:51:02 +080081
Milo Yip48378b72016-02-15 20:21:36 +080082TEST(SIMD, SIMD_SUFFIX(SkipWhitespace_EncodedMemoryStream)) {
83 for (size_t step = 1; step < 32; step++) {
Steve Hanson778dc8b2022-12-01 10:58:43 +000084 char buffer[SIMD_SIZE_ALIGN(1024)];
Milo Yip48378b72016-02-15 20:21:36 +080085 for (size_t i = 0; i < 1024; i++)
86 buffer[i] = " \t\r\n"[i % 4];
87 for (size_t i = 0; i < 1024; i += step)
88 buffer[i] = 'X';
89
90 MemoryStream ms(buffer, 1024);
91 EncodedInputStream<UTF8<>, MemoryStream> s(ms);
Milo Yip48378b72016-02-15 20:21:36 +080092 for (;;) {
93 SkipWhitespace(s);
94 if (s.Peek() == '\0')
95 break;
96 //EXPECT_EQ(i, s.Tell());
97 EXPECT_EQ('X', s.Take());
Milo Yip48378b72016-02-15 20:21:36 +080098 }
99 }
100}
101
Milo Yipd258f592016-02-03 12:51:02 +0800102struct ScanCopyUnescapedStringHandler : BaseReaderHandler<UTF8<>, ScanCopyUnescapedStringHandler> {
Milo Yip021d7462016-02-03 13:10:55 +0800103 bool String(const char* str, size_t length, bool) {
Milo Yipd258f592016-02-03 12:51:02 +0800104 memcpy(buffer, str, length + 1);
105 return true;
106 }
Milo Yipbdfa0442016-04-16 21:44:33 +0800107 char buffer[1024 + 5 + 32];
Milo Yipd258f592016-02-03 12:51:02 +0800108};
109
Milo Yip7c726402016-02-03 13:48:39 +0800110template <unsigned parseFlags, typename StreamType>
Milo Yipd258f592016-02-03 12:51:02 +0800111void TestScanCopyUnescapedString() {
Steve Hanson778dc8b2022-12-01 10:58:43 +0000112 char buffer[SIMD_SIZE_ALIGN(1024u + 5 + 32)];
113 char backup[SIMD_SIZE_ALIGN(1024u + 5 + 32)];
Milo Yipd258f592016-02-03 12:51:02 +0800114
Milo Yipbdfa0442016-04-16 21:44:33 +0800115 // Test "ABCDABCD...\\"
Milo Yip3da4afd2016-04-16 15:19:34 +0800116 for (size_t offset = 0; offset < 32; offset++) {
117 for (size_t step = 0; step < 1024; step++) {
118 char* json = buffer + offset;
119 char *p = json;
120 *p++ = '\"';
121 for (size_t i = 0; i < step; i++)
122 *p++ = "ABCD"[i % 4];
123 *p++ = '\\';
124 *p++ = '\\';
125 *p++ = '\"';
126 *p++ = '\0';
Milo Yipbdfa0442016-04-16 21:44:33 +0800127 strcpy(backup, json); // insitu parsing will overwrite buffer, so need to backup first
Milo Yip3da4afd2016-04-16 15:19:34 +0800128
129 StreamType s(json);
130 Reader reader;
131 ScanCopyUnescapedStringHandler h;
132 reader.Parse<parseFlags>(s, h);
Milo Yipbdfa0442016-04-16 21:44:33 +0800133 EXPECT_TRUE(memcmp(h.buffer, backup + 1, step) == 0);
Milo Yip3da4afd2016-04-16 15:19:34 +0800134 EXPECT_EQ('\\', h.buffer[step]); // escaped
135 EXPECT_EQ('\0', h.buffer[step + 1]);
136 }
Milo Yipd258f592016-02-03 12:51:02 +0800137 }
Milo Yipbdfa0442016-04-16 21:44:33 +0800138
139 // Test "\\ABCDABCD..."
140 for (size_t offset = 0; offset < 32; offset++) {
141 for (size_t step = 0; step < 1024; step++) {
142 char* json = buffer + offset;
143 char *p = json;
144 *p++ = '\"';
145 *p++ = '\\';
146 *p++ = '\\';
147 for (size_t i = 0; i < step; i++)
148 *p++ = "ABCD"[i % 4];
149 *p++ = '\"';
150 *p++ = '\0';
151 strcpy(backup, json); // insitu parsing will overwrite buffer, so need to backup first
152
153 StreamType s(json);
154 Reader reader;
155 ScanCopyUnescapedStringHandler h;
156 reader.Parse<parseFlags>(s, h);
157 EXPECT_TRUE(memcmp(h.buffer + 1, backup + 3, step) == 0);
158 EXPECT_EQ('\\', h.buffer[0]); // escaped
159 EXPECT_EQ('\0', h.buffer[step + 1]);
160 }
161 }
Milo Yipd258f592016-02-03 12:51:02 +0800162}
163
164TEST(SIMD, SIMD_SUFFIX(ScanCopyUnescapedString)) {
Milo Yip7c726402016-02-03 13:48:39 +0800165 TestScanCopyUnescapedString<kParseDefaultFlags, StringStream>();
166 TestScanCopyUnescapedString<kParseInsituFlag, InsituStringStream>();
Milo Yipd258f592016-02-03 12:51:02 +0800167}
Milo Yipcefae772016-02-03 13:29:25 +0800168
Milo Yip6a6d9c72016-02-14 17:37:53 +0800169TEST(SIMD, SIMD_SUFFIX(ScanWriteUnescapedString)) {
Steve Hanson778dc8b2022-12-01 10:58:43 +0000170 char buffer[SIMD_SIZE_ALIGN(2048 + 1 + 32)];
Milo Yipa6f9cb82016-04-16 16:11:34 +0800171 for (size_t offset = 0; offset < 32; offset++) {
172 for (size_t step = 0; step < 1024; step++) {
173 char* s = buffer + offset;
174 char* p = s;
175 for (size_t i = 0; i < step; i++)
176 *p++ = "ABCD"[i % 4];
177 char escape = "\0\n\\\""[step % 4];
178 *p++ = escape;
179 for (size_t i = 0; i < step; i++)
180 *p++ = "ABCD"[i % 4];
Milo Yip6a6d9c72016-02-14 17:37:53 +0800181
Milo Yipa6f9cb82016-04-16 16:11:34 +0800182 StringBuffer sb;
183 Writer<StringBuffer> writer(sb);
184 writer.String(s, SizeType(step * 2 + 1));
185 const char* q = sb.GetString();
Milo Yip6a6d9c72016-02-14 17:37:53 +0800186 EXPECT_EQ('\"', *q++);
Milo Yipa6f9cb82016-04-16 16:11:34 +0800187 for (size_t i = 0; i < step; i++)
188 EXPECT_EQ("ABCD"[i % 4], *q++);
189 if (escape == '\0') {
190 EXPECT_EQ('\\', *q++);
191 EXPECT_EQ('u', *q++);
192 EXPECT_EQ('0', *q++);
193 EXPECT_EQ('0', *q++);
194 EXPECT_EQ('0', *q++);
195 EXPECT_EQ('0', *q++);
196 }
197 else if (escape == '\n') {
198 EXPECT_EQ('\\', *q++);
199 EXPECT_EQ('n', *q++);
200 }
201 else if (escape == '\\') {
202 EXPECT_EQ('\\', *q++);
203 EXPECT_EQ('\\', *q++);
204 }
205 else if (escape == '\"') {
206 EXPECT_EQ('\\', *q++);
207 EXPECT_EQ('\"', *q++);
208 }
209 for (size_t i = 0; i < step; i++)
210 EXPECT_EQ("ABCD"[i % 4], *q++);
211 EXPECT_EQ('\"', *q++);
212 EXPECT_EQ('\0', *q++);
Milo Yip6a6d9c72016-02-14 17:37:53 +0800213 }
Milo Yip6a6d9c72016-02-14 17:37:53 +0800214 }
215}
216
Milo Yipcefae772016-02-03 13:29:25 +0800217#ifdef __GNUC__
218RAPIDJSON_DIAG_POP
219#endif