blob: 7b58cd05f9dc8792fab22c5de215551781fa42eb [file] [log] [blame]
miloyip8d392822015-04-18 21:41:38 +08001// 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.
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);
90 size_t i = 0;
91 for (;;) {
92 SkipWhitespace(s);
93 if (s.Peek() == '\0')
94 break;
95 //EXPECT_EQ(i, s.Tell());
96 EXPECT_EQ('X', s.Take());
97 i += step;
98 }
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() {
Milo Yip3da4afd2016-04-16 15:19:34 +0800112 char buffer[1024 + 5 + 32];
Milo Yipbdfa0442016-04-16 21:44:33 +0800113 char backup[1024 + 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)) {
Milo Yipa6f9cb82016-04-16 16:11:34 +0800170 char buffer[2048 + 1 + 32];
171 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