blob: 6fa0d491db7cc516660d95974f233f13815027ee [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
Milo Yip0571a212015-04-15 22:36:00 +080052template <typename StreamType>
53void TestSkipWhitespace() {
Milo Yip74c8dcf2015-12-18 18:34:04 +080054 for (size_t step = 1; step < 32; step++) {
Milo Yip4d3c64a2015-04-15 21:07:30 +080055 char buffer[1025];
56 for (size_t i = 0; i < 1024; i++)
57 buffer[i] = " \t\r\n"[i % 4];
58 for (size_t i = 0; i < 1024; i += step)
59 buffer[i] = 'X';
60 buffer[1024] = '\0';
miloyipa32d8b72015-04-15 18:18:49 +080061
Milo Yip0571a212015-04-15 22:36:00 +080062 StreamType s(buffer);
Milo Yip4d3c64a2015-04-15 21:07:30 +080063 size_t i = 0;
64 for (;;) {
65 SkipWhitespace(s);
66 if (s.Peek() == '\0')
67 break;
68 EXPECT_EQ(i, s.Tell());
69 EXPECT_EQ('X', s.Take());
70 i += step;
71 }
miloyipa32d8b72015-04-15 18:18:49 +080072 }
73}
Milo Yip0571a212015-04-15 22:36:00 +080074
75TEST(SIMD, SIMD_SUFFIX(SkipWhitespace)) {
76 TestSkipWhitespace<StringStream>();
77 TestSkipWhitespace<InsituStringStream>();
78}
Milo Yipd258f592016-02-03 12:51:02 +080079
Milo Yip48378b72016-02-15 20:21:36 +080080TEST(SIMD, SIMD_SUFFIX(SkipWhitespace_EncodedMemoryStream)) {
81 for (size_t step = 1; step < 32; step++) {
82 char buffer[1024];
83 for (size_t i = 0; i < 1024; i++)
84 buffer[i] = " \t\r\n"[i % 4];
85 for (size_t i = 0; i < 1024; i += step)
86 buffer[i] = 'X';
87
88 MemoryStream ms(buffer, 1024);
89 EncodedInputStream<UTF8<>, MemoryStream> s(ms);
Milo Yip48378b72016-02-15 20:21:36 +080090 for (;;) {
91 SkipWhitespace(s);
92 if (s.Peek() == '\0')
93 break;
94 //EXPECT_EQ(i, s.Tell());
95 EXPECT_EQ('X', s.Take());
Milo Yip48378b72016-02-15 20:21:36 +080096 }
97 }
98}
99
Milo Yipd258f592016-02-03 12:51:02 +0800100struct ScanCopyUnescapedStringHandler : BaseReaderHandler<UTF8<>, ScanCopyUnescapedStringHandler> {
Milo Yip021d7462016-02-03 13:10:55 +0800101 bool String(const char* str, size_t length, bool) {
Milo Yipd258f592016-02-03 12:51:02 +0800102 memcpy(buffer, str, length + 1);
103 return true;
104 }
Milo Yipbdfa0442016-04-16 21:44:33 +0800105 char buffer[1024 + 5 + 32];
Milo Yipd258f592016-02-03 12:51:02 +0800106};
107
Milo Yip7c726402016-02-03 13:48:39 +0800108template <unsigned parseFlags, typename StreamType>
Milo Yipd258f592016-02-03 12:51:02 +0800109void TestScanCopyUnescapedString() {
Philipp A Hartmanna26267d2018-07-15 16:01:02 +0200110 char buffer[1024u + 5 + 32];
111 char backup[1024u + 5 + 32];
Milo Yipd258f592016-02-03 12:51:02 +0800112
Milo Yipbdfa0442016-04-16 21:44:33 +0800113 // Test "ABCDABCD...\\"
Milo Yip3da4afd2016-04-16 15:19:34 +0800114 for (size_t offset = 0; offset < 32; offset++) {
115 for (size_t step = 0; step < 1024; step++) {
116 char* json = buffer + offset;
117 char *p = json;
118 *p++ = '\"';
119 for (size_t i = 0; i < step; i++)
120 *p++ = "ABCD"[i % 4];
121 *p++ = '\\';
122 *p++ = '\\';
123 *p++ = '\"';
124 *p++ = '\0';
Milo Yipbdfa0442016-04-16 21:44:33 +0800125 strcpy(backup, json); // insitu parsing will overwrite buffer, so need to backup first
Milo Yip3da4afd2016-04-16 15:19:34 +0800126
127 StreamType s(json);
128 Reader reader;
129 ScanCopyUnescapedStringHandler h;
130 reader.Parse<parseFlags>(s, h);
Milo Yipbdfa0442016-04-16 21:44:33 +0800131 EXPECT_TRUE(memcmp(h.buffer, backup + 1, step) == 0);
Milo Yip3da4afd2016-04-16 15:19:34 +0800132 EXPECT_EQ('\\', h.buffer[step]); // escaped
133 EXPECT_EQ('\0', h.buffer[step + 1]);
134 }
Milo Yipd258f592016-02-03 12:51:02 +0800135 }
Milo Yipbdfa0442016-04-16 21:44:33 +0800136
137 // Test "\\ABCDABCD..."
138 for (size_t offset = 0; offset < 32; offset++) {
139 for (size_t step = 0; step < 1024; step++) {
140 char* json = buffer + offset;
141 char *p = json;
142 *p++ = '\"';
143 *p++ = '\\';
144 *p++ = '\\';
145 for (size_t i = 0; i < step; i++)
146 *p++ = "ABCD"[i % 4];
147 *p++ = '\"';
148 *p++ = '\0';
149 strcpy(backup, json); // insitu parsing will overwrite buffer, so need to backup first
150
151 StreamType s(json);
152 Reader reader;
153 ScanCopyUnescapedStringHandler h;
154 reader.Parse<parseFlags>(s, h);
155 EXPECT_TRUE(memcmp(h.buffer + 1, backup + 3, step) == 0);
156 EXPECT_EQ('\\', h.buffer[0]); // escaped
157 EXPECT_EQ('\0', h.buffer[step + 1]);
158 }
159 }
Milo Yipd258f592016-02-03 12:51:02 +0800160}
161
162TEST(SIMD, SIMD_SUFFIX(ScanCopyUnescapedString)) {
Milo Yip7c726402016-02-03 13:48:39 +0800163 TestScanCopyUnescapedString<kParseDefaultFlags, StringStream>();
164 TestScanCopyUnescapedString<kParseInsituFlag, InsituStringStream>();
Milo Yipd258f592016-02-03 12:51:02 +0800165}
Milo Yipcefae772016-02-03 13:29:25 +0800166
Milo Yip6a6d9c72016-02-14 17:37:53 +0800167TEST(SIMD, SIMD_SUFFIX(ScanWriteUnescapedString)) {
Milo Yipa6f9cb82016-04-16 16:11:34 +0800168 char buffer[2048 + 1 + 32];
169 for (size_t offset = 0; offset < 32; offset++) {
170 for (size_t step = 0; step < 1024; step++) {
171 char* s = buffer + offset;
172 char* p = s;
173 for (size_t i = 0; i < step; i++)
174 *p++ = "ABCD"[i % 4];
175 char escape = "\0\n\\\""[step % 4];
176 *p++ = escape;
177 for (size_t i = 0; i < step; i++)
178 *p++ = "ABCD"[i % 4];
Milo Yip6a6d9c72016-02-14 17:37:53 +0800179
Milo Yipa6f9cb82016-04-16 16:11:34 +0800180 StringBuffer sb;
181 Writer<StringBuffer> writer(sb);
182 writer.String(s, SizeType(step * 2 + 1));
183 const char* q = sb.GetString();
Milo Yip6a6d9c72016-02-14 17:37:53 +0800184 EXPECT_EQ('\"', *q++);
Milo Yipa6f9cb82016-04-16 16:11:34 +0800185 for (size_t i = 0; i < step; i++)
186 EXPECT_EQ("ABCD"[i % 4], *q++);
187 if (escape == '\0') {
188 EXPECT_EQ('\\', *q++);
189 EXPECT_EQ('u', *q++);
190 EXPECT_EQ('0', *q++);
191 EXPECT_EQ('0', *q++);
192 EXPECT_EQ('0', *q++);
193 EXPECT_EQ('0', *q++);
194 }
195 else if (escape == '\n') {
196 EXPECT_EQ('\\', *q++);
197 EXPECT_EQ('n', *q++);
198 }
199 else if (escape == '\\') {
200 EXPECT_EQ('\\', *q++);
201 EXPECT_EQ('\\', *q++);
202 }
203 else if (escape == '\"') {
204 EXPECT_EQ('\\', *q++);
205 EXPECT_EQ('\"', *q++);
206 }
207 for (size_t i = 0; i < step; i++)
208 EXPECT_EQ("ABCD"[i % 4], *q++);
209 EXPECT_EQ('\"', *q++);
210 EXPECT_EQ('\0', *q++);
Milo Yip6a6d9c72016-02-14 17:37:53 +0800211 }
Milo Yip6a6d9c72016-02-14 17:37:53 +0800212 }
213}
214
Milo Yipcefae772016-02-03 13:29:25 +0800215#ifdef __GNUC__
216RAPIDJSON_DIAG_POP
217#endif