Codebase list blockattack / a642a40
New upstream version 2.6.0 Markus Koschany 3 years ago
106 changed file(s) with 4205 addition(s) and 1816 deletion(s). Raw diff Collapse all Expand all
22 set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${blockattack_SOURCE_DIR}/source/misc/cmake")
33 set(BIN_DIR ${blockattack_SOURCE_DIR}/Game)
44
5 SET(CPACK_PACKAGE_VERSION "2.5.0")
5 SET(CPACK_PACKAGE_VERSION "2.6.0")
66 SET(CPACK_PACKAGE_VERSION_MAJOR "2")
7 SET(CPACK_PACKAGE_VERSION_MINOR "5")
7 SET(CPACK_PACKAGE_VERSION_MINOR "6")
88 SET(CPACK_PACKAGE_VERSION_PATCH "0")
99 SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Block Attack - Rise of the Blocks ${CPACK_PACKAGE_VERSION}")
1010 SET(CPACK_PACKAGE_VENDOR "Poul Sander")
3939 endif()
4040
4141 if (NOT WIN32 AND NOT STANDALONE)
42 #The path to the data dir must be compiled into the binary
43 add_definitions(-DSHAREDIR=\"${CMAKE_INSTALL_PREFIX}/${INSTALL_DATA_DIR}\")
44 add_definitions(-DLOCALEDIR=\"${CMAKE_INSTALL_PREFIX}/${INSTALL_LOCALE_DIR}\")
42 #The path to the data dir must be compiled into the binary
43 if (IS_ABSOLUTE ${INSTALL_DATA_DIR})
44 add_definitions(-DSHAREDIR=\"${INSTALL_DATA_DIR}\")
45 else()
46 add_definitions(-DSHAREDIR=\"${CMAKE_INSTALL_PREFIX}/${INSTALL_DATA_DIR}\")
47 endif()
48 if (IS_ABSOLUTE ${INSTALL_DATA_DIR})
49 add_definitions(-DLOCALEDIR=\"${INSTALL_LOCALE_DIR}\")
50 else()
51 add_definitions(-DLOCALEDIR=\"${CMAKE_INSTALL_PREFIX}/${INSTALL_LOCALE_DIR}\")
52 endif()
4553 endif()
4654
4755 #Compiler options
6169 pkg_search_module(SDL2MIXER REQUIRED SDL2_mixer)
6270 pkg_search_module(SDL2IMAGE REQUIRED SDL2_image)
6371 pkg_search_module(SDL2TTF REQUIRED SDL2_ttf)
72
73 include_directories(${SDL2MIXER_INCLUDE_DIRS})
74 include_directories(${SDL2IMAGE_INCLUDE_DIRS})
75 include_directories(${SDL2TTF_INCLUDE_DIRS})
6476
6577 find_package(Boost COMPONENTS program_options REQUIRED)
6678
+0
-11
ReleaseNotes-2.5.0.txt less more
0 This is Block Attack - Rise of the Blocks - version 2.5.0
1
2 Changes since 2.4.0:
3 Added option to always use the software renderer
4 Automatically start in software render the first time after a crash
5 Fixed the search order in archives
6 Added widescreen support. Only used in fullscreen by default.
7 Added appstream metadata
8 Screenshot feature no longer crashes in hardware acceleration. Still only works in software mode
9
10 Feedback can be given on https://blockattack.net or https://github.com/blockattack/blockattack-game
0 This is Block Attack - Rise of the Blocks - version 2.6.0
1
2 The main focus of this release is improved controller support.
3
4 Changes since 2.5.0:
5
6 Modified the controller keybind. "B" is now Cancel instead of "Y"
7 There is a virtual keyboard on the enter name screen allowing using a mouse or a gamepad to type.
8 Added patch by bmwiedemann for sorting in the data file
9 Update embedded Cerial from 1.2.2 to 1.3.0
10 Update library versions for the compiled Linux version:
11 * SDL2: 2.0.9 to 2.0.12
12 * SDL2_image: 2.0.4 to 2.0.5
13 * SDL2_ttf: 2.0.14 to 2.0.15
14 * physfs: 2.0.3 to 3.0.2
15
0 .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.10.
1 .TH BLOCKATTACK "6" "May 2019" "blockattack 2.5.0" "Games"
0 .\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.13.
1 .TH BLOCKATTACK "6" "September 2020" "blockattack 2.6.0" "Games"
22 .SH NAME
33 blockattack \- a puzzle game inspired by Tetris Attack
44 .SH SYNOPSIS
55 .B blockattack
66 [\fI\,OPTION\/\fR]...
77 .SH DESCRIPTION
8 Block Attack \- Rise of the blocks 2.5.0
8 Block Attack \- Rise of the blocks 2.6.0
99 .PP
1010 Block Attack \- Rise of the Blocks is a puzzle/blockfall game inspired by Tetris Attack for the SNES.
1111 .PP
00 #!/bin/bash
11 set -e
2 zip -9rjX Game/blockattack.data source/AUTH
2 zip -9jX Game/blockattack.data source/AUTH
33 cd Game/data
4 zip -9rX ../blockattack.data * -x \*svn*
4 zip -9X $(find ../blockattack.data * | sort) -x \*svn*
55 cd ../../man
6 gzip -9 -c blockattack.man > blockattack.6.gz
6 gzip -9n -c blockattack.man > blockattack.6.gz
77 cd ../source/misc/translation/
88 ./build_mo_all.sh
99
6464 #include <sstream>
6565 #include <deque>
6666
67 using std::string;
68 using std::stringstream;
69 using std::cerr;
70 using std::vector;
7167
7268 //Function to convert numbers to string (2 diget)
73 static string itoa2(int num) {
69 static std::string itoa2(int num) {
7470 char buffer[20];
7571 snprintf(buffer, sizeof(buffer), "%02i", num);
7672 return buffer;
10551051 LongChainDoneEvent();
10561052 }
10571053 if (chainSize[i]>1 && !puzzleMode && recordStats) {
1058 Stats::getInstance()->addOne((string)"chainX"+std::to_string(chainSize[i]));
1054 Stats::getInstance()->addOne((std::string)"chainX"+std::to_string(chainSize[i]));
10591055 }
10601056 chainUsed[i]=false;
10611057 }
13921388
13931389 double BlockGame::firstInLine1(int line) {
13941390 if (line > 20 || line < 0) {
1395 cerr << "Warning: first in Line1: " << line << "\n";
1391 std::cerr << "Warning: first in Line1: " << line << "\n";
13961392 return 3.0;
13971393 }
13981394 for (int i=0; i<6; i++) {
14061402 //returns the first coordinate of the block of type
14071403 double BlockGame::firstInLine(int line, int type) {
14081404 if (line > 20 || line < 0) {
1409 cerr << "Warning: first in Line: " << line << "\n";
1405 std::cerr << "Warning: first in Line: " << line << "\n";
14101406 return 3.0;
14111407 }
14121408 for (int i=0; i<6; i++) {
15671563 int placeToCenter = (int)(firstInLine(AIlineToClear, AIcolorToClear)/3.0+firstInLine(AIlineToClear+1, AIcolorToClear)/3.0+firstInLine(AIlineToClear+2, AIcolorToClear)/3.0);
15681564 int unlimitedLoop=0;
15691565 if (AIlineToClear < 0 || AIlineToClear > 20) {
1570 cerr << "AIlineToClear out of range: " << AIlineToClear << "\n";
1566 std::cerr << "AIlineToClear out of range: " << AIlineToClear << "\n";
15711567 return;
15721568 }
15731569 if (placeToCenter<0 || placeToCenter > 5) {
1574 cerr << "placeToCenter out of range: " << placeToCenter << "\n";
1570 std::cerr << "placeToCenter out of range: " << placeToCenter << "\n";
15751571 return;
15761572 }
15771573 while (((board[placeToCenter][AIlineToClear]>1000000)||(board[placeToCenter][AIlineToClear+1]>1000000)||(board[placeToCenter][AIlineToClear+2]>1000000))&&(unlimitedLoop<10)) {
167167 private:
168168 //Draws all the bricks to the board (including garbage)
169169 void PaintBricks() const {
170 for (int i=0; ((i<13)&&(i<30)); i++) {
171 for (int j=0; j<6; j++) {
170 for (int i=0; i<13; ++i) {
171 for (int j=0; j<6; ++j) {
172172 int basicBrick = board[j][i]%10; //The basic brick, stored on the least significant digit
173173 if ((basicBrick > -1) && (basicBrick < 7) && ((board[j][i]/1000000)%10==0)) {
174174 DrawImgBoardBounded(bricks[basicBrick], j*bsize, bsize*12-i*bsize-pixels);
264264 if ((board[j][i]/1000000)%10==1) {
265265 int left, right, over, under;
266266 int number = board[j][i];
267 if (j<1) {
268 left = -1;
269 }
270 else {
271 left = board[j-1][i];
272 }
273 if (j>5) {
274 right = -1;
275 }
276 else {
277 right = board[j+1][i];
278 }
267 left = -1;
268 right = board[j+1][i];
279269 if (i>28) {
280270 over = -1;
281271 }
2424 #include "global.hpp"
2525 #include "common.h"
2626 #include "ReadKeyboard.h"
27 #include "utf8.h"
28 #include "MenuSystem.h"
2729
2830 static void setButtonFont(const sago::SagoDataHolder* holder, sago::SagoTextField& field, const char* text) {
2931 field.SetHolder(holder);
9395 sagoTextSetBlueFont(textField);
9496 sagoTextSetBlueFont(cursorLabel);
9597 cursorLabel.SetText("|");
98 for (auto position = virtualKeyboard.alphabet.begin(); position != virtualKeyboard.alphabet.end() ; utf8::advance(position, 1, virtualKeyboard.alphabet.end())) {
99 auto endPosition = position;
100 utf8::advance(endPosition, 1, virtualKeyboard.alphabet.end());
101 std::string theChar(position, endPosition);
102 virtualKeyboard.gamePadChars.push_back(theChar);
103 virtualKeyboard.gamePadCharFields.emplace_back();
104 sago::SagoTextField& tf = virtualKeyboard.gamePadCharFields.back();
105 setButtonFont(&globalData.spriteHolder->GetDataHolder(), tf, theChar.c_str());
106 if (globalData.verboseLevel) {
107 std::cout << *position;
108 }
109 }
110 if (globalData.verboseLevel) {
111 std::cout << "\n";
112 }
96113 }
97114
98115
103120 return isActive;
104121 }
105122
123 static bool insideRect (int x, int y, int height, int width) {
124 if (globalData.mousex < x) {
125 return false;
126 }
127 if (globalData.mousex > x+width) {
128 return false;
129 }
130 if (globalData.mousey < y) {
131 return false;
132 }
133 if (globalData.mousey > y+height) {
134 return false;
135 }
136 return true;
137 }
138
139 // For use with the mouse/gamepad keyboard
140 int keyboardRowLimit = 20;
106141
107142 void DialogBox::Draw(SDL_Renderer* target) {
108143 DrawBackground(globalData.screen);
110145 this->y = globalData.ysize/2-100;
111146 DrawRectYellow(target, x, y, 200, 600);
112147 headerLabel.Draw(target, x+300, y+20, sago::SagoTextField::Alignment::center);
148 DrawRectYellow(target, x+25, y+128, 50, 250);
113149 enterLabel.Draw(target, x+150, y+140, sago::SagoTextField::Alignment::center);
150 DrawRectYellow(target, x+325, y+128, 50, 250);
114151 cancelLabel.Draw(target, x+450, y+140, sago::SagoTextField::Alignment::center);
115152 DrawRectWhite(target, x+26, y+64, 54, 600-2*26);
116153 textField.SetText(rk->GetString());
124161 width -= 2;
125162 cursorLabel.Draw(target, x+40+width,y+76);
126163 }
127 }
164 const sago::SagoSprite& marked = globalData.spriteHolder->GetSprite("i_level_check_box_marked");
165 for (size_t i = 0; i<virtualKeyboard.gamePadCharFields.size(); ++i) {
166 if (virtualKeyboard.selectedChar == static_cast<int>(i)) {
167 marked.Draw(target, SDL_GetTicks(), globalData.xsize/2-400+(i%keyboardRowLimit)*40-5, globalData.ysize/2+150+(i/keyboardRowLimit)*40-5);
168 }
169 sago::SagoTextField& f = virtualKeyboard.gamePadCharFields.at(i);
170 f.Draw(target, globalData.xsize/2-400+(i%keyboardRowLimit)*40, globalData.ysize/2+150+(i/keyboardRowLimit)*40);
171 }
172 }
173
174
175 static bool isGamePadStartEvent(const SDL_Event& event) {
176 if (event.type == SDL_CONTROLLERBUTTONDOWN) {
177 if (event.cbutton.button == SDL_CONTROLLER_BUTTON_START ) {
178 return true;
179 }
180 }
181 return false;
182 }
183
184 static bool isGamePadLEvent(const SDL_Event& event) {
185 if (event.type == SDL_CONTROLLERBUTTONDOWN) {
186 if (event.cbutton.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER ) {
187 return true;
188 }
189 }
190 return false;
191 }
192
193 static bool isGamePadREvent(const SDL_Event& event) {
194 if (event.type == SDL_CONTROLLERBUTTONDOWN) {
195 if (event.cbutton.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER ) {
196 return true;
197 }
198 }
199 return false;
200 }
201
202
203 void DialogBox::virtualKeyboardWriteSelectedChar(ReadKeyboard* rk, const std::string& insertChar) const {
204 if (insertChar == virtualKeyboard.backspace) {
205 rk->emulateBackspace();
206 }
207 else if (insertChar == virtualKeyboard.leftChar) {
208 rk->cursorLeft();
209 }
210 else if (insertChar == virtualKeyboard.rightChar) {
211 rk->cursorRight();
212 }
213 else {
214 rk->putchar(insertChar);
215 }
216 }
217
128218
129219 void DialogBox::ProcessInput(const SDL_Event& event, bool& processed) {
130220 if (event.type == SDL_TEXTINPUT) {
148238 }
149239 }
150240 }
241 else {
242 if (isGamePadStartEvent(event)) {
243 name = rk->GetString();
244 updated = true;
245 isActive = false;
246 }
247 if (isEscapeEvent(event)) {
248 isActive = false;
249 }
250 if (isConfirmEvent(event)) {
251 const sago::SagoTextField& f = virtualKeyboard.gamePadCharFields.at(virtualKeyboard.selectedChar);
252 const std::string& insertChar = f.GetText();
253 virtualKeyboardWriteSelectedChar(rk.get(), insertChar);
254 }
255 if (event.type == SDL_CONTROLLERBUTTONDOWN) {
256 if (event.cbutton.button == SDL_CONTROLLER_BUTTON_X ) {
257 rk->emulateBackspace();
258 }
259 if (event.cbutton.button == SDL_CONTROLLER_BUTTON_Y ) {
260 rk->putchar(" ");
261 }
262 }
263 if (isGamePadLEvent(event)) {
264 rk->cursorLeft();
265 }
266 if (isGamePadREvent(event)) {
267 rk->cursorRight();
268 }
269 if (isRightEvent(event)) {
270 if ( (virtualKeyboard.selectedChar+1)/keyboardRowLimit != virtualKeyboard.selectedChar/keyboardRowLimit ) {
271 virtualKeyboard.selectedChar -= keyboardRowLimit;
272 }
273 ++virtualKeyboard.selectedChar;
274 if (virtualKeyboard.selectedChar >= static_cast<int>(virtualKeyboard.gamePadCharFields.size())) {
275 virtualKeyboard.selectedChar -= virtualKeyboard.selectedChar%keyboardRowLimit;
276 }
277 }
278 if (isLeftEvent(event)) {
279 if ( (virtualKeyboard.selectedChar-1)/keyboardRowLimit != virtualKeyboard.selectedChar/keyboardRowLimit || virtualKeyboard.selectedChar == 0 ) {
280 virtualKeyboard.selectedChar += keyboardRowLimit;
281 }
282 --virtualKeyboard.selectedChar;
283 }
284 if (isDownEvent(event)) {
285 virtualKeyboard.selectedChar+= keyboardRowLimit;
286 }
287 if (isUpEvent(event)) {
288 virtualKeyboard.selectedChar -= keyboardRowLimit;
289 }
290 if (virtualKeyboard.selectedChar < 0) {
291 virtualKeyboard.selectedChar = 0;
292 }
293 if (virtualKeyboard.selectedChar >= static_cast<int>(virtualKeyboard.gamePadCharFields.size())) {
294 virtualKeyboard.selectedChar = virtualKeyboard.gamePadCharFields.size()-1;
295 }
296 }
151297 processed = true;
298 if ( !(SDL_GetMouseState(nullptr, nullptr)&SDL_BUTTON(1)) ) {
299 bMouseUp=true;
300 }
301
302 if (SDL_GetMouseState(nullptr,nullptr)&SDL_BUTTON(1) && bMouseUp) {
303 bMouseUp = false;
304 if (insideRect(x+25, y+128, 50, 250)) {
305 name = rk->GetString();
306 updated = true;
307 isActive = false;
308 }
309 if (insideRect(x+325, y+128, 50, 250)) {
310 isActive = false;
311 }
312 for (size_t i = 0; i<virtualKeyboard.gamePadCharFields.size(); ++i) {
313 sago::SagoTextField& f = virtualKeyboard.gamePadCharFields.at(i);
314 auto topx = globalData.xsize/2-400+(i%keyboardRowLimit)*40-5;
315 auto topy = globalData.ysize/2+150+(i/keyboardRowLimit)*40-5;
316 if (insideRect(topx, topy, 30, 30)) {
317 std::string insertChar = f.GetText();
318 virtualKeyboardWriteSelectedChar(rk.get(), insertChar);
319 }
320 }
321 }
322
323 if (globalData.mousex != oldmousex || globalData.mousey != oldmousey) {
324 for (size_t i = 0; i<virtualKeyboard.gamePadCharFields.size(); ++i) {
325 auto topx = globalData.xsize/2-400+(i%keyboardRowLimit)*40-5;
326 auto topy = globalData.ysize/2+150+(i/keyboardRowLimit)*40-5;
327 if (insideRect(topx, topy, 30, 30)) {
328 virtualKeyboard.selectedChar = i;
329 }
330 }
331 oldmousex = globalData.mousex;
332 oldmousey = globalData.mousey;
333 }
152334 }
153335
154336 void DialogBox::SetName(const std::string& name) {
3030 #include "scopeHelpers.hpp"
3131 #include "global.hpp"
3232
33 struct VirtualKeyboard {
34 const std::string leftChar = "‹";
35 const std::string rightChar = "›";
36 const std::string backspace = "«";
37 std::string alphabet = std::string(_("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
38 "abcdefghijklmnopqrstuvwxyz"
39 ".,:!?+_^@#%&=*")) + leftChar + rightChar + backspace;
40 std::vector<std::string> gamePadChars;
41 std::vector<sago::SagoTextField> gamePadCharFields;
42 int selectedChar = 0;
43 };
44
3345 class DialogBox : public sago::GameStateInterface {
3446 public:
3547 DialogBox(int x, int y, const std::string& name, const std::string& header);
4456 std::string GetName() const;
4557 bool IsUpdated() const;
4658 private:
59 void virtualKeyboardWriteSelectedChar(ReadKeyboard *rk, const std::string& insertChar) const;
4760 bool isActive = true;
61 bool bMouseUp = false;
4862 std::shared_ptr<ReadKeyboard> rk;
4963 int x;
5064 int y;
5771 sago::SagoTextField cancelLabel;
5872 sago::SagoTextField textField;
5973 sago::SagoTextField cursorLabel;
74 VirtualKeyboard virtualKeyboard;
75 int oldmousex = 0;
76 int oldmousey = 0;
6077 };
78
79 void DrawRectYellow(SDL_Renderer* target, int topx, int topy, int height, int width);
6180
6281 #endif /* DIALOGBOX_HPP */
6382
2020 ===========================================================================
2121 */
2222
23 #include "DialogBox.hpp"
24 #include "HelpCommon.hpp"
2325 #include "HelpAboutState.hpp"
2426 #include "global.hpp"
2527 #include "common.h"
4244 field.SetText(text);
4345 }
4446
45 static void setHelpGamepadFont(const sago::SagoDataHolder* holder, sago::SagoTextBox& field, const char* text) {
46 field.SetHolder(holder);
47 field.SetFont("freeserif");
48 field.SetColor({255,255,255,255});
49 field.SetColor({0,0,0,255});
50 field.SetFontSize(20);
51 field.SetOutline(0, {0,0,0,255});
52 field.SetText(text);
53 }
47
5448
5549
5650
7973 infoStream << _("Save folder:") << " " << PHYSFS_getWriteDir() << "\n";
8074 infoStream << _("Locale:") << " " << setlocale( LC_CTYPE, nullptr ) << "\n";
8175 setHelpGamepadFont(&globalData.spriteHolder->GetDataHolder(), titleField, _("About"));
82 setHelpGamepadFont(&globalData.spriteHolder->GetDataHolder(), infoBox, infoStream.str().c_str());
76 setHelpBoxFont(&globalData.spriteHolder->GetDataHolder(), infoBox, infoStream.str().c_str());
8377 sago::WriteFileContent("about.txt", infoStream.str());
8478 }
8579
9993 processed = true;
10094 }
10195 }
102
103 extern void DrawRectYellow(SDL_Renderer* target, int topx, int topy, int height, int width);
10496
10597 void HelpAboutState::Draw(SDL_Renderer* target) {
10698 DrawBackground(target);
135127 }
136128
137129 }
138 }
130 }
0 /*
1 ===========================================================================
2 blockattack - Block Attack - Rise of the Blocks
3 Copyright (C) 2005-2020 Poul Sander
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see http://www.gnu.org/licenses/
17
18 Source information and contacts persons can be found at
19 https://blockattack.net
20 ===========================================================================
21 */
22
23 #include "HelpCommon.hpp"
24
25
26
27 template<typename T> void setHelp30FontTemplate(const sago::SagoDataHolder* holder, T& field, const char* text) {
28 field.SetHolder(holder);
29 field.SetFont("freeserif");
30 field.SetColor({255,255,255,255});
31 field.SetFontSize(30);
32 field.SetOutline(2, {0,0,0,255});
33 field.SetText(text);
34 }
35
36 void setHelp30Font(const sago::SagoDataHolder* holder, sago::SagoTextField& field, const char* text) {
37 setHelp30FontTemplate(holder, field, text);
38 }
39
40 void setHelp30Font(const sago::SagoDataHolder* holder, sago::SagoTextBox& field, const char* text) {
41 setHelp30FontTemplate(holder, field, text);
42 }
43
44 void setHelpBoxFont(const sago::SagoDataHolder* holder, sago::SagoTextBox& field, const char* text) {
45 field.SetHolder(holder);
46 field.SetFont("freeserif");
47 field.SetColor({255,255,255,255});
48 field.SetColor({0,0,0,255});
49 field.SetFontSize(20);
50 field.SetOutline(0, {0,0,0,255});
51 field.SetText(text);
52 }
0 /*
1 ===========================================================================
2 blockattack - Block Attack - Rise of the Blocks
3 Copyright (C) 2005-2020 Poul Sander
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 2 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see http://www.gnu.org/licenses/
17
18 Source information and contacts persons can be found at
19 https://blockattack.net
20 ===========================================================================
21 */
22
23
24 #ifndef _HELP_COMMON_HPP
25 #define _HELP_COMMON_HPP
26
27 #include "sago/SagoTextBox.hpp"
28 #include "sago/SagoTextField.hpp"
29
30
31 void setHelp30Font(const sago::SagoDataHolder* holder, sago::SagoTextField& field, const char* text);
32 void setHelp30Font(const sago::SagoDataHolder* holder, sago::SagoTextBox& field, const char* text);
33
34 void setHelpBoxFont(const sago::SagoDataHolder* holder, sago::SagoTextBox& field, const char* text);
35
36 #endif //_HELP_COMMON_HPP
2020 ===========================================================================
2121 */
2222
23 #include "HelpCommon.hpp"
2324 #include "HelpGamepadState.hpp"
2425 #include "global.hpp"
2526 #include "common.h"
2829
2930 const int buttonOffset = 160;
3031
31 static void setHelpGamepadFont(const sago::SagoDataHolder* holder, sago::SagoTextField& field, const char* text) {
32 field.SetHolder(holder);
33 field.SetFont("freeserif");
34 field.SetColor({255,255,255,255});
35 field.SetFontSize(30);
36 field.SetOutline(2, {0,0,0,255});
37 field.SetText(text);
38 }
3932
40 static void setHelpGamepadFont(const sago::SagoDataHolder* holder, sago::SagoTextBox& field, const char* text) {
41 field.SetHolder(holder);
42 field.SetFont("freeserif");
43 field.SetColor({255,255,255,255});
44 field.SetFontSize(30);
45 field.SetOutline(2, {0,0,0,255});
46 field.SetText(text);
47 }
48
49
50 HelpGamepadState::HelpGamepadState() {
51 setHelpGamepadFont(&globalData.spriteHolder->GetDataHolder(), moveLabel, _("Move cursor"));
52 setHelpGamepadFont(&globalData.spriteHolder->GetDataHolder(), pushLabel, _("Push line"));
53 setHelpGamepadFont(&globalData.spriteHolder->GetDataHolder(), backLabel, _("Back (Menu)"));
54 setHelpGamepadFont(&globalData.spriteHolder->GetDataHolder(), switchLabel, _("Switch"));
55 setHelpGamepadFont(&globalData.spriteHolder->GetDataHolder(), confirmLabel, _("Confirm"));
33 static std::string getLabelForSupportedControllerNames() {
5634 std::string s = _("Only SDL2 compatible controllers are supported!\nSupported controllers: ");
5735 for (size_t i = 0 ; i<GetSupportedControllerNames().size(); ++i ) {
5836 if (i != 0) {
6038 }
6139 s+= GetSupportedControllerNames().at(i);
6240 }
63 setHelpGamepadFont(&globalData.spriteHolder->GetDataHolder(), supportedControllers, s.c_str());
41 return s;
42 }
43
44
45 HelpGamepadState::HelpGamepadState() {
46 setHelp30Font(&globalData.spriteHolder->GetDataHolder(), moveLabel, _("Move cursor"));
47 setHelp30Font(&globalData.spriteHolder->GetDataHolder(), pushLabel, _("Push line"));
48 setHelp30Font(&globalData.spriteHolder->GetDataHolder(), backLabel, _("Back (Menu)"));
49 setHelp30Font(&globalData.spriteHolder->GetDataHolder(), switchLabel, _("Switch"));
50 setHelp30Font(&globalData.spriteHolder->GetDataHolder(), confirmLabel, _("Confirm"));
51 std::string s = getLabelForSupportedControllerNames();
52 setHelp30Font(&globalData.spriteHolder->GetDataHolder(), supportedControllers, s.c_str());
6453 supportedControllers.SetMaxWidth(740);
6554 }
6655
7362
7463 void HelpGamepadState::ProcessInput(const SDL_Event& event, bool& processed) {
7564 UpdateMouseCoordinates(event, globalData.mousex, globalData.mousey);
65
66 if (isGameControllerConnectionEvent(event)) {
67 UnInitGameControllers();
68 InitGameControllers();
69 std::string s = getLabelForSupportedControllerNames();
70 setHelp30Font(&globalData.spriteHolder->GetDataHolder(), supportedControllers, s.c_str());
71 processed = true;
72 }
7673
7774 if (isConfirmEvent(event) || isEscapeEvent(event)) {
7875 isActive = false;
10198 SDL_RenderDrawLine(target, globalData.xsize/2, 80, globalData.xsize/2, 90);
10299 pushLabel.Draw(target, globalData.xsize/2, 80, sago::SagoTextField::Alignment::center, sago::SagoTextField::VerticalAlignment::bottom);
103100 //Back lines
104 SDL_RenderDrawLine(target, 625+OFFSETX, 168, 800+OFFSETX, 168);
105 SDL_RenderDrawLine(target, 800+OFFSETX, 158, 800+OFFSETX, 195);
106 SDL_RenderDrawLine(target, 490+OFFSETX, 195, 800+OFFSETX, 195);
101 SDL_RenderDrawLine(target, 800+OFFSETX, 158, 800+OFFSETX, 207);
102 SDL_RenderDrawLine(target, 490+OFFSETX, 180, 800+OFFSETX, 180);
103 SDL_RenderDrawLine(target, 490+OFFSETX, 180, 490+OFFSETX, 195);
104 SDL_RenderDrawLine(target, 663+OFFSETX, 207, 800+OFFSETX, 207);
107105 backLabel.Draw(target, 800+OFFSETX, 156, sago::SagoTextField::Alignment::center, sago::SagoTextField::VerticalAlignment::bottom);
108106 SDL_RenderDrawLine(target, 625+OFFSETX, 241, 900+OFFSETX, 241);
109 SDL_RenderDrawLine(target, 663+OFFSETX, 207, 900+OFFSETX, 207);
110 SDL_RenderDrawLine(target, 900+OFFSETX, 207, 900+OFFSETX, 400);
107 SDL_RenderDrawLine(target, 900+OFFSETX, 241, 900+OFFSETX, 400);
111108 switchLabel.Draw(target, 900+OFFSETX, 404, sago::SagoTextField::Alignment::center);
112109 confirmLabel.Draw(target, 900+OFFSETX, 404+30, sago::SagoTextField::Alignment::center);
113110 bExit.Draw(globalData.screen, SDL_GetTicks(), globalData.xsize-buttonOffset, globalData.ysize-buttonOffset);
139136 }
140137
141138 }
142 }
139 }
55
66 See LICENSE for more information
77
8 Version 1.2.2
8 Version 1.3.0
00 /*! \file access.hpp
1 \brief Access control, default construction, and serialization disambiguation */
1 \brief Access control and default construction */
22 /*
33 Copyright (c) 2014, Randolph Voorhies, Shane Grant
44 All rights reserved.
3434 #include <functional>
3535
3636 #include "cereal/macros.hpp"
37 #include "cereal/specialize.hpp"
3738 #include "cereal/details/helpers.hpp"
3839
3940 namespace cereal
109110 // forward decl for construct
110111 //! @cond PRIVATE_NEVERDEFINED
111112 namespace memory_detail{ template <class Ar, class T> struct LoadAndConstructLoadWrapper; }
113 namespace boost_variant_detail{ template <class Ar, class T> struct LoadAndConstructLoadWrapper; }
112114 //! @endcond
113115
114116 //! Used to construct types with no default constructor
201203 }
202204
203205 private:
204 template <class A, class B> friend struct ::cereal::memory_detail::LoadAndConstructLoadWrapper;
206 template <class Ar, class TT> friend struct ::cereal::memory_detail::LoadAndConstructLoadWrapper;
207 template <class Ar, class TT> friend struct ::cereal::boost_variant_detail::LoadAndConstructLoadWrapper;
205208
206209 construct( T * p ) : itsPtr( p ), itsEnableSharedRestoreFunction( [](){} ), itsValid( false ) {}
207210 construct( T * p, std::function<void()> enableSharedFunc ) : // g++4.7 ice with default lambda to std func
331334 }; // end class access
332335
333336 // ######################################################################
334 //! A specifier used in conjunction with cereal::specialize to disambiguate
335 //! serialization in special cases
336 /*! @relates specialize
337 @ingroup Access */
338 enum class specialization
339 {
340 member_serialize, //!< Force the use of a member serialize function
341 member_load_save, //!< Force the use of a member load/save pair
342 member_load_save_minimal, //!< Force the use of a member minimal load/save pair
343 non_member_serialize, //!< Force the use of a non-member serialize function
344 non_member_load_save, //!< Force the use of a non-member load/save pair
345 non_member_load_save_minimal //!< Force the use of a non-member minimal load/save pair
346 };
347
348 //! A class used to disambiguate cases where cereal cannot detect a unique way of serializing a class
349 /*! cereal attempts to figure out which method of serialization (member vs. non-member serialize
350 or load/save pair) at compile time. If for some reason cereal cannot find a non-ambiguous way
351 of serializing a type, it will produce a static assertion complaining about this.
352
353 This can happen because you have both a serialize and load/save pair, or even because a base
354 class has a serialize (public or private with friend access) and a derived class does not
355 overwrite this due to choosing some other serialization type.
356
357 Specializing this class will tell cereal to explicitly use the serialization type you specify
358 and it will not complain about ambiguity in its compile time selection. However, if cereal detects
359 an ambiguity in specializations, it will continue to issue a static assertion.
360
361 @code{.cpp}
362 class MyParent
363 {
364 friend class cereal::access;
365 template <class Archive>
366 void serialize( Archive & ar ) {}
367 };
368
369 // Although serialize is private in MyParent, to cereal::access it will look public,
370 // even through MyDerived
371 class MyDerived : public MyParent
372 {
373 public:
374 template <class Archive>
375 void load( Archive & ar ) {}
376
377 template <class Archive>
378 void save( Archive & ar ) {}
379 };
380
381 // The load/save pair in MyDerived is ambiguous because serialize in MyParent can
382 // be accessed from cereal::access. This looks the same as making serialize public
383 // in MyParent, making it seem as though MyDerived has both a serialize and a load/save pair.
384 // cereal will complain about this at compile time unless we disambiguate:
385
386 namespace cereal
387 {
388 // This struct specialization will tell cereal which is the right way to serialize the ambiguity
389 template <class Archive> struct specialize<Archive, MyDerived, cereal::specialization::member_load_save> {};
390
391 // If we only had a disambiguation for a specific archive type, it would look something like this
392 template <> struct specialize<cereal::BinaryOutputArchive, MyDerived, cereal::specialization::member_load_save> {};
393 }
394 @endcode
395
396 You can also choose to use the macros CEREAL_SPECIALIZE_FOR_ALL_ARCHIVES or
397 CEREAL_SPECIALIZE_FOR_ARCHIVE if you want to type a little bit less.
398
399 @tparam T The type to specialize the serialization for
400 @tparam S The specialization type to use for T
401 @ingroup Access */
402 template <class Archive, class T, specialization S>
403 struct specialize : public std::false_type {};
404
405 //! Convenient macro for performing specialization for all archive types
406 /*! This performs specialization for the specific type for all types of archives.
407 This macro should be placed at the global namespace.
408
409 @code{cpp}
410 struct MyType {};
411 CEREAL_SPECIALIZE_FOR_ALL_ARCHIVES( MyType, cereal::specialization::member_load_save );
412 @endcode
413
414 @relates specialize
415 @ingroup Access */
416 #define CEREAL_SPECIALIZE_FOR_ALL_ARCHIVES( Type, Specialization ) \
417 namespace cereal { template <class Archive> struct specialize<Archive, Type, Specialization> {}; }
418
419 //! Convenient macro for performing specialization for a single archive type
420 /*! This performs specialization for the specific type for a single type of archive.
421 This macro should be placed at the global namespace.
422
423 @code{cpp}
424 struct MyType {};
425 CEREAL_SPECIALIZE_FOR_ARCHIVE( cereal::XMLInputArchive, MyType, cereal::specialization::member_load_save );
426 @endcode
427
428 @relates specialize
429 @ingroup Access */
430 #define CEREAL_SPECIALIZE_FOR_ARCHIVE( Archive, Type, Specialization ) \
431 namespace cereal { template <> struct specialize<Archive, Type, Specialization> {}; }
432
433 // ######################################################################
434337 // Deferred Implementation, see construct for more information
435338 template <class T> template <class ... Args> inline
436339 void construct<T>::operator()( Args && ... args )
6161 ~BinaryOutputArchive() CEREAL_NOEXCEPT = default;
6262
6363 //! Writes size bytes of data to the output stream
64 void saveBinary( const void * data, std::size_t size )
64 void saveBinary( const void * data, std::streamsize size )
6565 {
66 auto const writtenSize = static_cast<std::size_t>( itsStream.rdbuf()->sputn( reinterpret_cast<const char*>( data ), size ) );
66 auto const writtenSize = itsStream.rdbuf()->sputn( reinterpret_cast<const char*>( data ), size );
6767
6868 if(writtenSize != size)
6969 throw Exception("Failed to write " + std::to_string(size) + " bytes to output stream! Wrote " + std::to_string(writtenSize));
9696 ~BinaryInputArchive() CEREAL_NOEXCEPT = default;
9797
9898 //! Reads size bytes of data from the input stream
99 void loadBinary( void * const data, std::size_t size )
99 void loadBinary( void * const data, std::streamsize size )
100100 {
101 auto const readSize = static_cast<std::size_t>( itsStream.rdbuf()->sgetn( reinterpret_cast<char*>( data ), size ) );
101 auto const readSize = itsStream.rdbuf()->sgetn( reinterpret_cast<char*>( data ), size );
102102
103103 if(readSize != size)
104104 throw Exception("Failed to read " + std::to_string(size) + " bytes from input stream! Read " + std::to_string(readSize));
147147 template <class T> inline
148148 void CEREAL_SAVE_FUNCTION_NAME(BinaryOutputArchive & ar, BinaryData<T> const & bd)
149149 {
150 ar.saveBinary( bd.data, static_cast<std::size_t>( bd.size ) );
150 ar.saveBinary( bd.data, static_cast<std::streamsize>( bd.size ) );
151151 }
152152
153153 //! Loading binary data
154154 template <class T> inline
155155 void CEREAL_LOAD_FUNCTION_NAME(BinaryInputArchive & ar, BinaryData<T> & bd)
156156 {
157 ar.loadBinary(bd.data, static_cast<std::size_t>(bd.size));
157 ar.loadBinary(bd.data, static_cast<std::streamsize>( bd.size ) );
158158 }
159159 } // namespace cereal
160160
3939 { RapidJSONException( const char * what_ ) : Exception( what_ ) {} };
4040 }
4141
42 // Inform rapidjson that assert will throw
43 #ifndef CEREAL_RAPIDJSON_ASSERT_THROWS
44 #define CEREAL_RAPIDJSON_ASSERT_THROWS
45 #endif // CEREAL_RAPIDJSON_ASSERT_THROWS
46
4247 // Override rapidjson assertions to throw exceptions by default
4348 #ifndef CEREAL_RAPIDJSON_ASSERT
4449 #define CEREAL_RAPIDJSON_ASSERT(x) if(!(x)){ \
4651 #endif // RAPIDJSON_ASSERT
4752
4853 // Enable support for parsing of nan, inf, -inf
54 #ifndef CEREAL_RAPIDJSON_WRITE_DEFAULT_FLAGS
4955 #define CEREAL_RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNanAndInfFlag
56 #endif
57
58 // Enable support for parsing of nan, inf, -inf
59 #ifndef CEREAL_RAPIDJSON_PARSE_DEFAULT_FLAGS
5060 #define CEREAL_RAPIDJSON_PARSE_DEFAULT_FLAGS kParseFullPrecisionFlag | kParseNanAndInfFlag
61 #endif
5162
5263 #include "cereal/external/rapidjson/prettywriter.h"
5364 #include "cereal/external/rapidjson/ostreamwrapper.h"
208219 {
209220 case NodeType::StartArray:
210221 itsWriter.StartArray();
222 // fall through
211223 case NodeType::InArray:
212224 itsWriter.EndArray();
213225 break;
214226 case NodeType::StartObject:
215227 itsWriter.StartObject();
228 // fall through
216229 case NodeType::InObject:
217230 itsWriter.EndObject();
218231 break;
476489 }
477490
478491 Iterator(ValueIterator begin, ValueIterator end) :
479 itsValueItBegin(begin), itsValueItEnd(end), itsIndex(0), itsType(Value)
492 itsValueItBegin(begin), itsIndex(0), itsType(Value)
480493 {
481494 if( std::distance( begin, end ) == 0 )
482495 itsType = Null_;
531544
532545 private:
533546 MemberIterator itsMemberItBegin, itsMemberItEnd; //!< The member iterator (object)
534 ValueIterator itsValueItBegin, itsValueItEnd; //!< The value iterator (array)
547 ValueIterator itsValueItBegin; //!< The value iterator (array)
535548 size_t itsIndex; //!< The current index of this iterator
536549 enum Type {Value, Member, Null_} itsType; //!< Whether this holds values (array) or members (objects) or nothing
537550 };
751764 { }
752765
753766 // ######################################################################
767 //! Prologue for deferred data for JSON archives
768 /*! Do nothing for the defer wrapper */
769 template <class T> inline
770 void prologue( JSONOutputArchive &, DeferredData<T> const & )
771 { }
772
773 //! Prologue for deferred data for JSON archives
774 template <class T> inline
775 void prologue( JSONInputArchive &, DeferredData<T> const & )
776 { }
777
778 // ######################################################################
779 //! Epilogue for deferred for JSON archives
780 /*! NVPs do not start or finish nodes - they just set up the names */
781 template <class T> inline
782 void epilogue( JSONOutputArchive &, DeferredData<T> const & )
783 { }
784
785 //! Epilogue for deferred for JSON archives
786 /*! Do nothing for the defer wrapper */
787 template <class T> inline
788 void epilogue( JSONInputArchive &, DeferredData<T> const & )
789 { }
790
791 // ######################################################################
754792 //! Prologue for SizeTags for JSON archives
755793 /*! SizeTags are strictly ignored for JSON, they just indicate
756794 that the current node should be made into an array */
127127 ~PortableBinaryOutputArchive() CEREAL_NOEXCEPT = default;
128128
129129 //! Writes size bytes of data to the output stream
130 template <std::size_t DataSize> inline
131 void saveBinary( const void * data, std::size_t size )
132 {
133 std::size_t writtenSize = 0;
130 template <std::streamsize DataSize> inline
131 void saveBinary( const void * data, std::streamsize size )
132 {
133 std::streamsize writtenSize = 0;
134134
135135 if( itsConvertEndianness )
136136 {
137 for( std::size_t i = 0; i < size; i += DataSize )
138 for( std::size_t j = 0; j < DataSize; ++j )
139 writtenSize += static_cast<std::size_t>( itsStream.rdbuf()->sputn( reinterpret_cast<const char*>( data ) + DataSize - j - 1 + i, 1 ) );
137 for( std::streamsize i = 0; i < size; i += DataSize )
138 for( std::streamsize j = 0; j < DataSize; ++j )
139 writtenSize += itsStream.rdbuf()->sputn( reinterpret_cast<const char*>( data ) + DataSize - j - 1 + i, 1 );
140140 }
141141 else
142 writtenSize = static_cast<std::size_t>( itsStream.rdbuf()->sputn( reinterpret_cast<const char*>( data ), size ) );
142 writtenSize = itsStream.rdbuf()->sputn( reinterpret_cast<const char*>( data ), size );
143143
144144 if(writtenSize != size)
145145 throw Exception("Failed to write " + std::to_string(size) + " bytes to output stream! Wrote " + std::to_string(writtenSize));
234234 /*! @param data The data to save
235235 @param size The number of bytes in the data
236236 @tparam DataSize T The size of the actual type of the data elements being loaded */
237 template <std::size_t DataSize> inline
238 void loadBinary( void * const data, std::size_t size )
237 template <std::streamsize DataSize> inline
238 void loadBinary( void * const data, std::streamsize size )
239239 {
240240 // load data
241 auto const readSize = static_cast<std::size_t>( itsStream.rdbuf()->sgetn( reinterpret_cast<char*>( data ), size ) );
241 auto const readSize = itsStream.rdbuf()->sgetn( reinterpret_cast<char*>( data ), size );
242242
243243 if(readSize != size)
244244 throw Exception("Failed to read " + std::to_string(size) + " bytes from input stream! Read " + std::to_string(readSize));
247247 if( itsConvertEndianness )
248248 {
249249 std::uint8_t * ptr = reinterpret_cast<std::uint8_t*>( data );
250 for( std::size_t i = 0; i < size; i += DataSize )
250 for( std::streamsize i = 0; i < size; i += DataSize )
251251 portable_binary_detail::swap_bytes<DataSize>( ptr + i );
252252 }
253253 }
307307 (std::is_floating_point<TT>::value && std::numeric_limits<TT>::is_iec559),
308308 "Portable binary only supports IEEE 754 standardized floating point" );
309309
310 ar.template saveBinary<sizeof(TT)>( bd.data, static_cast<std::size_t>( bd.size ) );
310 ar.template saveBinary<sizeof(TT)>( bd.data, static_cast<std::streamsize>( bd.size ) );
311311 }
312312
313313 //! Loading binary data from portable binary
319319 (std::is_floating_point<TT>::value && std::numeric_limits<TT>::is_iec559),
320320 "Portable binary only supports IEEE 754 standardized floating point" );
321321
322 ar.template loadBinary<sizeof(TT)>( bd.data, static_cast<std::size_t>( bd.size ) );
322 ar.template loadBinary<sizeof(TT)>( bd.data, static_cast<std::streamsize>( bd.size ) );
323323 }
324324 } // namespace cereal
325325
100100 //! @{
101101
102102 //! A class containing various advanced options for the XML archive
103 /*! Options can either be directly passed to the constructor, or chained using the
104 modifier functions for an interface analogous to named parameters */
103105 class Options
104106 {
105107 public:
106108 //! Default options
107109 static Options Default(){ return Options(); }
108110
109 //! Default options with no indentation
110 static Options NoIndent(){ return Options( std::numeric_limits<double>::max_digits10, false ); }
111
112111 //! Specify specific options for the XMLOutputArchive
113 /*! @param precision The precision used for floating point numbers
114 @param indent Whether to indent each line of XML
115 @param outputType Whether to output the type of each serialized object as an attribute */
116 explicit Options( int precision = std::numeric_limits<double>::max_digits10,
117 bool indent = true,
118 bool outputType = false ) :
119 itsPrecision( precision ),
120 itsIndent( indent ),
121 itsOutputType( outputType ) { }
112 /*! @param precision_ The precision used for floating point numbers
113 @param indent_ Whether to indent each line of XML
114 @param outputType_ Whether to output the type of each serialized object as an attribute
115 @param sizeAttributes_ Whether dynamically sized containers output the size=dynamic attribute */
116 explicit Options( int precision_ = std::numeric_limits<double>::max_digits10,
117 bool indent_ = true,
118 bool outputType_ = false,
119 bool sizeAttributes_ = true ) :
120 itsPrecision( precision_ ),
121 itsIndent( indent_ ),
122 itsOutputType( outputType_ ),
123 itsSizeAttributes( sizeAttributes_ )
124 { }
125
126 /*! @name Option Modifiers
127 An interface for setting option settings analogous to named parameters.
128
129 @code{cpp}
130 cereal::XMLOutputArchive ar( myStream,
131 cereal::XMLOutputArchive::Options()
132 .indent(true)
133 .sizeAttributes(false) );
134 @endcode
135 */
136 //! @{
137
138 //! Sets the precision used for floaing point numbers
139 Options & precision( int value ){ itsPrecision = value; return * this; }
140 //! Whether to indent each line of XML
141 Options & indent( bool enable ){ itsIndent = enable; return *this; }
142 //! Whether to output the type of each serialized object as an attribute
143 Options & outputType( bool enable ){ itsOutputType = enable; return *this; }
144 //! Whether dynamically sized containers (e.g. vector) output the size=dynamic attribute
145 Options & sizeAttributes( bool enable ){ itsSizeAttributes = enable; return *this; }
146
147 //! @}
122148
123149 private:
124150 friend class XMLOutputArchive;
125151 int itsPrecision;
126152 bool itsIndent;
127153 bool itsOutputType;
154 bool itsSizeAttributes;
128155 };
129156
130157 //! Construct, outputting to the provided stream upon destruction
136163 OutputArchive<XMLOutputArchive>(this),
137164 itsStream(stream),
138165 itsOutputType( options.itsOutputType ),
139 itsIndent( options.itsIndent )
166 itsIndent( options.itsIndent ),
167 itsSizeAttributes(options.itsSizeAttributes)
140168 {
141169 // rapidxml will delete all allocations when xml_document is cleared
142170 auto node = itsXML.allocate_node( rapidxml::node_declaration );
181209 itsNodes.top().node->append_attribute( itsXML.allocate_attribute( "type", "cereal binary data" ) );
182210
183211 finishNode();
184 };
212 }
185213
186214 //! @}
187215 /*! @name Internal Functionality
287315 auto valuePtr = itsXML.allocate_string( value );
288316 itsNodes.top().node->append_attribute( itsXML.allocate_attribute( namePtr, valuePtr ) );
289317 }
318
319 bool hasSizeAttributes() const { return itsSizeAttributes; }
290320
291321 protected:
292322 //! A struct that contains metadata about a node
329359 std::ostringstream itsOS; //!< Used to format strings internally
330360 bool itsOutputType; //!< Controls whether type information is printed
331361 bool itsIndent; //!< Controls whether indenting is used
362 bool itsSizeAttributes; //!< Controls whether lists have a size attribute
332363 }; // XMLOutputArchive
333364
334365 // ######################################################################
435466 std::memcpy( data, decoded.data(), decoded.size() );
436467
437468 finishNode();
438 };
469 }
439470
440471 //! @}
441472 /*! @name Internal Functionality
758789 { }
759790
760791 // ######################################################################
792 //! Prologue for deferred data for XML archives
793 /*! Do nothing for the defer wrapper */
794 template <class T> inline
795 void prologue( XMLOutputArchive &, DeferredData<T> const & )
796 { }
797
798 //! Prologue for deferred data for XML archives
799 template <class T> inline
800 void prologue( XMLInputArchive &, DeferredData<T> const & )
801 { }
802
803 // ######################################################################
804 //! Epilogue for deferred for XML archives
805 /*! NVPs do not start or finish nodes - they just set up the names */
806 template <class T> inline
807 void epilogue( XMLOutputArchive &, DeferredData<T> const & )
808 { }
809
810 //! Epilogue for deferred for XML archives
811 /*! Do nothing for the defer wrapper */
812 template <class T> inline
813 void epilogue( XMLInputArchive &, DeferredData<T> const & )
814 { }
815
816 // ######################################################################
761817 //! Prologue for SizeTags for XML output archives
762818 /*! SizeTags do not start or finish nodes */
763819 template <class T> inline
764820 void prologue( XMLOutputArchive & ar, SizeTag<T> const & )
765821 {
766 ar.appendAttribute( "size", "dynamic" );
822 if (ar.hasSizeAttributes())
823 {
824 ar.appendAttribute("size", "dynamic");
825 }
767826 }
768827
769828 template <class T> inline
3131 #include <type_traits>
3232 #include <string>
3333 #include <memory>
34 #include <functional>
3435 #include <unordered_map>
3536 #include <unordered_set>
3637 #include <vector>
9495 SizeTag<T> make_size_tag( T && sz )
9596 {
9697 return {std::forward<T>(sz)};
98 }
99
100 // ######################################################################
101 //! Marks data for deferred serialization
102 /*! cereal performs a recursive depth-first traversal of data it serializes. When
103 serializing smart pointers to large, nested, or cyclical data structures, it
104 is possible to encounter a stack overflow from excessive recursion when following
105 a chain of pointers.
106
107 Deferment can help in these situations if the data can be serialized separately from
108 the pointers used to traverse the structure. For example, a graph structure can have its
109 nodes serialized before its edges:
110
111 @code{.cpp}
112 struct MyEdge
113 {
114 std::shared_ptr<MyNode> connection;
115 int some_value;
116
117 template<class Archive>
118 void serialize(Archive & archive)
119 {
120 // when we serialize an edge, we'll defer serializing the associated node
121 archive( cereal::defer( connection ),
122 some_value );
123 }
124 };
125
126 struct MyGraphStructure
127 {
128 std::vector<MyEdge> edges;
129 std::vector<MyNodes> nodes;
130
131 template<class Archive>
132 void serialize(Archive & archive)
133 {
134 // because of the deferment, we ensure all nodes are fully serialized
135 // before any connection pointers to those nodes are serialized
136 archive( edges, nodes );
137
138 // we have to explicitly inform the archive when it is safe to serialize
139 // the deferred data
140 archive.serializeDeferments();
141 }
142 };
143 @endcode
144
145 @relates DeferredData
146 @ingroup Utility */
147 template <class T> inline
148 DeferredData<T> defer( T && value )
149 {
150 return {std::forward<T>(value)};
97151 }
98152
99153 // ######################################################################
144198 instantiate_polymorphic_binding( T*, Archive*, BindingTag, adl_tag ); \
145199 } } /* end namespaces */
146200
201 //! Helper macro to omit unused warning
202 #if defined(__GNUC__)
203 // GCC / clang don't want the function
204 #define CEREAL_UNUSED_FUNCTION
205 #else
206 #define CEREAL_UNUSED_FUNCTION static void unused() { (void)version; }
207 #endif
208
147209 // ######################################################################
148210 //! Defines a class version for some type
149211 /*! Versioning information is optional and adds some small amount of
206268 std::type_index(typeid(TYPE)).hash_code(), VERSION_NUMBER ); \
207269 return VERSION_NUMBER; \
208270 } \
209 static void unused() { (void)version; } \
271 CEREAL_UNUSED_FUNCTION \
210272 }; /* end Version */ \
211273 const std::uint32_t Version<TYPE>::version = \
212274 Version<TYPE>::registerVersion(); \
249311 return *self;
250312 }
251313
314 //! Serializes any data marked for deferment using defer
315 /*! This will cause any data wrapped in DeferredData to be immediately serialized */
316 void serializeDeferments()
317 {
318 for( auto & deferment : itsDeferments )
319 deferment();
320 }
321
252322 /*! @name Boost Transition Layer
253323 Functionality that mirrors the syntax for Boost. This is useful if you are transitioning
254324 a large project from Boost to cereal. The preferred interface for cereal is using operator(). */
257327 //! Indicates this archive is not intended for loading
258328 /*! This ensures compatibility with boost archive types. If you are transitioning
259329 from boost, you can check this value within a member or external serialize function
260 (i.e., Archive::is_loading::value) to disable behavior specific to loading, until
330 (i.e., Archive::is_loading::value) to disable behavior specific to loading, until
261331 you can transition to split save/load or save_minimal/load_minimal functions */
262332 using is_loading = std::false_type;
263333
264334 //! Indicates this archive is intended for saving
265335 /*! This ensures compatibility with boost archive types. If you are transitioning
266336 from boost, you can check this value within a member or external serialize function
267 (i.e., Archive::is_saving::value) to enable behavior specific to loading, until
337 (i.e., Archive::is_saving::value) to enable behavior specific to loading, until
268338 you can transition to split save/load or save_minimal/load_minimal functions */
269339 using is_saving = std::true_type;
270340
375445 ArchiveType & processImpl(base_class<T> const & b)
376446 {
377447 self->processImpl( *b.base_ptr );
448 return *self;
449 }
450
451 std::vector<std::function<void(void)>> itsDeferments;
452
453 template <class T> inline
454 ArchiveType & processImpl(DeferredData<T> const & d)
455 {
456 std::function<void(void)> deferment( [=](){ self->process( d.value ); } );
457 itsDeferments.emplace_back( std::move(deferment) );
458
378459 return *self;
379460 }
380461
482563 /*! If this is the first time this class has been serialized, we will record its
483564 version number and serialize that.
484565
485 @tparam T The type of the class being serialized
486 @param version The version number associated with it */
566 @tparam T The type of the class being serialized */
487567 template <class T> inline
488568 std::uint32_t registerClassVersion()
489569 {
619699 return *self;
620700 }
621701
702 //! Serializes any data marked for deferment using defer
703 /*! This will cause any data wrapped in DeferredData to be immediately serialized */
704 void serializeDeferments()
705 {
706 for( auto & deferment : itsDeferments )
707 deferment();
708 }
709
622710 /*! @name Boost Transition Layer
623711 Functionality that mirrors the syntax for Boost. This is useful if you are transitioning
624712 a large project from Boost to cereal. The preferred interface for cereal is using operator(). */
627715 //! Indicates this archive is intended for loading
628716 /*! This ensures compatibility with boost archive types. If you are transitioning
629717 from boost, you can check this value within a member or external serialize function
630 (i.e., Archive::is_loading::value) to enable behavior specific to loading, until
718 (i.e., Archive::is_loading::value) to enable behavior specific to loading, until
631719 you can transition to split save/load or save_minimal/load_minimal functions */
632720 using is_loading = std::true_type;
633721
634722 //! Indicates this archive is not intended for saving
635723 /*! This ensures compatibility with boost archive types. If you are transitioning
636724 from boost, you can check this value within a member or external serialize function
637 (i.e., Archive::is_saving::value) to disable behavior specific to loading, until
725 (i.e., Archive::is_saving::value) to disable behavior specific to loading, until
638726 you can transition to split save/load or save_minimal/load_minimal functions */
639727 using is_saving = std::false_type;
640728
666754 /*! This is used to retrieve a previously registered shared_ptr
667755 which has already been loaded.
668756
757 @internal
669758 @param id The unique id that was serialized for the pointer
670759 @return A shared pointer to the data
671760 @throw Exception if the id does not exist */
684773 /*! After a shared pointer has been allocated for the first time, it should
685774 be registered with its loaded id for future references to it.
686775
776 @internal
687777 @param id The unique identifier for the shared pointer
688778 @param ptr The actual shared pointer */
689779 inline void registerSharedPointer(std::uint32_t const id, std::shared_ptr<void> ptr)
696786 /*! This is used to retrieve a string previously registered during
697787 a polymorphic load.
698788
789 @internal
699790 @param id The unique id that was serialized for the polymorphic type
700791 @return The string identifier for the tyep */
701792 inline std::string getPolymorphicName(std::uint32_t const id)
712803 /*! After a polymorphic type has been loaded for the first time, it should
713804 be registered with its loaded id for future references to it.
714805
806 @internal
715807 @param id The unique identifier for the polymorphic type
716808 @param name The name associated with the tyep */
717809 inline void registerPolymorphicName(std::uint32_t const id, std::string const & name)
758850 ArchiveType & processImpl(base_class<T> & b)
759851 {
760852 self->processImpl( *b.base_ptr );
853 return *self;
854 }
855
856 std::vector<std::function<void(void)>> itsDeferments;
857
858 template <class T> inline
859 ArchiveType & processImpl(DeferredData<T> const & d)
860 {
861 std::function<void(void)> deferment( [=](){ self->process( d.value ); } );
862 itsDeferments.emplace_back( std::move(deferment) );
863
761864 return *self;
762865 }
763866
874977 /*! If this is the first time this class has been serialized, we will record its
875978 version number and serialize that.
876979
877 @tparam T The type of the class being serialized
878 @param version The version number associated with it */
980 @tparam T The type of the class being serialized */
879981 template <class T> inline
880982 std::uint32_t loadClassVersion()
881983 {
6767 namespace detail
6868 {
6969 struct NameValuePairCore {}; //!< Traits struct for NVPs
70 struct DeferredDataCore {}; //!< Traits struct for DeferredData
7071 }
7172
73 // ######################################################################
7274 //! For holding name value pairs
7375 /*! This pairs a name (some string) with some value such that an archive
7476 can potentially take advantage of the pairing.
209211 {
210212 //! Internally store the pointer as a void *, keeping const if created with
211213 //! a const pointer
212 using PT = typename std::conditional<std::is_const<typename std::remove_pointer<T>::type>::value,
214 using PT = typename std::conditional<std::is_const<typename std::remove_pointer<typename std::remove_reference<T>::type>::type>::value,
213215 const void *,
214216 void *>::type;
215217
217219
218220 PT data; //!< pointer to beginning of data
219221 uint64_t size; //!< size in bytes
222 };
223
224 // ######################################################################
225 //! A wrapper around data that should be serialized after all non-deferred data
226 /*! This class is used to demarcate data that can only be safely serialized after
227 any data not wrapped in this class.
228
229 @internal */
230 template <class T>
231 class DeferredData : detail::DeferredDataCore
232 {
233 private:
234 // If we get passed an array, keep the type as is, otherwise store
235 // a reference if we were passed an l value reference, else copy the value
236 using Type = typename std::conditional<std::is_array<typename std::remove_reference<T>::type>::value,
237 typename std::remove_cv<T>::type,
238 typename std::conditional<std::is_lvalue_reference<T>::value,
239 T,
240 typename std::decay<T>::type>::type>::type;
241
242 // prevent nested nvps
243 static_assert( !std::is_base_of<detail::DeferredDataCore, T>::value,
244 "Cannot defer DeferredData" );
245
246 DeferredData & operator=( DeferredData const & ) = delete;
247
248 public:
249 //! Constructs a new NameValuePair
250 /*! @param v The value to defer. Ideally this should be an l-value reference so that
251 the value can be both loaded and saved to. If you pass an r-value reference,
252 the DeferredData will store a copy of it instead of a reference. Thus you should
253 only pass r-values in cases where this makes sense, such as the result of some
254 size() call.
255 @internal */
256 DeferredData( T && v ) : value(std::forward<T>(v)) {}
257
258 Type value;
220259 };
221260
222261 // ######################################################################
255294 struct adl_tag;
256295
257296 // used during saving pointers
258 static const int32_t msb_32bit = 0x80000000;
297 static const uint32_t msb_32bit = 0x80000000;
259298 static const int32_t msb2_32bit = 0x40000000;
260299 }
261300
5555 #include <set>
5656 #include <stack>
5757
58 //! Helper macro to omit unused warning
59 #if defined(__GNUC__)
60 // GCC / clang don't want the function
61 #define CEREAL_BIND_TO_ARCHIVES_UNUSED_FUNCTION
62 #else
63 #define CEREAL_BIND_TO_ARCHIVES_UNUSED_FUNCTION static void unused() { (void)b; }
64 #endif
65
5866 //! Binds a polymorhic type to all registered archives
5967 /*! This binds a polymorphic type to all compatible registered archives that
6068 have been registered with CEREAL_REGISTER_ARCHIVE. This must be called
6674 template<> \
6775 struct init_binding<__VA_ARGS__> { \
6876 static bind_to_archives<__VA_ARGS__> const & b; \
69 static void unused() { (void)b; } \
77 CEREAL_BIND_TO_ARCHIVES_UNUSED_FUNCTION \
7078 }; \
7179 bind_to_archives<__VA_ARGS__> const & init_binding<__VA_ARGS__>::b = \
7280 ::cereal::detail::StaticObject< \
114122 all registered mappings between base and derived types. */
115123 struct PolymorphicCasters
116124 {
125 //! Maps from a derived type index to a set of chainable casters
126 using DerivedCasterMap = std::unordered_map<std::type_index, std::vector<PolymorphicCaster const *>>;
117127 //! Maps from base type index to a map from derived type index to caster
118 std::map<std::type_index, std::map<std::type_index, std::vector<PolymorphicCaster const*>>> map;
128 std::unordered_map<std::type_index, DerivedCasterMap> map;
119129
120130 std::multimap<std::type_index, std::type_index> reverseMap;
121131
126136 "Make sure you either serialize the base class at some point via cereal::base_class or cereal::virtual_base_class.\n" \
127137 "Alternatively, manually register the association with CEREAL_REGISTER_POLYMORPHIC_RELATION.");
128138
129 //! Checks if the mapping object that can perform the upcast or downcast
139 //! Checks if the mapping object that can perform the upcast or downcast exists, and returns it if so
130140 /*! Uses the type index from the base and derived class to find the matching
131 registered caster. If no matching caster exists, returns false. */
132 static bool exists( std::type_index const & baseIndex, std::type_index const & derivedIndex )
141 registered caster. If no matching caster exists, the bool in the pair will be false and the vector
142 reference should not be used. */
143 static std::pair<bool, std::vector<PolymorphicCaster const *> const &>
144 lookup_if_exists( std::type_index const & baseIndex, std::type_index const & derivedIndex )
133145 {
134146 // First phase of lookup - match base type index
135147 auto const & baseMap = StaticObject<PolymorphicCasters>::getInstance().map;
136148 auto baseIter = baseMap.find( baseIndex );
137149 if (baseIter == baseMap.end())
138 return false;
150 return {false, {}};
139151
140152 // Second phase - find a match from base to derived
141 auto & derivedMap = baseIter->second;
153 auto const & derivedMap = baseIter->second;
142154 auto derivedIter = derivedMap.find( derivedIndex );
143155 if (derivedIter == derivedMap.end())
144 return false;
145
146 return true;
156 return {false, {}};
157
158 return {true, derivedIter->second};
147159 }
148160
149161 //! Gets the mapping object that can perform the upcast or downcast
161173 exceptionFunc();
162174
163175 // Second phase - find a match from base to derived
164 auto & derivedMap = baseIter->second;
176 auto const & derivedMap = baseIter->second;
165177 auto derivedIter = derivedMap.find( derivedIndex );
166178 if( derivedIter == derivedMap.end() )
167179 exceptionFunc();
175187 {
176188 auto const & mapping = lookup( baseInfo, typeid(Derived), [&](){ UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION(save) } );
177189
178 for( auto const * map : mapping )
179 dptr = map->downcast( dptr );
190 for( auto const * dmap : mapping )
191 dptr = dmap->downcast( dptr );
180192
181193 return static_cast<Derived const *>( dptr );
182194 }
212224 #undef UNREGISTERED_POLYMORPHIC_CAST_EXCEPTION
213225 };
214226
227 #ifdef CEREAL_OLDER_GCC
228 #define CEREAL_EMPLACE_MAP(map, key, value) \
229 map.insert( std::make_pair(std::move(key), std::move(value)) );
230 #else // NOT CEREAL_OLDER_GCC
231 #define CEREAL_EMPLACE_MAP(map, key, value) \
232 map.emplace( key, value );
233 #endif // NOT_CEREAL_OLDER_GCC
234
215235 //! Strongly typed derivation of PolymorphicCaster
216236 template <class Base, class Derived>
217237 struct PolymorphicVirtualCaster : PolymorphicCaster
228248 // First insert the relation Base->Derived
229249 const auto lock = StaticObject<PolymorphicCasters>::lock();
230250 auto & baseMap = StaticObject<PolymorphicCasters>::getInstance().map;
231 auto lb = baseMap.lower_bound(baseKey);
232251
233252 {
234 auto & derivedMap = baseMap.insert( lb, {baseKey, {}} )->second;
235 auto lbd = derivedMap.lower_bound(derivedKey);
236 auto & derivedVec = derivedMap.insert( lbd, { std::move(derivedKey), {}} )->second;
253 auto & derivedMap = baseMap.insert( {baseKey, PolymorphicCasters::DerivedCasterMap{}} ).first->second;
254 auto & derivedVec = derivedMap.insert( {derivedKey, {}} ).first->second;
237255 derivedVec.push_back( this );
238256 }
239257
240258 // Insert reverse relation Derived->Base
241259 auto & reverseMap = StaticObject<PolymorphicCasters>::getInstance().reverseMap;
242 reverseMap.insert( {derivedKey, baseKey} );
260 CEREAL_EMPLACE_MAP(reverseMap, derivedKey, baseKey);
243261
244262 // Find all chainable unregistered relations
245263 /* The strategy here is to process only the nodes in the class hierarchy graph that have been
253271 // Checks whether there is a path from parent->child and returns a <dist, path> pair
254272 // dist is set to MAX if the path does not exist
255273 auto checkRelation = [](std::type_index const & parentInfo, std::type_index const & childInfo) ->
256 std::pair<size_t, std::vector<PolymorphicCaster const *>>
274 std::pair<size_t, std::vector<PolymorphicCaster const *> const &>
257275 {
258 if( PolymorphicCasters::exists( parentInfo, childInfo ) )
276 auto result = PolymorphicCasters::lookup_if_exists( parentInfo, childInfo );
277 if( result.first )
259278 {
260 auto const & path = PolymorphicCasters::lookup( parentInfo, childInfo, [](){} );
279 auto const & path = result.second;
261280 return {path.size(), path};
262281 }
263282 else
264 return {std::numeric_limits<size_t>::max(), {}};
283 return {(std::numeric_limits<size_t>::max)(), {}};
265284 };
266285
267 std::stack<std::type_index> parentStack; // Holds the parent nodes to be processed
268 std::set<std::type_index> dirtySet; // Marks child nodes that have been changed
269 std::set<std::type_index> processedParents; // Marks parent nodes that have been processed
286 std::stack<std::type_index> parentStack; // Holds the parent nodes to be processed
287 std::vector<std::type_index> dirtySet; // Marks child nodes that have been changed
288 std::unordered_set<std::type_index> processedParents; // Marks parent nodes that have been processed
289
290 // Checks if a child has been marked dirty
291 auto isDirty = [&](std::type_index const & c)
292 {
293 auto const dirtySetSize = dirtySet.size();
294 for( size_t i = 0; i < dirtySetSize; ++i )
295 if( dirtySet[i] == c )
296 return true;
297
298 return false;
299 };
270300
271301 // Begin processing the base key and mark derived as dirty
272302 parentStack.push( baseKey );
273 dirtySet.insert( derivedKey );
303 dirtySet.emplace_back( derivedKey );
274304
275305 while( !parentStack.empty() )
276306 {
277 using Relations = std::multimap<std::type_index, std::pair<std::type_index, std::vector<PolymorphicCaster const *>>>;
307 using Relations = std::unordered_multimap<std::type_index, std::pair<std::type_index, std::vector<PolymorphicCaster const *>>>;
278308 Relations unregisteredRelations; // Defer insertions until after main loop to prevent iterator invalidation
279309
280310 const auto parent = parentStack.top();
284314 for( auto const & childPair : baseMap[parent] )
285315 {
286316 const auto child = childPair.first;
287 if( dirtySet.count( child ) && baseMap.count( child ) )
317 if( isDirty( child ) && baseMap.count( child ) )
288318 {
289319 auto parentChildPath = checkRelation( parent, child );
290320
339369 {
340370 auto & derivedMap = baseMap.find( it.first )->second;
341371 derivedMap[it.second.first] = it.second.second;
342 reverseMap.insert( {it.second.first, it.first} );
372 CEREAL_EMPLACE_MAP(reverseMap, it.second.first, it.first );
343373 }
344374
345375 // Mark current parent as modified
346 dirtySet.insert( parent );
376 dirtySet.emplace_back( parent );
347377
348378 // Insert all parents of the current parent node that haven't yet been processed
349379 auto parentRange = reverseMap.equal_range( parent );
360390 } // end chainable relations
361391 } // end PolymorphicVirtualCaster()
362392
393 #undef CEREAL_EMPLACE_MAP
394
363395 //! Performs the proper downcast with the templated types
364396 void const * downcast( void const * const ptr ) const override
365397 {
4747 # define CEREAL_DLL_EXPORT __declspec(dllexport)
4848 # define CEREAL_USED
4949 #else // clang or gcc
50 # define CEREAL_DLL_EXPORT
50 # define CEREAL_DLL_EXPORT __attribute__ ((visibility("default")))
5151 # define CEREAL_USED __attribute__ ((__used__))
5252 #endif
5353
6666 class CEREAL_DLL_EXPORT StaticObject
6767 {
6868 private:
69 //! Forces instantiation at pre-execution time
70 static void instantiate( T const & ) {}
7169
7270 static T & create()
7371 {
7472 static T t;
75 instantiate(instance);
73 //! Forces instantiation at pre-execution time
74 (void)instance;
7675 return t;
7776 }
7877
9493 std::unique_lock<std::mutex> lock;
9594 #else
9695 public:
96 LockGuard(LockGuard const &) = default; // prevents implicit copy ctor warning
9797 ~LockGuard() CEREAL_NOEXCEPT {} // prevents variable not used
9898 #endif
9999 };
799799
800800 See notes from member load_minimal implementation.
801801
802 Note that there should be an additional const check on load_minimal after the valid check,
803 but this currently interferes with many valid uses of minimal serialization. It has been
804 removed (see #565 on github) and previously was:
805
806 @code
807 static_assert( check::const_valid || !check::exists,
808 "cereal detected an invalid serialization type parameter in non-member " #test_name ". "
809 #test_name " non-member functions must accept their serialization type by non-const reference" );
810 @endcode
811
812 See #132, #436, #263, and #565 on https://github.com/USCiLab/cereal for more details.
813
802814 @param test_name The name to give the test (e.g. load_minimal or versioned_load_minimal)
803815 @param save_name The corresponding name the save test would have (e.g. save_minimal or versioned_save_minimal)
804816 @param versioned Either blank or the macro CEREAL_MAKE_VERSIONED_TEST */
846858 static_assert( check::valid || !check::exists, "cereal detected different types in corresponding non-member " \
847859 #test_name " and " #save_name " functions. \n " \
848860 "the paramater to " #test_name " must be a constant reference to the type that " #save_name " returns." ); \
849 static_assert( check::const_valid || !check::exists, \
850 "cereal detected an invalid serialization type parameter in non-member " #test_name ". " \
851 #test_name " non-member functions must accept their serialization type by non-const reference" ); \
852861 }; \
853862 } /* namespace detail */ \
854863 \
868877 #undef CEREAL_MAKE_HAS_NON_MEMBER_LOAD_MINIMAL_TEST
869878
870879 // ######################################################################
880 namespace detail
881 {
882 // const stripped away before reaching here, prevents errors on conversion from
883 // construct<const T> to construct<T>
884 template<typename T, typename A>
885 struct has_member_load_and_construct_impl : std::integral_constant<bool,
886 std::is_same<decltype( access::load_and_construct<T>( std::declval<A&>(), std::declval< ::cereal::construct<T>&>() ) ), void>::value>
887 { };
888
889 template<typename T, typename A>
890 struct has_member_versioned_load_and_construct_impl : std::integral_constant<bool,
891 std::is_same<decltype( access::load_and_construct<T>( std::declval<A&>(), std::declval< ::cereal::construct<T>&>(), 0 ) ), void>::value>
892 { };
893 } // namespace detail
894
871895 //! Member load and construct check
872896 template<typename T, typename A>
873 struct has_member_load_and_construct : std::integral_constant<bool,
874 std::is_same<decltype( access::load_and_construct<T>( std::declval<A&>(), std::declval< ::cereal::construct<T>&>() ) ), void>::value>
897 struct has_member_load_and_construct : detail::has_member_load_and_construct_impl<typename std::remove_const<T>::type, A>
875898 { };
876899
877 // ######################################################################
878900 //! Member load and construct check (versioned)
879901 template<typename T, typename A>
880 struct has_member_versioned_load_and_construct : std::integral_constant<bool,
881 std::is_same<decltype( access::load_and_construct<T>( std::declval<A&>(), std::declval< ::cereal::construct<T>&>(), 0 ) ), void>::value>
902 struct has_member_versioned_load_and_construct : detail::has_member_versioned_load_and_construct_impl<typename std::remove_const<T>::type, A>
882903 { };
883904
884905 // ######################################################################
900921 }; \
901922 } /* end namespace detail */ \
902923 template <class T, class A> \
903 struct has_non_member_##test_name : std::integral_constant<bool, detail::has_non_member_##test_name##_impl<T, A>::value> {};
924 struct has_non_member_##test_name : \
925 std::integral_constant<bool, detail::has_non_member_##test_name##_impl<typename std::remove_const<T>::type, A>::value> {};
904926
905927 // ######################################################################
906928 //! Non member load and construct check
2323
2424 #ifndef CEREAL_EXTERNAL_BASE64_HPP_
2525 #define CEREAL_EXTERNAL_BASE64_HPP_
26
27 #ifdef __GNUC__
28 #pragma GCC diagnostic push
29 #pragma GCC diagnostic ignored "-Wconversion"
30 #endif
2631
2732 #include <string>
2833
122127 }
123128 } // namespace base64
124129 } // namespace cereal
125
130 #ifdef __GNUC__
131 #pragma GCC diagnostic pop
132 #endif
126133 #endif // CEREAL_EXTERNAL_BASE64_HPP_
5151 \endcode
5252 */
5353
54
55 /*! \def CEREAL_RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY
56 \ingroup CEREAL_RAPIDJSON_CONFIG
57 \brief User-defined kDefaultChunkCapacity definition.
58
59 User can define this as any \c size that is a power of 2.
60 */
61
62 #ifndef CEREAL_RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY
63 #define CEREAL_RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY (64 * 1024)
64 #endif
65
66
5467 ///////////////////////////////////////////////////////////////////////////////
5568 // CrtAllocator
5669
235248 */
236249 bool AddChunk(size_t capacity) {
237250 if (!baseAllocator_)
238 ownBaseAllocator_ = baseAllocator_ = CEREAL_RAPIDJSON_NEW(BaseAllocator());
251 ownBaseAllocator_ = baseAllocator_ = CEREAL_RAPIDJSON_NEW(BaseAllocator)();
239252 if (ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(CEREAL_RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) {
240253 chunk->capacity = capacity;
241254 chunk->size = 0;
247260 return false;
248261 }
249262
250 static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.
263 static const int kDefaultChunkCapacity = CEREAL_RAPIDJSON_ALLOCATOR_DEFAULT_CHUNK_CAPACITY; //!< Default chunk capacity.
251264
252265 //! Chunk header for perpending to each chunk.
253266 /*! Chunks are stored as a singly linked list.
0 // Tencent is pleased to support the open source community by making RapidJSON available.
1 //
2 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
3 //
4 // Licensed under the MIT License (the "License"); you may not use this file except
5 // in compliance with the License. You may obtain a copy of the License at
6 //
7 // http://opensource.org/licenses/MIT
8 //
9 // Unless required by applicable law or agreed to in writing, software distributed
10 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
12 // specific language governing permissions and limitations under the License.
13
14 #ifndef CEREAL_RAPIDJSON_CURSORSTREAMWRAPPER_H_
15 #define CEREAL_RAPIDJSON_CURSORSTREAMWRAPPER_H_
16
17 #include "stream.h"
18
19 #if defined(__GNUC__)
20 CEREAL_RAPIDJSON_DIAG_PUSH
21 CEREAL_RAPIDJSON_DIAG_OFF(effc++)
22 #endif
23
24 #if defined(_MSC_VER) && _MSC_VER <= 1800
25 CEREAL_RAPIDJSON_DIAG_PUSH
26 CEREAL_RAPIDJSON_DIAG_OFF(4702) // unreachable code
27 CEREAL_RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
28 #endif
29
30 CEREAL_RAPIDJSON_NAMESPACE_BEGIN
31
32
33 //! Cursor stream wrapper for counting line and column number if error exists.
34 /*!
35 \tparam InputStream Any stream that implements Stream Concept
36 */
37 template <typename InputStream, typename Encoding = UTF8<> >
38 class CursorStreamWrapper : public GenericStreamWrapper<InputStream, Encoding> {
39 public:
40 typedef typename Encoding::Ch Ch;
41
42 CursorStreamWrapper(InputStream& is):
43 GenericStreamWrapper<InputStream, Encoding>(is), line_(1), col_(0) {}
44
45 // counting line and column number
46 Ch Take() {
47 Ch ch = this->is_.Take();
48 if(ch == '\n') {
49 line_ ++;
50 col_ = 0;
51 } else {
52 col_ ++;
53 }
54 return ch;
55 }
56
57 //! Get the error line number, if error exists.
58 size_t GetLine() const { return line_; }
59 //! Get the error column number, if error exists.
60 size_t GetColumn() const { return col_; }
61
62 private:
63 size_t line_; //!< Current Line
64 size_t col_; //!< Current Column
65 };
66
67 #if defined(_MSC_VER) && _MSC_VER <= 1800
68 CEREAL_RAPIDJSON_DIAG_POP
69 #endif
70
71 #if defined(__GNUC__)
72 CEREAL_RAPIDJSON_DIAG_POP
73 #endif
74
75 CEREAL_RAPIDJSON_NAMESPACE_END
76
77 #endif // CEREAL_RAPIDJSON_CURSORSTREAMWRAPPER_H_
00 // Tencent is pleased to support the open source community by making RapidJSON available.
1 //
1 //
22 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
33 //
44 // Licensed under the MIT License (the "License"); you may not use this file except
66 //
77 // http://opensource.org/licenses/MIT
88 //
9 // Unless required by applicable law or agreed to in writing, software distributed
10 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 // Unless required by applicable law or agreed to in writing, software distributed
10 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
1212 // specific language governing permissions and limitations under the License.
1313
1414 #ifndef CEREAL_RAPIDJSON_DOCUMENT_H_
2525 #include <limits>
2626
2727 CEREAL_RAPIDJSON_DIAG_PUSH
28 #ifdef _MSC_VER
29 CEREAL_RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
30 CEREAL_RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data
31 #endif
32
3328 #ifdef __clang__
3429 CEREAL_RAPIDJSON_DIAG_OFF(padded)
3530 CEREAL_RAPIDJSON_DIAG_OFF(switch-enum)
3631 CEREAL_RAPIDJSON_DIAG_OFF(c++98-compat)
32 #elif defined(_MSC_VER)
33 CEREAL_RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
34 CEREAL_RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data
3735 #endif
3836
3937 #ifdef __GNUC__
4038 CEREAL_RAPIDJSON_DIAG_OFF(effc++)
41 #if __GNUC__ >= 6
42 CEREAL_RAPIDJSON_DIAG_OFF(terminate) // ignore throwing CEREAL_RAPIDJSON_ASSERT in CEREAL_RAPIDJSON_NOEXCEPT functions
43 #endif
4439 #endif // __GNUC__
4540
4641 #ifndef CEREAL_RAPIDJSON_NOMEMBERITERATORCLASS
47 #include <iterator> // std::iterator, std::random_access_iterator_tag
42 #include <iterator> // std::random_access_iterator_tag
4843 #endif
4944
5045 #if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS
6661 But a compiler (IBM XL C/C++ for AIX) have reported to have problem with that so it moved as a namespace scope struct.
6762 https://code.google.com/p/rapidjson/issues/detail?id=64
6863 */
69 template <typename Encoding, typename Allocator>
70 struct GenericMember {
64 template <typename Encoding, typename Allocator>
65 struct GenericMember {
7166 GenericValue<Encoding, Allocator> name; //!< name of member (must be a string)
7267 GenericValue<Encoding, Allocator> value; //!< value of member.
68
69 // swap() for std::sort() and other potential use in STL.
70 friend inline void swap(GenericMember& a, GenericMember& b) CEREAL_RAPIDJSON_NOEXCEPT {
71 a.name.Swap(b.name);
72 a.value.Swap(b.value);
73 }
7374 };
7475
7576 ///////////////////////////////////////////////////////////////////////////////
9798 \see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator
9899 */
99100 template <bool Const, typename Encoding, typename Allocator>
100 class GenericMemberIterator
101 : public std::iterator<std::random_access_iterator_tag
102 , typename internal::MaybeAddConst<Const,GenericMember<Encoding,Allocator> >::Type> {
101 class GenericMemberIterator {
103102
104103 friend class GenericValue<Encoding,Allocator>;
105104 template <bool, typename, typename> friend class GenericMemberIterator;
106105
107106 typedef GenericMember<Encoding,Allocator> PlainType;
108107 typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;
109 typedef std::iterator<std::random_access_iterator_tag,ValueType> BaseType;
110108
111109 public:
112110 //! Iterator type itself
116114 //! Non-constant iterator type
117115 typedef GenericMemberIterator<false,Encoding,Allocator> NonConstIterator;
118116
117 /** \name std::iterator_traits support */
118 //@{
119 typedef ValueType value_type;
120 typedef ValueType * pointer;
121 typedef ValueType & reference;
122 typedef std::ptrdiff_t difference_type;
123 typedef std::random_access_iterator_tag iterator_category;
124 //@}
125
119126 //! Pointer to (const) GenericMember
120 typedef typename BaseType::pointer Pointer;
127 typedef pointer Pointer;
121128 //! Reference to (const) GenericMember
122 typedef typename BaseType::reference Reference;
129 typedef reference Reference;
123130 //! Signed integer type (e.g. \c ptrdiff_t)
124 typedef typename BaseType::difference_type DifferenceType;
131 typedef difference_type DifferenceType;
125132
126133 //! Default constructor (singular value)
127134 /*! Creates an iterator pointing to no element.
197204 // class-based member iterator implementation disabled, use plain pointers
198205
199206 template <bool Const, typename Encoding, typename Allocator>
200 struct GenericMemberIterator;
207 class GenericMemberIterator;
201208
202209 //! non-const GenericMemberIterator
203210 template <typename Encoding, typename Allocator>
204 struct GenericMemberIterator<false,Encoding,Allocator> {
211 class GenericMemberIterator<false,Encoding,Allocator> {
205212 //! use plain pointer as iterator type
206213 typedef GenericMember<Encoding,Allocator>* Iterator;
207214 };
208215 //! const GenericMemberIterator
209216 template <typename Encoding, typename Allocator>
210 struct GenericMemberIterator<true,Encoding,Allocator> {
217 class GenericMemberIterator<true,Encoding,Allocator> {
211218 //! use plain const pointer as iterator type
212219 typedef const GenericMember<Encoding,Allocator>* Iterator;
213220 };
299306 */
300307 #endif
301308 explicit GenericStringRef(const CharType* str)
302 : s(str), length(internal::StrLen(str)){ CEREAL_RAPIDJSON_ASSERT(s != 0); }
309 : s(str), length(NotNullStrLen(str)) {}
303310
304311 //! Create constant string reference from pointer and length
305312 #ifndef __clang__ // -Wdocumentation
311318 */
312319 #endif
313320 GenericStringRef(const CharType* str, SizeType len)
314 : s(str), length(len) { CEREAL_RAPIDJSON_ASSERT(s != 0); }
321 : s(CEREAL_RAPIDJSON_LIKELY(str) ? str : emptyString), length(len) { CEREAL_RAPIDJSON_ASSERT(str != 0 || len == 0u); }
315322
316323 GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {}
317
318 GenericStringRef& operator=(const GenericStringRef& rhs) { s = rhs.s; length = rhs.length; }
319324
320325 //! implicit conversion to plain CharType pointer
321326 operator const Ch *() const { return s; }
324329 const SizeType length; //!< length of the string (excluding the trailing NULL terminator)
325330
326331 private:
332 SizeType NotNullStrLen(const CharType* str) {
333 CEREAL_RAPIDJSON_ASSERT(str != 0);
334 return internal::StrLen(str);
335 }
336
337 /// Empty string - used when passing in a NULL pointer
338 static const Ch emptyString[];
339
327340 //! Disallow construction from non-const array
328341 template<SizeType N>
329342 GenericStringRef(CharType (&str)[N]) /* = delete */;
343 //! Copy assignment operator not permitted - immutable type
344 GenericStringRef& operator=(const GenericStringRef& rhs) /* = delete */;
330345 };
346
347 template<typename CharType>
348 const CharType GenericStringRef<CharType>::emptyString[] = { CharType() };
331349
332350 //! Mark a character pointer as constant string
333351 /*! Mark a plain character pointer as a "string literal". This function
343361 */
344362 template<typename CharType>
345363 inline GenericStringRef<CharType> StringRef(const CharType* str) {
346 return GenericStringRef<CharType>(str, internal::StrLen(str));
364 return GenericStringRef<CharType>(str);
347365 }
348366
349367 //! Mark a character pointer as constant string
409427 template <typename ValueType, typename T>
410428 struct TypeHelper {};
411429
412 template<typename ValueType>
430 template<typename ValueType>
413431 struct TypeHelper<ValueType, bool> {
414432 static bool Is(const ValueType& v) { return v.IsBool(); }
415433 static bool Get(const ValueType& v) { return v.GetBool(); }
417435 static ValueType& Set(ValueType& v, bool data, typename ValueType::AllocatorType&) { return v.SetBool(data); }
418436 };
419437
420 template<typename ValueType>
438 template<typename ValueType>
421439 struct TypeHelper<ValueType, int> {
422440 static bool Is(const ValueType& v) { return v.IsInt(); }
423441 static int Get(const ValueType& v) { return v.GetInt(); }
425443 static ValueType& Set(ValueType& v, int data, typename ValueType::AllocatorType&) { return v.SetInt(data); }
426444 };
427445
428 template<typename ValueType>
446 template<typename ValueType>
429447 struct TypeHelper<ValueType, unsigned> {
430448 static bool Is(const ValueType& v) { return v.IsUint(); }
431449 static unsigned Get(const ValueType& v) { return v.GetUint(); }
433451 static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); }
434452 };
435453
436 template<typename ValueType>
454 #ifdef _MSC_VER
455 CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(long) == sizeof(int));
456 template<typename ValueType>
457 struct TypeHelper<ValueType, long> {
458 static bool Is(const ValueType& v) { return v.IsInt(); }
459 static long Get(const ValueType& v) { return v.GetInt(); }
460 static ValueType& Set(ValueType& v, long data) { return v.SetInt(data); }
461 static ValueType& Set(ValueType& v, long data, typename ValueType::AllocatorType&) { return v.SetInt(data); }
462 };
463
464 CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(unsigned long) == sizeof(unsigned));
465 template<typename ValueType>
466 struct TypeHelper<ValueType, unsigned long> {
467 static bool Is(const ValueType& v) { return v.IsUint(); }
468 static unsigned long Get(const ValueType& v) { return v.GetUint(); }
469 static ValueType& Set(ValueType& v, unsigned long data) { return v.SetUint(data); }
470 static ValueType& Set(ValueType& v, unsigned long data, typename ValueType::AllocatorType&) { return v.SetUint(data); }
471 };
472 #endif
473
474 template<typename ValueType>
437475 struct TypeHelper<ValueType, int64_t> {
438476 static bool Is(const ValueType& v) { return v.IsInt64(); }
439477 static int64_t Get(const ValueType& v) { return v.GetInt64(); }
441479 static ValueType& Set(ValueType& v, int64_t data, typename ValueType::AllocatorType&) { return v.SetInt64(data); }
442480 };
443481
444 template<typename ValueType>
482 template<typename ValueType>
445483 struct TypeHelper<ValueType, uint64_t> {
446484 static bool Is(const ValueType& v) { return v.IsUint64(); }
447485 static uint64_t Get(const ValueType& v) { return v.GetUint64(); }
449487 static ValueType& Set(ValueType& v, uint64_t data, typename ValueType::AllocatorType&) { return v.SetUint64(data); }
450488 };
451489
452 template<typename ValueType>
490 template<typename ValueType>
453491 struct TypeHelper<ValueType, double> {
454492 static bool Is(const ValueType& v) { return v.IsDouble(); }
455493 static double Get(const ValueType& v) { return v.GetDouble(); }
457495 static ValueType& Set(ValueType& v, double data, typename ValueType::AllocatorType&) { return v.SetDouble(data); }
458496 };
459497
460 template<typename ValueType>
498 template<typename ValueType>
461499 struct TypeHelper<ValueType, float> {
462500 static bool Is(const ValueType& v) { return v.IsFloat(); }
463501 static float Get(const ValueType& v) { return v.GetFloat(); }
465503 static ValueType& Set(ValueType& v, float data, typename ValueType::AllocatorType&) { return v.SetFloat(data); }
466504 };
467505
468 template<typename ValueType>
506 template<typename ValueType>
469507 struct TypeHelper<ValueType, const typename ValueType::Ch*> {
470508 typedef const typename ValueType::Ch* StringType;
471509 static bool Is(const ValueType& v) { return v.IsString(); }
475513 };
476514
477515 #if CEREAL_RAPIDJSON_HAS_STDSTRING
478 template<typename ValueType>
516 template<typename ValueType>
479517 struct TypeHelper<ValueType, std::basic_string<typename ValueType::Ch> > {
480518 typedef std::basic_string<typename ValueType::Ch> StringType;
481519 static bool Is(const ValueType& v) { return v.IsString(); }
484522 };
485523 #endif
486524
487 template<typename ValueType>
525 template<typename ValueType>
488526 struct TypeHelper<ValueType, typename ValueType::Array> {
489527 typedef typename ValueType::Array ArrayType;
490528 static bool Is(const ValueType& v) { return v.IsArray(); }
493531 static ValueType& Set(ValueType& v, ArrayType data, typename ValueType::AllocatorType&) { return v = data; }
494532 };
495533
496 template<typename ValueType>
534 template<typename ValueType>
497535 struct TypeHelper<ValueType, typename ValueType::ConstArray> {
498536 typedef typename ValueType::ConstArray ArrayType;
499537 static bool Is(const ValueType& v) { return v.IsArray(); }
500538 static ArrayType Get(const ValueType& v) { return v.GetArray(); }
501539 };
502540
503 template<typename ValueType>
541 template<typename ValueType>
504542 struct TypeHelper<ValueType, typename ValueType::Object> {
505543 typedef typename ValueType::Object ObjectType;
506544 static bool Is(const ValueType& v) { return v.IsObject(); }
507545 static ObjectType Get(ValueType& v) { return v.GetObject(); }
508546 static ValueType& Set(ValueType& v, ObjectType data) { return v = data; }
509 static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { v = data; }
547 static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { return v = data; }
510548 };
511549
512 template<typename ValueType>
550 template<typename ValueType>
513551 struct TypeHelper<ValueType, typename ValueType::ConstObject> {
514552 typedef typename ValueType::ConstObject ObjectType;
515553 static bool Is(const ValueType& v) { return v.IsObject(); }
535573 \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document)
536574 \tparam Allocator Allocator type for allocating memory of object, array and string.
537575 */
538 template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
576 template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
539577 class GenericValue {
540578 public:
541579 //! Name-value pair in an object.
589627 \note Default content for number is zero.
590628 */
591629 explicit GenericValue(Type type) CEREAL_RAPIDJSON_NOEXCEPT : data_() {
592 static const uint16_t defaultFlags[7] = {
630 static const uint16_t defaultFlags[] = {
593631 kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag,
594632 kNumberAnyFlag
595633 };
596 CEREAL_RAPIDJSON_ASSERT(type <= kNumberType);
634 CEREAL_RAPIDJSON_NOEXCEPT_ASSERT(type >= kNullType && type <= kNumberType);
597635 data_.f.flags = defaultFlags[type];
598636
599637 // Use ShortString to store empty string.
606644 \tparam SourceAllocator allocator of \c rhs
607645 \param rhs Value to copy from (read-only)
608646 \param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator().
647 \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer)
609648 \see CopyFrom()
610649 */
611 template< typename SourceAllocator >
612 GenericValue(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator & allocator);
650 template <typename SourceAllocator>
651 GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator, bool copyConstStrings = false) {
652 switch (rhs.GetType()) {
653 case kObjectType: {
654 SizeType count = rhs.data_.o.size;
655 Member* lm = reinterpret_cast<Member*>(allocator.Malloc(count * sizeof(Member)));
656 const typename GenericValue<Encoding,SourceAllocator>::Member* rm = rhs.GetMembersPointer();
657 for (SizeType i = 0; i < count; i++) {
658 new (&lm[i].name) GenericValue(rm[i].name, allocator, copyConstStrings);
659 new (&lm[i].value) GenericValue(rm[i].value, allocator, copyConstStrings);
660 }
661 data_.f.flags = kObjectFlag;
662 data_.o.size = data_.o.capacity = count;
663 SetMembersPointer(lm);
664 }
665 break;
666 case kArrayType: {
667 SizeType count = rhs.data_.a.size;
668 GenericValue* le = reinterpret_cast<GenericValue*>(allocator.Malloc(count * sizeof(GenericValue)));
669 const GenericValue<Encoding,SourceAllocator>* re = rhs.GetElementsPointer();
670 for (SizeType i = 0; i < count; i++)
671 new (&le[i]) GenericValue(re[i], allocator, copyConstStrings);
672 data_.f.flags = kArrayFlag;
673 data_.a.size = data_.a.capacity = count;
674 SetElementsPointer(le);
675 }
676 break;
677 case kStringType:
678 if (rhs.data_.f.flags == kConstStringFlag && !copyConstStrings) {
679 data_.f.flags = rhs.data_.f.flags;
680 data_ = *reinterpret_cast<const Data*>(&rhs.data_);
681 }
682 else
683 SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator);
684 break;
685 default:
686 data_.f.flags = rhs.data_.f.flags;
687 data_ = *reinterpret_cast<const Data*>(&rhs.data_);
688 break;
689 }
690 }
613691
614692 //! Constructor for boolean value.
615693 /*! \param b Boolean value
637715
638716 //! Constructor for unsigned value.
639717 explicit GenericValue(unsigned u) CEREAL_RAPIDJSON_NOEXCEPT : data_() {
640 data_.n.u64 = u;
718 data_.n.u64 = u;
641719 data_.f.flags = (u & 0x80000000) ? kNumberUintFlag : (kNumberUintFlag | kIntFlag | kInt64Flag);
642720 }
643721
671749 //! Constructor for double value.
672750 explicit GenericValue(double d) CEREAL_RAPIDJSON_NOEXCEPT : data_() { data_.n.d = d; data_.f.flags = kNumberDoubleFlag; }
673751
752 //! Constructor for float value.
753 explicit GenericValue(float f) CEREAL_RAPIDJSON_NOEXCEPT : data_() { data_.n.d = static_cast<double>(f); data_.f.flags = kNumberDoubleFlag; }
754
674755 //! Constructor for constant string (i.e. do not make a copy of string)
675756 GenericValue(const Ch* s, SizeType length) CEREAL_RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); }
676757
752833 /*! \param rhs Source of the assignment. It will become a null value after assignment.
753834 */
754835 GenericValue& operator=(GenericValue& rhs) CEREAL_RAPIDJSON_NOEXCEPT {
755 CEREAL_RAPIDJSON_ASSERT(this != &rhs);
756 this->~GenericValue();
757 RawAssign(rhs);
836 if (CEREAL_RAPIDJSON_LIKELY(this != &rhs)) {
837 this->~GenericValue();
838 RawAssign(rhs);
839 }
758840 return *this;
759841 }
760842
799881 \tparam SourceAllocator Allocator type of \c rhs
800882 \param rhs Value to copy from (read-only)
801883 \param allocator Allocator to use for copying
884 \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer)
802885 */
803886 template <typename SourceAllocator>
804 GenericValue& CopyFrom(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator& allocator) {
887 GenericValue& CopyFrom(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator& allocator, bool copyConstStrings = false) {
805888 CEREAL_RAPIDJSON_ASSERT(static_cast<void*>(this) != static_cast<void const*>(&rhs));
806889 this->~GenericValue();
807 new (this) GenericValue(rhs, allocator);
890 new (this) GenericValue(rhs, allocator, copyConstStrings);
808891 return *this;
809892 }
810893
845928 //! Equal-to operator
846929 /*!
847930 \note If an object contains duplicated named member, comparing equality with any object is always \c false.
848 \note Linear time complexity (number of all values in the subtree and total lengths of all strings).
931 \note Complexity is quadratic in Object's member number and linear for the rest (number of all values in the subtree and total lengths of all strings).
849932 */
850933 template <typename SourceAllocator>
851934 bool operator==(const GenericValue<Encoding, SourceAllocator>& rhs) const {
856939 switch (GetType()) {
857940 case kObjectType: // Warning: O(n^2) inner-loop
858941 if (data_.o.size != rhs.data_.o.size)
859 return false;
942 return false;
860943 for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) {
861944 typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name);
862945 if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value)
863946 return false;
864947 }
865948 return true;
866
949
867950 case kArrayType:
868951 if (data_.a.size != rhs.data_.a.size)
869952 return false;
9541037 uint64_t u = GetUint64();
9551038 volatile double d = static_cast<double>(u);
9561039 return (d >= 0.0)
957 && (d < static_cast<double>(std::numeric_limits<uint64_t>::max()))
1040 && (d < static_cast<double>((std::numeric_limits<uint64_t>::max)()))
9581041 && (u == static_cast<uint64_t>(d));
9591042 }
9601043 if (IsInt64()) {
9611044 int64_t i = GetInt64();
9621045 volatile double d = static_cast<double>(i);
963 return (d >= static_cast<double>(std::numeric_limits<int64_t>::min()))
964 && (d < static_cast<double>(std::numeric_limits<int64_t>::max()))
1046 return (d >= static_cast<double>((std::numeric_limits<int64_t>::min)()))
1047 && (d < static_cast<double>((std::numeric_limits<int64_t>::max)()))
9651048 && (i == static_cast<int64_t>(d));
9661049 }
9671050 return true; // double, int, uint are always lossless
9781061 bool IsLosslessFloat() const {
9791062 if (!IsNumber()) return false;
9801063 double a = GetDouble();
981 if (a < static_cast<double>(-std::numeric_limits<float>::max())
982 || a > static_cast<double>(std::numeric_limits<float>::max()))
1064 if (a < static_cast<double>(-(std::numeric_limits<float>::max)())
1065 || a > static_cast<double>((std::numeric_limits<float>::max)()))
9831066 return false;
9841067 double b = static_cast<double>(static_cast<float>(a));
9851068 return a >= b && a <= b; // Prevent -Wfloat-equal
10131096
10141097 //! Get the number of members in the object.
10151098 SizeType MemberCount() const { CEREAL_RAPIDJSON_ASSERT(IsObject()); return data_.o.size; }
1099
1100 //! Get the capacity of object.
1101 SizeType MemberCapacity() const { CEREAL_RAPIDJSON_ASSERT(IsObject()); return data_.o.capacity; }
10161102
10171103 //! Check whether the object is empty.
10181104 bool ObjectEmpty() const { CEREAL_RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; }
10821168 /*! \pre IsObject() == true */
10831169 MemberIterator MemberEnd() { CEREAL_RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); }
10841170
1171 //! Request the object to have enough capacity to store members.
1172 /*! \param newCapacity The capacity that the object at least need to have.
1173 \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
1174 \return The value itself for fluent API.
1175 \note Linear time complexity.
1176 */
1177 GenericValue& MemberReserve(SizeType newCapacity, Allocator &allocator) {
1178 CEREAL_RAPIDJSON_ASSERT(IsObject());
1179 if (newCapacity > data_.o.capacity) {
1180 SetMembersPointer(reinterpret_cast<Member*>(allocator.Realloc(GetMembersPointer(), data_.o.capacity * sizeof(Member), newCapacity * sizeof(Member))));
1181 data_.o.capacity = newCapacity;
1182 }
1183 return *this;
1184 }
1185
10851186 //! Check whether a member exists in the object.
10861187 /*!
10871188 \param name Member name to be searched.
11871288 CEREAL_RAPIDJSON_ASSERT(name.IsString());
11881289
11891290 ObjectData& o = data_.o;
1190 if (o.size >= o.capacity) {
1191 if (o.capacity == 0) {
1192 o.capacity = kDefaultObjectCapacity;
1193 SetMembersPointer(reinterpret_cast<Member*>(allocator.Malloc(o.capacity * sizeof(Member))));
1194 }
1195 else {
1196 SizeType oldCapacity = o.capacity;
1197 o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5
1198 SetMembersPointer(reinterpret_cast<Member*>(allocator.Realloc(GetMembersPointer(), oldCapacity * sizeof(Member), o.capacity * sizeof(Member))));
1199 }
1200 }
1291 if (o.size >= o.capacity)
1292 MemberReserve(o.capacity == 0 ? kDefaultObjectCapacity : (o.capacity + (o.capacity + 1) / 2), allocator);
12011293 Member* members = GetMembersPointer();
12021294 members[o.size].name.RawAssign(name);
12031295 members[o.size].value.RawAssign(value);
13341426 \note Linear time complexity.
13351427 */
13361428 void RemoveAllMembers() {
1337 CEREAL_RAPIDJSON_ASSERT(IsObject());
1429 CEREAL_RAPIDJSON_ASSERT(IsObject());
13381430 for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
13391431 m->~Member();
13401432 data_.o.size = 0;
14241516 MemberIterator pos = MemberBegin() + (first - MemberBegin());
14251517 for (MemberIterator itr = pos; itr != last; ++itr)
14261518 itr->~Member();
1427 std::memmove(&*pos, &*last, static_cast<size_t>(MemberEnd() - last) * sizeof(Member));
1519 std::memmove(static_cast<void*>(&*pos), &*last, static_cast<size_t>(MemberEnd() - last) * sizeof(Member));
14281520 data_.o.size -= static_cast<SizeType>(last - first);
14291521 return pos;
14301522 }
14801572 \note Linear time complexity.
14811573 */
14821574 void Clear() {
1483 CEREAL_RAPIDJSON_ASSERT(IsArray());
1575 CEREAL_RAPIDJSON_ASSERT(IsArray());
14841576 GenericValue* e = GetElementsPointer();
14851577 for (GenericValue* v = e; v != e + data_.a.size; ++v)
14861578 v->~GenericValue();
16271719 CEREAL_RAPIDJSON_ASSERT(last <= End());
16281720 ValueIterator pos = Begin() + (first - Begin());
16291721 for (ValueIterator itr = pos; itr != last; ++itr)
1630 itr->~GenericValue();
1631 std::memmove(pos, last, static_cast<size_t>(End() - last) * sizeof(GenericValue));
1722 itr->~GenericValue();
1723 std::memmove(static_cast<void*>(pos), last, static_cast<size_t>(End() - last) * sizeof(GenericValue));
16321724 data_.a.size -= static_cast<SizeType>(last - first);
16331725 return pos;
16341726 }
16701762 GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; }
16711763 GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; }
16721764 GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; }
1673 GenericValue& SetFloat(float f) { this->~GenericValue(); new (this) GenericValue(f); return *this; }
1765 GenericValue& SetFloat(float f) { this->~GenericValue(); new (this) GenericValue(static_cast<double>(f)); return *this; }
16741766
16751767 //@}
16761768
16861778
16871779 //! Set this value as a string without copying source string.
16881780 /*! This version has better performance with supplied length, and also support string containing null character.
1689 \param s source string pointer.
1781 \param s source string pointer.
16901782 \param length The length of source string, excluding the trailing null terminator.
16911783 \return The value itself for fluent API.
16921784 \post IsString() == true && GetString() == s && GetStringLength() == length
17031795
17041796 //! Set this value as a string by copying from source string.
17051797 /*! This version has better performance with supplied length, and also support string containing null character.
1706 \param s source string.
1798 \param s source string.
17071799 \param length The length of source string, excluding the trailing null terminator.
17081800 \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
17091801 \return The value itself for fluent API.
17101802 \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length
17111803 */
1712 GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(StringRef(s, length), allocator); return *this; }
1804 GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { return SetString(StringRef(s, length), allocator); }
17131805
17141806 //! Set this value as a string by copying from source string.
1715 /*! \param s source string.
1807 /*! \param s source string.
17161808 \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
17171809 \return The value itself for fluent API.
17181810 \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length
17191811 */
1720 GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(s, internal::StrLen(s), allocator); }
1812 GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(StringRef(s), allocator); }
1813
1814 //! Set this value as a string by copying from source string.
1815 /*! \param s source string reference
1816 \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
1817 \return The value itself for fluent API.
1818 \post IsString() == true && GetString() != s.s && strcmp(GetString(),s) == 0 && GetStringLength() == length
1819 */
1820 GenericValue& SetString(StringRefType s, Allocator& allocator) { this->~GenericValue(); SetStringRaw(s, allocator); return *this; }
17211821
17221822 #if CEREAL_RAPIDJSON_HAS_STDSTRING
17231823 //! Set this value as a string by copying from source string.
17271827 \post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size()
17281828 \note Requires the definition of the preprocessor symbol \ref CEREAL_RAPIDJSON_HAS_STDSTRING.
17291829 */
1730 GenericValue& SetString(const std::basic_string<Ch>& s, Allocator& allocator) { return SetString(s.data(), SizeType(s.size()), allocator); }
1830 GenericValue& SetString(const std::basic_string<Ch>& s, Allocator& allocator) { return SetString(StringRef(s), allocator); }
17311831 #endif
17321832
17331833 //@}
17891889 if (CEREAL_RAPIDJSON_UNLIKELY(!v->Accept(handler)))
17901890 return false;
17911891 return handler.EndArray(data_.a.size);
1792
1892
17931893 case kStringType:
17941894 return handler.String(GetString(), GetStringLength(), (data_.f.flags & kCopyFlag) != 0);
1795
1895
17961896 default:
17971897 CEREAL_RAPIDJSON_ASSERT(GetType() == kNumberType);
17981898 if (IsDouble()) return handler.Double(data_.n.d);
19352035 if (count) {
19362036 GenericValue* e = static_cast<GenericValue*>(allocator.Malloc(count * sizeof(GenericValue)));
19372037 SetElementsPointer(e);
1938 std::memcpy(e, values, count * sizeof(GenericValue));
2038 std::memcpy(static_cast<void*>(e), values, count * sizeof(GenericValue));
19392039 }
19402040 else
19412041 SetElementsPointer(0);
19482048 if (count) {
19492049 Member* m = static_cast<Member*>(allocator.Malloc(count * sizeof(Member)));
19502050 SetMembersPointer(m);
1951 std::memcpy(m, members, count * sizeof(Member));
2051 std::memcpy(static_cast<void*>(m), members, count * sizeof(Member));
19522052 }
19532053 else
19542054 SetMembersPointer(0);
20092109 typedef GenericValue<UTF8<> > Value;
20102110
20112111 ///////////////////////////////////////////////////////////////////////////////
2012 // GenericDocument
2112 // GenericDocument
20132113
20142114 //! A document for parsing JSON text as DOM.
20152115 /*!
20372137 GenericValue<Encoding, Allocator>(type), allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()
20382138 {
20392139 if (!allocator_)
2040 ownAllocator_ = allocator_ = CEREAL_RAPIDJSON_NEW(Allocator());
2140 ownAllocator_ = allocator_ = CEREAL_RAPIDJSON_NEW(Allocator)();
20412141 }
20422142
20432143 //! Constructor
2044 /*! Creates an empty document which type is Null.
2144 /*! Creates an empty document which type is Null.
20452145 \param allocator Optional allocator for allocating memory.
20462146 \param stackCapacity Optional initial capacity of stack in bytes.
20472147 \param stackAllocator Optional allocator for allocating memory for stack.
20482148 */
2049 GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) :
2149 GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) :
20502150 allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()
20512151 {
20522152 if (!allocator_)
2053 ownAllocator_ = allocator_ = CEREAL_RAPIDJSON_NEW(Allocator());
2153 ownAllocator_ = allocator_ = CEREAL_RAPIDJSON_NEW(Allocator)();
20542154 }
20552155
20562156 #if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS
21102210 internal::Swap(parseResult_, rhs.parseResult_);
21112211 return *this;
21122212 }
2213
2214 // Allow Swap with ValueType.
2215 // Refer to Effective C++ 3rd Edition/Item 33: Avoid hiding inherited names.
2216 using ValueType::Swap;
21132217
21142218 //! free-standing swap function helper
21152219 /*!
22422346 template <unsigned parseFlags, typename SourceEncoding>
22432347 GenericDocument& Parse(const typename SourceEncoding::Ch* str, size_t length) {
22442348 CEREAL_RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
2245 MemoryStream ms(static_cast<const char*>(str), length * sizeof(typename SourceEncoding::Ch));
2349 MemoryStream ms(reinterpret_cast<const char*>(str), length * sizeof(typename SourceEncoding::Ch));
22462350 EncodedInputStream<SourceEncoding, MemoryStream> is(ms);
22472351 ParseStream<parseFlags, SourceEncoding>(is);
22482352 return *this;
22522356 GenericDocument& Parse(const Ch* str, size_t length) {
22532357 return Parse<parseFlags, Encoding>(str, length);
22542358 }
2255
2359
22562360 GenericDocument& Parse(const Ch* str, size_t length) {
22572361 return Parse<kParseDefaultFlags>(str, length);
22582362 }
22722376 GenericDocument& Parse(const std::basic_string<Ch>& str) {
22732377 return Parse<kParseDefaultFlags>(str);
22742378 }
2275 #endif // CEREAL_RAPIDJSON_HAS_STDSTRING
2379 #endif // CEREAL_RAPIDJSON_HAS_STDSTRING
22762380
22772381 //!@}
22782382
22792383 //!@name Handling parse errors
22802384 //!@{
22812385
2282 //! Whether a parse error has occured in the last parsing.
2386 //! Whether a parse error has occurred in the last parsing.
22832387 bool HasParseError() const { return parseResult_.IsError(); }
22842388
22852389 //! Get the \ref ParseErrorCode of last parsing.
23372441 bool Uint64(uint64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
23382442 bool Double(double d) { new (stack_.template Push<ValueType>()) ValueType(d); return true; }
23392443
2340 bool RawNumber(const Ch* str, SizeType length, bool copy) {
2341 if (copy)
2444 bool RawNumber(const Ch* str, SizeType length, bool copy) {
2445 if (copy)
23422446 new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());
23432447 else
23442448 new (stack_.template Push<ValueType>()) ValueType(str, length);
23452449 return true;
23462450 }
23472451
2348 bool String(const Ch* str, SizeType length, bool copy) {
2349 if (copy)
2452 bool String(const Ch* str, SizeType length, bool copy) {
2453 if (copy)
23502454 new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());
23512455 else
23522456 new (stack_.template Push<ValueType>()) ValueType(str, length);
23542458 }
23552459
23562460 bool StartObject() { new (stack_.template Push<ValueType>()) ValueType(kObjectType); return true; }
2357
2461
23582462 bool Key(const Ch* str, SizeType length, bool copy) { return String(str, length, copy); }
23592463
23602464 bool EndObject(SizeType memberCount) {
23642468 }
23652469
23662470 bool StartArray() { new (stack_.template Push<ValueType>()) ValueType(kArrayType); return true; }
2367
2471
23682472 bool EndArray(SizeType elementCount) {
23692473 ValueType* elements = stack_.template Pop<ValueType>(elementCount);
23702474 stack_.template Top<ValueType>()->SetArrayRaw(elements, elementCount, GetAllocator());
23992503
24002504 //! GenericDocument with UTF8 encoding
24012505 typedef GenericDocument<UTF8<> > Document;
2402
2403 // defined here due to the dependency on GenericDocument
2404 template <typename Encoding, typename Allocator>
2405 template <typename SourceAllocator>
2406 inline
2407 GenericValue<Encoding,Allocator>::GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator)
2408 {
2409 switch (rhs.GetType()) {
2410 case kObjectType:
2411 case kArrayType: { // perform deep copy via SAX Handler
2412 GenericDocument<Encoding,Allocator> d(&allocator);
2413 rhs.Accept(d);
2414 RawAssign(*d.stack_.template Pop<GenericValue>(1));
2415 }
2416 break;
2417 case kStringType:
2418 if (rhs.data_.f.flags == kConstStringFlag) {
2419 data_.f.flags = rhs.data_.f.flags;
2420 data_ = *reinterpret_cast<const Data*>(&rhs.data_);
2421 } else {
2422 SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator);
2423 }
2424 break;
2425 default:
2426 data_.f.flags = rhs.data_.f.flags;
2427 data_ = *reinterpret_cast<const Data*>(&rhs.data_);
2428 break;
2429 }
2430 }
24312506
24322507 //! Helper class for accessing Value of array type.
24332508 /*!
25092584 ~GenericObject() {}
25102585
25112586 SizeType MemberCount() const { return value_.MemberCount(); }
2587 SizeType MemberCapacity() const { return value_.MemberCapacity(); }
25122588 bool ObjectEmpty() const { return value_.ObjectEmpty(); }
25132589 template <typename T> ValueType& operator[](T* name) const { return value_[name]; }
25142590 template <typename SourceAllocator> ValueType& operator[](const GenericValue<EncodingType, SourceAllocator>& name) const { return value_[name]; }
25172593 #endif
25182594 MemberIterator MemberBegin() const { return value_.MemberBegin(); }
25192595 MemberIterator MemberEnd() const { return value_.MemberEnd(); }
2596 GenericObject MemberReserve(SizeType newCapacity, AllocatorType &allocator) const { value_.MemberReserve(newCapacity, allocator); return *this; }
25202597 bool HasMember(const Ch* name) const { return value_.HasMember(name); }
25212598 #if CEREAL_RAPIDJSON_HAS_STDSTRING
25222599 bool HasMember(const std::basic_string<Ch>& name) const { return value_.HasMember(name); }
25422619 GenericObject AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
25432620 GenericObject AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
25442621 template <typename T> CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericObject)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
2545 void RemoveAllMembers() { return value_.RemoveAllMembers(); }
2622 void RemoveAllMembers() { value_.RemoveAllMembers(); }
25462623 bool RemoveMember(const Ch* name) const { return value_.RemoveMember(name); }
25472624 #if CEREAL_RAPIDJSON_HAS_STDSTRING
25482625 bool RemoveMember(const std::basic_string<Ch>& name) const { return value_.RemoveMember(name); }
199199 // xx xx xx xx UTF-8
200200
201201 if (!hasBOM_) {
202 unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
202 int pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
203203 switch (pattern) {
204204 case 0x08: type_ = kUTF32BE; break;
205205 case 0x0A: type_ = kUTF16BE; break;
1616
1717 #include "rapidjson.h"
1818
19 #ifdef _MSC_VER
19 #if defined(_MSC_VER) && !defined(__clang__)
2020 CEREAL_RAPIDJSON_DIAG_PUSH
2121 CEREAL_RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data
2222 CEREAL_RAPIDJSON_DIAG_OFF(4702) // unreachable code
143143
144144 template <typename InputStream>
145145 static bool Decode(InputStream& is, unsigned* codepoint) {
146 #define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu)
147 #define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
148 #define TAIL() COPY(); TRANS(0x70)
146 #define CEREAL_RAPIDJSON_COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu)
147 #define CEREAL_RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
148 #define CEREAL_RAPIDJSON_TAIL() CEREAL_RAPIDJSON_COPY(); CEREAL_RAPIDJSON_TRANS(0x70)
149149 typename InputStream::Ch c = is.Take();
150150 if (!(c & 0x80)) {
151151 *codepoint = static_cast<unsigned char>(c);
156156 if (type >= 32) {
157157 *codepoint = 0;
158158 } else {
159 *codepoint = (0xFF >> type) & static_cast<unsigned char>(c);
159 *codepoint = (0xFFu >> type) & static_cast<unsigned char>(c);
160160 }
161161 bool result = true;
162162 switch (type) {
163 case 2: TAIL(); return result;
164 case 3: TAIL(); TAIL(); return result;
165 case 4: COPY(); TRANS(0x50); TAIL(); return result;
166 case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
167 case 6: TAIL(); TAIL(); TAIL(); return result;
168 case 10: COPY(); TRANS(0x20); TAIL(); return result;
169 case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
163 case 2: CEREAL_RAPIDJSON_TAIL(); return result;
164 case 3: CEREAL_RAPIDJSON_TAIL(); CEREAL_RAPIDJSON_TAIL(); return result;
165 case 4: CEREAL_RAPIDJSON_COPY(); CEREAL_RAPIDJSON_TRANS(0x50); CEREAL_RAPIDJSON_TAIL(); return result;
166 case 5: CEREAL_RAPIDJSON_COPY(); CEREAL_RAPIDJSON_TRANS(0x10); CEREAL_RAPIDJSON_TAIL(); CEREAL_RAPIDJSON_TAIL(); return result;
167 case 6: CEREAL_RAPIDJSON_TAIL(); CEREAL_RAPIDJSON_TAIL(); CEREAL_RAPIDJSON_TAIL(); return result;
168 case 10: CEREAL_RAPIDJSON_COPY(); CEREAL_RAPIDJSON_TRANS(0x20); CEREAL_RAPIDJSON_TAIL(); return result;
169 case 11: CEREAL_RAPIDJSON_COPY(); CEREAL_RAPIDJSON_TRANS(0x60); CEREAL_RAPIDJSON_TAIL(); CEREAL_RAPIDJSON_TAIL(); return result;
170170 default: return false;
171171 }
172 #undef COPY
173 #undef TRANS
174 #undef TAIL
172 #undef CEREAL_RAPIDJSON_COPY
173 #undef CEREAL_RAPIDJSON_TRANS
174 #undef CEREAL_RAPIDJSON_TAIL
175175 }
176176
177177 template <typename InputStream, typename OutputStream>
178178 static bool Validate(InputStream& is, OutputStream& os) {
179 #define COPY() os.Put(c = is.Take())
180 #define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
181 #define TAIL() COPY(); TRANS(0x70)
179 #define CEREAL_RAPIDJSON_COPY() os.Put(c = is.Take())
180 #define CEREAL_RAPIDJSON_TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
181 #define CEREAL_RAPIDJSON_TAIL() CEREAL_RAPIDJSON_COPY(); CEREAL_RAPIDJSON_TRANS(0x70)
182182 Ch c;
183 COPY();
183 CEREAL_RAPIDJSON_COPY();
184184 if (!(c & 0x80))
185185 return true;
186186
187187 bool result = true;
188188 switch (GetRange(static_cast<unsigned char>(c))) {
189 case 2: TAIL(); return result;
190 case 3: TAIL(); TAIL(); return result;
191 case 4: COPY(); TRANS(0x50); TAIL(); return result;
192 case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
193 case 6: TAIL(); TAIL(); TAIL(); return result;
194 case 10: COPY(); TRANS(0x20); TAIL(); return result;
195 case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
189 case 2: CEREAL_RAPIDJSON_TAIL(); return result;
190 case 3: CEREAL_RAPIDJSON_TAIL(); CEREAL_RAPIDJSON_TAIL(); return result;
191 case 4: CEREAL_RAPIDJSON_COPY(); CEREAL_RAPIDJSON_TRANS(0x50); CEREAL_RAPIDJSON_TAIL(); return result;
192 case 5: CEREAL_RAPIDJSON_COPY(); CEREAL_RAPIDJSON_TRANS(0x10); CEREAL_RAPIDJSON_TAIL(); CEREAL_RAPIDJSON_TAIL(); return result;
193 case 6: CEREAL_RAPIDJSON_TAIL(); CEREAL_RAPIDJSON_TAIL(); CEREAL_RAPIDJSON_TAIL(); return result;
194 case 10: CEREAL_RAPIDJSON_COPY(); CEREAL_RAPIDJSON_TRANS(0x20); CEREAL_RAPIDJSON_TAIL(); return result;
195 case 11: CEREAL_RAPIDJSON_COPY(); CEREAL_RAPIDJSON_TRANS(0x60); CEREAL_RAPIDJSON_TAIL(); CEREAL_RAPIDJSON_TAIL(); return result;
196196 default: return false;
197197 }
198 #undef COPY
199 #undef TRANS
200 #undef TAIL
198 #undef CEREAL_RAPIDJSON_COPY
199 #undef CEREAL_RAPIDJSON_TRANS
200 #undef CEREAL_RAPIDJSON_TAIL
201201 }
202202
203203 static unsigned char GetRange(unsigned char c) {
282282 CEREAL_RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
283283 unsigned v = codepoint - 0x10000;
284284 os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
285 os.Put((v & 0x3FF) | 0xDC00);
285 os.Put(static_cast<typename OutputStream::Ch>((v & 0x3FF) | 0xDC00));
286286 }
287287 }
288288
298298 CEREAL_RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
299299 unsigned v = codepoint - 0x10000;
300300 PutUnsafe(os, static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
301 PutUnsafe(os, (v & 0x3FF) | 0xDC00);
301 PutUnsafe(os, static_cast<typename OutputStream::Ch>((v & 0x3FF) | 0xDC00));
302302 }
303303 }
304304
383383 static CharType Take(InputByteStream& is) {
384384 CEREAL_RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
385385 unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
386 c |= static_cast<uint8_t>(is.Take());
386 c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take()));
387387 return static_cast<CharType>(c);
388388 }
389389
619619 #define CEREAL_RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
620620
621621 template<typename OutputStream>
622 CEREAL_RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) {
622 static CEREAL_RAPIDJSON_FORCEINLINE void Encode(OutputStream& os, unsigned codepoint) {
623623 typedef void (*EncodeFunc)(OutputStream&, unsigned);
624624 static const EncodeFunc f[] = { CEREAL_RAPIDJSON_ENCODINGS_FUNC(Encode) };
625625 (*f[os.GetType()])(os, codepoint);
626626 }
627627
628628 template<typename OutputStream>
629 CEREAL_RAPIDJSON_FORCEINLINE static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
629 static CEREAL_RAPIDJSON_FORCEINLINE void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
630630 typedef void (*EncodeFunc)(OutputStream&, unsigned);
631631 static const EncodeFunc f[] = { CEREAL_RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) };
632632 (*f[os.GetType()])(os, codepoint);
633633 }
634634
635635 template <typename InputStream>
636 CEREAL_RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) {
636 static CEREAL_RAPIDJSON_FORCEINLINE bool Decode(InputStream& is, unsigned* codepoint) {
637637 typedef bool (*DecodeFunc)(InputStream&, unsigned*);
638638 static const DecodeFunc f[] = { CEREAL_RAPIDJSON_ENCODINGS_FUNC(Decode) };
639639 return (*f[is.GetType()])(is, codepoint);
640640 }
641641
642642 template <typename InputStream, typename OutputStream>
643 CEREAL_RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
643 static CEREAL_RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {
644644 typedef bool (*ValidateFunc)(InputStream&, OutputStream&);
645645 static const ValidateFunc f[] = { CEREAL_RAPIDJSON_ENCODINGS_FUNC(Validate) };
646646 return (*f[is.GetType()])(is, os);
657657 struct Transcoder {
658658 //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
659659 template<typename InputStream, typename OutputStream>
660 CEREAL_RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
660 static CEREAL_RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) {
661661 unsigned codepoint;
662662 if (!SourceEncoding::Decode(is, &codepoint))
663663 return false;
666666 }
667667
668668 template<typename InputStream, typename OutputStream>
669 CEREAL_RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
669 static CEREAL_RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
670670 unsigned codepoint;
671671 if (!SourceEncoding::Decode(is, &codepoint))
672672 return false;
676676
677677 //! Validate one Unicode codepoint from an encoded stream.
678678 template<typename InputStream, typename OutputStream>
679 CEREAL_RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
679 static CEREAL_RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {
680680 return Transcode(is, os); // Since source/target encoding is different, must transcode.
681681 }
682682 };
689689 template<typename Encoding>
690690 struct Transcoder<Encoding, Encoding> {
691691 template<typename InputStream, typename OutputStream>
692 CEREAL_RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
692 static CEREAL_RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) {
693693 os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class.
694694 return true;
695695 }
696696
697697 template<typename InputStream, typename OutputStream>
698 CEREAL_RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
698 static CEREAL_RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
699699 PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class.
700700 return true;
701701 }
702702
703703 template<typename InputStream, typename OutputStream>
704 CEREAL_RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
704 static CEREAL_RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) {
705705 return Encoding::Validate(is, os); // source/target encoding are the same
706706 }
707707 };
708708
709709 CEREAL_RAPIDJSON_NAMESPACE_END
710710
711 #if defined(__GNUC__) || defined(_MSC_VER)
711 #if defined(__GNUC__) || (defined(_MSC_VER) && !defined(__clang__))
712712 CEREAL_RAPIDJSON_DIAG_POP
713713 #endif
714714
103103 \see GenericReader::Parse, GenericDocument::Parse
104104 */
105105 struct ParseResult {
106 //!! Unspecified boolean type
107 typedef bool (ParseResult::*BooleanType)() const;
106108 public:
107109 //! Default constructor, no error.
108110 ParseResult() : code_(kParseErrorNone), offset_(0) {}
114116 //! Get the error offset, if \ref IsError(), 0 otherwise.
115117 size_t Offset() const { return offset_; }
116118
117 //! Conversion to \c bool, returns \c true, iff !\ref IsError().
118 operator bool() const { return !IsError(); }
119 //! Explicit conversion to \c bool, returns \c true, iff !\ref IsError().
120 operator BooleanType() const { return !IsError() ? &ParseResult::IsError : NULL; }
119121 //! Whether the result is an error.
120122 bool IsError() const { return code_ != kParseErrorNone; }
121123
122124 bool operator==(const ParseResult& that) const { return code_ == that.code_; }
123125 bool operator==(ParseErrorCode code) const { return code_ == code; }
124126 friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; }
127
128 bool operator!=(const ParseResult& that) const { return !(*this == that); }
129 bool operator!=(ParseErrorCode code) const { return !(*this == code); }
130 friend bool operator!=(ParseErrorCode code, const ParseResult & err) { return err != code; }
125131
126132 //! Reset error code.
127133 void Clear() { Set(kParseErrorNone); }
5858
5959 // For encoding detection only.
6060 const Ch* Peek4() const {
61 return (current_ + 4 <= bufferLast_) ? current_ : 0;
61 return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0;
6262 }
6363
6464 private:
6767 ++current_;
6868 else if (!eof_) {
6969 count_ += readCount_;
70 readCount_ = fread(buffer_, 1, bufferSize_, fp_);
70 readCount_ = std::fread(buffer_, 1, bufferSize_, fp_);
7171 bufferLast_ = buffer_ + readCount_ - 1;
7272 current_ = buffer_;
7373
2424
2525 CEREAL_RAPIDJSON_NAMESPACE_BEGIN
2626
27 //! Wrapper of C file stream for input using fread().
27 //! Wrapper of C file stream for output using fwrite().
2828 /*!
2929 \note implements Stream concept
3030 */
6161
6262 void Flush() {
6363 if (current_ != buffer_) {
64 size_t result = fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
64 size_t result = std::fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
6565 if (result < static_cast<size_t>(current_ - buffer_)) {
6666 // failure deliberately ignored at this time
6767 // added to avoid warn_unused_result build errors
1616
1717 #include "../rapidjson.h"
1818
19 #if defined(_MSC_VER) && defined(_M_AMD64)
19 #if defined(_MSC_VER) && !__INTEL_COMPILER && defined(_M_AMD64)
2020 #include <intrin.h> // for _umul128
2121 #pragma intrinsic(_umul128)
2222 #endif
132132 CEREAL_RAPIDJSON_ASSERT(count_ + offset <= kCapacity);
133133
134134 if (interShift == 0) {
135 std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type));
135 std::memmove(digits_ + offset, digits_, count_ * sizeof(Type));
136136 count_ += offset;
137137 }
138138 else {
00 // Tencent is pleased to support the open source community by making RapidJSON available.
1 //
1 //
22 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
33 //
44 // Licensed under the MIT License (the "License"); you may not use this file except
66 //
77 // http://opensource.org/licenses/MIT
88 //
9 // Unless required by applicable law or agreed to in writing, software distributed
10 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 // Unless required by applicable law or agreed to in writing, software distributed
10 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
1212 // specific language governing permissions and limitations under the License.
1313
1414 // This is a C++ header-only implementation of Grisu2 algorithm from the publication:
1919 #define CEREAL_RAPIDJSON_DIYFP_H_
2020
2121 #include "../rapidjson.h"
22
23 #if defined(_MSC_VER) && defined(_M_AMD64)
22 #include <limits>
23
24 #if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER)
2425 #include <intrin.h>
2526 #pragma intrinsic(_BitScanReverse64)
2627 #pragma intrinsic(_umul128)
5556 if (biased_e != 0) {
5657 f = significand + kDpHiddenBit;
5758 e = biased_e - kDpExponentBias;
58 }
59 }
5960 else {
6061 f = significand;
6162 e = kDpMinExponent + 1;
9899 }
99100
100101 DiyFp Normalize() const {
102 CEREAL_RAPIDJSON_ASSERT(f != 0); // https://stackoverflow.com/a/26809183/291737
101103 #if defined(_MSC_VER) && defined(_M_AMD64)
102104 unsigned long index;
103105 _BitScanReverse64(&index, f);
140142 double d;
141143 uint64_t u64;
142144 }u;
143 const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :
145 CEREAL_RAPIDJSON_ASSERT(f <= kDpHiddenBit + kDpSignificandMask);
146 if (e < kDpDenormalExponent) {
147 // Underflow.
148 return 0.0;
149 }
150 if (e >= kDpMaxExponent) {
151 // Overflow.
152 return std::numeric_limits<double>::infinity();
153 }
154 const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :
144155 static_cast<uint64_t>(e + kDpExponentBias);
145156 u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
146157 return u.d;
219230 641, 667, 694, 720, 747, 774, 800, 827, 853, 880,
220231 907, 933, 960, 986, 1013, 1039, 1066
221232 };
233 CEREAL_RAPIDJSON_ASSERT(index < 87);
222234 return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
223235 }
224
236
225237 inline DiyFp GetCachedPower(int e, int* K) {
226238
227239 //int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
237249 }
238250
239251 inline DiyFp GetCachedPower10(int exp, int *outExp) {
240 unsigned index = (static_cast<unsigned>(exp) + 348u) / 8u;
241 *outExp = -348 + static_cast<int>(index) * 8;
242 return GetCachedPowerByIndex(index);
243 }
252 CEREAL_RAPIDJSON_ASSERT(exp >= -348);
253 unsigned index = static_cast<unsigned>(exp + 348) / 8u;
254 *outExp = -348 + static_cast<int>(index) * 8;
255 return GetCachedPowerByIndex(index);
256 }
244257
245258 #ifdef __GNUC__
246259 CEREAL_RAPIDJSON_DIAG_POP
4040 }
4141 }
4242
43 inline unsigned CountDecimalDigit32(uint32_t n) {
43 inline int CountDecimalDigit32(uint32_t n) {
4444 // Simple pure C++ implementation was faster than __builtin_clz version in this situation.
4545 if (n < 10) return 1;
4646 if (n < 100) return 2;
6262 const DiyFp wp_w = Mp - W;
6363 uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
6464 uint64_t p2 = Mp.f & (one.f - 1);
65 unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
65 int kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
6666 *len = 0;
6767
6868 while (kappa > 0) {
101101 kappa--;
102102 if (p2 < delta) {
103103 *K += kappa;
104 int index = -static_cast<int>(kappa);
105 GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[-static_cast<int>(kappa)] : 0));
104 int index = -kappa;
105 GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[index] : 0));
106106 return;
107107 }
108108 }
4747 int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; }
4848 uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; }
4949
50 static unsigned EffectiveSignificandSize(int order) {
50 static int EffectiveSignificandSize(int order) {
5151 if (order >= -1021)
5252 return 53;
5353 else if (order <= -1074)
5454 return 0;
5555 else
56 return static_cast<unsigned>(order) + 1074;
56 return order + 1074;
5757 }
5858
5959 private:
00 // Tencent is pleased to support the open source community by making RapidJSON available.
1 //
1 //
22 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
33 //
44 // Licensed under the MIT License (the "License"); you may not use this file except
66 //
77 // http://opensource.org/licenses/MIT
88 //
9 // Unless required by applicable law or agreed to in writing, software distributed
10 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 // Unless required by applicable law or agreed to in writing, software distributed
10 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
1212 // specific language governing permissions and limitations under the License.
1313
1414 #ifndef CEREAL_RAPIDJSON_ITOA_
3636 }
3737
3838 inline char* u32toa(uint32_t value, char* buffer) {
39 CEREAL_RAPIDJSON_ASSERT(buffer != 0);
40
3941 const char* cDigitsLut = GetDigitsLut();
4042
4143 if (value < 10000) {
4244 const uint32_t d1 = (value / 100) << 1;
4345 const uint32_t d2 = (value % 100) << 1;
44
46
4547 if (value >= 1000)
4648 *buffer++ = cDigitsLut[d1];
4749 if (value >= 100)
5456 // value = bbbbcccc
5557 const uint32_t b = value / 10000;
5658 const uint32_t c = value % 10000;
57
59
5860 const uint32_t d1 = (b / 100) << 1;
5961 const uint32_t d2 = (b % 100) << 1;
60
62
6163 const uint32_t d3 = (c / 100) << 1;
6264 const uint32_t d4 = (c % 100) << 1;
63
65
6466 if (value >= 10000000)
6567 *buffer++ = cDigitsLut[d1];
6668 if (value >= 1000000)
6870 if (value >= 100000)
6971 *buffer++ = cDigitsLut[d2];
7072 *buffer++ = cDigitsLut[d2 + 1];
71
73
7274 *buffer++ = cDigitsLut[d3];
7375 *buffer++ = cDigitsLut[d3 + 1];
7476 *buffer++ = cDigitsLut[d4];
7678 }
7779 else {
7880 // value = aabbbbcccc in decimal
79
81
8082 const uint32_t a = value / 100000000; // 1 to 42
8183 value %= 100000000;
82
84
8385 if (a >= 10) {
8486 const unsigned i = a << 1;
8587 *buffer++ = cDigitsLut[i];
9092
9193 const uint32_t b = value / 10000; // 0 to 9999
9294 const uint32_t c = value % 10000; // 0 to 9999
93
95
9496 const uint32_t d1 = (b / 100) << 1;
9597 const uint32_t d2 = (b % 100) << 1;
96
98
9799 const uint32_t d3 = (c / 100) << 1;
98100 const uint32_t d4 = (c % 100) << 1;
99
101
100102 *buffer++ = cDigitsLut[d1];
101103 *buffer++ = cDigitsLut[d1 + 1];
102104 *buffer++ = cDigitsLut[d2];
110112 }
111113
112114 inline char* i32toa(int32_t value, char* buffer) {
115 CEREAL_RAPIDJSON_ASSERT(buffer != 0);
113116 uint32_t u = static_cast<uint32_t>(value);
114117 if (value < 0) {
115118 *buffer++ = '-';
120123 }
121124
122125 inline char* u64toa(uint64_t value, char* buffer) {
126 CEREAL_RAPIDJSON_ASSERT(buffer != 0);
123127 const char* cDigitsLut = GetDigitsLut();
124128 const uint64_t kTen8 = 100000000;
125129 const uint64_t kTen9 = kTen8 * 10;
130134 const uint64_t kTen14 = kTen8 * 1000000;
131135 const uint64_t kTen15 = kTen8 * 10000000;
132136 const uint64_t kTen16 = kTen8 * kTen8;
133
137
134138 if (value < kTen8) {
135139 uint32_t v = static_cast<uint32_t>(value);
136140 if (v < 10000) {
137141 const uint32_t d1 = (v / 100) << 1;
138142 const uint32_t d2 = (v % 100) << 1;
139
143
140144 if (v >= 1000)
141145 *buffer++ = cDigitsLut[d1];
142146 if (v >= 100)
149153 // value = bbbbcccc
150154 const uint32_t b = v / 10000;
151155 const uint32_t c = v % 10000;
152
156
153157 const uint32_t d1 = (b / 100) << 1;
154158 const uint32_t d2 = (b % 100) << 1;
155
159
156160 const uint32_t d3 = (c / 100) << 1;
157161 const uint32_t d4 = (c % 100) << 1;
158
162
159163 if (value >= 10000000)
160164 *buffer++ = cDigitsLut[d1];
161165 if (value >= 1000000)
163167 if (value >= 100000)
164168 *buffer++ = cDigitsLut[d2];
165169 *buffer++ = cDigitsLut[d2 + 1];
166
170
167171 *buffer++ = cDigitsLut[d3];
168172 *buffer++ = cDigitsLut[d3 + 1];
169173 *buffer++ = cDigitsLut[d4];
173177 else if (value < kTen16) {
174178 const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
175179 const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
176
180
177181 const uint32_t b0 = v0 / 10000;
178182 const uint32_t c0 = v0 % 10000;
179
183
180184 const uint32_t d1 = (b0 / 100) << 1;
181185 const uint32_t d2 = (b0 % 100) << 1;
182
186
183187 const uint32_t d3 = (c0 / 100) << 1;
184188 const uint32_t d4 = (c0 % 100) << 1;
185189
186190 const uint32_t b1 = v1 / 10000;
187191 const uint32_t c1 = v1 % 10000;
188
192
189193 const uint32_t d5 = (b1 / 100) << 1;
190194 const uint32_t d6 = (b1 % 100) << 1;
191
195
192196 const uint32_t d7 = (c1 / 100) << 1;
193197 const uint32_t d8 = (c1 % 100) << 1;
194198
206210 *buffer++ = cDigitsLut[d3 + 1];
207211 if (value >= kTen9)
208212 *buffer++ = cDigitsLut[d4];
209 if (value >= kTen8)
210 *buffer++ = cDigitsLut[d4 + 1];
211
213
214 *buffer++ = cDigitsLut[d4 + 1];
212215 *buffer++ = cDigitsLut[d5];
213216 *buffer++ = cDigitsLut[d5 + 1];
214217 *buffer++ = cDigitsLut[d6];
221224 else {
222225 const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844
223226 value %= kTen16;
224
227
225228 if (a < 10)
226229 *buffer++ = static_cast<char>('0' + static_cast<char>(a));
227230 else if (a < 100) {
231234 }
232235 else if (a < 1000) {
233236 *buffer++ = static_cast<char>('0' + static_cast<char>(a / 100));
234
237
235238 const uint32_t i = (a % 100) << 1;
236239 *buffer++ = cDigitsLut[i];
237240 *buffer++ = cDigitsLut[i + 1];
244247 *buffer++ = cDigitsLut[j];
245248 *buffer++ = cDigitsLut[j + 1];
246249 }
247
250
248251 const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
249252 const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
250
253
251254 const uint32_t b0 = v0 / 10000;
252255 const uint32_t c0 = v0 % 10000;
253
256
254257 const uint32_t d1 = (b0 / 100) << 1;
255258 const uint32_t d2 = (b0 % 100) << 1;
256
259
257260 const uint32_t d3 = (c0 / 100) << 1;
258261 const uint32_t d4 = (c0 % 100) << 1;
259
262
260263 const uint32_t b1 = v1 / 10000;
261264 const uint32_t c1 = v1 % 10000;
262
265
263266 const uint32_t d5 = (b1 / 100) << 1;
264267 const uint32_t d6 = (b1 % 100) << 1;
265
268
266269 const uint32_t d7 = (c1 / 100) << 1;
267270 const uint32_t d8 = (c1 % 100) << 1;
268
271
269272 *buffer++ = cDigitsLut[d1];
270273 *buffer++ = cDigitsLut[d1 + 1];
271274 *buffer++ = cDigitsLut[d2];
283286 *buffer++ = cDigitsLut[d8];
284287 *buffer++ = cDigitsLut[d8 + 1];
285288 }
286
289
287290 return buffer;
288291 }
289292
290293 inline char* i64toa(int64_t value, char* buffer) {
294 CEREAL_RAPIDJSON_ASSERT(buffer != 0);
291295 uint64_t u = static_cast<uint64_t>(value);
292296 if (value < 0) {
293297 *buffer++ = '-';
2020 CEREAL_RAPIDJSON_DIAG_PUSH
2121 CEREAL_RAPIDJSON_DIAG_OFF(effc++)
2222 #endif
23 #if defined(_MSC_VER)
23
24 #if defined(_MSC_VER) && !defined(__clang__)
2425 CEREAL_RAPIDJSON_DIAG_PUSH
2526 CEREAL_RAPIDJSON_DIAG_OFF(6334)
2627 #endif
173174 CEREAL_RAPIDJSON_NAMESPACE_END
174175 //@endcond
175176
176 #if defined(__GNUC__) || defined(_MSC_VER)
177 #if defined(_MSC_VER) && !defined(__clang__)
178 CEREAL_RAPIDJSON_DIAG_POP
179 #endif
180
181 #ifdef __GNUC__
177182 CEREAL_RAPIDJSON_DIAG_POP
178183 #endif
179184
2323 CEREAL_RAPIDJSON_DIAG_OFF(padded)
2424 CEREAL_RAPIDJSON_DIAG_OFF(switch-enum)
2525 CEREAL_RAPIDJSON_DIAG_OFF(implicit-fallthrough)
26 #elif defined(_MSC_VER)
27 CEREAL_RAPIDJSON_DIAG_PUSH
28 CEREAL_RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
2629 #endif
2730
2831 #ifdef __GNUC__
2932 CEREAL_RAPIDJSON_DIAG_PUSH
3033 CEREAL_RAPIDJSON_DIAG_OFF(effc++)
34 #if __GNUC__ >= 7
35 CEREAL_RAPIDJSON_DIAG_OFF(implicit-fallthrough)
3136 #endif
32
33 #ifdef _MSC_VER
34 CEREAL_RAPIDJSON_DIAG_PUSH
35 CEREAL_RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
3637 #endif
3738
3839 #ifndef CEREAL_RAPIDJSON_REGEX_VERBOSE
4344 namespace internal {
4445
4546 ///////////////////////////////////////////////////////////////////////////////
47 // DecodedStream
48
49 template <typename SourceStream, typename Encoding>
50 class DecodedStream {
51 public:
52 DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); }
53 unsigned Peek() { return codepoint_; }
54 unsigned Take() {
55 unsigned c = codepoint_;
56 if (c) // No further decoding when '\0'
57 Decode();
58 return c;
59 }
60
61 private:
62 void Decode() {
63 if (!Encoding::Decode(ss_, &codepoint_))
64 codepoint_ = 0;
65 }
66
67 SourceStream& ss_;
68 unsigned codepoint_;
69 };
70
71 ///////////////////////////////////////////////////////////////////////////////
4672 // GenericRegex
4773
4874 static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1
4975 static const SizeType kRegexInvalidRange = ~SizeType(0);
76
77 template <typename Encoding, typename Allocator>
78 class GenericRegexSearch;
5079
5180 //! Regular expression engine with subset of ECMAscript grammar.
5281 /*!
83112 template <typename Encoding, typename Allocator = CrtAllocator>
84113 class GenericRegex {
85114 public:
115 typedef Encoding EncodingType;
86116 typedef typename Encoding::Ch Ch;
117 template <typename, typename> friend class GenericRegexSearch;
87118
88119 GenericRegex(const Ch* source, Allocator* allocator = 0) :
89 states_(allocator, 256), ranges_(allocator, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(),
90 stateSet_(), state0_(allocator, 0), state1_(allocator, 0), anchorBegin_(), anchorEnd_()
120 ownAllocator_(allocator ? 0 : CEREAL_RAPIDJSON_NEW(Allocator)()), allocator_(allocator ? allocator : ownAllocator_),
121 states_(allocator_, 256), ranges_(allocator_, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(),
122 anchorBegin_(), anchorEnd_()
91123 {
92124 GenericStringStream<Encoding> ss(source);
93 DecodedStream<GenericStringStream<Encoding> > ds(ss);
125 DecodedStream<GenericStringStream<Encoding>, Encoding> ds(ss);
94126 Parse(ds);
95127 }
96128
97 ~GenericRegex() {
98 Allocator::Free(stateSet_);
129 ~GenericRegex()
130 {
131 CEREAL_RAPIDJSON_DELETE(ownAllocator_);
99132 }
100133
101134 bool IsValid() const {
102135 return root_ != kRegexInvalidState;
103 }
104
105 template <typename InputStream>
106 bool Match(InputStream& is) const {
107 return SearchWithAnchoring(is, true, true);
108 }
109
110 bool Match(const Ch* s) const {
111 GenericStringStream<Encoding> is(s);
112 return Match(is);
113 }
114
115 template <typename InputStream>
116 bool Search(InputStream& is) const {
117 return SearchWithAnchoring(is, anchorBegin_, anchorEnd_);
118 }
119
120 bool Search(const Ch* s) const {
121 GenericStringStream<Encoding> is(s);
122 return Search(is);
123136 }
124137
125138 private:
156169 SizeType minIndex;
157170 };
158171
159 template <typename SourceStream>
160 class DecodedStream {
161 public:
162 DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); }
163 unsigned Peek() { return codepoint_; }
164 unsigned Take() {
165 unsigned c = codepoint_;
166 if (c) // No further decoding when '\0'
167 Decode();
168 return c;
169 }
170
171 private:
172 void Decode() {
173 if (!Encoding::Decode(ss_, &codepoint_))
174 codepoint_ = 0;
175 }
176
177 SourceStream& ss_;
178 unsigned codepoint_;
179 };
180
181172 State& GetState(SizeType index) {
182173 CEREAL_RAPIDJSON_ASSERT(index < stateCount_);
183174 return states_.template Bottom<State>()[index];
199190 }
200191
201192 template <typename InputStream>
202 void Parse(DecodedStream<InputStream>& ds) {
203 Allocator allocator;
204 Stack<Allocator> operandStack(&allocator, 256); // Frag
205 Stack<Allocator> operatorStack(&allocator, 256); // Operator
206 Stack<Allocator> atomCountStack(&allocator, 256); // unsigned (Atom per parenthesis)
193 void Parse(DecodedStream<InputStream, Encoding>& ds) {
194 Stack<Allocator> operandStack(allocator_, 256); // Frag
195 Stack<Allocator> operatorStack(allocator_, 256); // Operator
196 Stack<Allocator> atomCountStack(allocator_, 256); // unsigned (Atom per parenthesis)
207197
208198 *atomCountStack.template Push<unsigned>() = 0;
209199
326316 printf("\n");
327317 #endif
328318 }
329
330 // Preallocate buffer for SearchWithAnchoring()
331 CEREAL_RAPIDJSON_ASSERT(stateSet_ == 0);
332 if (stateCount_ > 0) {
333 stateSet_ = static_cast<unsigned*>(states_.GetAllocator().Malloc(GetStateSetSize()));
334 state0_.template Reserve<SizeType>(stateCount_);
335 state1_.template Reserve<SizeType>(stateCount_);
336 }
337319 }
338320
339321 SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) {
412394 }
413395 return false;
414396
415 default:
416 CEREAL_RAPIDJSON_ASSERT(op == kOneOrMore);
397 case kOneOrMore:
417398 if (operandStack.GetSize() >= sizeof(Frag)) {
418399 Frag e = *operandStack.template Pop<Frag>(1);
419400 SizeType s = NewState(kRegexInvalidState, e.start, 0);
421402 *operandStack.template Push<Frag>() = Frag(e.start, s, e.minIndex);
422403 return true;
423404 }
405 return false;
406
407 default:
408 // syntax error (e.g. unclosed kLeftParenthesis)
424409 return false;
425410 }
426411 }
482467 }
483468
484469 template <typename InputStream>
485 bool ParseUnsigned(DecodedStream<InputStream>& ds, unsigned* u) {
470 bool ParseUnsigned(DecodedStream<InputStream, Encoding>& ds, unsigned* u) {
486471 unsigned r = 0;
487472 if (ds.Peek() < '0' || ds.Peek() > '9')
488473 return false;
496481 }
497482
498483 template <typename InputStream>
499 bool ParseRange(DecodedStream<InputStream>& ds, SizeType* range) {
484 bool ParseRange(DecodedStream<InputStream, Encoding>& ds, SizeType* range) {
500485 bool isBegin = true;
501486 bool negate = false;
502487 int step = 0;
574559 }
575560
576561 template <typename InputStream>
577 bool CharacterEscape(DecodedStream<InputStream>& ds, unsigned* escapedCodepoint) {
562 bool CharacterEscape(DecodedStream<InputStream, Encoding>& ds, unsigned* escapedCodepoint) {
578563 unsigned codepoint;
579564 switch (codepoint = ds.Take()) {
580565 case '^':
602587 }
603588 }
604589
590 Allocator* ownAllocator_;
591 Allocator* allocator_;
592 Stack<Allocator> states_;
593 Stack<Allocator> ranges_;
594 SizeType root_;
595 SizeType stateCount_;
596 SizeType rangeCount_;
597
598 static const unsigned kInfinityQuantifier = ~0u;
599
600 // For SearchWithAnchoring()
601 bool anchorBegin_;
602 bool anchorEnd_;
603 };
604
605 template <typename RegexType, typename Allocator = CrtAllocator>
606 class GenericRegexSearch {
607 public:
608 typedef typename RegexType::EncodingType Encoding;
609 typedef typename Encoding::Ch Ch;
610
611 GenericRegexSearch(const RegexType& regex, Allocator* allocator = 0) :
612 regex_(regex), allocator_(allocator), ownAllocator_(0),
613 state0_(allocator, 0), state1_(allocator, 0), stateSet_()
614 {
615 CEREAL_RAPIDJSON_ASSERT(regex_.IsValid());
616 if (!allocator_)
617 ownAllocator_ = allocator_ = CEREAL_RAPIDJSON_NEW(Allocator)();
618 stateSet_ = static_cast<unsigned*>(allocator_->Malloc(GetStateSetSize()));
619 state0_.template Reserve<SizeType>(regex_.stateCount_);
620 state1_.template Reserve<SizeType>(regex_.stateCount_);
621 }
622
623 ~GenericRegexSearch() {
624 Allocator::Free(stateSet_);
625 CEREAL_RAPIDJSON_DELETE(ownAllocator_);
626 }
627
605628 template <typename InputStream>
606 bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) const {
607 CEREAL_RAPIDJSON_ASSERT(IsValid());
608 DecodedStream<InputStream> ds(is);
629 bool Match(InputStream& is) {
630 return SearchWithAnchoring(is, true, true);
631 }
632
633 bool Match(const Ch* s) {
634 GenericStringStream<Encoding> is(s);
635 return Match(is);
636 }
637
638 template <typename InputStream>
639 bool Search(InputStream& is) {
640 return SearchWithAnchoring(is, regex_.anchorBegin_, regex_.anchorEnd_);
641 }
642
643 bool Search(const Ch* s) {
644 GenericStringStream<Encoding> is(s);
645 return Search(is);
646 }
647
648 private:
649 typedef typename RegexType::State State;
650 typedef typename RegexType::Range Range;
651
652 template <typename InputStream>
653 bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) {
654 DecodedStream<InputStream, Encoding> ds(is);
609655
610656 state0_.Clear();
611657 Stack<Allocator> *current = &state0_, *next = &state1_;
612658 const size_t stateSetSize = GetStateSetSize();
613659 std::memset(stateSet_, 0, stateSetSize);
614660
615 bool matched = AddState(*current, root_);
661 bool matched = AddState(*current, regex_.root_);
616662 unsigned codepoint;
617663 while (!current->Empty() && (codepoint = ds.Take()) != 0) {
618664 std::memset(stateSet_, 0, stateSetSize);
619665 next->Clear();
620666 matched = false;
621667 for (const SizeType* s = current->template Bottom<SizeType>(); s != current->template End<SizeType>(); ++s) {
622 const State& sr = GetState(*s);
668 const State& sr = regex_.GetState(*s);
623669 if (sr.codepoint == codepoint ||
624 sr.codepoint == kAnyCharacterClass ||
625 (sr.codepoint == kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint)))
670 sr.codepoint == RegexType::kAnyCharacterClass ||
671 (sr.codepoint == RegexType::kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint)))
626672 {
627673 matched = AddState(*next, sr.out) || matched;
628674 if (!anchorEnd && matched)
629675 return true;
630676 }
631677 if (!anchorBegin)
632 AddState(*next, root_);
678 AddState(*next, regex_.root_);
633679 }
634680 internal::Swap(current, next);
635681 }
638684 }
639685
640686 size_t GetStateSetSize() const {
641 return (stateCount_ + 31) / 32 * 4;
687 return (regex_.stateCount_ + 31) / 32 * 4;
642688 }
643689
644690 // Return whether the added states is a match state
645 bool AddState(Stack<Allocator>& l, SizeType index) const {
691 bool AddState(Stack<Allocator>& l, SizeType index) {
646692 CEREAL_RAPIDJSON_ASSERT(index != kRegexInvalidState);
647693
648 const State& s = GetState(index);
694 const State& s = regex_.GetState(index);
649695 if (s.out1 != kRegexInvalidState) { // Split
650696 bool matched = AddState(l, s.out);
651697 return AddState(l, s.out1) || matched;
652698 }
653 else if (!(stateSet_[index >> 5] & (1 << (index & 31)))) {
654 stateSet_[index >> 5] |= (1 << (index & 31));
699 else if (!(stateSet_[index >> 5] & (1u << (index & 31)))) {
700 stateSet_[index >> 5] |= (1u << (index & 31));
655701 *l.template PushUnsafe<SizeType>() = index;
656702 }
657703 return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation.
658704 }
659705
660706 bool MatchRange(SizeType rangeIndex, unsigned codepoint) const {
661 bool yes = (GetRange(rangeIndex).start & kRangeNegationFlag) == 0;
707 bool yes = (regex_.GetRange(rangeIndex).start & RegexType::kRangeNegationFlag) == 0;
662708 while (rangeIndex != kRegexInvalidRange) {
663 const Range& r = GetRange(rangeIndex);
664 if (codepoint >= (r.start & ~kRangeNegationFlag) && codepoint <= r.end)
709 const Range& r = regex_.GetRange(rangeIndex);
710 if (codepoint >= (r.start & ~RegexType::kRangeNegationFlag) && codepoint <= r.end)
665711 return yes;
666712 rangeIndex = r.next;
667713 }
668714 return !yes;
669715 }
670716
671 Stack<Allocator> states_;
672 Stack<Allocator> ranges_;
673 SizeType root_;
674 SizeType stateCount_;
675 SizeType rangeCount_;
676
677 static const unsigned kInfinityQuantifier = ~0u;
678
679 // For SearchWithAnchoring()
680 uint32_t* stateSet_; // allocated by states_.GetAllocator()
681 mutable Stack<Allocator> state0_;
682 mutable Stack<Allocator> state1_;
683 bool anchorBegin_;
684 bool anchorEnd_;
717 const RegexType& regex_;
718 Allocator* allocator_;
719 Allocator* ownAllocator_;
720 Stack<Allocator> state0_;
721 Stack<Allocator> state1_;
722 uint32_t* stateSet_;
685723 };
686724
687725 typedef GenericRegex<UTF8<> > Regex;
726 typedef GenericRegexSearch<Regex> RegexSearch;
688727
689728 } // namespace internal
690729 CEREAL_RAPIDJSON_NAMESPACE_END
691730
692 #ifdef __clang__
731 #ifdef __GNUC__
693732 CEREAL_RAPIDJSON_DIAG_POP
694733 #endif
695734
696 #ifdef _MSC_VER
735 #if defined(__clang__) || defined(_MSC_VER)
697736 CEREAL_RAPIDJSON_DIAG_POP
698737 #endif
699738
1616
1717 #include "../allocators.h"
1818 #include "swap.h"
19 #include <cstddef>
1920
2021 #if defined(__clang__)
2122 CEREAL_RAPIDJSON_DIAG_PUSH
99100 void ShrinkToFit() {
100101 if (Empty()) {
101102 // If the stack is empty, completely deallocate the memory.
102 Allocator::Free(stack_);
103 Allocator::Free(stack_); // NOLINT (+clang-analyzer-unix.Malloc)
103104 stack_ = 0;
104105 stackTop_ = 0;
105106 stackEnd_ = 0;
113114 template<typename T>
114115 CEREAL_RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
115116 // Expand the stack if needed
116 if (CEREAL_RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_))
117 if (CEREAL_RAPIDJSON_UNLIKELY(static_cast<std::ptrdiff_t>(sizeof(T) * count) > (stackEnd_ - stackTop_)))
117118 Expand<T>(count);
118119 }
119120
125126
126127 template<typename T>
127128 CEREAL_RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
128 CEREAL_RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_);
129 CEREAL_RAPIDJSON_ASSERT(stackTop_);
130 CEREAL_RAPIDJSON_ASSERT(static_cast<std::ptrdiff_t>(sizeof(T) * count) <= (stackEnd_ - stackTop_));
129131 T* ret = reinterpret_cast<T*>(stackTop_);
130132 stackTop_ += sizeof(T) * count;
131133 return ret;
182184 size_t newCapacity;
183185 if (stack_ == 0) {
184186 if (!allocator_)
185 ownAllocator_ = allocator_ = CEREAL_RAPIDJSON_NEW(Allocator());
187 ownAllocator_ = allocator_ = CEREAL_RAPIDJSON_NEW(Allocator)();
186188 newCapacity = initialCapacity_;
187189 } else {
188190 newCapacity = GetCapacity();
1515 #define CEREAL_RAPIDJSON_INTERNAL_STRFUNC_H_
1616
1717 #include "../stream.h"
18 #include <cwchar>
1819
1920 CEREAL_RAPIDJSON_NAMESPACE_BEGIN
2021 namespace internal {
2728 */
2829 template <typename Ch>
2930 inline SizeType StrLen(const Ch* s) {
31 CEREAL_RAPIDJSON_ASSERT(s != 0);
3032 const Ch* p = s;
3133 while (*p) ++p;
3234 return SizeType(p - s);
3335 }
3436
37 template <>
38 inline SizeType StrLen(const char* s) {
39 return SizeType(std::strlen(s));
40 }
41
42 template <>
43 inline SizeType StrLen(const wchar_t* s) {
44 return SizeType(std::wcslen(s));
45 }
46
3547 //! Returns number of code points in a encoded string.
3648 template<typename Encoding>
3749 bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) {
50 CEREAL_RAPIDJSON_ASSERT(s != 0);
51 CEREAL_RAPIDJSON_ASSERT(outCount != 0);
3852 GenericStringStream<Encoding> is(s);
3953 const typename Encoding::Ch* end = s + length;
4054 SizeType count = 0;
1818 #include "biginteger.h"
1919 #include "diyfp.h"
2020 #include "pow10.h"
21 #include <climits>
22 #include <limits>
2123
2224 CEREAL_RAPIDJSON_NAMESPACE_BEGIN
2325 namespace internal {
125127 }
126128
127129 // Compute an approximation and see if it is within 1/2 ULP
128 inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) {
130 inline bool StrtodDiyFp(const char* decimals, int dLen, int dExp, double* result) {
129131 uint64_t significand = 0;
130 size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
131 for (; i < length; i++) {
132 int i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999
133 for (; i < dLen; i++) {
132134 if (significand > CEREAL_RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
133135 (significand == CEREAL_RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
134136 break;
135137 significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
136138 }
137139
138 if (i < length && decimals[i] >= '5') // Rounding
140 if (i < dLen && decimals[i] >= '5') // Rounding
139141 significand++;
140142
141 size_t remaining = length - i;
142 const unsigned kUlpShift = 3;
143 const unsigned kUlp = 1 << kUlpShift;
143 int remaining = dLen - i;
144 const int kUlpShift = 3;
145 const int kUlp = 1 << kUlpShift;
144146 int64_t error = (remaining == 0) ? 0 : kUlp / 2;
145147
146148 DiyFp v(significand, 0);
147149 v = v.Normalize();
148150 error <<= -v.e;
149151
150 const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(i) + exp;
152 dExp += remaining;
151153
152154 int actualExp;
153155 DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
154156 if (actualExp != dExp) {
155157 static const DiyFp kPow10[] = {
156 DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1
157 DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2
158 DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3
159 DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50), // 10^4
160 DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47), // 10^5
161 DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6
162 DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7
158 DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0xa0000000, 0x00000000), -60), // 10^1
159 DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0xc8000000, 0x00000000), -57), // 10^2
160 DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0xfa000000, 0x00000000), -54), // 10^3
161 DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), -50), // 10^4
162 DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0xc3500000, 0x00000000), -47), // 10^5
163 DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0xf4240000, 0x00000000), -44), // 10^6
164 DiyFp(CEREAL_RAPIDJSON_UINT64_C2(0x98968000, 0x00000000), -40) // 10^7
163165 };
164 int adjustment = dExp - actualExp - 1;
165 CEREAL_RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7);
166 v = v * kPow10[adjustment];
167 if (length + static_cast<unsigned>(adjustment)> 19u) // has more digits than decimal digits in 64-bit
166 int adjustment = dExp - actualExp;
167 CEREAL_RAPIDJSON_ASSERT(adjustment >= 1 && adjustment < 8);
168 v = v * kPow10[adjustment - 1];
169 if (dLen + adjustment > 19) // has more digits than decimal digits in 64-bit
168170 error += kUlp / 2;
169171 }
170172
176178 v = v.Normalize();
177179 error <<= oldExp - v.e;
178180
179 const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e);
180 unsigned precisionSize = 64 - effectiveSignificandSize;
181 const int effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e);
182 int precisionSize = 64 - effectiveSignificandSize;
181183 if (precisionSize + kUlpShift >= 64) {
182 unsigned scaleExp = (precisionSize + kUlpShift) - 63;
184 int scaleExp = (precisionSize + kUlpShift) - 63;
183185 v.f >>= scaleExp;
184186 v.e += scaleExp;
185 error = (error >> scaleExp) + 1 + static_cast<int>(kUlp);
187 error = (error >> scaleExp) + 1 + kUlp;
186188 precisionSize -= scaleExp;
187189 }
188190
189 DiyFp rounded(v.f >> precisionSize, v.e + static_cast<int>(precisionSize));
191 DiyFp rounded(v.f >> precisionSize, v.e + precisionSize);
190192 const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;
191193 const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;
192194 if (precisionBits >= halfWay + static_cast<unsigned>(error)) {
202204 return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);
203205 }
204206
205 inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) {
206 const BigInteger dInt(decimals, length);
207 const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(length) + exp;
207 inline double StrtodBigInteger(double approx, const char* decimals, int dLen, int dExp) {
208 CEREAL_RAPIDJSON_ASSERT(dLen >= 0);
209 const BigInteger dInt(decimals, static_cast<unsigned>(dLen));
208210 Double a(approx);
209211 int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
210212 if (cmp < 0)
224226 CEREAL_RAPIDJSON_ASSERT(d >= 0.0);
225227 CEREAL_RAPIDJSON_ASSERT(length >= 1);
226228
227 double result;
229 double result = 0.0;
228230 if (StrtodFast(d, p, &result))
229231 return result;
230232
233 CEREAL_RAPIDJSON_ASSERT(length <= INT_MAX);
234 int dLen = static_cast<int>(length);
235
236 CEREAL_RAPIDJSON_ASSERT(length >= decimalPosition);
237 CEREAL_RAPIDJSON_ASSERT(length - decimalPosition <= INT_MAX);
238 int dExpAdjust = static_cast<int>(length - decimalPosition);
239
240 CEREAL_RAPIDJSON_ASSERT(exp >= INT_MIN + dExpAdjust);
241 int dExp = exp - dExpAdjust;
242
243 // Make sure length+dExp does not overflow
244 CEREAL_RAPIDJSON_ASSERT(dExp <= INT_MAX - dLen);
245
231246 // Trim leading zeros
232 while (*decimals == '0' && length > 1) {
233 length--;
247 while (dLen > 0 && *decimals == '0') {
248 dLen--;
234249 decimals++;
235 decimalPosition--;
236250 }
237251
238252 // Trim trailing zeros
239 while (decimals[length - 1] == '0' && length > 1) {
240 length--;
241 decimalPosition--;
242 exp++;
253 while (dLen > 0 && decimals[dLen - 1] == '0') {
254 dLen--;
255 dExp++;
256 }
257
258 if (dLen == 0) { // Buffer only contains zeros.
259 return 0.0;
243260 }
244261
245262 // Trim right-most digits
246 const int kMaxDecimalDigit = 780;
247 if (static_cast<int>(length) > kMaxDecimalDigit) {
248 int delta = (static_cast<int>(length) - kMaxDecimalDigit);
249 exp += delta;
250 decimalPosition -= static_cast<unsigned>(delta);
251 length = kMaxDecimalDigit;
252 }
253
254 // If too small, underflow to zero
255 if (int(length) + exp < -324)
263 const int kMaxDecimalDigit = 767 + 1;
264 if (dLen > kMaxDecimalDigit) {
265 dExp += dLen - kMaxDecimalDigit;
266 dLen = kMaxDecimalDigit;
267 }
268
269 // If too small, underflow to zero.
270 // Any x <= 10^-324 is interpreted as zero.
271 if (dLen + dExp <= -324)
256272 return 0.0;
257273
258 if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result))
274 // If too large, overflow to infinity.
275 // Any x >= 10^309 is interpreted as +infinity.
276 if (dLen + dExp > 309)
277 return std::numeric_limits<double>::infinity();
278
279 if (StrtodDiyFp(decimals, dLen, dExp, &result))
259280 return result;
260281
261282 // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison
262 return StrtodBigInteger(result, decimals, length, decimalPosition, exp);
283 return StrtodBigInteger(result, decimals, dLen, dExp);
263284 }
264285
265286 } // namespace internal
00 // Tencent is pleased to support the open source community by making RapidJSON available.
1 //
1 //
22 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
33 //
44 // Licensed under the MIT License (the "License"); you may not use this file except
66 //
77 // http://opensource.org/licenses/MIT
88 //
9 // Unless required by applicable law or agreed to in writing, software distributed
10 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 // Unless required by applicable law or agreed to in writing, software distributed
10 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
1212 // specific language governing permissions and limitations under the License.
1313
1414 #ifndef CEREAL_RAPIDJSON_ISTREAMWRAPPER_H_
1616
1717 #include "stream.h"
1818 #include <iosfwd>
19 #include <ios>
1920
2021 #ifdef __clang__
2122 CEREAL_RAPIDJSON_DIAG_PUSH
2223 CEREAL_RAPIDJSON_DIAG_OFF(padded)
23 #endif
24
25 #ifdef _MSC_VER
24 #elif defined(_MSC_VER)
2625 CEREAL_RAPIDJSON_DIAG_PUSH
2726 CEREAL_RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized
28 CEREAL_RAPIDJSON_DIAG_OFF(4127) // ignore assert(false) for triggering exception
2927 #endif
3028
3129 CEREAL_RAPIDJSON_NAMESPACE_BEGIN
4543
4644 \tparam StreamType Class derived from \c std::basic_istream.
4745 */
48
46
4947 template <typename StreamType>
5048 class BasicIStreamWrapper {
5149 public:
5250 typedef typename StreamType::char_type Ch;
53 BasicIStreamWrapper(StreamType& stream) : stream_(stream), count_(), peekBuffer_() {}
5451
55 Ch Peek() const {
56 typename StreamType::int_type c = stream_.peek();
57 return CEREAL_RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast<Ch>(c) : '\0';
52 //! Constructor.
53 /*!
54 \param stream stream opened for read.
55 */
56 BasicIStreamWrapper(StreamType &stream) : stream_(stream), buffer_(peekBuffer_), bufferSize_(4), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
57 Read();
5858 }
5959
60 Ch Take() {
61 typename StreamType::int_type c = stream_.get();
62 if (CEREAL_RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) {
63 count_++;
64 return static_cast<Ch>(c);
65 }
66 else
67 return '\0';
60 //! Constructor.
61 /*!
62 \param stream stream opened for read.
63 \param buffer user-supplied buffer.
64 \param bufferSize size of buffer in bytes. Must >=4 bytes.
65 */
66 BasicIStreamWrapper(StreamType &stream, char* buffer, size_t bufferSize) : stream_(stream), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) {
67 CEREAL_RAPIDJSON_ASSERT(bufferSize >= 4);
68 Read();
6869 }
6970
70 // tellg() may return -1 when failed. So we count by ourself.
71 size_t Tell() const { return count_; }
71 Ch Peek() const { return *current_; }
72 Ch Take() { Ch c = *current_; Read(); return c; }
73 size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
7274
75 // Not implemented
76 void Put(Ch) { CEREAL_RAPIDJSON_ASSERT(false); }
77 void Flush() { CEREAL_RAPIDJSON_ASSERT(false); }
7378 Ch* PutBegin() { CEREAL_RAPIDJSON_ASSERT(false); return 0; }
74 void Put(Ch) { CEREAL_RAPIDJSON_ASSERT(false); }
75 void Flush() { CEREAL_RAPIDJSON_ASSERT(false); }
7679 size_t PutEnd(Ch*) { CEREAL_RAPIDJSON_ASSERT(false); return 0; }
7780
7881 // For encoding detection only.
7982 const Ch* Peek4() const {
80 CEREAL_RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream.
81 int i;
82 bool hasError = false;
83 for (i = 0; i < 4; ++i) {
84 typename StreamType::int_type c = stream_.get();
85 if (c == StreamType::traits_type::eof()) {
86 hasError = true;
87 stream_.clear();
88 break;
89 }
90 peekBuffer_[i] = static_cast<Ch>(c);
91 }
92 for (--i; i >= 0; --i)
93 stream_.putback(peekBuffer_[i]);
94 return !hasError ? peekBuffer_ : 0;
83 return (current_ + 4 - !eof_ <= bufferLast_) ? current_ : 0;
9584 }
9685
9786 private:
87 BasicIStreamWrapper();
9888 BasicIStreamWrapper(const BasicIStreamWrapper&);
9989 BasicIStreamWrapper& operator=(const BasicIStreamWrapper&);
10090
101 StreamType& stream_;
102 size_t count_; //!< Number of characters read. Note:
103 mutable Ch peekBuffer_[4];
91 void Read() {
92 if (current_ < bufferLast_)
93 ++current_;
94 else if (!eof_) {
95 count_ += readCount_;
96 readCount_ = bufferSize_;
97 bufferLast_ = buffer_ + readCount_ - 1;
98 current_ = buffer_;
99
100 if (!stream_.read(buffer_, static_cast<std::streamsize>(bufferSize_))) {
101 readCount_ = static_cast<size_t>(stream_.gcount());
102 *(bufferLast_ = buffer_ + readCount_) = '\0';
103 eof_ = true;
104 }
105 }
106 }
107
108 StreamType &stream_;
109 Ch peekBuffer_[4], *buffer_;
110 size_t bufferSize_;
111 Ch *bufferLast_;
112 Ch *current_;
113 size_t readCount_;
114 size_t count_; //!< Number of characters read
115 bool eof_;
104116 };
105117
106118 typedef BasicIStreamWrapper<std::istream> IStreamWrapper;
00 // Tencent is pleased to support the open source community by making RapidJSON available.
1 //
1 //
22 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
33 //
44 // Licensed under the MIT License (the "License"); you may not use this file except
66 //
77 // http://opensource.org/licenses/MIT
88 //
9 // Unless required by applicable law or agreed to in writing, software distributed
10 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 // Unless required by applicable law or agreed to in writing, software distributed
10 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
1212 // specific language governing permissions and limitations under the License.
1313
1414 #ifndef CEREAL_RAPIDJSON_MEMORYSTREAM_H_
2020 CEREAL_RAPIDJSON_DIAG_PUSH
2121 CEREAL_RAPIDJSON_DIAG_OFF(unreachable-code)
2222 CEREAL_RAPIDJSON_DIAG_OFF(missing-noreturn)
23 #endif
24
25 #ifdef _MSC_VER
26 CEREAL_RAPIDJSON_DIAG_PUSH
27 CEREAL_RAPIDJSON_DIAG_OFF( 4127 ) // ignore assert(false) for triggering exception
2823 #endif
2924
3025 CEREAL_RAPIDJSON_NAMESPACE_BEGIN
6863
6964 CEREAL_RAPIDJSON_NAMESPACE_END
7065
71 #if defined(__clang__) || defined(_MSC_VER)
66 #ifdef __clang__
7267 CEREAL_RAPIDJSON_DIAG_POP
7368 #endif
7469
2020 #ifdef __clang__
2121 CEREAL_RAPIDJSON_DIAG_PUSH
2222 CEREAL_RAPIDJSON_DIAG_OFF(switch-enum)
23 #endif
24
25 #ifdef _MSC_VER
23 #elif defined(_MSC_VER)
2624 CEREAL_RAPIDJSON_DIAG_PUSH
2725 CEREAL_RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
2826 #endif
164162 GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast<Token*>(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
165163
166164 //! Copy constructor.
167 GenericPointer(const GenericPointer& rhs, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
165 GenericPointer(const GenericPointer& rhs) : allocator_(rhs.allocator_), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
166 *this = rhs;
167 }
168
169 //! Copy constructor.
170 GenericPointer(const GenericPointer& rhs, Allocator* allocator) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
168171 *this = rhs;
169172 }
170173
195198 }
196199 return *this;
197200 }
201
202 //! Swap the content of this pointer with an other.
203 /*!
204 \param other The pointer to swap with.
205 \note Constant complexity.
206 */
207 GenericPointer& Swap(GenericPointer& other) CEREAL_RAPIDJSON_NOEXCEPT {
208 internal::Swap(allocator_, other.allocator_);
209 internal::Swap(ownAllocator_, other.ownAllocator_);
210 internal::Swap(nameBuffer_, other.nameBuffer_);
211 internal::Swap(tokens_, other.tokens_);
212 internal::Swap(tokenCount_, other.tokenCount_);
213 internal::Swap(parseErrorOffset_, other.parseErrorOffset_);
214 internal::Swap(parseErrorCode_, other.parseErrorCode_);
215 return *this;
216 }
217
218 //! free-standing swap function helper
219 /*!
220 Helper function to enable support for common swap implementation pattern based on \c std::swap:
221 \code
222 void swap(MyClass& a, MyClass& b) {
223 using std::swap;
224 swap(a.pointer, b.pointer);
225 // ...
226 }
227 \endcode
228 \see Swap()
229 */
230 friend inline void swap(GenericPointer& a, GenericPointer& b) CEREAL_RAPIDJSON_NOEXCEPT { a.Swap(b); }
198231
199232 //@}
200233
239272 template <typename T>
240273 CEREAL_RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >), (GenericPointer))
241274 Append(T* name, Allocator* allocator = 0) const {
242 return Append(name, StrLen(name), allocator);
275 return Append(name, internal::StrLen(name), allocator);
243276 }
244277
245278 #if CEREAL_RAPIDJSON_HAS_STDSTRING
273306 else {
274307 Ch name[21];
275308 for (size_t i = 0; i <= length; i++)
276 name[i] = buffer[i];
309 name[i] = static_cast<Ch>(buffer[i]);
277310 Token token = { name, length, index };
278311 return Append(token, allocator);
279312 }
351384 \note When any pointers are invalid, always returns true.
352385 */
353386 bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); }
387
388 //! Less than operator.
389 /*!
390 \note Invalid pointers are always greater than valid ones.
391 */
392 bool operator<(const GenericPointer& rhs) const {
393 if (!IsValid())
394 return false;
395 if (!rhs.IsValid())
396 return true;
397
398 if (tokenCount_ != rhs.tokenCount_)
399 return tokenCount_ < rhs.tokenCount_;
400
401 for (size_t i = 0; i < tokenCount_; i++) {
402 if (tokens_[i].index != rhs.tokens_[i].index)
403 return tokens_[i].index < rhs.tokens_[i].index;
404
405 if (tokens_[i].length != rhs.tokens_[i].length)
406 return tokens_[i].length < rhs.tokens_[i].length;
407
408 if (int cmp = std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch) * tokens_[i].length))
409 return cmp < 0;
410 }
411
412 return false;
413 }
354414
355415 //@}
356416
531591 */
532592 ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const {
533593 bool alreadyExist;
534 Value& v = Create(root, allocator, &alreadyExist);
594 ValueType& v = Create(root, allocator, &alreadyExist);
535595 return alreadyExist ? v : v.CopyFrom(defaultValue, allocator);
536596 }
537597
538598 //! Query a value in a subtree with default null-terminated string.
539599 ValueType& GetWithDefault(ValueType& root, const Ch* defaultValue, typename ValueType::AllocatorType& allocator) const {
540600 bool alreadyExist;
541 Value& v = Create(root, allocator, &alreadyExist);
601 ValueType& v = Create(root, allocator, &alreadyExist);
542602 return alreadyExist ? v : v.SetString(defaultValue, allocator);
543603 }
544604
546606 //! Query a value in a subtree with default std::basic_string.
547607 ValueType& GetWithDefault(ValueType& root, const std::basic_string<Ch>& defaultValue, typename ValueType::AllocatorType& allocator) const {
548608 bool alreadyExist;
549 Value& v = Create(root, allocator, &alreadyExist);
609 ValueType& v = Create(root, allocator, &alreadyExist);
550610 return alreadyExist ? v : v.SetString(defaultValue, allocator);
551611 }
552612 #endif
757817 */
758818 Ch* CopyFromRaw(const GenericPointer& rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) {
759819 if (!allocator_) // allocator is independently owned.
760 ownAllocator_ = allocator_ = CEREAL_RAPIDJSON_NEW(Allocator());
820 ownAllocator_ = allocator_ = CEREAL_RAPIDJSON_NEW(Allocator)();
761821
762822 size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens
763823 for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t)
805865
806866 // Create own allocator if user did not supply.
807867 if (!allocator_)
808 ownAllocator_ = allocator_ = CEREAL_RAPIDJSON_NEW(Allocator());
868 ownAllocator_ = allocator_ = CEREAL_RAPIDJSON_NEW(Allocator)();
809869
810870 // Count number of '/' as tokenCount
811871 tokenCount_ = 0;
10281088 unsigned char u = static_cast<unsigned char>(c);
10291089 static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
10301090 os_.Put('%');
1031 os_.Put(hexDigits[u >> 4]);
1032 os_.Put(hexDigits[u & 15]);
1091 os_.Put(static_cast<typename OutputStream::Ch>(hexDigits[u >> 4]));
1092 os_.Put(static_cast<typename OutputStream::Ch>(hexDigits[u & 15]));
10331093 }
10341094 private:
10351095 OutputStream& os_;
13461406
13471407 CEREAL_RAPIDJSON_NAMESPACE_END
13481408
1349 #ifdef __clang__
1409 #if defined(__clang__) || defined(_MSC_VER)
13501410 CEREAL_RAPIDJSON_DIAG_POP
13511411 #endif
13521412
1353 #ifdef _MSC_VER
1354 CEREAL_RAPIDJSON_DIAG_POP
1355 #endif
1356
13571413 #endif // CEREAL_RAPIDJSON_POINTER_H_
2121 CEREAL_RAPIDJSON_DIAG_OFF(effc++)
2222 #endif
2323
24 #if defined(__clang__)
25 CEREAL_RAPIDJSON_DIAG_PUSH
26 CEREAL_RAPIDJSON_DIAG_OFF(c++98-compat)
27 #endif
28
2429 CEREAL_RAPIDJSON_NAMESPACE_BEGIN
2530
2631 //! Combination of PrettyWriter format flags.
3338
3439 //! Writer with indentation and spacing.
3540 /*!
36 \tparam OutputStream Type of ouptut os.
41 \tparam OutputStream Type of output os.
3742 \tparam SourceEncoding Encoding of source string.
3843 \tparam TargetEncoding Encoding of output stream.
3944 \tparam StackAllocator Type of allocator for allocating memory of stack.
4146 template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
4247 class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> {
4348 public:
44 typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator> Base;
49 typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> Base;
4550 typedef typename Base::Ch Ch;
4651
4752 //! Constructor
5560
5661 explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) :
5762 Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
63
64 #if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS
65 PrettyWriter(PrettyWriter&& rhs) :
66 Base(std::forward<PrettyWriter>(rhs)), indentChar_(rhs.indentChar_), indentCharCount_(rhs.indentCharCount_), formatOptions_(rhs.formatOptions_) {}
67 #endif
5868
5969 //! Set custom indentation.
6070 /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r').
8191 */
8292 //@{
8393
84 bool Null() { PrettyPrefix(kNullType); return Base::WriteNull(); }
85 bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); }
86 bool Int(int i) { PrettyPrefix(kNumberType); return Base::WriteInt(i); }
87 bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::WriteUint(u); }
88 bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); }
89 bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); }
90 bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); }
94 bool Null() { PrettyPrefix(kNullType); return Base::EndValue(Base::WriteNull()); }
95 bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::EndValue(Base::WriteBool(b)); }
96 bool Int(int i) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteInt(i)); }
97 bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteUint(u)); }
98 bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteInt64(i64)); }
99 bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteUint64(u64)); }
100 bool Double(double d) { PrettyPrefix(kNumberType); return Base::EndValue(Base::WriteDouble(d)); }
91101
92102 bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
103 CEREAL_RAPIDJSON_ASSERT(str != 0);
93104 (void)copy;
94105 PrettyPrefix(kNumberType);
95 return Base::WriteString(str, length);
106 return Base::EndValue(Base::WriteString(str, length));
96107 }
97108
98109 bool String(const Ch* str, SizeType length, bool copy = false) {
110 CEREAL_RAPIDJSON_ASSERT(str != 0);
99111 (void)copy;
100112 PrettyPrefix(kStringType);
101 return Base::WriteString(str, length);
113 return Base::EndValue(Base::WriteString(str, length));
102114 }
103115
104116 #if CEREAL_RAPIDJSON_HAS_STDSTRING
123135
124136 bool EndObject(SizeType memberCount = 0) {
125137 (void)memberCount;
126 CEREAL_RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
127 CEREAL_RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray);
138 CEREAL_RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); // not inside an Object
139 CEREAL_RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray); // currently inside an Array, not Object
140 CEREAL_RAPIDJSON_ASSERT(0 == Base::level_stack_.template Top<typename Base::Level>()->valueCount % 2); // Object has a Key without a Value
141
128142 bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
129143
130144 if (!empty) {
131145 Base::os_->Put('\n');
132146 WriteIndent();
133147 }
134 bool ret = Base::WriteEndObject();
148 bool ret = Base::EndValue(Base::WriteEndObject());
135149 (void)ret;
136150 CEREAL_RAPIDJSON_ASSERT(ret == true);
137151 if (Base::level_stack_.Empty()) // end of json text
138 Base::os_->Flush();
152 Base::Flush();
139153 return true;
140154 }
141155
155169 Base::os_->Put('\n');
156170 WriteIndent();
157171 }
158 bool ret = Base::WriteEndArray();
172 bool ret = Base::EndValue(Base::WriteEndArray());
159173 (void)ret;
160174 CEREAL_RAPIDJSON_ASSERT(ret == true);
161175 if (Base::level_stack_.Empty()) // end of json text
162 Base::os_->Flush();
176 Base::Flush();
163177 return true;
164178 }
165179
183197 \param type Type of the root of json.
184198 \note When using PrettyWriter::RawValue(), the result json may not be indented correctly.
185199 */
186 bool RawValue(const Ch* json, size_t length, Type type) { PrettyPrefix(type); return Base::WriteRawValue(json, length); }
200 bool RawValue(const Ch* json, size_t length, Type type) {
201 CEREAL_RAPIDJSON_ASSERT(json != 0);
202 PrettyPrefix(type);
203 return Base::EndValue(Base::WriteRawValue(json, length));
204 }
187205
188206 protected:
189207 void PrettyPrefix(Type type) {
232250
233251 void WriteIndent() {
234252 size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
235 PutN(*Base::os_, static_cast<typename TargetEncoding::Ch>(indentChar_), count);
253 PutN(*Base::os_, static_cast<typename OutputStream::Ch>(indentChar_), count);
236254 }
237255
238256 Ch indentChar_;
247265
248266 CEREAL_RAPIDJSON_NAMESPACE_END
249267
268 #if defined(__clang__)
269 CEREAL_RAPIDJSON_DIAG_POP
270 #endif
271
250272 #ifdef __GNUC__
251273 CEREAL_RAPIDJSON_DIAG_POP
252274 #endif
2525
2626 Some RapidJSON features are configurable to adapt the library to a wide
2727 variety of platforms, environments and usage scenarios. Most of the
28 features can be configured in terms of overriden or predefined
28 features can be configured in terms of overridden or predefined
2929 preprocessor macros at compile-time.
3030
3131 Some additional customization is available in the \ref CEREAL_RAPIDJSON_ERRORS APIs.
4848 // token stringification
4949 #define CEREAL_RAPIDJSON_STRINGIFY(x) CEREAL_RAPIDJSON_DO_STRINGIFY(x)
5050 #define CEREAL_RAPIDJSON_DO_STRINGIFY(x) #x
51
52 // token concatenation
53 #define CEREAL_RAPIDJSON_JOIN(X, Y) CEREAL_RAPIDJSON_DO_JOIN(X, Y)
54 #define CEREAL_RAPIDJSON_DO_JOIN(X, Y) CEREAL_RAPIDJSON_DO_JOIN2(X, Y)
55 #define CEREAL_RAPIDJSON_DO_JOIN2(X, Y) X##Y
5156 //!@endcond
5257
5358 /*! \def CEREAL_RAPIDJSON_MAJOR_VERSION
6772 \brief Version of RapidJSON in "<major>.<minor>.<patch>" string format.
6873 */
6974 #define CEREAL_RAPIDJSON_MAJOR_VERSION 1
70 #define CEREAL_RAPIDJSON_MINOR_VERSION 0
71 #define CEREAL_RAPIDJSON_PATCH_VERSION 2
75 #define CEREAL_RAPIDJSON_MINOR_VERSION 1
76 #define CEREAL_RAPIDJSON_PATCH_VERSION 0
7277 #define CEREAL_RAPIDJSON_VERSION_STRING \
7378 CEREAL_RAPIDJSON_STRINGIFY(CEREAL_RAPIDJSON_MAJOR_VERSION.CEREAL_RAPIDJSON_MINOR_VERSION.CEREAL_RAPIDJSON_PATCH_VERSION)
7479
213218 # elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
214219 # define CEREAL_RAPIDJSON_ENDIAN CEREAL_RAPIDJSON_BIGENDIAN
215220 # else
216 # error Unknown machine endianess detected. User needs to define CEREAL_RAPIDJSON_ENDIAN.
221 # error Unknown machine endianness detected. User needs to define CEREAL_RAPIDJSON_ENDIAN.
217222 # endif // __BYTE_ORDER__
218223 // Detect with GLIBC's endian.h
219224 # elif defined(__GLIBC__)
223228 # elif (__BYTE_ORDER == __BIG_ENDIAN)
224229 # define CEREAL_RAPIDJSON_ENDIAN CEREAL_RAPIDJSON_BIGENDIAN
225230 # else
226 # error Unknown machine endianess detected. User needs to define CEREAL_RAPIDJSON_ENDIAN.
231 # error Unknown machine endianness detected. User needs to define CEREAL_RAPIDJSON_ENDIAN.
227232 # endif // __GLIBC__
228233 // Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro
229234 # elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
235240 # define CEREAL_RAPIDJSON_ENDIAN CEREAL_RAPIDJSON_BIGENDIAN
236241 # elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__)
237242 # define CEREAL_RAPIDJSON_ENDIAN CEREAL_RAPIDJSON_LITTLEENDIAN
238 # elif defined(_MSC_VER) && defined(_M_ARM)
243 # elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64))
239244 # define CEREAL_RAPIDJSON_ENDIAN CEREAL_RAPIDJSON_LITTLEENDIAN
240245 # elif defined(CEREAL_RAPIDJSON_DOXYGEN_RUNNING)
241246 # define CEREAL_RAPIDJSON_ENDIAN
242247 # else
243 # error Unknown machine endianess detected. User needs to define CEREAL_RAPIDJSON_ENDIAN.
248 # error Unknown machine endianness detected. User needs to define CEREAL_RAPIDJSON_ENDIAN.
244249 # endif
245250 #endif // CEREAL_RAPIDJSON_ENDIAN
246251
263268 /*! \ingroup CEREAL_RAPIDJSON_CONFIG
264269 \param x pointer to align
265270
266 Some machines require strict data alignment. Currently the default uses 4 bytes
267 alignment on 32-bit platforms and 8 bytes alignment for 64-bit platforms.
271 Some machines require strict data alignment. The default is 8 bytes.
268272 User can customize by defining the CEREAL_RAPIDJSON_ALIGN function macro.
269273 */
270274 #ifndef CEREAL_RAPIDJSON_ALIGN
271 #if CEREAL_RAPIDJSON_64BIT == 1
272 #define CEREAL_RAPIDJSON_ALIGN(x) (((x) + static_cast<uint64_t>(7u)) & ~static_cast<uint64_t>(7u))
273 #else
274 #define CEREAL_RAPIDJSON_ALIGN(x) (((x) + 3u) & ~3u)
275 #endif
275 #define CEREAL_RAPIDJSON_ALIGN(x) (((x) + static_cast<size_t>(7u)) & ~static_cast<size_t>(7u))
276276 #endif
277277
278278 ///////////////////////////////////////////////////////////////////////////////
319319 #endif
320320
321321 ///////////////////////////////////////////////////////////////////////////////
322 // CEREAL_RAPIDJSON_SSE2/CEREAL_RAPIDJSON_SSE42/CEREAL_RAPIDJSON_SIMD
322 // CEREAL_RAPIDJSON_SSE2/CEREAL_RAPIDJSON_SSE42/CEREAL_RAPIDJSON_NEON/CEREAL_RAPIDJSON_SIMD
323323
324324 /*! \def CEREAL_RAPIDJSON_SIMD
325325 \ingroup CEREAL_RAPIDJSON_CONFIG
326 \brief Enable SSE2/SSE4.2 optimization.
326 \brief Enable SSE2/SSE4.2/Neon optimization.
327327
328328 RapidJSON supports optimized implementations for some parsing operations
329 based on the SSE2 or SSE4.2 SIMD extensions on modern Intel-compatible
330 processors.
331
332 To enable these optimizations, two different symbols can be defined;
329 based on the SSE2, SSE4.2 or NEon SIMD extensions on modern Intel
330 or ARM compatible processors.
331
332 To enable these optimizations, three different symbols can be defined;
333333 \code
334334 // Enable SSE2 optimization.
335335 #define CEREAL_RAPIDJSON_SSE2
338338 #define CEREAL_RAPIDJSON_SSE42
339339 \endcode
340340
341 \c CEREAL_RAPIDJSON_SSE42 takes precedence, if both are defined.
341 // Enable ARM Neon optimization.
342 #define CEREAL_RAPIDJSON_NEON
343 \endcode
344
345 \c CEREAL_RAPIDJSON_SSE42 takes precedence over SSE2, if both are defined.
342346
343347 If any of these symbols is defined, RapidJSON defines the macro
344348 \c CEREAL_RAPIDJSON_SIMD to indicate the availability of the optimized code.
345349 */
346350 #if defined(CEREAL_RAPIDJSON_SSE2) || defined(CEREAL_RAPIDJSON_SSE42) \
347 || defined(CEREAL_RAPIDJSON_DOXYGEN_RUNNING)
351 || defined(CEREAL_RAPIDJSON_NEON) || defined(CEREAL_RAPIDJSON_DOXYGEN_RUNNING)
348352 #define CEREAL_RAPIDJSON_SIMD
349353 #endif
350354
404408 ///////////////////////////////////////////////////////////////////////////////
405409 // CEREAL_RAPIDJSON_STATIC_ASSERT
406410
407 // Adopt from boost
411 // Prefer C++11 static_assert, if available
412 #ifndef CEREAL_RAPIDJSON_STATIC_ASSERT
413 #if __cplusplus >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 )
414 #define CEREAL_RAPIDJSON_STATIC_ASSERT(x) \
415 static_assert(x, CEREAL_RAPIDJSON_STRINGIFY(x))
416 #endif // C++11
417 #endif // CEREAL_RAPIDJSON_STATIC_ASSERT
418
419 // Adopt C++03 implementation from boost
408420 #ifndef CEREAL_RAPIDJSON_STATIC_ASSERT
409421 #ifndef __clang__
410422 //!@cond CEREAL_RAPIDJSON_HIDDEN_FROM_DOXYGEN
412424 CEREAL_RAPIDJSON_NAMESPACE_BEGIN
413425 template <bool x> struct STATIC_ASSERTION_FAILURE;
414426 template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
415 template<int x> struct StaticAssertTest {};
427 template <size_t x> struct StaticAssertTest {};
416428 CEREAL_RAPIDJSON_NAMESPACE_END
417429
418 #define CEREAL_RAPIDJSON_JOIN(X, Y) CEREAL_RAPIDJSON_DO_JOIN(X, Y)
419 #define CEREAL_RAPIDJSON_DO_JOIN(X, Y) CEREAL_RAPIDJSON_DO_JOIN2(X, Y)
420 #define CEREAL_RAPIDJSON_DO_JOIN2(X, Y) X##Y
421
422 #if defined(__GNUC__)
430 #if defined(__GNUC__) || defined(__clang__)
423431 #define CEREAL_RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused))
424432 #else
425433 #define CEREAL_RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
437445 typedef ::CEREAL_RAPIDJSON_NAMESPACE::StaticAssertTest< \
438446 sizeof(::CEREAL_RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE<bool(x) >)> \
439447 CEREAL_RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) CEREAL_RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
440 #endif
448 #endif // CEREAL_RAPIDJSON_STATIC_ASSERT
441449
442450 ///////////////////////////////////////////////////////////////////////////////
443451 // CEREAL_RAPIDJSON_LIKELY, CEREAL_RAPIDJSON_UNLIKELY
529537 #ifndef CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS
530538 #if defined(__clang__)
531539 #if __has_feature(cxx_rvalue_references) && \
532 (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306)
540 (defined(_MSC_VER) || defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306)
533541 #define CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
534542 #else
535543 #define CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS 0
536544 #endif
537545 #elif (defined(CEREAL_RAPIDJSON_GNUC) && (CEREAL_RAPIDJSON_GNUC >= CEREAL_RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
538 (defined(_MSC_VER) && _MSC_VER >= 1600)
546 (defined(_MSC_VER) && _MSC_VER >= 1600) || \
547 (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__))
539548
540549 #define CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
541550 #else
546555 #ifndef CEREAL_RAPIDJSON_HAS_CXX11_NOEXCEPT
547556 #if defined(__clang__)
548557 #define CEREAL_RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept)
549 #elif (defined(CEREAL_RAPIDJSON_GNUC) && (CEREAL_RAPIDJSON_GNUC >= CEREAL_RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__))
550 // (defined(_MSC_VER) && _MSC_VER >= ????) // not yet supported
558 #elif (defined(CEREAL_RAPIDJSON_GNUC) && (CEREAL_RAPIDJSON_GNUC >= CEREAL_RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
559 (defined(_MSC_VER) && _MSC_VER >= 1900) || \
560 (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__))
551561 #define CEREAL_RAPIDJSON_HAS_CXX11_NOEXCEPT 1
552562 #else
553563 #define CEREAL_RAPIDJSON_HAS_CXX11_NOEXCEPT 0
561571
562572 // no automatic detection, yet
563573 #ifndef CEREAL_RAPIDJSON_HAS_CXX11_TYPETRAITS
574 #if (defined(_MSC_VER) && _MSC_VER >= 1700)
575 #define CEREAL_RAPIDJSON_HAS_CXX11_TYPETRAITS 1
576 #else
564577 #define CEREAL_RAPIDJSON_HAS_CXX11_TYPETRAITS 0
578 #endif
565579 #endif
566580
567581 #ifndef CEREAL_RAPIDJSON_HAS_CXX11_RANGE_FOR
568582 #if defined(__clang__)
569583 #define CEREAL_RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for)
570 #elif (defined(CEREAL_RAPIDJSON_GNUC) && (CEREAL_RAPIDJSON_GNUC >= CEREAL_RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
571 (defined(_MSC_VER) && _MSC_VER >= 1700)
584 #elif (defined(CEREAL_RAPIDJSON_GNUC) && (CEREAL_RAPIDJSON_GNUC >= CEREAL_RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
585 (defined(_MSC_VER) && _MSC_VER >= 1700) || \
586 (defined(__SUNPRO_CC) && __SUNPRO_CC >= 0x5140 && defined(__GXX_EXPERIMENTAL_CXX0X__))
572587 #define CEREAL_RAPIDJSON_HAS_CXX11_RANGE_FOR 1
573588 #else
574589 #define CEREAL_RAPIDJSON_HAS_CXX11_RANGE_FOR 0
576591 #endif // CEREAL_RAPIDJSON_HAS_CXX11_RANGE_FOR
577592
578593 //!@endcond
594
595 //! Assertion (in non-throwing contexts).
596 /*! \ingroup CEREAL_RAPIDJSON_CONFIG
597 Some functions provide a \c noexcept guarantee, if the compiler supports it.
598 In these cases, the \ref CEREAL_RAPIDJSON_ASSERT macro cannot be overridden to
599 throw an exception. This macro adds a separate customization point for
600 such cases.
601
602 Defaults to C \c assert() (as \ref CEREAL_RAPIDJSON_ASSERT), if \c noexcept is
603 supported, and to \ref CEREAL_RAPIDJSON_ASSERT otherwise.
604 */
605
606 ///////////////////////////////////////////////////////////////////////////////
607 // CEREAL_RAPIDJSON_NOEXCEPT_ASSERT
608
609 #ifndef CEREAL_RAPIDJSON_NOEXCEPT_ASSERT
610 #ifdef CEREAL_RAPIDJSON_ASSERT_THROWS
611 #if CEREAL_RAPIDJSON_HAS_CXX11_NOEXCEPT
612 #define CEREAL_RAPIDJSON_NOEXCEPT_ASSERT(x)
613 #else
614 #define CEREAL_RAPIDJSON_NOEXCEPT_ASSERT(x) CEREAL_RAPIDJSON_ASSERT(x)
615 #endif // CEREAL_RAPIDJSON_HAS_CXX11_NOEXCEPT
616 #else
617 #define CEREAL_RAPIDJSON_NOEXCEPT_ASSERT(x) CEREAL_RAPIDJSON_ASSERT(x)
618 #endif // CEREAL_RAPIDJSON_ASSERT_THROWS
619 #endif // CEREAL_RAPIDJSON_NOEXCEPT_ASSERT
579620
580621 ///////////////////////////////////////////////////////////////////////////////
581622 // new/delete
582623
583624 #ifndef CEREAL_RAPIDJSON_NEW
584625 ///! customization point for global \c new
585 #define CEREAL_RAPIDJSON_NEW(x) new x
626 #define CEREAL_RAPIDJSON_NEW(TypeName) new TypeName
586627 #endif
587628 #ifndef CEREAL_RAPIDJSON_DELETE
588629 ///! customization point for global \c delete
3232 #include <nmmintrin.h>
3333 #elif defined(CEREAL_RAPIDJSON_SSE2)
3434 #include <emmintrin.h>
35 #endif
36
37 #ifdef _MSC_VER
38 CEREAL_RAPIDJSON_DIAG_PUSH
39 CEREAL_RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
40 CEREAL_RAPIDJSON_DIAG_OFF(4702) // unreachable code
35 #elif defined(CEREAL_RAPIDJSON_NEON)
36 #include <arm_neon.h>
4137 #endif
4238
4339 #ifdef __clang__
4541 CEREAL_RAPIDJSON_DIAG_OFF(old-style-cast)
4642 CEREAL_RAPIDJSON_DIAG_OFF(padded)
4743 CEREAL_RAPIDJSON_DIAG_OFF(switch-enum)
44 #elif defined(_MSC_VER)
45 CEREAL_RAPIDJSON_DIAG_PUSH
46 CEREAL_RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
47 CEREAL_RAPIDJSON_DIAG_OFF(4702) // unreachable code
4848 #endif
4949
5050 #ifdef __GNUC__
298298
299299 for (;; p += 16) {
300300 const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
301 const int r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY));
302 if (r != 0) { // some of characters is non-whitespace
303 #ifdef _MSC_VER // Find the index of first non-whitespace
304 unsigned long offset;
305 _BitScanForward(&offset, r);
306 return p + offset;
307 #else
308 return p + __builtin_ffs(r) - 1;
309 #endif
310 }
301 const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY);
302 if (r != 16) // some of characters is non-whitespace
303 return p + r;
311304 }
312305 }
313306
324317
325318 for (; p <= end - 16; p += 16) {
326319 const __m128i s = _mm_loadu_si128(reinterpret_cast<const __m128i *>(p));
327 const int r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY));
328 if (r != 0) { // some of characters is non-whitespace
329 #ifdef _MSC_VER // Find the index of first non-whitespace
330 unsigned long offset;
331 _BitScanForward(&offset, r);
332 return p + offset;
333 #else
334 return p + __builtin_ffs(r) - 1;
335 #endif
336 }
320 const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY);
321 if (r != 16) // some of characters is non-whitespace
322 return p + r;
337323 }
338324
339325 return SkipWhitespace(p, end);
424410 return SkipWhitespace(p, end);
425411 }
426412
427 #endif // CEREAL_RAPIDJSON_SSE2
413 #elif defined(CEREAL_RAPIDJSON_NEON)
414
415 //! Skip whitespace with ARM Neon instructions, testing 16 8-byte characters at once.
416 inline const char *SkipWhitespace_SIMD(const char* p) {
417 // Fast return for single non-whitespace
418 if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
419 ++p;
420 else
421 return p;
422
423 // 16-byte align to the next boundary
424 const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
425 while (p != nextAligned)
426 if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
427 ++p;
428 else
429 return p;
430
431 const uint8x16_t w0 = vmovq_n_u8(' ');
432 const uint8x16_t w1 = vmovq_n_u8('\n');
433 const uint8x16_t w2 = vmovq_n_u8('\r');
434 const uint8x16_t w3 = vmovq_n_u8('\t');
435
436 for (;; p += 16) {
437 const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(p));
438 uint8x16_t x = vceqq_u8(s, w0);
439 x = vorrq_u8(x, vceqq_u8(s, w1));
440 x = vorrq_u8(x, vceqq_u8(s, w2));
441 x = vorrq_u8(x, vceqq_u8(s, w3));
442
443 x = vmvnq_u8(x); // Negate
444 x = vrev64q_u8(x); // Rev in 64
445 uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
446 uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
447
448 if (low == 0) {
449 if (high != 0) {
450 int lz =__builtin_clzll(high);;
451 return p + 8 + (lz >> 3);
452 }
453 } else {
454 int lz = __builtin_clzll(low);;
455 return p + (lz >> 3);
456 }
457 }
458 }
459
460 inline const char *SkipWhitespace_SIMD(const char* p, const char* end) {
461 // Fast return for single non-whitespace
462 if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t'))
463 ++p;
464 else
465 return p;
466
467 const uint8x16_t w0 = vmovq_n_u8(' ');
468 const uint8x16_t w1 = vmovq_n_u8('\n');
469 const uint8x16_t w2 = vmovq_n_u8('\r');
470 const uint8x16_t w3 = vmovq_n_u8('\t');
471
472 for (; p <= end - 16; p += 16) {
473 const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(p));
474 uint8x16_t x = vceqq_u8(s, w0);
475 x = vorrq_u8(x, vceqq_u8(s, w1));
476 x = vorrq_u8(x, vceqq_u8(s, w2));
477 x = vorrq_u8(x, vceqq_u8(s, w3));
478
479 x = vmvnq_u8(x); // Negate
480 x = vrev64q_u8(x); // Rev in 64
481 uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
482 uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
483
484 if (low == 0) {
485 if (high != 0) {
486 int lz = __builtin_clzll(high);
487 return p + 8 + (lz >> 3);
488 }
489 } else {
490 int lz = __builtin_clzll(low);
491 return p + (lz >> 3);
492 }
493 }
494
495 return SkipWhitespace(p, end);
496 }
497
498 #endif // CEREAL_RAPIDJSON_NEON
428499
429500 #ifdef CEREAL_RAPIDJSON_SIMD
430501 //! Template function specialization for InsituStringStream
470541 /*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)
471542 \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing)
472543 */
473 GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(stackAllocator, stackCapacity), parseResult_() {}
544 GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) :
545 stack_(stackAllocator, stackCapacity), parseResult_(), state_(IterativeParsingStartState) {}
474546
475547 //! Parse JSON text.
476548 /*! \tparam parseFlags Combination of \ref ParseFlag.
526598 return Parse<kParseDefaultFlags>(is, handler);
527599 }
528600
529 //! Whether a parse error has occured in the last parsing.
601 //! Initialize JSON text token-by-token parsing
602 /*!
603 */
604 void IterativeParseInit() {
605 parseResult_.Clear();
606 state_ = IterativeParsingStartState;
607 }
608
609 //! Parse one token from JSON text
610 /*! \tparam InputStream Type of input stream, implementing Stream concept
611 \tparam Handler Type of handler, implementing Handler concept.
612 \param is Input stream to be parsed.
613 \param handler The handler to receive events.
614 \return Whether the parsing is successful.
615 */
616 template <unsigned parseFlags, typename InputStream, typename Handler>
617 bool IterativeParseNext(InputStream& is, Handler& handler) {
618 while (CEREAL_RAPIDJSON_LIKELY(is.Peek() != '\0')) {
619 SkipWhitespaceAndComments<parseFlags>(is);
620
621 Token t = Tokenize(is.Peek());
622 IterativeParsingState n = Predict(state_, t);
623 IterativeParsingState d = Transit<parseFlags>(state_, t, n, is, handler);
624
625 // If we've finished or hit an error...
626 if (CEREAL_RAPIDJSON_UNLIKELY(IsIterativeParsingCompleteState(d))) {
627 // Report errors.
628 if (d == IterativeParsingErrorState) {
629 HandleError(state_, is);
630 return false;
631 }
632
633 // Transition to the finish state.
634 CEREAL_RAPIDJSON_ASSERT(d == IterativeParsingFinishState);
635 state_ = d;
636
637 // If StopWhenDone is not set...
638 if (!(parseFlags & kParseStopWhenDoneFlag)) {
639 // ... and extra non-whitespace data is found...
640 SkipWhitespaceAndComments<parseFlags>(is);
641 if (is.Peek() != '\0') {
642 // ... this is considered an error.
643 HandleError(state_, is);
644 return false;
645 }
646 }
647
648 // Success! We are done!
649 return true;
650 }
651
652 // Transition to the new state.
653 state_ = d;
654
655 // If we parsed anything other than a delimiter, we invoked the handler, so we can return true now.
656 if (!IsIterativeParsingDelimiterState(n))
657 return true;
658 }
659
660 // We reached the end of file.
661 stack_.Clear();
662
663 if (state_ != IterativeParsingFinishState) {
664 HandleError(state_, is);
665 return false;
666 }
667
668 return true;
669 }
670
671 //! Check if token-by-token parsing JSON text is complete
672 /*! \return Whether the JSON has been fully decoded.
673 */
674 CEREAL_RAPIDJSON_FORCEINLINE bool IterativeParseComplete() const {
675 return IsIterativeParsingCompleteState(state_);
676 }
677
678 //! Whether a parse error has occurred in the last parsing.
530679 bool HasParseError() const { return parseResult_.IsError(); }
531680
532681 //! Get the \ref ParseErrorCode of last parsing.
574723 }
575724 }
576725 else if (CEREAL_RAPIDJSON_LIKELY(Consume(is, '/')))
577 while (is.Peek() != '\0' && is.Take() != '\n');
726 while (is.Peek() != '\0' && is.Take() != '\n') {}
578727 else
579728 CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
580729
749898 return false;
750899 }
751900
752 // Helper function to parse four hexidecimal digits in \uXXXX in ParseString().
901 // Helper function to parse four hexadecimal digits in \uXXXX in ParseString().
753902 template<typename InputStream>
754903 unsigned ParseHex4(InputStream& is, size_t escapeOffset) {
755904 unsigned codepoint = 0;
8561005
8571006 Ch c = is.Peek();
8581007 if (CEREAL_RAPIDJSON_UNLIKELY(c == '\\')) { // Escape
859 size_t escapeOffset = is.Tell(); // For invalid escaping, report the inital '\\' as error offset
1008 size_t escapeOffset = is.Tell(); // For invalid escaping, report the initial '\\' as error offset
8601009 is.Take();
8611010 Ch e = is.Peek();
8621011 if ((sizeof(Ch) == 1 || unsigned(e) < 256) && CEREAL_RAPIDJSON_LIKELY(escape[static_cast<unsigned char>(e)])) {
8911040 if (c == '\0')
8921041 CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell());
8931042 else
894 CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell());
1043 CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell());
8951044 }
8961045 else {
8971046 size_t offset = is.Tell();
9261075 // The rest of string using SIMD
9271076 static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
9281077 static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
929 static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
1078 static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F };
9301079 const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
9311080 const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
9321081 const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
9351084 const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
9361085 const __m128i t1 = _mm_cmpeq_epi8(s, dq);
9371086 const __m128i t2 = _mm_cmpeq_epi8(s, bs);
938 const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
1087 const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F
9391088 const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
9401089 unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
9411090 if (CEREAL_RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
9471096 #else
9481097 length = static_cast<SizeType>(__builtin_ffs(r) - 1);
9491098 #endif
950 char* q = reinterpret_cast<char*>(os.Push(length));
951 for (size_t i = 0; i < length; i++)
952 q[i] = p[i];
953
954 p += length;
1099 if (length != 0) {
1100 char* q = reinterpret_cast<char*>(os.Push(length));
1101 for (size_t i = 0; i < length; i++)
1102 q[i] = p[i];
1103
1104 p += length;
1105 }
9551106 break;
9561107 }
9571108 _mm_storeu_si128(reinterpret_cast<__m128i *>(os.Push(16)), s);
9871138 // The rest of string using SIMD
9881139 static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
9891140 static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
990 static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
1141 static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F };
9911142 const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
9921143 const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
9931144 const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
9961147 const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
9971148 const __m128i t1 = _mm_cmpeq_epi8(s, dq);
9981149 const __m128i t2 = _mm_cmpeq_epi8(s, bs);
999 const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
1150 const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F
10001151 const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
10011152 unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
10021153 if (CEREAL_RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
10351186 // The rest of string using SIMD
10361187 static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
10371188 static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
1038 static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
1189 static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F };
10391190 const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
10401191 const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
10411192 const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
10441195 const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
10451196 const __m128i t1 = _mm_cmpeq_epi8(s, dq);
10461197 const __m128i t2 = _mm_cmpeq_epi8(s, bs);
1047 const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
1198 const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F
10481199 const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
10491200 unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
10501201 if (CEREAL_RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
10631214
10641215 is.src_ = is.dst_ = p;
10651216 }
1066 #endif
1217 #elif defined(CEREAL_RAPIDJSON_NEON)
1218 // StringStream -> StackStream<char>
1219 static CEREAL_RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream<char>& os) {
1220 const char* p = is.src_;
1221
1222 // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
1223 const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
1224 while (p != nextAligned)
1225 if (CEREAL_RAPIDJSON_UNLIKELY(*p == '\"') || CEREAL_RAPIDJSON_UNLIKELY(*p == '\\') || CEREAL_RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
1226 is.src_ = p;
1227 return;
1228 }
1229 else
1230 os.Put(*p++);
1231
1232 // The rest of string using SIMD
1233 const uint8x16_t s0 = vmovq_n_u8('"');
1234 const uint8x16_t s1 = vmovq_n_u8('\\');
1235 const uint8x16_t s2 = vmovq_n_u8('\b');
1236 const uint8x16_t s3 = vmovq_n_u8(32);
1237
1238 for (;; p += 16) {
1239 const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(p));
1240 uint8x16_t x = vceqq_u8(s, s0);
1241 x = vorrq_u8(x, vceqq_u8(s, s1));
1242 x = vorrq_u8(x, vceqq_u8(s, s2));
1243 x = vorrq_u8(x, vcltq_u8(s, s3));
1244
1245 x = vrev64q_u8(x); // Rev in 64
1246 uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
1247 uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
1248
1249 SizeType length = 0;
1250 bool escaped = false;
1251 if (low == 0) {
1252 if (high != 0) {
1253 unsigned lz = (unsigned)__builtin_clzll(high);;
1254 length = 8 + (lz >> 3);
1255 escaped = true;
1256 }
1257 } else {
1258 unsigned lz = (unsigned)__builtin_clzll(low);;
1259 length = lz >> 3;
1260 escaped = true;
1261 }
1262 if (CEREAL_RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped
1263 if (length != 0) {
1264 char* q = reinterpret_cast<char*>(os.Push(length));
1265 for (size_t i = 0; i < length; i++)
1266 q[i] = p[i];
1267
1268 p += length;
1269 }
1270 break;
1271 }
1272 vst1q_u8(reinterpret_cast<uint8_t *>(os.Push(16)), s);
1273 }
1274
1275 is.src_ = p;
1276 }
1277
1278 // InsituStringStream -> InsituStringStream
1279 static CEREAL_RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) {
1280 CEREAL_RAPIDJSON_ASSERT(&is == &os);
1281 (void)os;
1282
1283 if (is.src_ == is.dst_) {
1284 SkipUnescapedString(is);
1285 return;
1286 }
1287
1288 char* p = is.src_;
1289 char *q = is.dst_;
1290
1291 // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
1292 const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
1293 while (p != nextAligned)
1294 if (CEREAL_RAPIDJSON_UNLIKELY(*p == '\"') || CEREAL_RAPIDJSON_UNLIKELY(*p == '\\') || CEREAL_RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
1295 is.src_ = p;
1296 is.dst_ = q;
1297 return;
1298 }
1299 else
1300 *q++ = *p++;
1301
1302 // The rest of string using SIMD
1303 const uint8x16_t s0 = vmovq_n_u8('"');
1304 const uint8x16_t s1 = vmovq_n_u8('\\');
1305 const uint8x16_t s2 = vmovq_n_u8('\b');
1306 const uint8x16_t s3 = vmovq_n_u8(32);
1307
1308 for (;; p += 16, q += 16) {
1309 const uint8x16_t s = vld1q_u8(reinterpret_cast<uint8_t *>(p));
1310 uint8x16_t x = vceqq_u8(s, s0);
1311 x = vorrq_u8(x, vceqq_u8(s, s1));
1312 x = vorrq_u8(x, vceqq_u8(s, s2));
1313 x = vorrq_u8(x, vcltq_u8(s, s3));
1314
1315 x = vrev64q_u8(x); // Rev in 64
1316 uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
1317 uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
1318
1319 SizeType length = 0;
1320 bool escaped = false;
1321 if (low == 0) {
1322 if (high != 0) {
1323 unsigned lz = (unsigned)__builtin_clzll(high);
1324 length = 8 + (lz >> 3);
1325 escaped = true;
1326 }
1327 } else {
1328 unsigned lz = (unsigned)__builtin_clzll(low);
1329 length = lz >> 3;
1330 escaped = true;
1331 }
1332 if (CEREAL_RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped
1333 for (const char* pend = p + length; p != pend; ) {
1334 *q++ = *p++;
1335 }
1336 break;
1337 }
1338 vst1q_u8(reinterpret_cast<uint8_t *>(q), s);
1339 }
1340
1341 is.src_ = p;
1342 is.dst_ = q;
1343 }
1344
1345 // When read/write pointers are the same for insitu stream, just skip unescaped characters
1346 static CEREAL_RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) {
1347 CEREAL_RAPIDJSON_ASSERT(is.src_ == is.dst_);
1348 char* p = is.src_;
1349
1350 // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
1351 const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
1352 for (; p != nextAligned; p++)
1353 if (CEREAL_RAPIDJSON_UNLIKELY(*p == '\"') || CEREAL_RAPIDJSON_UNLIKELY(*p == '\\') || CEREAL_RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
1354 is.src_ = is.dst_ = p;
1355 return;
1356 }
1357
1358 // The rest of string using SIMD
1359 const uint8x16_t s0 = vmovq_n_u8('"');
1360 const uint8x16_t s1 = vmovq_n_u8('\\');
1361 const uint8x16_t s2 = vmovq_n_u8('\b');
1362 const uint8x16_t s3 = vmovq_n_u8(32);
1363
1364 for (;; p += 16) {
1365 const uint8x16_t s = vld1q_u8(reinterpret_cast<uint8_t *>(p));
1366 uint8x16_t x = vceqq_u8(s, s0);
1367 x = vorrq_u8(x, vceqq_u8(s, s1));
1368 x = vorrq_u8(x, vceqq_u8(s, s2));
1369 x = vorrq_u8(x, vcltq_u8(s, s3));
1370
1371 x = vrev64q_u8(x); // Rev in 64
1372 uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
1373 uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
1374
1375 if (low == 0) {
1376 if (high != 0) {
1377 int lz = __builtin_clzll(high);
1378 p += 8 + (lz >> 3);
1379 break;
1380 }
1381 } else {
1382 int lz = __builtin_clzll(low);
1383 p += lz >> 3;
1384 break;
1385 }
1386 }
1387
1388 is.src_ = is.dst_ = p;
1389 }
1390 #endif // CEREAL_RAPIDJSON_NEON
10671391
10681392 template<typename InputStream, bool backup, bool pushOnTake>
10691393 class NumberStream;
10741398 typedef typename InputStream::Ch Ch;
10751399
10761400 NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader; }
1077 ~NumberStream() {}
10781401
10791402 CEREAL_RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); }
10801403 CEREAL_RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); }
10961419 typedef NumberStream<InputStream, false, false> Base;
10971420 public:
10981421 NumberStream(GenericReader& reader, InputStream& s) : Base(reader, s), stackStream(reader.stack_) {}
1099 ~NumberStream() {}
11001422
11011423 CEREAL_RAPIDJSON_FORCEINLINE Ch TakePush() {
11021424 stackStream.Put(static_cast<char>(Base::is.Peek()));
11231445 typedef NumberStream<InputStream, true, false> Base;
11241446 public:
11251447 NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is) {}
1126 ~NumberStream() {}
11271448
11281449 CEREAL_RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); }
11291450 };
11841505 }
11851506 // Parse NaN or Infinity here
11861507 else if ((parseFlags & kParseNanAndInfFlag) && CEREAL_RAPIDJSON_LIKELY((s.Peek() == 'I' || s.Peek() == 'N'))) {
1187 useNanOrInf = true;
1188 if (CEREAL_RAPIDJSON_LIKELY(Consume(s, 'N') && Consume(s, 'a') && Consume(s, 'N'))) {
1189 d = std::numeric_limits<double>::quiet_NaN();
1190 }
1191 else if (CEREAL_RAPIDJSON_LIKELY(Consume(s, 'I') && Consume(s, 'n') && Consume(s, 'f'))) {
1192 d = (minus ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity());
1193 if (CEREAL_RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n')
1194 && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y'))))
1195 CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
1196 }
1197 else
1508 if (Consume(s, 'N')) {
1509 if (Consume(s, 'a') && Consume(s, 'N')) {
1510 d = std::numeric_limits<double>::quiet_NaN();
1511 useNanOrInf = true;
1512 }
1513 }
1514 else if (CEREAL_RAPIDJSON_LIKELY(Consume(s, 'I'))) {
1515 if (Consume(s, 'n') && Consume(s, 'f')) {
1516 d = (minus ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity());
1517 useNanOrInf = true;
1518
1519 if (CEREAL_RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n')
1520 && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y')))) {
1521 CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
1522 }
1523 }
1524 }
1525
1526 if (CEREAL_RAPIDJSON_UNLIKELY(!useNanOrInf)) {
11981527 CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
1528 }
11991529 }
12001530 else
12011531 CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
12301560 // Force double for big integer
12311561 if (useDouble) {
12321562 while (CEREAL_RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
1233 if (CEREAL_RAPIDJSON_UNLIKELY(d >= 1.7976931348623157e307)) // DBL_MAX / 10.0
1234 CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);
12351563 d = d * 10 + (s.TakePush() - '0');
12361564 }
12371565 }
13011629 if (CEREAL_RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
13021630 exp = static_cast<int>(s.Take() - '0');
13031631 if (expMinus) {
1632 // (exp + expFrac) must not underflow int => we're detecting when -exp gets
1633 // dangerously close to INT_MIN (a pessimistic next digit 9 would push it into
1634 // underflow territory):
1635 //
1636 // -(exp * 10 + 9) + expFrac >= INT_MIN
1637 // <=> exp <= (expFrac - INT_MIN - 9) / 10
1638 CEREAL_RAPIDJSON_ASSERT(expFrac <= 0);
1639 int maxExp = (expFrac + 2147483639) / 10;
1640
13041641 while (CEREAL_RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
13051642 exp = exp * 10 + static_cast<int>(s.Take() - '0');
1306 if (exp >= 214748364) { // Issue #313: prevent overflow exponent
1643 if (CEREAL_RAPIDJSON_UNLIKELY(exp > maxExp)) {
13071644 while (CEREAL_RAPIDJSON_UNLIKELY(s.Peek() >= '0' && s.Peek() <= '9')) // Consume the rest of exponent
13081645 s.Take();
13091646 }
13611698 d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp);
13621699 else
13631700 d = internal::StrtodNormalPrecision(d, p);
1701
1702 // Use > max, instead of == inf, to fix bogus warning -Wfloat-equal
1703 if (d > (std::numeric_limits<double>::max)()) {
1704 // Overflow
1705 // TODO: internal::StrtodX should report overflow (or underflow)
1706 CEREAL_RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);
1707 }
13641708
13651709 cont = handler.Double(minus ? -d : d);
13661710 }
14071751
14081752 // States
14091753 enum IterativeParsingState {
1410 IterativeParsingStartState = 0,
1411 IterativeParsingFinishState,
1412 IterativeParsingErrorState,
1754 IterativeParsingFinishState = 0, // sink states at top
1755 IterativeParsingErrorState, // sink states at top
1756 IterativeParsingStartState,
14131757
14141758 // Object states
14151759 IterativeParsingObjectInitialState,
14161760 IterativeParsingMemberKeyState,
1417 IterativeParsingKeyValueDelimiterState,
14181761 IterativeParsingMemberValueState,
1419 IterativeParsingMemberDelimiterState,
14201762 IterativeParsingObjectFinishState,
14211763
14221764 // Array states
14231765 IterativeParsingArrayInitialState,
14241766 IterativeParsingElementState,
1767 IterativeParsingArrayFinishState,
1768
1769 // Single value state
1770 IterativeParsingValueState,
1771
1772 // Delimiter states (at bottom)
14251773 IterativeParsingElementDelimiterState,
1426 IterativeParsingArrayFinishState,
1427
1428 // Single value state
1429 IterativeParsingValueState
1774 IterativeParsingMemberDelimiterState,
1775 IterativeParsingKeyValueDelimiterState,
1776
1777 cIterativeParsingStateCount
14301778 };
1431
1432 enum { cIterativeParsingStateCount = IterativeParsingValueState + 1 };
14331779
14341780 // Tokens
14351781 enum Token {
14511797 kTokenCount
14521798 };
14531799
1454 CEREAL_RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) {
1800 CEREAL_RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) const {
14551801
14561802 //!@cond CEREAL_RAPIDJSON_HIDDEN_FROM_DOXYGEN
14571803 #define N NumberToken
14781824 return NumberToken;
14791825 }
14801826
1481 CEREAL_RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) {
1827 CEREAL_RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) const {
14821828 // current state x one lookahead token -> new state
14831829 static const char G[cIterativeParsingStateCount][kTokenCount] = {
1830 // Finish(sink state)
1831 {
1832 IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
1833 IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
1834 IterativeParsingErrorState
1835 },
1836 // Error(sink state)
1837 {
1838 IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
1839 IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
1840 IterativeParsingErrorState
1841 },
14841842 // Start
14851843 {
14861844 IterativeParsingArrayInitialState, // Left bracket
14941852 IterativeParsingValueState, // True
14951853 IterativeParsingValueState, // Null
14961854 IterativeParsingValueState // Number
1497 },
1498 // Finish(sink state)
1499 {
1500 IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
1501 IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
1502 IterativeParsingErrorState
1503 },
1504 // Error(sink state)
1505 {
1506 IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
1507 IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
1508 IterativeParsingErrorState
15091855 },
15101856 // ObjectInitial
15111857 {
15351881 IterativeParsingErrorState, // Null
15361882 IterativeParsingErrorState // Number
15371883 },
1538 // KeyValueDelimiter
1539 {
1540 IterativeParsingArrayInitialState, // Left bracket(push MemberValue state)
1541 IterativeParsingErrorState, // Right bracket
1542 IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state)
1543 IterativeParsingErrorState, // Right curly bracket
1544 IterativeParsingErrorState, // Comma
1545 IterativeParsingErrorState, // Colon
1546 IterativeParsingMemberValueState, // String
1547 IterativeParsingMemberValueState, // False
1548 IterativeParsingMemberValueState, // True
1549 IterativeParsingMemberValueState, // Null
1550 IterativeParsingMemberValueState // Number
1551 },
15521884 // MemberValue
15531885 {
15541886 IterativeParsingErrorState, // Left bracket
15621894 IterativeParsingErrorState, // True
15631895 IterativeParsingErrorState, // Null
15641896 IterativeParsingErrorState // Number
1565 },
1566 // MemberDelimiter
1567 {
1568 IterativeParsingErrorState, // Left bracket
1569 IterativeParsingErrorState, // Right bracket
1570 IterativeParsingErrorState, // Left curly bracket
1571 IterativeParsingObjectFinishState, // Right curly bracket
1572 IterativeParsingErrorState, // Comma
1573 IterativeParsingErrorState, // Colon
1574 IterativeParsingMemberKeyState, // String
1575 IterativeParsingErrorState, // False
1576 IterativeParsingErrorState, // True
1577 IterativeParsingErrorState, // Null
1578 IterativeParsingErrorState // Number
15791897 },
15801898 // ObjectFinish(sink state)
15811899 {
16111929 IterativeParsingErrorState, // Null
16121930 IterativeParsingErrorState // Number
16131931 },
1932 // ArrayFinish(sink state)
1933 {
1934 IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
1935 IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
1936 IterativeParsingErrorState
1937 },
1938 // Single Value (sink state)
1939 {
1940 IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
1941 IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
1942 IterativeParsingErrorState
1943 },
16141944 // ElementDelimiter
16151945 {
16161946 IterativeParsingArrayInitialState, // Left bracket(push Element state)
16251955 IterativeParsingElementState, // Null
16261956 IterativeParsingElementState // Number
16271957 },
1628 // ArrayFinish(sink state)
1958 // MemberDelimiter
16291959 {
1630 IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
1631 IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
1632 IterativeParsingErrorState
1960 IterativeParsingErrorState, // Left bracket
1961 IterativeParsingErrorState, // Right bracket
1962 IterativeParsingErrorState, // Left curly bracket
1963 IterativeParsingObjectFinishState, // Right curly bracket
1964 IterativeParsingErrorState, // Comma
1965 IterativeParsingErrorState, // Colon
1966 IterativeParsingMemberKeyState, // String
1967 IterativeParsingErrorState, // False
1968 IterativeParsingErrorState, // True
1969 IterativeParsingErrorState, // Null
1970 IterativeParsingErrorState // Number
16331971 },
1634 // Single Value (sink state)
1972 // KeyValueDelimiter
16351973 {
1636 IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
1637 IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
1638 IterativeParsingErrorState
1639 }
1974 IterativeParsingArrayInitialState, // Left bracket(push MemberValue state)
1975 IterativeParsingErrorState, // Right bracket
1976 IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state)
1977 IterativeParsingErrorState, // Right curly bracket
1978 IterativeParsingErrorState, // Comma
1979 IterativeParsingErrorState, // Colon
1980 IterativeParsingMemberValueState, // String
1981 IterativeParsingMemberValueState, // False
1982 IterativeParsingMemberValueState, // True
1983 IterativeParsingMemberValueState, // Null
1984 IterativeParsingMemberValueState // Number
1985 },
16401986 }; // End of G
16411987
16421988 return static_cast<IterativeParsingState>(G[state][token]);
18172163 }
18182164 }
18192165
2166 CEREAL_RAPIDJSON_FORCEINLINE bool IsIterativeParsingDelimiterState(IterativeParsingState s) const {
2167 return s >= IterativeParsingElementDelimiterState;
2168 }
2169
2170 CEREAL_RAPIDJSON_FORCEINLINE bool IsIterativeParsingCompleteState(IterativeParsingState s) const {
2171 return s <= IterativeParsingErrorState;
2172 }
2173
18202174 template <unsigned parseFlags, typename InputStream, typename Handler>
18212175 ParseResult IterativeParse(InputStream& is, Handler& handler) {
18222176 parseResult_.Clear();
18552209 static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string.
18562210 internal::Stack<StackAllocator> stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing.
18572211 ParseResult parseResult_;
2212 IterativeParsingState state_;
18582213 }; // class GenericReader
18592214
18602215 //! Reader with UTF8 encoding and default allocator.
18622217
18632218 CEREAL_RAPIDJSON_NAMESPACE_END
18642219
1865 #ifdef __clang__
2220 #if defined(__clang__) || defined(_MSC_VER)
18662221 CEREAL_RAPIDJSON_DIAG_POP
18672222 #endif
18682223
18712226 CEREAL_RAPIDJSON_DIAG_POP
18722227 #endif
18732228
1874 #ifdef _MSC_VER
1875 CEREAL_RAPIDJSON_DIAG_POP
1876 #endif
1877
18782229 #endif // CEREAL_RAPIDJSON_READER_H_
1616
1717 #include "document.h"
1818 #include "pointer.h"
19 #include "stringbuffer.h"
1920 #include <cmath> // abs, floor
2021
2122 #if !defined(CEREAL_RAPIDJSON_SCHEMA_USE_INTERNALREGEX)
2425 #define CEREAL_RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0
2526 #endif
2627
27 #if !CEREAL_RAPIDJSON_SCHEMA_USE_INTERNALREGEX && !defined(CEREAL_RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800))
28 #if !CEREAL_RAPIDJSON_SCHEMA_USE_INTERNALREGEX && defined(CEREAL_RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800))
2829 #define CEREAL_RAPIDJSON_SCHEMA_USE_STDREGEX 1
2930 #else
3031 #define CEREAL_RAPIDJSON_SCHEMA_USE_STDREGEX 0
6162 CEREAL_RAPIDJSON_DIAG_OFF(exit-time-destructors)
6263 CEREAL_RAPIDJSON_DIAG_OFF(c++98-compat-pedantic)
6364 CEREAL_RAPIDJSON_DIAG_OFF(variadic-macros)
64 #endif
65
66 #ifdef _MSC_VER
65 #elif defined(_MSC_VER)
6766 CEREAL_RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
6867 #endif
6968
157156 };
158157
159158 ///////////////////////////////////////////////////////////////////////////////
159 // IValidationErrorHandler
160
161 template <typename SchemaType>
162 class IValidationErrorHandler {
163 public:
164 typedef typename SchemaType::Ch Ch;
165 typedef typename SchemaType::SValue SValue;
166
167 virtual ~IValidationErrorHandler() {}
168
169 virtual void NotMultipleOf(int64_t actual, const SValue& expected) = 0;
170 virtual void NotMultipleOf(uint64_t actual, const SValue& expected) = 0;
171 virtual void NotMultipleOf(double actual, const SValue& expected) = 0;
172 virtual void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) = 0;
173 virtual void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) = 0;
174 virtual void AboveMaximum(double actual, const SValue& expected, bool exclusive) = 0;
175 virtual void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) = 0;
176 virtual void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) = 0;
177 virtual void BelowMinimum(double actual, const SValue& expected, bool exclusive) = 0;
178
179 virtual void TooLong(const Ch* str, SizeType length, SizeType expected) = 0;
180 virtual void TooShort(const Ch* str, SizeType length, SizeType expected) = 0;
181 virtual void DoesNotMatch(const Ch* str, SizeType length) = 0;
182
183 virtual void DisallowedItem(SizeType index) = 0;
184 virtual void TooFewItems(SizeType actualCount, SizeType expectedCount) = 0;
185 virtual void TooManyItems(SizeType actualCount, SizeType expectedCount) = 0;
186 virtual void DuplicateItems(SizeType index1, SizeType index2) = 0;
187
188 virtual void TooManyProperties(SizeType actualCount, SizeType expectedCount) = 0;
189 virtual void TooFewProperties(SizeType actualCount, SizeType expectedCount) = 0;
190 virtual void StartMissingProperties() = 0;
191 virtual void AddMissingProperty(const SValue& name) = 0;
192 virtual bool EndMissingProperties() = 0;
193 virtual void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) = 0;
194 virtual void DisallowedProperty(const Ch* name, SizeType length) = 0;
195
196 virtual void StartDependencyErrors() = 0;
197 virtual void StartMissingDependentProperties() = 0;
198 virtual void AddMissingDependentProperty(const SValue& targetName) = 0;
199 virtual void EndMissingDependentProperties(const SValue& sourceName) = 0;
200 virtual void AddDependencySchemaError(const SValue& souceName, ISchemaValidator* subvalidator) = 0;
201 virtual bool EndDependencyErrors() = 0;
202
203 virtual void DisallowedValue() = 0;
204 virtual void StartDisallowedType() = 0;
205 virtual void AddExpectedType(const typename SchemaType::ValueType& expectedType) = 0;
206 virtual void EndDisallowedType(const typename SchemaType::ValueType& actualType) = 0;
207 virtual void NotAllOf(ISchemaValidator** subvalidators, SizeType count) = 0;
208 virtual void NoneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
209 virtual void NotOneOf(ISchemaValidator** subvalidators, SizeType count) = 0;
210 virtual void Disallowed() = 0;
211 };
212
213
214 ///////////////////////////////////////////////////////////////////////////////
160215 // Hasher
161216
162217 // For comparison of compound value
260315 struct SchemaValidationContext {
261316 typedef Schema<SchemaDocumentType> SchemaType;
262317 typedef ISchemaStateFactory<SchemaType> SchemaValidatorFactoryType;
318 typedef IValidationErrorHandler<SchemaType> ErrorHandlerType;
263319 typedef typename SchemaType::ValueType ValueType;
264320 typedef typename ValueType::Ch Ch;
265321
269325 kPatternValidatorWithAdditionalProperty
270326 };
271327
272 SchemaValidationContext(SchemaValidatorFactoryType& f, const SchemaType* s) :
328 SchemaValidationContext(SchemaValidatorFactoryType& f, ErrorHandlerType& eh, const SchemaType* s) :
273329 factory(f),
330 error_handler(eh),
274331 schema(s),
275332 valueSchema(),
276333 invalidKeyword(),
310367 }
311368
312369 SchemaValidatorFactoryType& factory;
370 ErrorHandlerType& error_handler;
313371 const SchemaType* schema;
314372 const SchemaType* valueSchema;
315373 const Ch* invalidKeyword;
344402 typedef SchemaValidationContext<SchemaDocumentType> Context;
345403 typedef Schema<SchemaDocumentType> SchemaType;
346404 typedef GenericValue<EncodingType, AllocatorType> SValue;
405 typedef IValidationErrorHandler<Schema> ErrorHandler;
347406 friend class GenericSchemaDocument<ValueType, AllocatorType>;
348407
349408 Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) :
350409 allocator_(allocator),
410 uri_(schemaDocument->GetURI(), *allocator),
411 pointer_(p, allocator),
412 typeless_(schemaDocument->GetTypeless()),
351413 enum_(),
352414 enumCount_(),
353415 not_(),
354416 type_((1 << kTotalSchemaType) - 1), // typeless
355417 validatorCount_(),
418 notValidatorIndex_(),
356419 properties_(),
357420 additionalPropertiesSchema_(),
358421 patternProperties_(),
376439 minLength_(0),
377440 maxLength_(~SizeType(0)),
378441 exclusiveMinimum_(false),
379 exclusiveMaximum_(false)
442 exclusiveMaximum_(false),
443 defaultValueLength_(0)
380444 {
381445 typedef typename SchemaDocumentType::ValueType ValueType;
382446 typedef typename ValueType::ConstValueIterator ConstValueIterator;
399463 enum_ = static_cast<uint64_t*>(allocator_->Malloc(sizeof(uint64_t) * v->Size()));
400464 for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
401465 typedef Hasher<EncodingType, MemoryPoolAllocator<> > EnumHasherType;
402 char buffer[256 + 24];
466 char buffer[256u + 24];
403467 MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer));
404468 EnumHasherType h(&hasherAllocator, 256);
405469 itr->Accept(h);
452516 for (SizeType i = 0; i < propertyCount_; i++) {
453517 new (&properties_[i]) Property();
454518 properties_[i].name = allProperties[i];
455 properties_[i].schema = GetTypeless();
519 properties_[i].schema = typeless_;
456520 }
457521 }
458522 }
571635 if (const ValueType* v = GetMember(value, GetMultipleOfString()))
572636 if (v->IsNumber() && v->GetDouble() > 0.0)
573637 multipleOf_.CopyFrom(*v, *allocator_);
638
639 // Default
640 if (const ValueType* v = GetMember(value, GetDefaultValueString()))
641 if (v->IsString())
642 defaultValueLength_ = v->GetStringLength();
643
574644 }
575645
576646 ~Schema() {
577 if (allocator_) {
578 allocator_->Free(enum_);
579 }
647 AllocatorType::Free(enum_);
580648 if (properties_) {
581649 for (SizeType i = 0; i < propertyCount_; i++)
582650 properties_[i].~Property();
591659 #if CEREAL_RAPIDJSON_SCHEMA_HAS_REGEX
592660 if (pattern_) {
593661 pattern_->~RegexType();
594 allocator_->Free(pattern_);
662 AllocatorType::Free(pattern_);
595663 }
596664 #endif
665 }
666
667 const SValue& GetURI() const {
668 return uri_;
669 }
670
671 const PointerType& GetPointer() const {
672 return pointer_;
597673 }
598674
599675 bool BeginValue(Context& context) const {
609685 else if (additionalItemsSchema_)
610686 context.valueSchema = additionalItemsSchema_;
611687 else if (additionalItems_)
612 context.valueSchema = GetTypeless();
613 else
688 context.valueSchema = typeless_;
689 else {
690 context.error_handler.DisallowedItem(context.arrayElementIndex);
614691 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString());
692 }
615693 }
616694 else
617 context.valueSchema = GetTypeless();
695 context.valueSchema = typeless_;
618696
619697 context.arrayElementIndex++;
620698 }
636714 }
637715
638716 if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) {
639 if (!patternValid)
717 if (!patternValid) {
718 context.error_handler.PropertyViolations(context.patternPropertiesValidators, count);
640719 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
720 }
641721 }
642722 else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) {
643 if (!patternValid || !otherValid)
723 if (!patternValid || !otherValid) {
724 context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);
644725 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
645 }
646 else if (!patternValid && !otherValid) // kPatternValidatorWithAdditionalProperty)
726 }
727 }
728 else if (!patternValid && !otherValid) { // kPatternValidatorWithAdditionalProperty)
729 context.error_handler.PropertyViolations(context.patternPropertiesValidators, count + 1);
647730 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
731 }
648732 }
649733
650734 if (enum_) {
652736 for (SizeType i = 0; i < enumCount_; i++)
653737 if (enum_[i] == h)
654738 goto foundEnum;
739 context.error_handler.DisallowedValue();
655740 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString());
656741 foundEnum:;
657742 }
658743
659744 if (allOf_.schemas)
660745 for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
661 if (!context.validators[i]->IsValid())
746 if (!context.validators[i]->IsValid()) {
747 context.error_handler.NotAllOf(&context.validators[allOf_.begin], allOf_.count);
662748 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString());
749 }
663750
664751 if (anyOf_.schemas) {
665752 for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
666753 if (context.validators[i]->IsValid())
667754 goto foundAny;
755 context.error_handler.NoneOf(&context.validators[anyOf_.begin], anyOf_.count);
668756 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString());
669757 foundAny:;
670758 }
673761 bool oneValid = false;
674762 for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
675763 if (context.validators[i]->IsValid()) {
676 if (oneValid)
764 if (oneValid) {
765 context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count);
677766 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
678 else
767 } else
679768 oneValid = true;
680769 }
681 if (!oneValid)
770 if (!oneValid) {
771 context.error_handler.NotOneOf(&context.validators[oneOf_.begin], oneOf_.count);
682772 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
683 }
684
685 if (not_ && context.validators[notValidatorIndex_]->IsValid())
773 }
774 }
775
776 if (not_ && context.validators[notValidatorIndex_]->IsValid()) {
777 context.error_handler.Disallowed();
686778 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString());
779 }
687780
688781 return true;
689782 }
690783
691 bool Null(Context& context) const {
692 if (!(type_ & (1 << kNullSchemaType)))
784 bool Null(Context& context) const {
785 if (!(type_ & (1 << kNullSchemaType))) {
786 DisallowedType(context, GetNullString());
693787 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
788 }
694789 return CreateParallelValidator(context);
695790 }
696791
697 bool Bool(Context& context, bool) const {
698 if (!(type_ & (1 << kBooleanSchemaType)))
792 bool Bool(Context& context, bool) const {
793 if (!(type_ & (1 << kBooleanSchemaType))) {
794 DisallowedType(context, GetBooleanString());
699795 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
796 }
700797 return CreateParallelValidator(context);
701798 }
702799
725822 }
726823
727824 bool Double(Context& context, double d) const {
728 if (!(type_ & (1 << kNumberSchemaType)))
825 if (!(type_ & (1 << kNumberSchemaType))) {
826 DisallowedType(context, GetNumberString());
729827 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
828 }
730829
731830 if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
732831 return false;
741840 }
742841
743842 bool String(Context& context, const Ch* str, SizeType length, bool) const {
744 if (!(type_ & (1 << kStringSchemaType)))
843 if (!(type_ & (1 << kStringSchemaType))) {
844 DisallowedType(context, GetStringString());
745845 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
846 }
746847
747848 if (minLength_ != 0 || maxLength_ != SizeType(~0)) {
748849 SizeType count;
749850 if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {
750 if (count < minLength_)
851 if (count < minLength_) {
852 context.error_handler.TooShort(str, length, minLength_);
751853 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString());
752 if (count > maxLength_)
854 }
855 if (count > maxLength_) {
856 context.error_handler.TooLong(str, length, maxLength_);
753857 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString());
754 }
755 }
756
757 if (pattern_ && !IsPatternMatch(pattern_, str, length))
858 }
859 }
860 }
861
862 if (pattern_ && !IsPatternMatch(pattern_, str, length)) {
863 context.error_handler.DoesNotMatch(str, length);
758864 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString());
865 }
759866
760867 return CreateParallelValidator(context);
761868 }
762869
763 bool StartObject(Context& context) const {
764 if (!(type_ & (1 << kObjectSchemaType)))
870 bool StartObject(Context& context) const {
871 if (!(type_ & (1 << kObjectSchemaType))) {
872 DisallowedType(context, GetObjectString());
765873 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
874 }
766875
767876 if (hasDependencies_ || hasRequired_) {
768877 context.propertyExist = static_cast<bool*>(context.factory.MallocState(sizeof(bool) * propertyCount_));
783892 if (patternProperties_) {
784893 context.patternPropertiesSchemaCount = 0;
785894 for (SizeType i = 0; i < patternPropertyCount_; i++)
786 if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len))
895 if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) {
787896 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema;
897 context.valueSchema = typeless_;
898 }
788899 }
789900
790901 SizeType index;
791902 if (FindPropertyIndex(ValueType(str, len).Move(), &index)) {
792903 if (context.patternPropertiesSchemaCount > 0) {
793904 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema;
794 context.valueSchema = GetTypeless();
905 context.valueSchema = typeless_;
795906 context.valuePatternValidatorType = Context::kPatternValidatorWithProperty;
796907 }
797908 else
806917 if (additionalPropertiesSchema_) {
807918 if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) {
808919 context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_;
809 context.valueSchema = GetTypeless();
920 context.valueSchema = typeless_;
810921 context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty;
811922 }
812923 else
814925 return true;
815926 }
816927 else if (additionalProperties_) {
817 context.valueSchema = GetTypeless();
928 context.valueSchema = typeless_;
818929 return true;
819930 }
820931
821 if (context.patternPropertiesSchemaCount == 0) // patternProperties are not additional properties
932 if (context.patternPropertiesSchemaCount == 0) { // patternProperties are not additional properties
933 context.error_handler.DisallowedProperty(str, len);
822934 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString());
935 }
823936
824937 return true;
825938 }
826939
827940 bool EndObject(Context& context, SizeType memberCount) const {
828 if (hasRequired_)
941 if (hasRequired_) {
942 context.error_handler.StartMissingProperties();
829943 for (SizeType index = 0; index < propertyCount_; index++)
830 if (properties_[index].required)
831 if (!context.propertyExist[index])
832 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString());
833
834 if (memberCount < minProperties_)
944 if (properties_[index].required && !context.propertyExist[index])
945 if (properties_[index].schema->defaultValueLength_ == 0 )
946 context.error_handler.AddMissingProperty(properties_[index].name);
947 if (context.error_handler.EndMissingProperties())
948 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString());
949 }
950
951 if (memberCount < minProperties_) {
952 context.error_handler.TooFewProperties(memberCount, minProperties_);
835953 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString());
836
837 if (memberCount > maxProperties_)
954 }
955
956 if (memberCount > maxProperties_) {
957 context.error_handler.TooManyProperties(memberCount, maxProperties_);
838958 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString());
959 }
839960
840961 if (hasDependencies_) {
841 for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++)
962 context.error_handler.StartDependencyErrors();
963 for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) {
964 const Property& source = properties_[sourceIndex];
842965 if (context.propertyExist[sourceIndex]) {
843 if (properties_[sourceIndex].dependencies) {
966 if (source.dependencies) {
967 context.error_handler.StartMissingDependentProperties();
844968 for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
845 if (properties_[sourceIndex].dependencies[targetIndex] && !context.propertyExist[targetIndex])
846 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
969 if (source.dependencies[targetIndex] && !context.propertyExist[targetIndex])
970 context.error_handler.AddMissingDependentProperty(properties_[targetIndex].name);
971 context.error_handler.EndMissingDependentProperties(source.name);
847972 }
848 else if (properties_[sourceIndex].dependenciesSchema)
849 if (!context.validators[properties_[sourceIndex].dependenciesValidatorIndex]->IsValid())
850 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
973 else if (source.dependenciesSchema) {
974 ISchemaValidator* dependenciesValidator = context.validators[source.dependenciesValidatorIndex];
975 if (!dependenciesValidator->IsValid())
976 context.error_handler.AddDependencySchemaError(source.name, dependenciesValidator);
977 }
851978 }
979 }
980 if (context.error_handler.EndDependencyErrors())
981 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
852982 }
853983
854984 return true;
855985 }
856986
857 bool StartArray(Context& context) const {
858 if (!(type_ & (1 << kArraySchemaType)))
987 bool StartArray(Context& context) const {
988 if (!(type_ & (1 << kArraySchemaType))) {
989 DisallowedType(context, GetArrayString());
859990 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
991 }
860992
861993 context.arrayElementIndex = 0;
862994 context.inArray = true;
864996 return CreateParallelValidator(context);
865997 }
866998
867 bool EndArray(Context& context, SizeType elementCount) const {
999 bool EndArray(Context& context, SizeType elementCount) const {
8681000 context.inArray = false;
8691001
870 if (elementCount < minItems_)
1002 if (elementCount < minItems_) {
1003 context.error_handler.TooFewItems(elementCount, minItems_);
8711004 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString());
1005 }
8721006
873 if (elementCount > maxItems_)
1007 if (elementCount > maxItems_) {
1008 context.error_handler.TooManyItems(elementCount, maxItems_);
8741009 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString());
1010 }
8751011
8761012 return true;
8771013 }
8801016 #define CEREAL_RAPIDJSON_STRING_(name, ...) \
8811017 static const ValueType& Get##name##String() {\
8821018 static const Ch s[] = { __VA_ARGS__, '\0' };\
883 static const ValueType v(s, sizeof(s) / sizeof(Ch) - 1);\
1019 static const ValueType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1));\
8841020 return v;\
8851021 }
8861022
9171053 CEREAL_RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm')
9181054 CEREAL_RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm')
9191055 CEREAL_RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f')
1056 CEREAL_RAPIDJSON_STRING_(DefaultValue, 'd', 'e', 'f', 'a', 'u', 'l', 't')
9201057
9211058 #undef CEREAL_RAPIDJSON_STRING_
9221059
9331070 };
9341071
9351072 #if CEREAL_RAPIDJSON_SCHEMA_USE_INTERNALREGEX
936 typedef internal::GenericRegex<EncodingType> RegexType;
1073 typedef internal::GenericRegex<EncodingType, AllocatorType> RegexType;
9371074 #elif CEREAL_RAPIDJSON_SCHEMA_USE_STDREGEX
9381075 typedef std::basic_regex<Ch> RegexType;
9391076 #else
9471084 SizeType begin; // begin index of context.validators
9481085 SizeType count;
9491086 };
950
951 static const SchemaType* GetTypeless() {
952 static SchemaType typeless(0, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), 0);
953 return &typeless;
954 }
9551087
9561088 template <typename V1, typename V2>
9571089 void AddUniqueElement(V1& a, const V2& v) {
9981130 template <typename ValueType>
9991131 RegexType* CreatePattern(const ValueType& value) {
10001132 if (value.IsString()) {
1001 RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString());
1133 RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), allocator_);
10021134 if (!r->IsValid()) {
10031135 r->~RegexType();
10041136 AllocatorType::Free(r);
10101142 }
10111143
10121144 static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) {
1013 return pattern->Search(str);
1145 GenericRegexSearch<RegexType> rs(*pattern);
1146 return rs.Search(str);
10141147 }
10151148 #elif CEREAL_RAPIDJSON_SCHEMA_USE_STDREGEX
10161149 template <typename ValueType>
10171150 RegexType* CreatePattern(const ValueType& value) {
1018 if (value.IsString())
1151 if (value.IsString()) {
1152 RegexType *r = static_cast<RegexType*>(allocator_->Malloc(sizeof(RegexType)));
10191153 try {
1020 return new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript);
1154 return new (r) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript);
10211155 }
10221156 catch (const std::regex_error&) {
1023 }
1157 AllocatorType::Free(r);
1158 }
1159 }
10241160 return 0;
10251161 }
10261162
10961232 }
10971233
10981234 bool CheckInt(Context& context, int64_t i) const {
1099 if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
1235 if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
1236 DisallowedType(context, GetIntegerString());
11001237 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
1238 }
11011239
11021240 if (!minimum_.IsNull()) {
11031241 if (minimum_.IsInt64()) {
1104 if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64())
1242 if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) {
1243 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
11051244 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
1245 }
11061246 }
11071247 else if (minimum_.IsUint64()) {
1248 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
11081249 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64()
11091250 }
11101251 else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
11131254
11141255 if (!maximum_.IsNull()) {
11151256 if (maximum_.IsInt64()) {
1116 if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64())
1257 if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) {
1258 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
11171259 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
1118 }
1119 else if (maximum_.IsUint64())
1120 /* do nothing */; // i <= max(int64_t) < maximum_.GetUint64()
1260 }
1261 }
1262 else if (maximum_.IsUint64()) { }
1263 /* do nothing */ // i <= max(int64_t) < maximum_.GetUint64()
11211264 else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
11221265 return false;
11231266 }
11241267
11251268 if (!multipleOf_.IsNull()) {
11261269 if (multipleOf_.IsUint64()) {
1127 if (static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0)
1270 if (static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) {
1271 context.error_handler.NotMultipleOf(i, multipleOf_);
11281272 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
1273 }
11291274 }
11301275 else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
11311276 return false;
11351280 }
11361281
11371282 bool CheckUint(Context& context, uint64_t i) const {
1138 if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
1283 if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) {
1284 DisallowedType(context, GetIntegerString());
11391285 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
1286 }
11401287
11411288 if (!minimum_.IsNull()) {
11421289 if (minimum_.IsUint64()) {
1143 if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64())
1290 if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) {
1291 context.error_handler.BelowMinimum(i, minimum_, exclusiveMinimum_);
11441292 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
1293 }
11451294 }
11461295 else if (minimum_.IsInt64())
11471296 /* do nothing */; // i >= 0 > minimum.Getint64()
11511300
11521301 if (!maximum_.IsNull()) {
11531302 if (maximum_.IsUint64()) {
1154 if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64())
1303 if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) {
1304 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
11551305 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
1156 }
1157 else if (maximum_.IsInt64())
1306 }
1307 }
1308 else if (maximum_.IsInt64()) {
1309 context.error_handler.AboveMaximum(i, maximum_, exclusiveMaximum_);
11581310 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); // i >= 0 > maximum_
1311 }
11591312 else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
11601313 return false;
11611314 }
11621315
11631316 if (!multipleOf_.IsNull()) {
11641317 if (multipleOf_.IsUint64()) {
1165 if (i % multipleOf_.GetUint64() != 0)
1318 if (i % multipleOf_.GetUint64() != 0) {
1319 context.error_handler.NotMultipleOf(i, multipleOf_);
11661320 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
1321 }
11671322 }
11681323 else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
11691324 return false;
11731328 }
11741329
11751330 bool CheckDoubleMinimum(Context& context, double d) const {
1176 if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble())
1331 if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) {
1332 context.error_handler.BelowMinimum(d, minimum_, exclusiveMinimum_);
11771333 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
1334 }
11781335 return true;
11791336 }
11801337
11811338 bool CheckDoubleMaximum(Context& context, double d) const {
1182 if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble())
1339 if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) {
1340 context.error_handler.AboveMaximum(d, maximum_, exclusiveMaximum_);
11831341 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
1342 }
11841343 return true;
11851344 }
11861345
11881347 double a = std::abs(d), b = std::abs(multipleOf_.GetDouble());
11891348 double q = std::floor(a / b);
11901349 double r = a - q * b;
1191 if (r > 0.0)
1350 if (r > 0.0) {
1351 context.error_handler.NotMultipleOf(d, multipleOf_);
11921352 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
1353 }
11931354 return true;
1355 }
1356
1357 void DisallowedType(Context& context, const ValueType& actualType) const {
1358 ErrorHandler& eh = context.error_handler;
1359 eh.StartDisallowedType();
1360
1361 if (type_ & (1 << kNullSchemaType)) eh.AddExpectedType(GetNullString());
1362 if (type_ & (1 << kBooleanSchemaType)) eh.AddExpectedType(GetBooleanString());
1363 if (type_ & (1 << kObjectSchemaType)) eh.AddExpectedType(GetObjectString());
1364 if (type_ & (1 << kArraySchemaType)) eh.AddExpectedType(GetArrayString());
1365 if (type_ & (1 << kStringSchemaType)) eh.AddExpectedType(GetStringString());
1366
1367 if (type_ & (1 << kNumberSchemaType)) eh.AddExpectedType(GetNumberString());
1368 else if (type_ & (1 << kIntegerSchemaType)) eh.AddExpectedType(GetIntegerString());
1369
1370 eh.EndDisallowedType(actualType);
11941371 }
11951372
11961373 struct Property {
12171394 };
12181395
12191396 AllocatorType* allocator_;
1397 SValue uri_;
1398 PointerType pointer_;
1399 const SchemaType* typeless_;
12201400 uint64_t* enum_;
12211401 SizeType enumCount_;
12221402 SchemaArray allOf_;
12571437 SValue multipleOf_;
12581438 bool exclusiveMinimum_;
12591439 bool exclusiveMaximum_;
1440
1441 SizeType defaultValueLength_;
12601442 };
12611443
12621444 template<typename Stack, typename Ch>
12661448 char buffer[21];
12671449 size_t length = static_cast<size_t>((sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer);
12681450 for (size_t i = 0; i < length; i++)
1269 *documentStack.template Push<Ch>() = buffer[i];
1451 *documentStack.template Push<Ch>() = static_cast<Ch>(buffer[i]);
12701452 }
12711453 };
12721454
13251507 typedef typename EncodingType::Ch Ch;
13261508 typedef internal::Schema<GenericSchemaDocument> SchemaType;
13271509 typedef GenericPointer<ValueType, Allocator> PointerType;
1510 typedef GenericValue<EncodingType, Allocator> URIType;
13281511 friend class internal::Schema<GenericSchemaDocument>;
13291512 template <typename, typename, typename>
13301513 friend class GenericSchemaValidator;
13341517 Compile a JSON document into schema document.
13351518
13361519 \param document A JSON document as source.
1520 \param uri The base URI of this schema document for purposes of violation reporting.
1521 \param uriLength Length of \c name, in code points.
13371522 \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null.
13381523 \param allocator An optional allocator instance for allocating memory. Can be null.
13391524 */
1340 explicit GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) :
1525 explicit GenericSchemaDocument(const ValueType& document, const Ch* uri = 0, SizeType uriLength = 0,
1526 IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) :
13411527 remoteProvider_(remoteProvider),
13421528 allocator_(allocator),
13431529 ownAllocator_(),
13441530 root_(),
1531 typeless_(),
13451532 schemaMap_(allocator, kInitialSchemaMapSize),
13461533 schemaRef_(allocator, kInitialSchemaRefSize)
13471534 {
13481535 if (!allocator_)
1349 ownAllocator_ = allocator_ = CEREAL_RAPIDJSON_NEW(Allocator());
1536 ownAllocator_ = allocator_ = CEREAL_RAPIDJSON_NEW(Allocator)();
1537
1538 Ch noUri[1] = {0};
1539 uri_.SetString(uri ? uri : noUri, uriLength, *allocator_);
1540
1541 typeless_ = static_cast<SchemaType*>(allocator_->Malloc(sizeof(SchemaType)));
1542 new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), allocator_);
13501543
13511544 // Generate root schema, it will call CreateSchema() to create sub-schemas,
13521545 // And call AddRefSchema() if there are $ref.
13641557 new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(refEntry->source, const_cast<SchemaType*>(s), false, allocator_);
13651558 }
13661559 }
1560 else if (refEntry->schema)
1561 *refEntry->schema = typeless_;
1562
13671563 refEntry->~SchemaRefEntry();
13681564 }
13691565
13791575 allocator_(rhs.allocator_),
13801576 ownAllocator_(rhs.ownAllocator_),
13811577 root_(rhs.root_),
1578 typeless_(rhs.typeless_),
13821579 schemaMap_(std::move(rhs.schemaMap_)),
1383 schemaRef_(std::move(rhs.schemaRef_))
1580 schemaRef_(std::move(rhs.schemaRef_)),
1581 uri_(std::move(rhs.uri_))
13841582 {
13851583 rhs.remoteProvider_ = 0;
13861584 rhs.allocator_ = 0;
13871585 rhs.ownAllocator_ = 0;
1586 rhs.typeless_ = 0;
13881587 }
13891588 #endif
13901589
13931592 while (!schemaMap_.Empty())
13941593 schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry();
13951594
1595 if (typeless_) {
1596 typeless_->~SchemaType();
1597 Allocator::Free(typeless_);
1598 }
1599
13961600 CEREAL_RAPIDJSON_DELETE(ownAllocator_);
13971601 }
1602
1603 const URIType& GetURI() const { return uri_; }
13981604
13991605 //! Get the root schema.
14001606 const SchemaType& GetRoot() const { return *root_; }
14271633
14281634 void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) {
14291635 if (schema)
1430 *schema = SchemaType::GetTypeless();
1636 *schema = typeless_;
14311637
14321638 if (v.GetType() == kObjectType) {
14331639 const SchemaType* s = GetSchema(pointer);
14721678
14731679 if (i > 0) { // Remote reference, resolve immediately
14741680 if (remoteProvider_) {
1475 if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i - 1)) {
1681 if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i)) {
14761682 PointerType pointer(&s[i], len - i, allocator_);
14771683 if (pointer.IsValid()) {
14781684 if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) {
14791685 if (schema)
14801686 *schema = sc;
1687 new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(source, const_cast<SchemaType*>(sc), false, allocator_);
14811688 return true;
14821689 }
14831690 }
15141721 return PointerType();
15151722 }
15161723
1724 const SchemaType* GetTypeless() const { return typeless_; }
1725
15171726 static const size_t kInitialSchemaMapSize = 64;
15181727 static const size_t kInitialSchemaRefSize = 64;
15191728
15211730 Allocator *allocator_;
15221731 Allocator *ownAllocator_;
15231732 const SchemaType* root_; //!< Root schema.
1733 SchemaType* typeless_;
15241734 internal::Stack<Allocator> schemaMap_; // Stores created Pointer -> Schemas
15251735 internal::Stack<Allocator> schemaRef_; // Stores Pointer from $ref and schema which holds the $ref
1736 URIType uri_;
15261737 };
15271738
15281739 //! GenericSchemaDocument using Value type.
15511762 typename StateAllocator = CrtAllocator>
15521763 class GenericSchemaValidator :
15531764 public internal::ISchemaStateFactory<typename SchemaDocumentType::SchemaType>,
1554 public internal::ISchemaValidator
1765 public internal::ISchemaValidator,
1766 public internal::IValidationErrorHandler<typename SchemaDocumentType::SchemaType>
15551767 {
15561768 public:
15571769 typedef typename SchemaDocumentType::SchemaType SchemaType;
15581770 typedef typename SchemaDocumentType::PointerType PointerType;
15591771 typedef typename SchemaType::EncodingType EncodingType;
1772 typedef typename SchemaType::SValue SValue;
15601773 typedef typename EncodingType::Ch Ch;
1774 typedef GenericStringRef<Ch> StringRefType;
1775 typedef GenericValue<EncodingType, StateAllocator> ValueType;
15611776
15621777 //! Constructor without output handler.
15631778 /*!
15741789 :
15751790 schemaDocument_(&schemaDocument),
15761791 root_(schemaDocument.GetRoot()),
1577 outputHandler_(GetNullHandler()),
15781792 stateAllocator_(allocator),
15791793 ownStateAllocator_(0),
15801794 schemaStack_(allocator, schemaStackCapacity),
15811795 documentStack_(allocator, documentStackCapacity),
1796 outputHandler_(0),
1797 error_(kObjectType),
1798 currentError_(),
1799 missingDependents_(),
15821800 valid_(true)
15831801 #if CEREAL_RAPIDJSON_SCHEMA_VERBOSE
15841802 , depth_(0)
16021820 :
16031821 schemaDocument_(&schemaDocument),
16041822 root_(schemaDocument.GetRoot()),
1605 outputHandler_(outputHandler),
16061823 stateAllocator_(allocator),
16071824 ownStateAllocator_(0),
16081825 schemaStack_(allocator, schemaStackCapacity),
16091826 documentStack_(allocator, documentStackCapacity),
1827 outputHandler_(&outputHandler),
1828 error_(kObjectType),
1829 currentError_(),
1830 missingDependents_(),
16101831 valid_(true)
16111832 #if CEREAL_RAPIDJSON_SCHEMA_VERBOSE
16121833 , depth_(0)
16251846 while (!schemaStack_.Empty())
16261847 PopSchema();
16271848 documentStack_.Clear();
1849 error_.SetObject();
1850 currentError_.SetNull();
1851 missingDependents_.SetNull();
16281852 valid_ = true;
16291853 }
16301854
16321856 // Implementation of ISchemaValidator
16331857 virtual bool IsValid() const { return valid_; }
16341858
1859 //! Gets the error object.
1860 ValueType& GetError() { return error_; }
1861 const ValueType& GetError() const { return error_; }
1862
16351863 //! Gets the JSON pointer pointed to the invalid schema.
16361864 PointerType GetInvalidSchemaPointer() const {
1637 return schemaStack_.Empty() ? PointerType() : schemaDocument_->GetPointer(&CurrentSchema());
1865 return schemaStack_.Empty() ? PointerType() : CurrentSchema().GetPointer();
16381866 }
16391867
16401868 //! Gets the keyword of invalid schema.
16441872
16451873 //! Gets the JSON pointer pointed to the invalid value.
16461874 PointerType GetInvalidDocumentPointer() const {
1647 return documentStack_.Empty() ? PointerType() : PointerType(documentStack_.template Bottom<Ch>(), documentStack_.GetSize() / sizeof(Ch));
1648 }
1875 if (documentStack_.Empty()) {
1876 return PointerType();
1877 }
1878 else {
1879 return PointerType(documentStack_.template Bottom<Ch>(), documentStack_.GetSize() / sizeof(Ch));
1880 }
1881 }
1882
1883 void NotMultipleOf(int64_t actual, const SValue& expected) {
1884 AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected);
1885 }
1886 void NotMultipleOf(uint64_t actual, const SValue& expected) {
1887 AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected);
1888 }
1889 void NotMultipleOf(double actual, const SValue& expected) {
1890 AddNumberError(SchemaType::GetMultipleOfString(), ValueType(actual).Move(), expected);
1891 }
1892 void AboveMaximum(int64_t actual, const SValue& expected, bool exclusive) {
1893 AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected,
1894 exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
1895 }
1896 void AboveMaximum(uint64_t actual, const SValue& expected, bool exclusive) {
1897 AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected,
1898 exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
1899 }
1900 void AboveMaximum(double actual, const SValue& expected, bool exclusive) {
1901 AddNumberError(SchemaType::GetMaximumString(), ValueType(actual).Move(), expected,
1902 exclusive ? &SchemaType::GetExclusiveMaximumString : 0);
1903 }
1904 void BelowMinimum(int64_t actual, const SValue& expected, bool exclusive) {
1905 AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected,
1906 exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
1907 }
1908 void BelowMinimum(uint64_t actual, const SValue& expected, bool exclusive) {
1909 AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected,
1910 exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
1911 }
1912 void BelowMinimum(double actual, const SValue& expected, bool exclusive) {
1913 AddNumberError(SchemaType::GetMinimumString(), ValueType(actual).Move(), expected,
1914 exclusive ? &SchemaType::GetExclusiveMinimumString : 0);
1915 }
1916
1917 void TooLong(const Ch* str, SizeType length, SizeType expected) {
1918 AddNumberError(SchemaType::GetMaxLengthString(),
1919 ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());
1920 }
1921 void TooShort(const Ch* str, SizeType length, SizeType expected) {
1922 AddNumberError(SchemaType::GetMinLengthString(),
1923 ValueType(str, length, GetStateAllocator()).Move(), SValue(expected).Move());
1924 }
1925 void DoesNotMatch(const Ch* str, SizeType length) {
1926 currentError_.SetObject();
1927 currentError_.AddMember(GetActualString(), ValueType(str, length, GetStateAllocator()).Move(), GetStateAllocator());
1928 AddCurrentError(SchemaType::GetPatternString());
1929 }
1930
1931 void DisallowedItem(SizeType index) {
1932 currentError_.SetObject();
1933 currentError_.AddMember(GetDisallowedString(), ValueType(index).Move(), GetStateAllocator());
1934 AddCurrentError(SchemaType::GetAdditionalItemsString(), true);
1935 }
1936 void TooFewItems(SizeType actualCount, SizeType expectedCount) {
1937 AddNumberError(SchemaType::GetMinItemsString(),
1938 ValueType(actualCount).Move(), SValue(expectedCount).Move());
1939 }
1940 void TooManyItems(SizeType actualCount, SizeType expectedCount) {
1941 AddNumberError(SchemaType::GetMaxItemsString(),
1942 ValueType(actualCount).Move(), SValue(expectedCount).Move());
1943 }
1944 void DuplicateItems(SizeType index1, SizeType index2) {
1945 ValueType duplicates(kArrayType);
1946 duplicates.PushBack(index1, GetStateAllocator());
1947 duplicates.PushBack(index2, GetStateAllocator());
1948 currentError_.SetObject();
1949 currentError_.AddMember(GetDuplicatesString(), duplicates, GetStateAllocator());
1950 AddCurrentError(SchemaType::GetUniqueItemsString(), true);
1951 }
1952
1953 void TooManyProperties(SizeType actualCount, SizeType expectedCount) {
1954 AddNumberError(SchemaType::GetMaxPropertiesString(),
1955 ValueType(actualCount).Move(), SValue(expectedCount).Move());
1956 }
1957 void TooFewProperties(SizeType actualCount, SizeType expectedCount) {
1958 AddNumberError(SchemaType::GetMinPropertiesString(),
1959 ValueType(actualCount).Move(), SValue(expectedCount).Move());
1960 }
1961 void StartMissingProperties() {
1962 currentError_.SetArray();
1963 }
1964 void AddMissingProperty(const SValue& name) {
1965 currentError_.PushBack(ValueType(name, GetStateAllocator()).Move(), GetStateAllocator());
1966 }
1967 bool EndMissingProperties() {
1968 if (currentError_.Empty())
1969 return false;
1970 ValueType error(kObjectType);
1971 error.AddMember(GetMissingString(), currentError_, GetStateAllocator());
1972 currentError_ = error;
1973 AddCurrentError(SchemaType::GetRequiredString());
1974 return true;
1975 }
1976 void PropertyViolations(ISchemaValidator** subvalidators, SizeType count) {
1977 for (SizeType i = 0; i < count; ++i)
1978 MergeError(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError());
1979 }
1980 void DisallowedProperty(const Ch* name, SizeType length) {
1981 currentError_.SetObject();
1982 currentError_.AddMember(GetDisallowedString(), ValueType(name, length, GetStateAllocator()).Move(), GetStateAllocator());
1983 AddCurrentError(SchemaType::GetAdditionalPropertiesString(), true);
1984 }
1985
1986 void StartDependencyErrors() {
1987 currentError_.SetObject();
1988 }
1989 void StartMissingDependentProperties() {
1990 missingDependents_.SetArray();
1991 }
1992 void AddMissingDependentProperty(const SValue& targetName) {
1993 missingDependents_.PushBack(ValueType(targetName, GetStateAllocator()).Move(), GetStateAllocator());
1994 }
1995 void EndMissingDependentProperties(const SValue& sourceName) {
1996 if (!missingDependents_.Empty())
1997 currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(),
1998 missingDependents_, GetStateAllocator());
1999 }
2000 void AddDependencySchemaError(const SValue& sourceName, ISchemaValidator* subvalidator) {
2001 currentError_.AddMember(ValueType(sourceName, GetStateAllocator()).Move(),
2002 static_cast<GenericSchemaValidator*>(subvalidator)->GetError(), GetStateAllocator());
2003 }
2004 bool EndDependencyErrors() {
2005 if (currentError_.ObjectEmpty())
2006 return false;
2007 ValueType error(kObjectType);
2008 error.AddMember(GetErrorsString(), currentError_, GetStateAllocator());
2009 currentError_ = error;
2010 AddCurrentError(SchemaType::GetDependenciesString());
2011 return true;
2012 }
2013
2014 void DisallowedValue() {
2015 currentError_.SetObject();
2016 AddCurrentError(SchemaType::GetEnumString());
2017 }
2018 void StartDisallowedType() {
2019 currentError_.SetArray();
2020 }
2021 void AddExpectedType(const typename SchemaType::ValueType& expectedType) {
2022 currentError_.PushBack(ValueType(expectedType, GetStateAllocator()).Move(), GetStateAllocator());
2023 }
2024 void EndDisallowedType(const typename SchemaType::ValueType& actualType) {
2025 ValueType error(kObjectType);
2026 error.AddMember(GetExpectedString(), currentError_, GetStateAllocator());
2027 error.AddMember(GetActualString(), ValueType(actualType, GetStateAllocator()).Move(), GetStateAllocator());
2028 currentError_ = error;
2029 AddCurrentError(SchemaType::GetTypeString());
2030 }
2031 void NotAllOf(ISchemaValidator** subvalidators, SizeType count) {
2032 for (SizeType i = 0; i < count; ++i) {
2033 MergeError(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError());
2034 }
2035 }
2036 void NoneOf(ISchemaValidator** subvalidators, SizeType count) {
2037 AddErrorArray(SchemaType::GetAnyOfString(), subvalidators, count);
2038 }
2039 void NotOneOf(ISchemaValidator** subvalidators, SizeType count) {
2040 AddErrorArray(SchemaType::GetOneOfString(), subvalidators, count);
2041 }
2042 void Disallowed() {
2043 currentError_.SetObject();
2044 AddCurrentError(SchemaType::GetNotString());
2045 }
2046
2047 #define CEREAL_RAPIDJSON_STRING_(name, ...) \
2048 static const StringRefType& Get##name##String() {\
2049 static const Ch s[] = { __VA_ARGS__, '\0' };\
2050 static const StringRefType v(s, static_cast<SizeType>(sizeof(s) / sizeof(Ch) - 1)); \
2051 return v;\
2052 }
2053
2054 CEREAL_RAPIDJSON_STRING_(InstanceRef, 'i', 'n', 's', 't', 'a', 'n', 'c', 'e', 'R', 'e', 'f')
2055 CEREAL_RAPIDJSON_STRING_(SchemaRef, 's', 'c', 'h', 'e', 'm', 'a', 'R', 'e', 'f')
2056 CEREAL_RAPIDJSON_STRING_(Expected, 'e', 'x', 'p', 'e', 'c', 't', 'e', 'd')
2057 CEREAL_RAPIDJSON_STRING_(Actual, 'a', 'c', 't', 'u', 'a', 'l')
2058 CEREAL_RAPIDJSON_STRING_(Disallowed, 'd', 'i', 's', 'a', 'l', 'l', 'o', 'w', 'e', 'd')
2059 CEREAL_RAPIDJSON_STRING_(Missing, 'm', 'i', 's', 's', 'i', 'n', 'g')
2060 CEREAL_RAPIDJSON_STRING_(Errors, 'e', 'r', 'r', 'o', 'r', 's')
2061 CEREAL_RAPIDJSON_STRING_(Duplicates, 'd', 'u', 'p', 'l', 'i', 'c', 'a', 't', 'e', 's')
2062
2063 #undef CEREAL_RAPIDJSON_STRING_
16492064
16502065 #if CEREAL_RAPIDJSON_SCHEMA_VERBOSE
16512066 #define CEREAL_RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \
16782093 }
16792094
16802095 #define CEREAL_RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\
1681 return valid_ = EndValue() && outputHandler_.method arg2
2096 return valid_ = EndValue() && (!outputHandler_ || outputHandler_->method arg2)
16822097
16832098 #define CEREAL_RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \
16842099 CEREAL_RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\
16852100 CEREAL_RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\
16862101 CEREAL_RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2)
16872102
1688 bool Null() { CEREAL_RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext() ), ( )); }
2103 bool Null() { CEREAL_RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext()), ( )); }
16892104 bool Bool(bool b) { CEREAL_RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); }
16902105 bool Int(int i) { CEREAL_RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); }
16912106 bool Uint(unsigned u) { CEREAL_RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); }
17002115 bool StartObject() {
17012116 CEREAL_RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext()));
17022117 CEREAL_RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ());
1703 return valid_ = outputHandler_.StartObject();
2118 return valid_ = !outputHandler_ || outputHandler_->StartObject();
17042119 }
17052120
17062121 bool Key(const Ch* str, SizeType len, bool copy) {
17082123 AppendToken(str, len);
17092124 if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false;
17102125 CEREAL_RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy));
1711 return valid_ = outputHandler_.Key(str, len, copy);
2126 return valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy);
17122127 }
17132128
17142129 bool EndObject(SizeType memberCount) {
17212136 bool StartArray() {
17222137 CEREAL_RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext()));
17232138 CEREAL_RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ());
1724 return valid_ = outputHandler_.StartArray();
2139 return valid_ = !outputHandler_ || outputHandler_->StartArray();
17252140 }
17262141
17272142 bool EndArray(SizeType elementCount) {
17382153
17392154 // Implementation of ISchemaStateFactory<SchemaType>
17402155 virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root) {
1741 return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root,
2156 return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, documentStack_.template Bottom<char>(), documentStack_.GetSize(),
17422157 #if CEREAL_RAPIDJSON_SCHEMA_VERBOSE
17432158 depth_ + 1,
17442159 #endif
17702185 }
17712186
17722187 virtual void FreeState(void* p) {
1773 return StateAllocator::Free(p);
2188 StateAllocator::Free(p);
17742189 }
17752190
17762191 private:
17812196 GenericSchemaValidator(
17822197 const SchemaDocumentType& schemaDocument,
17832198 const SchemaType& root,
2199 const char* basePath, size_t basePathSize,
17842200 #if CEREAL_RAPIDJSON_SCHEMA_VERBOSE
17852201 unsigned depth,
17862202 #endif
17902206 :
17912207 schemaDocument_(&schemaDocument),
17922208 root_(root),
1793 outputHandler_(GetNullHandler()),
17942209 stateAllocator_(allocator),
17952210 ownStateAllocator_(0),
17962211 schemaStack_(allocator, schemaStackCapacity),
17972212 documentStack_(allocator, documentStackCapacity),
2213 outputHandler_(0),
2214 error_(kObjectType),
2215 currentError_(),
2216 missingDependents_(),
17982217 valid_(true)
17992218 #if CEREAL_RAPIDJSON_SCHEMA_VERBOSE
18002219 , depth_(depth)
18012220 #endif
18022221 {
2222 if (basePath && basePathSize)
2223 memcpy(documentStack_.template Push<char>(basePathSize), basePath, basePathSize);
18032224 }
18042225
18052226 StateAllocator& GetStateAllocator() {
18062227 if (!stateAllocator_)
1807 stateAllocator_ = ownStateAllocator_ = CEREAL_RAPIDJSON_NEW(StateAllocator());
2228 stateAllocator_ = ownStateAllocator_ = CEREAL_RAPIDJSON_NEW(StateAllocator)();
18082229 return *stateAllocator_;
18092230 }
18102231
18222243 const SchemaType** sa = CurrentContext().patternPropertiesSchemas;
18232244 typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType;
18242245 bool valueUniqueness = CurrentContext().valueUniqueness;
1825 if (CurrentContext().valueSchema)
1826 PushSchema(*CurrentContext().valueSchema);
2246 CEREAL_RAPIDJSON_ASSERT(CurrentContext().valueSchema);
2247 PushSchema(*CurrentContext().valueSchema);
18272248
18282249 if (count > 0) {
18292250 CurrentContext().objectPatternValidatorType = patternValidatorType;
18632284 if (!a)
18642285 CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType);
18652286 for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr)
1866 if (itr->GetUint64() == h)
2287 if (itr->GetUint64() == h) {
2288 DuplicateItems(static_cast<SizeType>(itr - a->Begin()), a->Size());
18672289 CEREAL_RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString());
2290 }
18682291 a->PushBack(h, GetStateAllocator());
18692292 }
18702293 }
18932316 }
18942317 }
18952318
1896 CEREAL_RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push<Context>()) Context(*this, &schema); }
2319 CEREAL_RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push<Context>()) Context(*this, *this, &schema); }
18972320
18982321 CEREAL_RAPIDJSON_FORCEINLINE void PopSchema() {
18992322 Context* c = schemaStack_.template Pop<Context>(1);
19042327 c->~Context();
19052328 }
19062329
2330 void AddErrorLocation(ValueType& result, bool parent) {
2331 GenericStringBuffer<EncodingType> sb;
2332 PointerType instancePointer = GetInvalidDocumentPointer();
2333 ((parent && instancePointer.GetTokenCount() > 0)
2334 ? PointerType(instancePointer.GetTokens(), instancePointer.GetTokenCount() - 1)
2335 : instancePointer).StringifyUriFragment(sb);
2336 ValueType instanceRef(sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)),
2337 GetStateAllocator());
2338 result.AddMember(GetInstanceRefString(), instanceRef, GetStateAllocator());
2339 sb.Clear();
2340 memcpy(sb.Push(CurrentSchema().GetURI().GetStringLength()),
2341 CurrentSchema().GetURI().GetString(),
2342 CurrentSchema().GetURI().GetStringLength() * sizeof(Ch));
2343 GetInvalidSchemaPointer().StringifyUriFragment(sb);
2344 ValueType schemaRef(sb.GetString(), static_cast<SizeType>(sb.GetSize() / sizeof(Ch)),
2345 GetStateAllocator());
2346 result.AddMember(GetSchemaRefString(), schemaRef, GetStateAllocator());
2347 }
2348
2349 void AddError(ValueType& keyword, ValueType& error) {
2350 typename ValueType::MemberIterator member = error_.FindMember(keyword);
2351 if (member == error_.MemberEnd())
2352 error_.AddMember(keyword, error, GetStateAllocator());
2353 else {
2354 if (member->value.IsObject()) {
2355 ValueType errors(kArrayType);
2356 errors.PushBack(member->value, GetStateAllocator());
2357 member->value = errors;
2358 }
2359 member->value.PushBack(error, GetStateAllocator());
2360 }
2361 }
2362
2363 void AddCurrentError(const typename SchemaType::ValueType& keyword, bool parent = false) {
2364 AddErrorLocation(currentError_, parent);
2365 AddError(ValueType(keyword, GetStateAllocator(), false).Move(), currentError_);
2366 }
2367
2368 void MergeError(ValueType& other) {
2369 for (typename ValueType::MemberIterator it = other.MemberBegin(), end = other.MemberEnd(); it != end; ++it) {
2370 AddError(it->name, it->value);
2371 }
2372 }
2373
2374 void AddNumberError(const typename SchemaType::ValueType& keyword, ValueType& actual, const SValue& expected,
2375 const typename SchemaType::ValueType& (*exclusive)() = 0) {
2376 currentError_.SetObject();
2377 currentError_.AddMember(GetActualString(), actual, GetStateAllocator());
2378 currentError_.AddMember(GetExpectedString(), ValueType(expected, GetStateAllocator()).Move(), GetStateAllocator());
2379 if (exclusive)
2380 currentError_.AddMember(ValueType(exclusive(), GetStateAllocator()).Move(), true, GetStateAllocator());
2381 AddCurrentError(keyword);
2382 }
2383
2384 void AddErrorArray(const typename SchemaType::ValueType& keyword,
2385 ISchemaValidator** subvalidators, SizeType count) {
2386 ValueType errors(kArrayType);
2387 for (SizeType i = 0; i < count; ++i)
2388 errors.PushBack(static_cast<GenericSchemaValidator*>(subvalidators[i])->GetError(), GetStateAllocator());
2389 currentError_.SetObject();
2390 currentError_.AddMember(GetErrorsString(), errors, GetStateAllocator());
2391 AddCurrentError(keyword);
2392 }
2393
19072394 const SchemaType& CurrentSchema() const { return *schemaStack_.template Top<Context>()->schema; }
19082395 Context& CurrentContext() { return *schemaStack_.template Top<Context>(); }
19092396 const Context& CurrentContext() const { return *schemaStack_.template Top<Context>(); }
1910
1911 static OutputHandler& GetNullHandler() {
1912 static OutputHandler nullHandler;
1913 return nullHandler;
1914 }
19152397
19162398 static const size_t kDefaultSchemaStackCapacity = 1024;
19172399 static const size_t kDefaultDocumentStackCapacity = 256;
19182400 const SchemaDocumentType* schemaDocument_;
19192401 const SchemaType& root_;
1920 OutputHandler& outputHandler_;
19212402 StateAllocator* stateAllocator_;
19222403 StateAllocator* ownStateAllocator_;
19232404 internal::Stack<StateAllocator> schemaStack_; //!< stack to store the current path of schema (BaseSchemaType *)
19242405 internal::Stack<StateAllocator> documentStack_; //!< stack to store the current path of validating document (Ch)
2406 OutputHandler* outputHandler_;
2407 ValueType error_;
2408 ValueType currentError_;
2409 ValueType missingDependents_;
19252410 bool valid_;
19262411 #if CEREAL_RAPIDJSON_SCHEMA_VERBOSE
19272412 unsigned depth_;
19532438 public:
19542439 typedef typename SchemaDocumentType::PointerType PointerType;
19552440 typedef typename InputStream::Ch Ch;
2441 typedef GenericValue<SourceEncoding, StackAllocator> ValueType;
19562442
19572443 //! Constructor
19582444 /*!
19592445 \param is Input stream.
19602446 \param sd Schema document.
19612447 */
1962 SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), isValid_(true) {}
2448 SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), error_(kObjectType), isValid_(true) {}
19632449
19642450 template <typename Handler>
19652451 bool operator()(Handler& handler) {
19722458 invalidSchemaPointer_ = PointerType();
19732459 invalidSchemaKeyword_ = 0;
19742460 invalidDocumentPointer_ = PointerType();
2461 error_.SetObject();
19752462 }
19762463 else {
19772464 invalidSchemaPointer_ = validator.GetInvalidSchemaPointer();
19782465 invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword();
19792466 invalidDocumentPointer_ = validator.GetInvalidDocumentPointer();
2467 error_.CopyFrom(validator.GetError(), allocator_);
19802468 }
19812469
19822470 return parseResult_;
19872475 const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; }
19882476 const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; }
19892477 const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; }
2478 const ValueType& GetError() const { return error_; }
19902479
19912480 private:
19922481 InputStream& is_;
19962485 PointerType invalidSchemaPointer_;
19972486 const Ch* invalidSchemaKeyword_;
19982487 PointerType invalidDocumentPointer_;
2488 StackAllocator allocator_;
2489 ValueType error_;
19992490 bool isValid_;
20002491 };
20012492
00 // Tencent is pleased to support the open source community by making RapidJSON available.
1 //
1 //
22 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
33 //
44 // Licensed under the MIT License (the "License"); you may not use this file except
66 //
77 // http://opensource.org/licenses/MIT
88 //
9 // Unless required by applicable law or agreed to in writing, software distributed
10 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
9 // Unless required by applicable law or agreed to in writing, software distributed
10 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
11 // CONDITIONS OF ANY KIND, either express or implied. See the License for the
1212 // specific language governing permissions and limitations under the License.
1313
1414 #include "rapidjson.h"
100100 }
101101
102102 ///////////////////////////////////////////////////////////////////////////////
103 // GenericStreamWrapper
104
105 //! A Stream Wrapper
106 /*! \tThis string stream is a wrapper for any stream by just forwarding any
107 \treceived message to the origin stream.
108 \note implements Stream concept
109 */
110
111 #if defined(_MSC_VER) && _MSC_VER <= 1800
112 CEREAL_RAPIDJSON_DIAG_PUSH
113 CEREAL_RAPIDJSON_DIAG_OFF(4702) // unreachable code
114 CEREAL_RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
115 #endif
116
117 template <typename InputStream, typename Encoding = UTF8<> >
118 class GenericStreamWrapper {
119 public:
120 typedef typename Encoding::Ch Ch;
121 GenericStreamWrapper(InputStream& is): is_(is) {}
122
123 Ch Peek() const { return is_.Peek(); }
124 Ch Take() { return is_.Take(); }
125 size_t Tell() { return is_.Tell(); }
126 Ch* PutBegin() { return is_.PutBegin(); }
127 void Put(Ch ch) { is_.Put(ch); }
128 void Flush() { is_.Flush(); }
129 size_t PutEnd(Ch* ch) { return is_.PutEnd(ch); }
130
131 // wrapper for MemoryStream
132 const Ch* Peek4() const { return is_.Peek4(); }
133
134 // wrapper for AutoUTFInputStream
135 UTFType GetType() const { return is_.GetType(); }
136 bool HasBOM() const { return is_.HasBOM(); }
137
138 protected:
139 InputStream& is_;
140 };
141
142 #if defined(_MSC_VER) && _MSC_VER <= 1800
143 CEREAL_RAPIDJSON_DIAG_POP
144 #endif
145
146 ///////////////////////////////////////////////////////////////////////////////
103147 // StringStream
104148
105149 //! Read-only string stream.
7777 return stack_.template Bottom<Ch>();
7878 }
7979
80 //! Get the size of string in bytes in the string buffer.
8081 size_t GetSize() const { return stack_.GetSize(); }
82
83 //! Get the length of string in Ch in the string buffer.
84 size_t GetLength() const { return stack_.GetSize() / sizeof(Ch); }
8185
8286 static const size_t kDefaultCapacity = 256;
8387 mutable internal::Stack<Allocator> stack_;
1515 #define CEREAL_RAPIDJSON_WRITER_H_
1616
1717 #include "stream.h"
18 #include "internal/meta.h"
1819 #include "internal/stack.h"
1920 #include "internal/strfunc.h"
2021 #include "internal/dtoa.h"
3031 #include <nmmintrin.h>
3132 #elif defined(CEREAL_RAPIDJSON_SSE2)
3233 #include <emmintrin.h>
33 #endif
34
35 #ifdef _MSC_VER
36 CEREAL_RAPIDJSON_DIAG_PUSH
37 CEREAL_RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
34 #elif defined(CEREAL_RAPIDJSON_NEON)
35 #include <arm_neon.h>
3836 #endif
3937
4038 #ifdef __clang__
4139 CEREAL_RAPIDJSON_DIAG_PUSH
4240 CEREAL_RAPIDJSON_DIAG_OFF(padded)
4341 CEREAL_RAPIDJSON_DIAG_OFF(unreachable-code)
42 CEREAL_RAPIDJSON_DIAG_OFF(c++98-compat)
43 #elif defined(_MSC_VER)
44 CEREAL_RAPIDJSON_DIAG_PUSH
45 CEREAL_RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
4446 #endif
4547
4648 CEREAL_RAPIDJSON_NAMESPACE_BEGIN
6264 enum WriteFlag {
6365 kWriteNoFlags = 0, //!< No flags are set.
6466 kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings.
65 kWriteNanAndInfFlag = 2, //!< Allow writing of Inf, -Inf and NaN.
67 kWriteNanAndInfFlag = 2, //!< Allow writing of Infinity, -Infinity and NaN.
6668 kWriteDefaultFlags = CEREAL_RAPIDJSON_WRITE_DEFAULT_FLAGS //!< Default write flags. Can be customized by defining CEREAL_RAPIDJSON_WRITE_DEFAULT_FLAGS
6769 };
6870
102104 Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
103105 os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
104106
107 #if CEREAL_RAPIDJSON_HAS_CXX11_RVALUE_REFS
108 Writer(Writer&& rhs) :
109 os_(rhs.os_), level_stack_(std::move(rhs.level_stack_)), maxDecimalPlaces_(rhs.maxDecimalPlaces_), hasRoot_(rhs.hasRoot_) {
110 rhs.os_ = 0;
111 }
112 #endif
113
105114 //! Reset the writer with a new stream.
106115 /*!
107116 This function reset the writer with a new stream and default settings,
183192 bool Double(double d) { Prefix(kNumberType); return EndValue(WriteDouble(d)); }
184193
185194 bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
195 CEREAL_RAPIDJSON_ASSERT(str != 0);
186196 (void)copy;
187197 Prefix(kNumberType);
188198 return EndValue(WriteString(str, length));
189199 }
190200
191201 bool String(const Ch* str, SizeType length, bool copy = false) {
202 CEREAL_RAPIDJSON_ASSERT(str != 0);
192203 (void)copy;
193204 Prefix(kStringType);
194205 return EndValue(WriteString(str, length));
208219
209220 bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
210221
222 #if CEREAL_RAPIDJSON_HAS_STDSTRING
223 bool Key(const std::basic_string<Ch>& str)
224 {
225 return Key(str.data(), SizeType(str.size()));
226 }
227 #endif
228
211229 bool EndObject(SizeType memberCount = 0) {
212230 (void)memberCount;
213 CEREAL_RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
214 CEREAL_RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
231 CEREAL_RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object
232 CEREAL_RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray); // currently inside an Array, not Object
233 CEREAL_RAPIDJSON_ASSERT(0 == level_stack_.template Top<Level>()->valueCount % 2); // Object has a Key without a Value
215234 level_stack_.template Pop<Level>(1);
216235 return EndValue(WriteEndObject());
217236 }
235254 //@{
236255
237256 //! Simpler but slower overload.
238 bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
239 bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
240
257 bool String(const Ch* const& str) { return String(str, internal::StrLen(str)); }
258 bool Key(const Ch* const& str) { return Key(str, internal::StrLen(str)); }
259
241260 //@}
242261
243262 //! Write a raw JSON value.
248267 \param length Length of the json.
249268 \param type Type of the root of json.
250269 */
251 bool RawValue(const Ch* json, size_t length, Type type) { Prefix(type); return EndValue(WriteRawValue(json, length)); }
270 bool RawValue(const Ch* json, size_t length, Type type) {
271 CEREAL_RAPIDJSON_ASSERT(json != 0);
272 Prefix(type);
273 return EndValue(WriteRawValue(json, length));
274 }
275
276 //! Flush the output stream.
277 /*!
278 Allows the user to flush the output stream immediately.
279 */
280 void Flush() {
281 os_->Flush();
282 }
252283
253284 protected:
254285 //! Information for each nested level
282313 const char* end = internal::i32toa(i, buffer);
283314 PutReserve(*os_, static_cast<size_t>(end - buffer));
284315 for (const char* p = buffer; p != end; ++p)
285 PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
316 PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
286317 return true;
287318 }
288319
291322 const char* end = internal::u32toa(u, buffer);
292323 PutReserve(*os_, static_cast<size_t>(end - buffer));
293324 for (const char* p = buffer; p != end; ++p)
294 PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
325 PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
295326 return true;
296327 }
297328
300331 const char* end = internal::i64toa(i64, buffer);
301332 PutReserve(*os_, static_cast<size_t>(end - buffer));
302333 for (const char* p = buffer; p != end; ++p)
303 PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
334 PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
304335 return true;
305336 }
306337
309340 char* end = internal::u64toa(u64, buffer);
310341 PutReserve(*os_, static_cast<size_t>(end - buffer));
311342 for (char* p = buffer; p != end; ++p)
312 PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
343 PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
313344 return true;
314345 }
315346
337368 char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
338369 PutReserve(*os_, static_cast<size_t>(end - buffer));
339370 for (char* p = buffer; p != end; ++p)
340 PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
371 PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(*p));
341372 return true;
342373 }
343374
344375 bool WriteString(const Ch* str, SizeType length) {
345 static const typename TargetEncoding::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
376 static const typename OutputStream::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
346377 static const char escape[256] = {
347378 #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
348379 //0 1 2 3 4 5 6 7 8 9 A B C D E F
398429 else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && CEREAL_RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)])) {
399430 is.Take();
400431 PutUnsafe(*os_, '\\');
401 PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(escape[static_cast<unsigned char>(c)]));
432 PutUnsafe(*os_, static_cast<typename OutputStream::Ch>(escape[static_cast<unsigned char>(c)]));
402433 if (escape[static_cast<unsigned char>(c)] == 'u') {
403434 PutUnsafe(*os_, '0');
404435 PutUnsafe(*os_, '0');
426457
427458 bool WriteRawValue(const Ch* json, size_t length) {
428459 PutReserve(*os_, length);
429 for (size_t i = 0; i < length; i++) {
430 CEREAL_RAPIDJSON_ASSERT(json[i] != '\0');
431 PutUnsafe(*os_, json[i]);
460 GenericStringStream<SourceEncoding> is(json);
461 while (CEREAL_RAPIDJSON_LIKELY(is.Tell() < length)) {
462 CEREAL_RAPIDJSON_ASSERT(is.Peek() != '\0');
463 if (CEREAL_RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ?
464 Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
465 Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
466 return false;
432467 }
433468 return true;
434469 }
456491 // Flush the value if it is the top level one.
457492 bool EndValue(bool ret) {
458493 if (CEREAL_RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text
459 os_->Flush();
494 Flush();
460495 return ret;
461496 }
462497
560595 // The rest of string using SIMD
561596 static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
562597 static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
563 static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
598 static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F };
564599 const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
565600 const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
566601 const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
569604 const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
570605 const __m128i t1 = _mm_cmpeq_epi8(s, dq);
571606 const __m128i t2 = _mm_cmpeq_epi8(s, bs);
572 const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
607 const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F
573608 const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
574609 unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
575610 if (CEREAL_RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
594629 is.src_ = p;
595630 return CEREAL_RAPIDJSON_LIKELY(is.Tell() < length);
596631 }
597 #endif // defined(CEREAL_RAPIDJSON_SSE2) || defined(CEREAL_RAPIDJSON_SSE42)
632 #elif defined(CEREAL_RAPIDJSON_NEON)
633 template<>
634 inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {
635 if (length < 16)
636 return CEREAL_RAPIDJSON_LIKELY(is.Tell() < length);
637
638 if (!CEREAL_RAPIDJSON_LIKELY(is.Tell() < length))
639 return false;
640
641 const char* p = is.src_;
642 const char* end = is.head_ + length;
643 const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
644 const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15));
645 if (nextAligned > end)
646 return true;
647
648 while (p != nextAligned)
649 if (*p < 0x20 || *p == '\"' || *p == '\\') {
650 is.src_ = p;
651 return CEREAL_RAPIDJSON_LIKELY(is.Tell() < length);
652 }
653 else
654 os_->PutUnsafe(*p++);
655
656 // The rest of string using SIMD
657 const uint8x16_t s0 = vmovq_n_u8('"');
658 const uint8x16_t s1 = vmovq_n_u8('\\');
659 const uint8x16_t s2 = vmovq_n_u8('\b');
660 const uint8x16_t s3 = vmovq_n_u8(32);
661
662 for (; p != endAligned; p += 16) {
663 const uint8x16_t s = vld1q_u8(reinterpret_cast<const uint8_t *>(p));
664 uint8x16_t x = vceqq_u8(s, s0);
665 x = vorrq_u8(x, vceqq_u8(s, s1));
666 x = vorrq_u8(x, vceqq_u8(s, s2));
667 x = vorrq_u8(x, vcltq_u8(s, s3));
668
669 x = vrev64q_u8(x); // Rev in 64
670 uint64_t low = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 0); // extract
671 uint64_t high = vgetq_lane_u64(reinterpret_cast<uint64x2_t>(x), 1); // extract
672
673 SizeType len = 0;
674 bool escaped = false;
675 if (low == 0) {
676 if (high != 0) {
677 unsigned lz = (unsigned)__builtin_clzll(high);
678 len = 8 + (lz >> 3);
679 escaped = true;
680 }
681 } else {
682 unsigned lz = (unsigned)__builtin_clzll(low);
683 len = lz >> 3;
684 escaped = true;
685 }
686 if (CEREAL_RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped
687 char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));
688 for (size_t i = 0; i < len; i++)
689 q[i] = p[i];
690
691 p += len;
692 break;
693 }
694 vst1q_u8(reinterpret_cast<uint8_t *>(os_->PushUnsafe(16)), s);
695 }
696
697 is.src_ = p;
698 return CEREAL_RAPIDJSON_LIKELY(is.Tell() < length);
699 }
700 #endif // CEREAL_RAPIDJSON_NEON
598701
599702 CEREAL_RAPIDJSON_NAMESPACE_END
600703
601 #ifdef _MSC_VER
704 #if defined(_MSC_VER) || defined(__clang__)
602705 CEREAL_RAPIDJSON_DIAG_POP
603706 #endif
604707
605 #ifdef __clang__
606 CEREAL_RAPIDJSON_DIAG_POP
607 #endif
608
609708 #endif // CEREAL_RAPIDJSON_CEREAL_RAPIDJSON_H_
8484
8585 //! Gets human readable description of error.
8686 //! \return Pointer to null terminated description of the error.
87 virtual const char *what() const throw()
87 virtual const char *what() const CEREAL_NOEXCEPT override
8888 {
8989 return m_what;
9090 }
316316 const Ch *tmp = p;
317317 while (*tmp)
318318 ++tmp;
319 return tmp - p;
319 return static_cast<std::size_t>(tmp - p);
320320 }
321321
322322 // Compare strings for equality
386386 //! If required, you can tweak <code>CEREAL_RAPIDXML_STATIC_POOL_SIZE</code>, <code>CEREAL_RAPIDXML_DYNAMIC_POOL_SIZE</code> and <code>CEREAL_RAPIDXML_ALIGNMENT</code>
387387 //! to obtain best wasted memory to performance compromise.
388388 //! To do it, define their values before rapidxml.hpp file is included.
389 //! \param Ch Character type of created nodes.
389 //! \tparam Ch Character type of created nodes.
390390 template<class Ch = char>
391391 class memory_pool
392392 {
655655
656656 //! Base class for xml_node and xml_attribute implementing common functions:
657657 //! name(), name_size(), value(), value_size() and parent().
658 //! \param Ch Character type to use
658 //! \tparam Ch Character type to use
659659 template<class Ch = char>
660660 class xml_base
661661 {
728728 //! <br><br>
729729 //! Size of name must be specified separately, because name does not have to be zero terminated.
730730 //! Use name(const Ch *) function to have the length automatically calculated (string must be zero terminated).
731 //! \param name Name of node to set. Does not have to be zero terminated.
731 //! \param name_ Name of node to set. Does not have to be zero terminated.
732732 //! \param size Size of name, in characters. This does not include zero terminator, if one is present.
733733 void name(const Ch *name_, std::size_t size)
734734 {
738738
739739 //! Sets name of node to a zero-terminated string.
740740 //! See also \ref ownership_of_strings and xml_node::name(const Ch *, std::size_t).
741 //! \param name Name of node to set. Must be zero terminated.
741 //! \param name_ Name of node to set. Must be zero terminated.
742742 void name(const Ch *name_)
743743 {
744744 this->name(name_, internal::measure(name_));
758758 //! <br><br>
759759 //! If an element has a child node of type node_data, it will take precedence over element value when printing.
760760 //! If you want to manipulate data of elements using values, use parser flag rapidxml::parse_no_data_nodes to prevent creation of data nodes by the parser.
761 //! \param value value of node to set. Does not have to be zero terminated.
761 //! \param value_ value of node to set. Does not have to be zero terminated.
762762 //! \param size Size of value, in characters. This does not include zero terminator, if one is present.
763763 void value(const Ch *value_, std::size_t size)
764764 {
768768
769769 //! Sets value of node to a zero-terminated string.
770770 //! See also \ref ownership_of_strings and xml_node::value(const Ch *, std::size_t).
771 //! \param value Vame of node to set. Must be zero terminated.
771 //! \param value_ Vame of node to set. Must be zero terminated.
772772 void value(const Ch *value_)
773773 {
774774 this->value(value_, internal::measure(value_));
805805 //! Each attribute has name and value strings, which are available through name() and value() functions (inherited from xml_base).
806806 //! Note that after parse, both name and value of attribute will point to interior of source text used for parsing.
807807 //! Thus, this text must persist in memory for the lifetime of attribute.
808 //! \param Ch Character type to use.
808 //! \tparam Ch Character type to use.
809809 template<class Ch = char>
810810 class xml_attribute: public xml_base<Ch>
811811 {
861861 }
862862
863863 //! Gets next attribute, optionally matching attribute name.
864 //! \param name Name of attribute to find, or 0 to return next attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
865 //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string
864 //! \param name_ Name of attribute to find, or 0 to return next attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
865 //! \param name_size_ Size of name, in characters, or 0 to have size calculated automatically from string
866866 //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
867867 //! \return Pointer to found attribute, or 0 if not found.
868868 xml_attribute<Ch> *next_attribute(const Ch *name_ = 0, std::size_t name_size_ = 0, bool case_sensitive = true) const
897897 //! <br><br>
898898 //! Note that after parse, both name and value of node, if any, will point interior of source text used for parsing.
899899 //! Thus, this text must persist in the memory for the lifetime of node.
900 //! \param Ch Character type to use.
900 //! \tparam Ch Character type to use.
901901 template<class Ch = char>
902902 class xml_node: public xml_base<Ch>
903903 {
909909
910910 //! Constructs an empty node with the specified type.
911911 //! Consider using memory_pool of appropriate document to allocate nodes manually.
912 //! \param type Type of node to construct.
912 //! \param type_ Type of node to construct.
913913 xml_node(node_type type_)
914914 : m_type(type_)
915915 , m_first_node(0)
941941 }
942942
943943 //! Gets first child node, optionally matching node name.
944 //! \param name Name of child to find, or 0 to return first child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
945 //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string
944 //! \param name_ Name of child to find, or 0 to return first child regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
945 //! \param name_size_ Size of name, in characters, or 0 to have size calculated automatically from string
946946 //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
947947 //! \return Pointer to found child, or 0 if not found.
948948 xml_node<Ch> *first_node(const Ch *name_ = 0, std::size_t name_size_ = 0, bool case_sensitive = true) const
10091009 //! Gets next sibling node, optionally matching node name.
10101010 //! Behaviour is undefined if node has no parent.
10111011 //! Use parent() to test if node has a parent.
1012 //! \param name Name of sibling to find, or 0 to return next sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
1013 //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string
1012 //! \param name_ Name of sibling to find, or 0 to return next sibling regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
1013 //! \param name_size_ Size of name, in characters, or 0 to have size calculated automatically from string
10141014 //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
10151015 //! \return Pointer to found sibling, or 0 if not found.
10161016 xml_node<Ch> *next_sibling(const Ch *name_ = 0, std::size_t name_size_ = 0, bool case_sensitive = true) const
10301030 }
10311031
10321032 //! Gets first attribute of node, optionally matching attribute name.
1033 //! \param name Name of attribute to find, or 0 to return first attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
1034 //! \param name_size Size of name, in characters, or 0 to have size calculated automatically from string
1033 //! \param name_ Name of attribute to find, or 0 to return first attribute regardless of its name; this string doesn't have to be zero-terminated if name_size is non-zero
1034 //! \param name_size_ Size of name, in characters, or 0 to have size calculated automatically from string
10351035 //! \param case_sensitive Should name comparison be case-sensitive; non case-sensitive comparison works properly only for ASCII characters
10361036 //! \return Pointer to found attribute, or 0 if not found.
10371037 xml_attribute<Ch> *first_attribute(const Ch *name_ = 0, std::size_t name_size_ = 0, bool case_sensitive = true) const
10731073 // Node modification
10741074
10751075 //! Sets type of node.
1076 //! \param type Type of node to set.
1076 //! \param type_ Type of node to set.
10771077 void type(node_type type_)
10781078 {
10791079 m_type = type_;
13651365 //! parse() function allocates memory for nodes and attributes by using functions of xml_document,
13661366 //! which are inherited from memory_pool.
13671367 //! To access root node of the document, use the document itself, as if it was an xml_node.
1368 //! \param Ch Character type to use.
1368 //! \tparam Ch Character type to use.
13691369 template<class Ch = char>
13701370 class xml_document: public xml_node<Ch>, public memory_pool<Ch>
13711371 {
15261526 {
15271527 // Insert 8-bit ASCII character
15281528 // Todo: possibly verify that code is less than 256 and use replacement char otherwise?
1529 text[0] = static_cast<unsigned char>(code);
1529 text[0] = static_cast<Ch>(code);
15301530 text += 1;
15311531 }
15321532 else
15341534 // Insert UTF8 sequence
15351535 if (code < 0x80) // 1 byte sequence
15361536 {
1537 text[0] = static_cast<unsigned char>(code);
1537 text[0] = static_cast<Ch>(code);
15381538 text += 1;
15391539 }
15401540 else if (code < 0x800) // 2 byte sequence
15411541 {
1542 text[1] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
1543 text[0] = static_cast<unsigned char>(code | 0xC0);
1542 text[1] = static_cast<Ch>((code | 0x80) & 0xBF); code >>= 6;
1543 text[0] = static_cast<Ch>(code | 0xC0);
15441544 text += 2;
15451545 }
15461546 else if (code < 0x10000) // 3 byte sequence
15471547 {
1548 text[2] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
1549 text[1] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
1550 text[0] = static_cast<unsigned char>(code | 0xE0);
1548 text[2] = static_cast<Ch>((code | 0x80) & 0xBF); code >>= 6;
1549 text[1] = static_cast<Ch>((code | 0x80) & 0xBF); code >>= 6;
1550 text[0] = static_cast<Ch>(code | 0xE0);
15511551 text += 3;
15521552 }
15531553 else if (code < 0x110000) // 4 byte sequence
15541554 {
1555 text[3] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
1556 text[2] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
1557 text[1] = static_cast<unsigned char>((code | 0x80) & 0xBF); code >>= 6;
1558 text[0] = static_cast<unsigned char>(code | 0xF0);
1555 text[3] = static_cast<Ch>((code | 0x80) & 0xBF); code >>= 6;
1556 text[2] = static_cast<Ch>((code | 0x80) & 0xBF); code >>= 6;
1557 text[1] = static_cast<Ch>((code | 0x80) & 0xBF); code >>= 6;
1558 text[0] = static_cast<Ch>(code | 0xF0);
15591559 text += 4;
15601560 }
15611561 else // Invalid, only codes up to 0x10FFFF are allowed in Unicode
18111811
18121812 // Create comment node
18131813 xml_node<Ch> *comment = this->allocate_node(node_comment);
1814 comment->value(value_, text - value_);
1814 comment->value(value_, static_cast<std::size_t>(text - value_));
18151815
18161816 // Place zero terminator after comment value
18171817 if (!(Flags & parse_no_string_terminators))
18701870 {
18711871 // Create a new doctype node
18721872 xml_node<Ch> *doctype = this->allocate_node(node_doctype);
1873 doctype->value(value_, text - value_);
1873 doctype->value(value_, static_cast<std::size_t>(text - value_));
18741874
18751875 // Place zero terminator after value
18761876 if (!(Flags & parse_no_string_terminators))
19021902 skip<node_name_pred, Flags>(text);
19031903 if (text == name_)
19041904 CEREAL_RAPIDXML_PARSE_ERROR("expected PI target", text);
1905 pi->name(name_, text - name_);
1905 pi->name(name_, static_cast<std::size_t>(text - name_));
19061906
19071907 // Skip whitespace between pi target and pi
19081908 skip<whitespace_pred, Flags>(text);
19191919 }
19201920
19211921 // Set pi value (verbatim, no entity expansion or whitespace normalization)
1922 pi->value(value_, text - value_);
1922 pi->value(value_, static_cast<std::size_t>(text - value_));
19231923
19241924 // Place zero terminator after name and value
19251925 if (!(Flags & parse_no_string_terminators))
19861986 if (!(Flags & parse_no_data_nodes))
19871987 {
19881988 xml_node<Ch> *data = this->allocate_node(node_data);
1989 data->value(value_, end - value_);
1989 data->value(value_, static_cast<std::size_t>(end - value_));
19901990 node->append_node(data);
19911991 }
19921992
19931993 // Add data to parent node if no data exists yet
19941994 if (!(Flags & parse_no_element_values))
19951995 if (*node->value() == Ch('\0'))
1996 node->value(value_, end - value_);
1996 node->value(value_, static_cast<std::size_t>(end - value_));
19971997
19981998 // Place zero terminator after value
19991999 if (!(Flags & parse_no_string_terminators))
20362036
20372037 // Create new cdata node
20382038 xml_node<Ch> *cdata = this->allocate_node(node_cdata);
2039 cdata->value(value_, text - value_);
2039 cdata->value(value_, static_cast<std::size_t>(text - value_));
20402040
20412041 // Place zero terminator after value
20422042 if (!(Flags & parse_no_string_terminators))
20582058 skip<node_name_pred, Flags>(text);
20592059 if (text == name_)
20602060 CEREAL_RAPIDXML_PARSE_ERROR("expected element name", text);
2061 element->name(name_, text - name_);
2061 element->name(name_, static_cast<std::size_t>(text - name_));
20622062
20632063 // Skip whitespace between element name and attributes or >
20642064 skip<whitespace_pred, Flags>(text);
22152215 // Skip and validate closing tag name
22162216 Ch *closing_name = text;
22172217 skip<node_name_pred, Flags>(text);
2218 if (!internal::compare(node->name(), node->name_size(), closing_name, text - closing_name, true))
2218 if (!internal::compare(node->name(), node->name_size(), closing_name, static_cast<std::size_t>(text - closing_name), true))
22192219 CEREAL_RAPIDXML_PARSE_ERROR("invalid closing tag name", text);
22202220 }
22212221 else
22312231
22322232 if (contents_end && contents_end != contents_start)
22332233 {
2234 node->value(contents_start, contents_end - contents_start);
2234 node->value(contents_start, static_cast<std::size_t>(contents_end - contents_start));
22352235 node->value()[node->value_size()] = Ch('\0');
22362236 }
22372237 return; // Node closed, finished parsing contents
22742274
22752275 // Create new attribute
22762276 xml_attribute<Ch> *attribute = this->allocate_attribute();
2277 attribute->name(name_, text - name_);
2277 attribute->name(name_, static_cast<std::size_t>(text - name_));
22782278 node->append_attribute(attribute);
22792279
22802280 // Skip whitespace after attribute name
23072307 end = skip_and_expand_character_refs<attribute_value_pred<Ch('"')>, attribute_value_pure_pred<Ch('"')>, AttFlags>(text, false);
23082308
23092309 // Set attribute value
2310 attribute->value(value_, end - value_);
2310 attribute->value(value_, static_cast<std::size_t>(end - value_));
23112311
23122312 // Make sure that end quote is present
23132313 if (*text != quote)
362362 out = print_pi_node(out, node, flags, indent);
363363 break;
364364
365 #ifndef __GNUC__
365366 // Unknown
366367 default:
367368 assert(0);
368369 break;
370 #endif
369371 }
370372
371373 // If indenting not disabled, add line break after node
131131 #endif // end !defined(CEREAL_HAS_NOEXCEPT)
132132 #endif // ifndef CEREAL_NOEXCEPT
133133
134 // ######################################################################
135 //! Checks if C++17 is available
136 #if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)
137 #define CEREAL_HAS_CPP17
138 #endif
139
140 //! Checks if C++14 is available
141 #if __cplusplus >= 201402L
142 #define CEREAL_HAS_CPP14
143 #endif
144
145 // ######################################################################
146 //! Defines the CEREAL_ALIGNOF macro to use instead of alignof
147 #if defined(_MSC_VER) && _MSC_VER < 1900
148 #define CEREAL_ALIGNOF __alignof
149 #else // not MSVC 2013 or older
150 #define CEREAL_ALIGNOF alignof
151 #endif // end MSVC check
152
134153 #endif // CEREAL_MACROS_HPP_
0 /*! \file specialize.hpp
1 \brief Serialization disambiguation */
2 /*
3 Copyright (c) 2014, Randolph Voorhies, Shane Grant
4 All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are met:
8 * Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 * Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 * Neither the name of cereal nor the
14 names of its contributors may be used to endorse or promote products
15 derived from this software without specific prior written permission.
16
17 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20 DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
21 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
22 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
23 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
24 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
26 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #ifndef CEREAL_SPECIALIZE_HPP_
30 #define CEREAL_SPECIALIZE_HPP_
31
32 namespace cereal
33 {
34 // Forward declaration of access class that users can become friends with
35 class access;
36
37 // ######################################################################
38 //! A specifier used in conjunction with cereal::specialize to disambiguate
39 //! serialization in special cases
40 /*! @relates specialize
41 @ingroup Access */
42 enum class specialization
43 {
44 member_serialize, //!< Force the use of a member serialize function
45 member_load_save, //!< Force the use of a member load/save pair
46 member_load_save_minimal, //!< Force the use of a member minimal load/save pair
47 non_member_serialize, //!< Force the use of a non-member serialize function
48 non_member_load_save, //!< Force the use of a non-member load/save pair
49 non_member_load_save_minimal //!< Force the use of a non-member minimal load/save pair
50 };
51
52 //! A class used to disambiguate cases where cereal cannot detect a unique way of serializing a class
53 /*! cereal attempts to figure out which method of serialization (member vs. non-member serialize
54 or load/save pair) at compile time. If for some reason cereal cannot find a non-ambiguous way
55 of serializing a type, it will produce a static assertion complaining about this.
56
57 This can happen because you have both a serialize and load/save pair, or even because a base
58 class has a serialize (public or private with friend access) and a derived class does not
59 overwrite this due to choosing some other serialization type.
60
61 Specializing this class will tell cereal to explicitly use the serialization type you specify
62 and it will not complain about ambiguity in its compile time selection. However, if cereal detects
63 an ambiguity in specializations, it will continue to issue a static assertion.
64
65 @code{.cpp}
66 class MyParent
67 {
68 friend class cereal::access;
69 template <class Archive>
70 void serialize( Archive & ar ) {}
71 };
72
73 // Although serialize is private in MyParent, to cereal::access it will look public,
74 // even through MyDerived
75 class MyDerived : public MyParent
76 {
77 public:
78 template <class Archive>
79 void load( Archive & ar ) {}
80
81 template <class Archive>
82 void save( Archive & ar ) {}
83 };
84
85 // The load/save pair in MyDerived is ambiguous because serialize in MyParent can
86 // be accessed from cereal::access. This looks the same as making serialize public
87 // in MyParent, making it seem as though MyDerived has both a serialize and a load/save pair.
88 // cereal will complain about this at compile time unless we disambiguate:
89
90 namespace cereal
91 {
92 // This struct specialization will tell cereal which is the right way to serialize the ambiguity
93 template <class Archive> struct specialize<Archive, MyDerived, cereal::specialization::member_load_save> {};
94
95 // If we only had a disambiguation for a specific archive type, it would look something like this
96 template <> struct specialize<cereal::BinaryOutputArchive, MyDerived, cereal::specialization::member_load_save> {};
97 }
98 @endcode
99
100 You can also choose to use the macros CEREAL_SPECIALIZE_FOR_ALL_ARCHIVES or
101 CEREAL_SPECIALIZE_FOR_ARCHIVE if you want to type a little bit less.
102
103 @tparam T The type to specialize the serialization for
104 @tparam S The specialization type to use for T
105 @ingroup Access */
106 template <class Archive, class T, specialization S>
107 struct specialize : public std::false_type {};
108
109 //! Convenient macro for performing specialization for all archive types
110 /*! This performs specialization for the specific type for all types of archives.
111 This macro should be placed at the global namespace.
112
113 @code{cpp}
114 struct MyType {};
115 CEREAL_SPECIALIZE_FOR_ALL_ARCHIVES( MyType, cereal::specialization::member_load_save );
116 @endcode
117
118 @relates specialize
119 @ingroup Access */
120 #define CEREAL_SPECIALIZE_FOR_ALL_ARCHIVES( Type, Specialization ) \
121 namespace cereal { template <class Archive> struct specialize<Archive, Type, Specialization> {}; }
122
123 //! Convenient macro for performing specialization for a single archive type
124 /*! This performs specialization for the specific type for a single type of archive.
125 This macro should be placed at the global namespace.
126
127 @code{cpp}
128 struct MyType {};
129 CEREAL_SPECIALIZE_FOR_ARCHIVE( cereal::XMLInputArchive, MyType, cereal::specialization::member_load_save );
130 @endcode
131
132 @relates specialize
133 @ingroup Access */
134 #define CEREAL_SPECIALIZE_FOR_ARCHIVE( Archive, Type, Specialization ) \
135 namespace cereal { template <> struct specialize<Archive, Type, Specialization> {}; }
136 }
137
138 #endif
0 /*! \file atomic.hpp
1 \brief Support for types found in \<atomic\>
2 \ingroup STLSupport */
3 /*
4 Copyright (c) 2014, Randolph Voorhies, Shane Grant
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in the
13 documentation and/or other materials provided with the distribution.
14 * Neither the name of cereal nor the
15 names of its contributors may be used to endorse or promote products
16 derived from this software without specific prior written permission.
17
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
22 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 #ifndef CEREAL_TYPES_ATOMIC_HPP_
30 #define CEREAL_TYPES_ATOMIC_HPP_
31
32 #include <cereal/cereal.hpp>
33 #include <atomic>
34
35 namespace cereal
36 {
37 //! Serializing (save) for std::atomic
38 template <class Archive, class T> inline
39 void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::atomic<T> const & a )
40 {
41 ar( CEREAL_NVP_("atomic_data", a.load()) );
42 }
43
44 //! Serializing (load) for std::atomic
45 template <class Archive, class T> inline
46 void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::atomic<T> & a )
47 {
48 T tmp;
49 ar( CEREAL_NVP_("atomic_data", tmp) );
50 a.store( tmp );
51 }
52 } // namespace cereal
53
54 #endif // CEREAL_TYPES_ATOMIC_HPP_
6262
6363 This also automatically registers polymorphic relation between the base and derived class, assuming they
6464 are indeed polymorphic. Note this is not the same as polymorphic type registration. For more information
65 see the documentation on polymorphism.
65 see the documentation on polymorphism. If using a polymorphic class, be sure to include support for
66 polymorphism (cereal/types/polymorphic.hpp).
6667
6768 \sa virtual_base_class
6869
119120
120121 This also automatically registers polymorphic relation between the base and derived class, assuming they
121122 are indeed polymorphic. Note this is not the same as polymorphic type registration. For more information
122 see the documentation on polymorphism.
123 see the documentation on polymorphism. If using a polymorphic class, be sure to include support for
124 polymorphism (cereal/types/polymorphic.hpp).
123125
124126 \sa base_class
125127
6666 if( bits[i] )
6767 chunk |= mask;
6868
69 mask >>= 1;
69 mask = static_cast<std::uint8_t>(mask >> 1);
7070
7171 // output current chunk when mask is empty (8 bits)
7272 if( mask == 0 )
162162 if( chunk & mask )
163163 bits[i] = 1;
164164
165 mask >>= 1;
165 mask = static_cast<std::uint8_t>(mask >> 1);
166166 }
167167 break;
168168 }
2929 #ifndef CEREAL_TYPES_BOOST_VARIANT_HPP_
3030 #define CEREAL_TYPES_BOOST_VARIANT_HPP_
3131
32 //! @internal
33 #if defined(_MSC_VER) && _MSC_VER < 1911
34 #define CEREAL_CONSTEXPR_LAMBDA
35 #else // MSVC 2017 or newer, all other compilers
36 #define CEREAL_CONSTEXPR_LAMBDA constexpr
37 #endif
38
3239 #include "cereal/cereal.hpp"
33 #include <boost/variant.hpp>
34 #include <boost/mpl/size.hpp>
40 #include <boost/variant/variant_fwd.hpp>
41 #include <boost/variant/static_visitor.hpp>
3542
3643 namespace cereal
3744 {
38 namespace variant_detail
45 namespace boost_variant_detail
3946 {
4047 //! @internal
4148 template <class Archive>
4451 variant_save_visitor(Archive & ar_) : ar(ar_) {}
4552
4653 template<class T>
47 void operator()(T const & value) const
48 {
49 ar( CEREAL_NVP_("data", value) );
50 }
54 void operator()(T const & value) const
55 {
56 ar( CEREAL_NVP_("data", value) );
57 }
5158
5259 Archive & ar;
5360 };
5461
5562 //! @internal
56 template<int N, class Variant, class ... Args, class Archive>
57 typename std::enable_if<N == boost::mpl::size<typename Variant::types>::value, void>::type
58 load_variant(Archive & /*ar*/, int /*target*/, Variant & /*variant*/)
63 template <class Archive, class T>
64 struct LoadAndConstructLoadWrapper
5965 {
60 throw ::cereal::Exception("Error traversing variant during load");
61 }
66 using ST = typename std::aligned_storage<sizeof(T), CEREAL_ALIGNOF(T)>::type;
67
68 LoadAndConstructLoadWrapper() :
69 construct( reinterpret_cast<T *>( &st ) )
70 { }
71
72 ~LoadAndConstructLoadWrapper()
73 {
74 if (construct.itsValid)
75 {
76 construct->~T();
77 }
78 }
79
80 void CEREAL_SERIALIZE_FUNCTION_NAME( Archive & ar )
81 {
82 ::cereal::detail::Construct<T, Archive>::load_andor_construct( ar, construct );
83 }
84
85 ST st;
86 ::cereal::construct<T> construct;
87 };
6288
6389 //! @internal
64 template<int N, class Variant, class H, class ... T, class Archive>
65 typename std::enable_if<N < boost::mpl::size<typename Variant::types>::value, void>::type
66 load_variant(Archive & ar, int target, Variant & variant)
90 template <class T> struct load_variant_wrapper;
91
92 //! Avoid serializing variant void_ type
93 /*! @internal */
94 template <>
95 struct load_variant_wrapper<boost::detail::variant::void_>
6796 {
68 if(N == target)
97 template <class Variant, class Archive>
98 static void load_variant( Archive &, Variant & )
99 { }
100 };
101
102 //! @internal
103 template <class T>
104 struct load_variant_wrapper
105 {
106 // default constructible
107 template <class Archive, class Variant>
108 static void load_variant_impl( Archive & ar, Variant & variant, std::true_type )
69109 {
70 H value;
110 T value;
71111 ar( CEREAL_NVP_("data", value) );
72 variant = value;
112 variant = std::move(value);
73113 }
74 else
75 load_variant<N+1, Variant, T...>(ar, target, variant);
76 }
77114
78 } // namespace variant_detail
115 // not default constructible
116 template<class Variant, class Archive>
117 static void load_variant_impl(Archive & ar, Variant & variant, std::false_type )
118 {
119 LoadAndConstructLoadWrapper<Archive, T> loadWrapper;
120
121 ar( CEREAL_NVP_("data", loadWrapper) );
122 variant = std::move(*loadWrapper.construct.ptr());
123 }
124
125 //! @internal
126 template<class Variant, class Archive>
127 static void load_variant(Archive & ar, Variant & variant)
128 {
129 load_variant_impl( ar, variant, typename std::is_default_constructible<T>::type() );
130 }
131 };
132 } // namespace boost_variant_detail
79133
80134 //! Saving for boost::variant
81 template <class Archive, typename VariantType1, typename... VariantTypes> inline
82 void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, boost::variant<VariantType1, VariantTypes...> const & variant )
135 template <class Archive, typename ... VariantTypes> inline
136 void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, boost::variant<VariantTypes...> const & variant )
83137 {
84138 int32_t which = variant.which();
85139 ar( CEREAL_NVP_("which", which) );
86 variant_detail::variant_save_visitor<Archive> visitor(ar);
140 boost_variant_detail::variant_save_visitor<Archive> visitor(ar);
87141 variant.apply_visitor(visitor);
88142 }
89143
90144 //! Loading for boost::variant
91 template <class Archive, typename VariantType1, typename... VariantTypes> inline
92 void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, boost::variant<VariantType1, VariantTypes...> & variant )
145 template <class Archive, typename ... VariantTypes> inline
146 void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, boost::variant<VariantTypes...> & variant )
93147 {
94 typedef typename boost::variant<VariantType1, VariantTypes...>::types types;
95
96148 int32_t which;
97149 ar( CEREAL_NVP_("which", which) );
98 if(which >= boost::mpl::size<types>::value)
150
151 using LoadFuncType = void(*)(Archive &, boost::variant<VariantTypes...> &);
152 CEREAL_CONSTEXPR_LAMBDA LoadFuncType loadFuncArray[] = {&boost_variant_detail::load_variant_wrapper<VariantTypes>::load_variant...};
153
154 if(which >= int32_t(sizeof(loadFuncArray)/sizeof(loadFuncArray[0])))
99155 throw Exception("Invalid 'which' selector when deserializing boost::variant");
100156
101 variant_detail::load_variant<0, boost::variant<VariantType1, VariantTypes...>, VariantType1, VariantTypes...>(ar, which, variant);
157 loadFuncArray[which](ar, variant);
102158 }
103159 } // namespace cereal
104160
161 #undef CEREAL_CONSTEXPR_LAMBDA
162
105163 #endif // CEREAL_TYPES_BOOST_VARIANT_HPP_
3333 #include <memory>
3434 #include <cstring>
3535
36 // Work around MSVC not having alignof
37 #if defined(_MSC_VER) && _MSC_VER < 1900
38 #define CEREAL_ALIGNOF __alignof
39 #else // not MSVC 2013 or older
40 #define CEREAL_ALIGNOF alignof
41 #endif // end MSVC check
42
4336 namespace cereal
4437 {
4538 namespace memory_detail
5346 PtrWrapper(T && p) : ptr(std::forward<T>(p)) {}
5447 T & ptr;
5548
49 PtrWrapper( PtrWrapper const & ) = default;
5650 PtrWrapper & operator=( PtrWrapper const & ) = delete;
5751 };
5852
108102 To get around these issues, we will store the memory for the enable_shared_from_this
109103 portion of the class and replace it after whatever happens to modify it (e.g. the
110104 user performing construction or the wrapper shared_ptr in saving).
105
106 Note that this goes into undefined behavior territory, but as of the initial writing
107 of this, all standard library implementations of std::enable_shared_from_this are
108 compatible with this memory manipulation. It is entirely possible that this may someday
109 break or may not work with convoluted use cases.
111110
112111 Example usage:
113112
135134 using BaseType = typename ::cereal::traits::get_shared_from_this_base<T>::type;
136135 using ParentType = std::enable_shared_from_this<BaseType>;
137136 using StorageType = typename std::aligned_storage<sizeof(ParentType), CEREAL_ALIGNOF(ParentType)>::type;
138
137
139138 public:
140139 //! Saves the state of some type inheriting from enable_shared_from_this
141140 /*! @param ptr The raw pointer held by the shared_ptr */
152151 {
153152 if( !itsRestored )
154153 {
155 std::memcpy( itsPtr, &itsState, sizeof(ParentType) );
154 // void * cast needed when type has no trivial copy-assignment
155 std::memcpy( static_cast<void *>(itsPtr), &itsState, sizeof(ParentType) );
156156 itsRestored = true;
157157 }
158158 }
277277 typename std::enable_if<traits::has_load_and_construct<T, Archive>::value, void>::type
278278 CEREAL_LOAD_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::shared_ptr<T> &> & wrapper )
279279 {
280 auto & ptr = wrapper.ptr;
281
282280 uint32_t id;
283281
284282 ar( CEREAL_NVP_("id", id) );
296294
297295 // Allocate our storage, which we will treat as
298296 // uninitialized until initialized with placement new
299 ptr.reset( reinterpret_cast<T *>( new ST() ),
300 [=]( T * t )
297 using NonConstT = typename std::remove_const<T>::type;
298 std::shared_ptr<NonConstT> ptr(reinterpret_cast<NonConstT *>(new ST()),
299 [=]( NonConstT * t )
301300 {
302301 if( *valid )
303302 t->~T();
309308 ar.registerSharedPointer( id, ptr );
310309
311310 // Perform the actual loading and allocation
312 memory_detail::loadAndConstructSharedPtr( ar, ptr.get(), typename ::cereal::traits::has_shared_from_this<T>::type() );
311 memory_detail::loadAndConstructSharedPtr( ar, ptr.get(), typename ::cereal::traits::has_shared_from_this<NonConstT>::type() );
313312
314313 // Mark pointer as valid (initialized)
315314 *valid = true;
315 wrapper.ptr = std::move(ptr);
316316 }
317317 else
318 ptr = std::static_pointer_cast<T>(ar.getSharedPointer(id));
318 wrapper.ptr = std::static_pointer_cast<T>(ar.getSharedPointer(id));
319319 }
320320
321321 //! Loading std::shared_ptr, case when no user load and construct (wrapper implementation)
324324 typename std::enable_if<!traits::has_load_and_construct<T, Archive>::value, void>::type
325325 CEREAL_LOAD_FUNCTION_NAME( Archive & ar, memory_detail::PtrWrapper<std::shared_ptr<T> &> & wrapper )
326326 {
327 auto & ptr = wrapper.ptr;
328
329327 uint32_t id;
330328
331329 ar( CEREAL_NVP_("id", id) );
332330
333331 if( id & detail::msb_32bit )
334332 {
335 ptr.reset( detail::Construct<T, Archive>::load_andor_construct() );
333 using NonConstT = typename std::remove_const<T>::type;
334 std::shared_ptr<NonConstT> ptr( detail::Construct<NonConstT, Archive>::load_andor_construct() );
336335 ar.registerSharedPointer( id, ptr );
337336 ar( CEREAL_NVP_("data", *ptr) );
337 wrapper.ptr = std::move(ptr);
338338 }
339339 else
340 ptr = std::static_pointer_cast<T>(ar.getSharedPointer(id));
340 wrapper.ptr = std::static_pointer_cast<T>(ar.getSharedPointer(id));
341341 }
342342
343343 //! Saving std::unique_ptr (wrapper implementation)
373373
374374 if( isValid )
375375 {
376 using NonConstT = typename std::remove_const<T>::type;
376377 // Storage type for the pointer - since we can't default construct this type,
377378 // we'll allocate it using std::aligned_storage
378 using ST = typename std::aligned_storage<sizeof(T), CEREAL_ALIGNOF(T)>::type;
379 using ST = typename std::aligned_storage<sizeof(NonConstT), CEREAL_ALIGNOF(NonConstT)>::type;
379380
380381 // Allocate storage - note the ST type so that deleter is correct if
381382 // an exception is thrown before we are initialized
382383 std::unique_ptr<ST> stPtr( new ST() );
383384
384385 // Use wrapper to enter into "data" nvp of ptr_wrapper
385 memory_detail::LoadAndConstructLoadWrapper<Archive, T> loadWrapper( reinterpret_cast<T *>( stPtr.get() ) );
386 memory_detail::LoadAndConstructLoadWrapper<Archive, NonConstT> loadWrapper( reinterpret_cast<NonConstT *>( stPtr.get() ) );
386387
387388 // Initialize storage
388389 ar( CEREAL_NVP_("data", loadWrapper) );
403404 uint8_t isValid;
404405 ar( CEREAL_NVP_("valid", isValid) );
405406
406 auto & ptr = wrapper.ptr;
407
408407 if( isValid )
409408 {
410 ptr.reset( detail::Construct<T, Archive>::load_andor_construct() );
409 using NonConstT = typename std::remove_const<T>::type;
410 std::unique_ptr<NonConstT, D> ptr( detail::Construct<NonConstT, Archive>::load_andor_construct() );
411411 ar( CEREAL_NVP_( "data", *ptr ) );
412 wrapper.ptr = std::move(ptr);
412413 }
413414 else
414415 {
415 ptr.reset( nullptr );
416 wrapper.ptr.reset( nullptr );
416417 }
417418 }
418419 } // namespace cereal
420421 // automatically include polymorphic support
421422 #include "cereal/types/polymorphic.hpp"
422423
423 #undef CEREAL_ALIGNOF
424 #endif // CEREAL_TYPES_SHARED_PTR_HPP_
424 #endif // CEREAL_TYPES_SHARED_PTR_HPP_
0 /*! \file optional.hpp
1 \brief Support for std::optional
2 \ingroup STLSupport */
3 /*
4 Copyright (c) 2017, Juan Pedro Bolivar Puente
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in the
13 documentation and/or other materials provided with the distribution.
14 * Neither the name of cereal nor the
15 names of its contributors may be used to endorse or promote products
16 derived from this software without specific prior written permission.
17
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
22 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 #ifndef CEREAL_TYPES_STD_OPTIONAL_
30 #define CEREAL_TYPES_STD_OPTIONAL_
31
32 #include "cereal/cereal.hpp"
33 #include <optional>
34
35 namespace cereal {
36 //! Saving for std::optional
37 template <class Archive, typename T> inline
38 void CEREAL_SAVE_FUNCTION_NAME(Archive& ar, const std::optional<T>& optional)
39 {
40 if(!optional) {
41 ar(CEREAL_NVP_("nullopt", true));
42 } else {
43 ar(CEREAL_NVP_("nullopt", false),
44 CEREAL_NVP_("data", *optional));
45 }
46 }
47
48 //! Loading for std::optional
49 template <class Archive, typename T> inline
50 void CEREAL_LOAD_FUNCTION_NAME(Archive& ar, std::optional<T>& optional)
51 {
52 bool nullopt;
53 ar(CEREAL_NVP_("nullopt", nullopt));
54
55 if (nullopt) {
56 optional = std::nullopt;
57 } else {
58 T value;
59 ar(CEREAL_NVP_("data", value));
60 optional = std::move(value);
61 }
62 }
63 } // namespace cereal
64
65 #endif // CEREAL_TYPES_STD_OPTIONAL_
164164 See CEREAL_REGISTER_DYNAMIC_INIT for detailed explanation
165165 of how this macro should be used. The name used should
166166 match that for CEREAL_REGISTER_DYNAMIC_INIT. */
167 #define CEREAL_FORCE_DYNAMIC_INIT(LibName) \
168 namespace cereal { \
169 namespace detail { \
170 void dynamic_init_dummy_##LibName(); \
171 } /* end detail */ \
172 namespace { \
173 void dynamic_init_##LibName() \
174 { \
175 ::cereal::detail::dynamic_init_dummy_##LibName(); \
176 } \
177 } } /* end namespaces */
167 #define CEREAL_FORCE_DYNAMIC_INIT(LibName) \
168 namespace cereal { \
169 namespace detail { \
170 void CEREAL_DLL_EXPORT dynamic_init_dummy_##LibName(); \
171 } /* end detail */ \
172 } /* end cereal */ \
173 namespace { \
174 struct dynamic_init_##LibName { \
175 dynamic_init_##LibName() { \
176 ::cereal::detail::dynamic_init_dummy_##LibName(); \
177 } \
178 } dynamic_init_instance_##LibName; \
179 } /* end anonymous namespace */
178180
179181 namespace cereal
180182 {
3737 namespace tuple_detail
3838 {
3939 //! Creates a c string from a sequence of characters
40 /*! The c string created will alwas be prefixed by "tuple_element"
40 /*! The c string created will always be prefixed by "tuple_element"
4141 Based on code from: http://stackoverflow/a/20973438/710791
4242 @internal */
4343 template<char...Cs>
6262 template <size_t Q, size_t R, char ... C>
6363 struct to_string_impl
6464 {
65 using type = typename to_string_impl<Q/10, Q%10, R+'0', C...>::type;
65 using type = typename to_string_impl<Q/10, Q%10, static_cast<char>(R+std::size_t{'0'}), C...>::type;
6666 };
6767
6868 //! Base case with no quotient
7070 template <size_t R, char ... C>
7171 struct to_string_impl<0, R, C...>
7272 {
73 using type = char_seq_to_c_str<R+'0', C...>;
73 using type = char_seq_to_c_str<static_cast<char>(R+std::size_t{'0'}), C...>;
7474 };
7575
7676 //! Generates a c string for a given index of a tuple
8383 struct tuple_element_name
8484 {
8585 using type = typename to_string_impl<T/10, T%10>::type;
86 static const typename type::arr_type c_str(){ return type::str; };
86 static const typename type::arr_type c_str(){ return type::str; }
8787 };
8888
8989 // unwinds a tuple to save it
0 /*! \file variant.hpp
1 \brief Support for std::variant
2 \ingroup STLSupport */
3 /*
4 Copyright (c) 2014, 2017, Randolph Voorhies, Shane Grant, Juan Pedro
5 Bolivar Puente. All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions are met:
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in the
13 documentation and/or other materials provided with the distribution.
14 * Neither the name of cereal nor the
15 names of its contributors may be used to endorse or promote products
16 derived from this software without specific prior written permission.
17
18 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
19 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
22 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 #ifndef CEREAL_TYPES_STD_VARIANT_HPP_
30 #define CEREAL_TYPES_STD_VARIANT_HPP_
31
32 #include "cereal/cereal.hpp"
33 #include <variant>
34 #include <cstdint>
35
36 namespace cereal
37 {
38 namespace variant_detail
39 {
40 //! @internal
41 template <class Archive>
42 struct variant_save_visitor
43 {
44 variant_save_visitor(Archive & ar_) : ar(ar_) {}
45
46 template<class T>
47 void operator()(T const & value) const
48 {
49 ar( CEREAL_NVP_("data", value) );
50 }
51
52 Archive & ar;
53 };
54
55 //! @internal
56 template<int N, class Variant, class ... Args, class Archive>
57 typename std::enable_if<N == std::variant_size_v<Variant>, void>::type
58 load_variant(Archive & /*ar*/, int /*target*/, Variant & /*variant*/)
59 {
60 throw ::cereal::Exception("Error traversing variant during load");
61 }
62 //! @internal
63 template<int N, class Variant, class H, class ... T, class Archive>
64 typename std::enable_if<N < std::variant_size_v<Variant>, void>::type
65 load_variant(Archive & ar, int target, Variant & variant)
66 {
67 if(N == target)
68 {
69 H value;
70 ar( CEREAL_NVP_("data", value) );
71 variant = std::move(value);
72 }
73 else
74 load_variant<N+1, Variant, T...>(ar, target, variant);
75 }
76
77 } // namespace variant_detail
78
79 //! Saving for std::variant
80 template <class Archive, typename VariantType1, typename... VariantTypes> inline
81 void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::variant<VariantType1, VariantTypes...> const & variant )
82 {
83 std::int32_t index = static_cast<std::int32_t>(variant.index());
84 ar( CEREAL_NVP_("index", index) );
85 variant_detail::variant_save_visitor<Archive> visitor(ar);
86 std::visit(visitor, variant);
87 }
88
89 //! Loading for std::variant
90 template <class Archive, typename... VariantTypes> inline
91 void CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::variant<VariantTypes...> & variant )
92 {
93 using variant_t = typename std::variant<VariantTypes...>;
94
95 std::int32_t index;
96 ar( CEREAL_NVP_("index", index) );
97 if(index >= static_cast<std::int32_t>(std::variant_size_v<variant_t>))
98 throw Exception("Invalid 'index' selector when deserializing std::variant");
99
100 variant_detail::load_variant<0, variant_t, VariantTypes...>(ar, index, variant);
101 }
102
103 //! Serializing a std::monostate
104 template <class Archive>
105 void CEREAL_SERIALIZE_FUNCTION_NAME( Archive &, std::monostate const & ) {}
106 } // namespace cereal
107
108 #endif // CEREAL_TYPES_STD_VARIANT_HPP_
5959
6060 //! Serialization for non-arithmetic vector types
6161 template <class Archive, class T, class A> inline
62 typename std::enable_if<!traits::is_output_serializable<BinaryData<T>, Archive>::value
63 || !std::is_arithmetic<T>::value, void>::type
62 typename std::enable_if<(!traits::is_output_serializable<BinaryData<T>, Archive>::value
63 || !std::is_arithmetic<T>::value) && !std::is_same<T, bool>::value, void>::type
6464 CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::vector<T, A> const & vector )
6565 {
6666 ar( make_size_tag( static_cast<size_type>(vector.size()) ) ); // number of elements
7070
7171 //! Serialization for non-arithmetic vector types
7272 template <class Archive, class T, class A> inline
73 typename std::enable_if<!traits::is_input_serializable<BinaryData<T>, Archive>::value
74 || !std::is_arithmetic<T>::value, void>::type
73 typename std::enable_if<(!traits::is_input_serializable<BinaryData<T>, Archive>::value
74 || !std::is_arithmetic<T>::value) && !std::is_same<T, bool>::value, void>::type
7575 CEREAL_LOAD_FUNCTION_NAME( Archive & ar, std::vector<T, A> & vector )
7676 {
7777 size_type size;
8787 void CEREAL_SAVE_FUNCTION_NAME( Archive & ar, std::vector<bool, A> const & vector )
8888 {
8989 ar( make_size_tag( static_cast<size_type>(vector.size()) ) ); // number of elements
90 for(auto && v : vector)
90 for(const auto v : vector)
9191 ar( static_cast<bool>(v) );
9292 }
9393
9999 ar( make_size_tag( size ) );
100100
101101 vector.resize( static_cast<std::size_t>( size ) );
102 for(auto && v : vector)
102 for(auto v : vector)
103103 {
104104 bool b;
105105 ar( b );
0 /*! \file version.hpp
1 \brief Macros to detect cereal version
2
3 These macros can assist in determining the version of cereal. Be
4 warned that cereal is not guaranteed to be compatible across
5 different versions. For more information on releases of cereal,
6 see https://github.com/USCiLab/cereal/releases.
7
8 \ingroup utility */
9 /*
10 Copyright (c) 2018, Shane Grant
11 All rights reserved.
12
13 Redistribution and use in source and binary forms, with or without
14 modification, are permitted provided that the following conditions are met:
15 * Redistributions of source code must retain the above copyright
16 notice, this list of conditions and the following disclaimer.
17 * Redistributions in binary form must reproduce the above copyright
18 notice, this list of conditions and the following disclaimer in the
19 documentation and/or other materials provided with the distribution.
20 * Neither the name of cereal nor the
21 names of its contributors may be used to endorse or promote products
22 derived from this software without specific prior written permission.
23
24 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
25 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
27 DISCLAIMED. IN NO EVENT SHALL RANDOLPH VOORHIES OR SHANE GRANT BE LIABLE FOR ANY
28 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
31 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
33 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 #ifndef CEREAL_VERSION_HPP_
37 #define CEREAL_VERSION_HPP_
38
39 //! The major version
40 #define CEREAL_VERSION_MAJOR 1
41 //! The minor version
42 #define CEREAL_VERSION_MINOR 3
43 //! The patch version
44 #define CEREAL_VERSION_PATCH 0
45
46 //! The full version as a single number
47 #define CEREAL_VERSION (CEREAL_VERSION_MAJOR * 10000 \
48 + CEREAL_VERSION_MINOR * 100 \
49 + CEREAL_VERSION_PATCH)
50
51 #endif // CEREAL_VERSION_HPP_
5858 return labels[text].get();
5959 }
6060
61 Button::Button() {
62 label = "";
63 marked = false;
64 action = nullptr;
65 popOnRun = false;
66 }
67
68 Button::~Button() {
69 }
70
7161 Button::Button(const Button& b) : action{b.action}, label{b.label}, marked{b.marked} {
7262 }
7363
151141 placeButtons();
152142 }
153143
154 Menu::Menu(SDL_Renderer* screen) {
155 this->screen = screen;
156 buttons = std::vector<Button*>(10);
157 isSubmenu = true;
144 Menu::Menu(SDL_Renderer* screen) : buttons{std::vector<Button*>(10)}, isSubmenu{true}, screen{screen} {
158145 exit.setLabel( _("Back") );
159146 }
160147
161 Menu::Menu(SDL_Renderer* screen,bool submenu) {
162 this->screen = screen;
163 buttons = std::vector<Button*>(0);
164 isSubmenu = submenu;
148 Menu::Menu(SDL_Renderer* screen,bool submenu) : buttons{std::vector<Button*>(0)}, isSubmenu{submenu}, screen{screen} {
165149 if (isSubmenu) {
166150 exit.setLabel( _("Back") );
167151 }
170154 }
171155 }
172156
173 Menu::Menu(SDL_Renderer* screen, const std::string& title, bool submenu) : title{title} {
174 this->screen = screen;
175 buttons = std::vector<Button*>(0);
176 isSubmenu = submenu;
157 Menu::Menu(SDL_Renderer* screen, const std::string& title, bool submenu) : buttons{std::vector<Button*>(0)}, isSubmenu{submenu}, screen{screen}, title{title} {
177158 if (isSubmenu) {
178159 exit.setLabel(_("Back") );
179160 }
188169 return true;
189170 }
190171 }
172 return isControllerUpEvent(event);
173 }
174
175 bool isDownEvent(const SDL_Event& event) {
176 if ( event.type == SDL_KEYDOWN ) {
177 if (event.key.keysym.sym == SDLK_DOWN) {
178 return true;
179 }
180 }
181 return isControllerDownEvent(event);
182 }
183
184 bool isLeftEvent(const SDL_Event& event) {
185 if ( event.type == SDL_KEYDOWN ) {
186 if (event.key.keysym.sym == SDLK_LEFT) {
187 return true;
188 }
189 }
190 return isControllerLeftEvent(event);
191 }
192
193 bool isRightEvent(const SDL_Event& event) {
194 if ( event.type == SDL_KEYDOWN ) {
195 if (event.key.keysym.sym == SDLK_RIGHT) {
196 return true;
197 }
198 }
199 return isControllerRightEvent(event);
200 }
201
202 bool isEscapeEvent(const SDL_Event& event) {
203 if ( event.type == SDL_KEYDOWN ) {
204 if ( event.key.keysym.sym == SDLK_ESCAPE ) {
205 return true;
206 }
207 }
191208 if (event.type == SDL_CONTROLLERBUTTONDOWN) {
192 if (event.cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_UP ) {
193 return true;
194 }
195 }
196 if (event.type == SDL_CONTROLLERAXISMOTION && event.caxis.axis == SDL_CONTROLLER_AXIS_LEFTY ) {
197 checkDeadZone(event);
198 const SDL_ControllerAxisEvent& a = event.caxis;
199 if (getDeadZone(a.which, a.axis)) {
200 if (event.caxis.value < -deadZoneLimit) {
201 setDeadZone(a.which,a.axis,false);
202 return true;
203 }
209 if (event.cbutton.button == SDL_CONTROLLER_BUTTON_B || event.cbutton.button == SDL_CONTROLLER_BUTTON_BACK ) {
210 return true;
204211 }
205212 }
206213 return false;
207214 }
208215
209 bool isDownEvent(const SDL_Event& event) {
210 if ( event.type == SDL_KEYDOWN ) {
211 if (event.key.keysym.sym == SDLK_DOWN) {
216 bool isConfirmEvent(const SDL_Event& event) {
217 if ( event.type == SDL_KEYDOWN ) {
218 if (event.key.keysym.sym == SDLK_RETURN || event.key.keysym.sym == SDLK_KP_ENTER ) {
212219 return true;
213220 }
214221 }
215222 if (event.type == SDL_CONTROLLERBUTTONDOWN) {
216 if (event.cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN ) {
217 return true;
218 }
219 }
220 if (event.type == SDL_CONTROLLERAXISMOTION && event.caxis.axis == SDL_CONTROLLER_AXIS_LEFTY ) {
221 checkDeadZone(event);
222 const SDL_ControllerAxisEvent& a = event.caxis;
223 if (getDeadZone(a.which, a.axis)) {
224 if (event.caxis.value > deadZoneLimit) {
225 setDeadZone(a.which,a.axis,false);
226 return true;
227 }
228 }
229 }
230 return false;
231 }
232
233 bool isLeftEvent(const SDL_Event& event) {
234 if ( event.type == SDL_KEYDOWN ) {
235 if (event.key.keysym.sym == SDLK_LEFT) {
236 return true;
237 }
238 }
239 if (event.type == SDL_CONTROLLERBUTTONDOWN) {
240 if (event.cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT ) {
241 return true;
242 }
243 }
244 if (event.type == SDL_CONTROLLERAXISMOTION && event.caxis.axis == SDL_CONTROLLER_AXIS_LEFTX ) {
245 checkDeadZone(event);
246 const SDL_ControllerAxisEvent& a = event.caxis;
247 if (getDeadZone(a.which, a.axis)) {
248 if (event.caxis.value < -deadZoneLimit) {
249 setDeadZone(a.which,a.axis,false);
250 return true;
251 }
252 }
253 }
254 return false;
255 }
256
257 bool isRightEvent(const SDL_Event& event) {
258 if ( event.type == SDL_KEYDOWN ) {
259 if (event.key.keysym.sym == SDLK_RIGHT) {
260 return true;
261 }
262 }
263 if (event.type == SDL_CONTROLLERBUTTONDOWN) {
264 if (event.cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT ) {
265 return true;
266 }
267 }
268 if (event.type == SDL_CONTROLLERAXISMOTION && event.caxis.axis == SDL_CONTROLLER_AXIS_LEFTX ) {
269 checkDeadZone(event);
270 const SDL_ControllerAxisEvent& a = event.caxis;
271 if (getDeadZone(a.which, a.axis)) {
272 if (event.caxis.value > deadZoneLimit) {
273 setDeadZone(a.which,a.axis,false);
274 return true;
275 }
276 }
277 }
278 return false;
279 }
280
281 bool isEscapeEvent(const SDL_Event& event) {
282 if ( event.type == SDL_KEYDOWN ) {
283 if ( event.key.keysym.sym == SDLK_ESCAPE ) {
284 return true;
285 }
286 }
287 if (event.type == SDL_CONTROLLERBUTTONDOWN) {
288 if (event.cbutton.button == SDL_CONTROLLER_BUTTON_Y || event.cbutton.button == SDL_CONTROLLER_BUTTON_BACK ) {
289 return true;
290 }
291 }
292 return false;
293 }
294
295 bool isConfirmEvent(const SDL_Event& event) {
296 if ( event.type == SDL_KEYDOWN ) {
297 if (event.key.keysym.sym == SDLK_RETURN || event.key.keysym.sym == SDLK_KP_ENTER ) {
298 return true;
299 }
300 }
301 if (event.type == SDL_CONTROLLERBUTTONDOWN) {
302 if (event.cbutton.button == SDL_CONTROLLER_BUTTON_A || event.cbutton.button == SDL_CONTROLLER_BUTTON_B ) {
223 if (event.cbutton.button == SDL_CONTROLLER_BUTTON_A ) {
303224 return true;
304225 }
305226 }
333254 #endif
334255 }
335256 void Menu::ProcessInput(const SDL_Event& event, bool& processed) {
257 if (isGameControllerConnectionEvent(event)) {
258 UnInitGameControllers();
259 InitGameControllers();
260 processed = true;
261 }
262
336263 if (isUpEvent(event)) {
337264 marked--;
338265 if (marked<0) {
6666 int x = 0;
6767 int y = 0;
6868
69 Button();
69 Button() = default;
7070 Button(const Button& b);
7171 Button& operator=(const Button& other);
72 virtual ~Button();
72 virtual ~Button() = default;
7373
7474
7575 //Set the text to write on the button
103103 //numberOfItems is the expected numberOfItems for vector initialization
104104 //SubMenu is true by default
105105 Menu(SDL_Renderer *screen,bool isSubmenu);
106 Menu(SDL_Renderer *screen);
106 explicit Menu(SDL_Renderer *screen);
107107 Menu(SDL_Renderer *screen, const std::string& title, bool isSubmenu);
108108 virtual ~Menu() {}
109
109
110110 //Add a button to the menu
111111 void addButton(Button *b);
112
112
113113 bool IsActive() override;
114114 void Draw(SDL_Renderer* target) override;
115115 void ProcessInput(const SDL_Event& event, bool &processed) override;
7070 return ReadKey(key.key.keysym.sym);
7171 }
7272
73 bool ReadKeyboard::cursorLeft() {
74 if (position>text_string.begin()) {
75 utf8::prior(position, text_string.begin());
76 return true;
77 }
78 return false;
79 }
80 bool ReadKeyboard::cursorRight() {
81 if (position<text_string.end()) {
82 utf8::next(position, text_string.end());
83 return true;
84 }
85 return false;
86 }
87
88 bool ReadKeyboard::emulateBackspace() {
89 if (position>text_string.begin()) {
90 utf8::prior(position, text_string.begin());
91 ReadKeyboard::removeChar();
92 return true;
93 }
94 return false;
95 }
96
7397 bool ReadKeyboard::ReadKey(SDL_Keycode keyPressed) {
7498 if (keyPressed == SDLK_DELETE) {
7599 if ((text_string.length()>0)&& (position<text_string.end())) {
78102 return true;
79103 }
80104 if (keyPressed == SDLK_BACKSPACE) {
81 if (position>text_string.begin()) {
82 utf8::prior(position, text_string.begin());
83 ReadKeyboard::removeChar();
84 return true;
85 }
86 return false;
105 return emulateBackspace();
87106 }
88107 if (keyPressed == SDLK_HOME) {
89108 position = text_string.begin();
93112 position=text_string.end();
94113 return true;
95114 }
96 if ((keyPressed == SDLK_LEFT) && (position>text_string.begin())) {
97 utf8::prior(position, text_string.begin());
115 if (keyPressed == SDLK_LEFT) {
116 cursorLeft();
98117 return true;
99118 }
100 if ((keyPressed == SDLK_RIGHT) && (position<text_string.end())) {
101 utf8::next(position, text_string.end());
119 if ((keyPressed == SDLK_RIGHT)) {
120 cursorRight();
102121 return true;
103122 }
104123 return true;
3636 int maxLength = 0;
3737 std::string::iterator position;
3838 std::string text_string;
39 void putchar(const std::string& );
4039 void removeChar();
4140 public:
4241 ReadKeyboard(void);
4342 ~ReadKeyboard(void);
44 ReadKeyboard(const char*);
43 explicit ReadKeyboard(const char*);
4544 int CharsBeforeCursor(); //Where should the cursor be placed?
45 void putchar(const std::string& );
46 bool cursorLeft();
47 bool cursorRight();
48 bool emulateBackspace();
4649 bool ReadKey(const SDL_Event&);
4750 bool ReadKey(SDL_Keycode); //true if key accepted
4851 const std::string& GetString(void) const;
6969 if (endless) {
7070 std::string header;
7171 switch (level) {
72 case 1:
73 header = _("Endless (Fast):");
74 break;
75 case 2:
76 header = _("Endless (Faster):");
77 break;
78 case 3:
79 header = _("Endless (Even faster):");
80 break;
81 case 4:
82 header = _("Endless (Fastest):");
83 break;
84 default:
85 header = _("Endless:");
72 case 1:
73 header = _("Endless (Fast):");
74 break;
75 case 2:
76 header = _("Endless (Faster):");
77 break;
78 case 3:
79 header = _("Endless (Even faster):");
80 break;
81 case 4:
82 header = _("Endless (Fastest):");
83 break;
84 default:
85 header = _("Endless:");
8686 };
8787 Write(globalData.screen, x+100,y+100, header.c_str() );
8888 }
9292 for (int i =0; i<10; i++) {
9393 record r;
9494 if (endless) {
95 switch(level) {
96 case 1:
97 r = theTopScoresEndless1.getScoreNumber(i);
98 break;
99 case 2:
100 r = theTopScoresEndless2.getScoreNumber(i);
101 break;
102 case 3:
103 r = theTopScoresEndless3.getScoreNumber(i);
104 break;
105 case 4:
106 r = theTopScoresEndless4.getScoreNumber(i);
107 break;
108 default:
109 r = theTopScoresEndless0.getScoreNumber(i);
95 switch (level) {
96 case 1:
97 r = theTopScoresEndless1.getScoreNumber(i);
98 break;
99 case 2:
100 r = theTopScoresEndless2.getScoreNumber(i);
101 break;
102 case 3:
103 r = theTopScoresEndless3.getScoreNumber(i);
104 break;
105 case 4:
106 r = theTopScoresEndless4.getScoreNumber(i);
107 break;
108 default:
109 r = theTopScoresEndless0.getScoreNumber(i);
110110 }
111111 }
112112 else {
194194
195195 void ScoresDisplay::Draw(SDL_Renderer*) {
196196 switch (page) {
197 case 0:
198 case 1:
199 case 2:
200 case 3:
201 case 4:
202 //Highscores, endless
203 DrawHighscores(100,100,true, page);
204 break;
205 case 5:
206 //Highscores, Time Trial
207 DrawHighscores(100,100,false);
208 break;
209 case 6:
210 default:
211 DrawStats();
197 case 0:
198 case 1:
199 case 2:
200 case 3:
201 case 4:
202 //Highscores, endless
203 DrawHighscores(100,100,true, page);
204 break;
205 case 5:
206 //Highscores, Time Trial
207 DrawHighscores(100,100,false);
208 break;
209 case 6:
210 default:
211 DrawStats();
212212 };
213213
214214 const sago::SagoDataHolder* holder = &globalData.spriteHolder->GetDataHolder();
1616 ===========================================================================
1717 */
1818
19 #include "DialogBox.hpp"
20 #include "HelpCommon.hpp"
1921 #include "ShowFileState.hpp"
2022 #include "global.hpp"
2123 #include "common.h"
3335 field.SetText(text);
3436 }
3537
36 static void setHelpGamepadFont(const sago::SagoDataHolder* holder, sago::SagoTextBox& field, const char* text) {
37 field.SetHolder(holder);
38 field.SetFont("freeserif");
39 field.SetColor({255,255,255,255});
40 field.SetColor({0,0,0,255});
41 field.SetFontSize(20);
42 field.SetOutline(0, {0,0,0,255});
43 field.SetText(text);
44 }
45
4638 ShowFileState::ShowFileState() {
4739 setHelpGamepadFont(&globalData.spriteHolder->GetDataHolder(), titleField, "");
48 setHelpGamepadFont(&globalData.spriteHolder->GetDataHolder(), infoBox, "");
49 setHelpGamepadFont(&globalData.spriteHolder->GetDataHolder(), filenameField, "");
40 setHelpBoxFont(&globalData.spriteHolder->GetDataHolder(), infoBox, "");
41 setHelpBoxFont(&globalData.spriteHolder->GetDataHolder(), filenameField, "");
5042 }
5143
5244 ShowFileState::~ShowFileState() {
6557 processed = true;
6658 }
6759 }
68
69 extern void DrawRectYellow(SDL_Renderer* target, int topx, int topy, int height, int width);
7060
7161 void ShowFileState::Draw(SDL_Renderer* target) {
7262 DrawBackground(target);
10393 }
10494
10595 }
106 }
96 }
3838 static std::map<SDL_JoystickID, ControllerStatus> controllerStatusMap;
3939 static std::map<std::string, int> gamecontrollers_assigned;
4040 static std::vector<std::string> supportedControllers;
41 static std::vector<SDL_GameController*> controllersOpened;
4142
4243
4344 void GameControllerSetVerbose(bool value) {
7980 return 2; //Even number means player 2
8081 }
8182 return 1;
83 }
84
85 void UnInitGameControllers() {
86 if (controllersOpened.empty()) {
87 return;
88 }
89 for (SDL_GameController* t : controllersOpened) {
90 SDL_GameControllerClose(t);
91 }
92 controllersOpened.clear();
93 controllerStatusMap.clear();
94 gamecontrollers_assigned.clear();
95 supportedControllers.clear();
8296 }
8397
8498 void InitGameControllers() {
100114 int assingToPlayer = GetNextPlayerByGui(guid);
101115 controllerStatusMap[instanceId].player = assingToPlayer;
102116 supportedControllers.push_back(GameControllerGetName(controller));
117 controllersOpened.push_back(controller);
103118 if (verbose) {
104119 std::cout << "Supported game controller detected: " << GameControllerGetName(controller) << ", mapping: " << SDL_GameControllerMapping(controller) << "\n";
105120 std::cout << "Assigned to player: " << controllerStatusMap[instanceId].player << "\n";
147162 return true;
148163 }
149164
165
166 bool isGameControllerConnectionEvent(const SDL_Event& event) {
167 if ( event.type == SDL_CONTROLLERDEVICEADDED
168 || event.type == SDL_CONTROLLERDEVICEREMOVED
169 || event.type == SDL_CONTROLLERDEVICEREMAPPED ) {
170 return true;
171 }
172 return false;
173 }
174
175 bool isControllerDownEvent(const SDL_Event& event) {
176 if (event.type == SDL_CONTROLLERBUTTONDOWN) {
177 if (event.cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN ) {
178 return true;
179 }
180 }
181 if (event.type == SDL_CONTROLLERAXISMOTION && event.caxis.axis == SDL_CONTROLLER_AXIS_LEFTY ) {
182 const SDL_ControllerAxisEvent& a = event.caxis;
183 checkDeadZone(event);
184 if (getDeadZone(a.which, a.axis)) {
185 if (event.caxis.value > deadZoneLimit) {
186 setDeadZone(a.which,a.axis,false);
187 return true;
188 }
189 }
190 }
191 return false;
192 }
193
150194 bool isPlayerDownEvent(int playerNumber, const SDL_Event& event) {
151195 if (skipThisPlayer(playerNumber, event)) {
152196 return false;
153197 }
154 if (event.type == SDL_CONTROLLERBUTTONDOWN) {
155 if (event.cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_DOWN ) {
198 return isControllerDownEvent(event);
199 }
200
201 bool isControllerUpEvent(const SDL_Event& event) {
202 if (event.type == SDL_CONTROLLERBUTTONDOWN) {
203 if (event.cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_UP ) {
156204 return true;
157205 }
158206 }
159207 if (event.type == SDL_CONTROLLERAXISMOTION && event.caxis.axis == SDL_CONTROLLER_AXIS_LEFTY ) {
160 const SDL_ControllerAxisEvent& a = event.caxis;
161 checkDeadZone(event);
208 checkDeadZone(event);
209 const SDL_ControllerAxisEvent& a = event.caxis;
210 if (getDeadZone(a.which, a.axis)) {
211 if (event.caxis.value < -deadZoneLimit) {
212 setDeadZone(a.which,a.axis,false);
213 return true;
214 }
215 }
216 }
217 return false;
218 }
219
220 bool isPlayerUpEvent(int playerNumber, const SDL_Event& event) {
221 if (skipThisPlayer(playerNumber, event)) {
222 return false;
223 }
224 return isControllerUpEvent(event);
225 }
226
227 bool isControllerLeftEvent(const SDL_Event& event) {
228 if (event.type == SDL_CONTROLLERBUTTONDOWN) {
229 if (event.cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT ) {
230 return true;
231 }
232 }
233 if (event.type == SDL_CONTROLLERAXISMOTION && event.caxis.axis == SDL_CONTROLLER_AXIS_LEFTX ) {
234 checkDeadZone(event);
235 const SDL_ControllerAxisEvent& a = event.caxis;
236 if (getDeadZone(a.which, a.axis)) {
237 if (event.caxis.value < -deadZoneLimit) {
238 setDeadZone(a.which,a.axis,false);
239 return true;
240 }
241 }
242 }
243 return false;
244 }
245
246 bool isPlayerLeftEvent(int playerNumber, const SDL_Event& event) {
247 if (skipThisPlayer(playerNumber, event)) {
248 return false;
249 }
250 return isControllerLeftEvent(event);
251 }
252
253 bool isControllerRightEvent(const SDL_Event& event) {
254 if (event.type == SDL_CONTROLLERBUTTONDOWN) {
255 if (event.cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT ) {
256 return true;
257 }
258 }
259 if (event.type == SDL_CONTROLLERAXISMOTION && event.caxis.axis == SDL_CONTROLLER_AXIS_LEFTX ) {
260 checkDeadZone(event);
261 const SDL_ControllerAxisEvent& a = event.caxis;
162262 if (getDeadZone(a.which, a.axis)) {
163263 if (event.caxis.value > deadZoneLimit) {
164264 setDeadZone(a.which,a.axis,false);
169269 return false;
170270 }
171271
172 bool isPlayerUpEvent(int playerNumber, const SDL_Event& event) {
173 if (skipThisPlayer(playerNumber, event)) {
174 return false;
175 }
176 if (event.type == SDL_CONTROLLERBUTTONDOWN) {
177 if (event.cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_UP ) {
178 return true;
179 }
180 }
181 if (event.type == SDL_CONTROLLERAXISMOTION && event.caxis.axis == SDL_CONTROLLER_AXIS_LEFTY ) {
182 checkDeadZone(event);
183 const SDL_ControllerAxisEvent& a = event.caxis;
184 if (getDeadZone(a.which, a.axis)) {
185 if (event.caxis.value < -deadZoneLimit) {
186 setDeadZone(a.which,a.axis,false);
187 return true;
188 }
189 }
190 }
191 return false;
192 }
193
194 bool isPlayerLeftEvent(int playerNumber, const SDL_Event& event) {
195 if (skipThisPlayer(playerNumber, event)) {
196 return false;
197 }
198 if (event.type == SDL_CONTROLLERBUTTONDOWN) {
199 if (event.cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_LEFT ) {
200 return true;
201 }
202 }
203 if (event.type == SDL_CONTROLLERAXISMOTION && event.caxis.axis == SDL_CONTROLLER_AXIS_LEFTX ) {
204 checkDeadZone(event);
205 const SDL_ControllerAxisEvent& a = event.caxis;
206 if (getDeadZone(a.which, a.axis)) {
207 if (event.caxis.value < -deadZoneLimit) {
208 setDeadZone(a.which,a.axis,false);
209 return true;
210 }
211 }
212 }
213 return false;
214 }
215
216272 bool isPlayerRightEvent(int playerNumber, const SDL_Event& event) {
217273 if (skipThisPlayer(playerNumber, event)) {
218274 return false;
219275 }
220 if (event.type == SDL_CONTROLLERBUTTONDOWN) {
221 if (event.cbutton.button == SDL_CONTROLLER_BUTTON_DPAD_RIGHT ) {
222 return true;
223 }
224 }
225 if (event.type == SDL_CONTROLLERAXISMOTION && event.caxis.axis == SDL_CONTROLLER_AXIS_LEFTX ) {
276 return isControllerRightEvent(event);
277 }
278
279 bool isPlayerSwitchEvent(int playerNumber, const SDL_Event& event) {
280 if (skipThisPlayer(playerNumber, event)) {
281 return false;
282 }
283 if (event.type == SDL_CONTROLLERBUTTONDOWN) {
284 if (event.cbutton.button == SDL_CONTROLLER_BUTTON_A || event.cbutton.button == SDL_CONTROLLER_BUTTON_B ) {
285 return true;
286 }
287 }
288 return false;
289 }
290
291 bool isPlayerPushEvent(int playerNumber, const SDL_Event& event) {
292 if (skipThisPlayer(playerNumber, event)) {
293 return false;
294 }
295 if (event.type == SDL_CONTROLLERBUTTONDOWN) {
296 if (event.cbutton.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER || event.cbutton.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER ) {
297 return true;
298 }
299 }
300 if (event.type == SDL_CONTROLLERAXISMOTION && (event.caxis.axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT || event.caxis.axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT ) ) {
226301 checkDeadZone(event);
227302 const SDL_ControllerAxisEvent& a = event.caxis;
228303 if (getDeadZone(a.which, a.axis)) {
234309 }
235310 return false;
236311 }
237
238 bool isPlayerSwitchEvent(int playerNumber, const SDL_Event& event) {
239 if (skipThisPlayer(playerNumber, event)) {
240 return false;
241 }
242 if (event.type == SDL_CONTROLLERBUTTONDOWN) {
243 if (event.cbutton.button == SDL_CONTROLLER_BUTTON_A || event.cbutton.button == SDL_CONTROLLER_BUTTON_B ) {
244 return true;
245 }
246 }
247 return false;
248 }
249
250 bool isPlayerPushEvent(int playerNumber, const SDL_Event& event) {
251 if (skipThisPlayer(playerNumber, event)) {
252 return false;
253 }
254 if (event.type == SDL_CONTROLLERBUTTONDOWN) {
255 if (event.cbutton.button == SDL_CONTROLLER_BUTTON_LEFTSHOULDER || event.cbutton.button == SDL_CONTROLLER_BUTTON_RIGHTSHOULDER ) {
256 return true;
257 }
258 }
259 if (event.type == SDL_CONTROLLERAXISMOTION && (event.caxis.axis == SDL_CONTROLLER_AXIS_TRIGGERLEFT || event.caxis.axis == SDL_CONTROLLER_AXIS_TRIGGERRIGHT ) ) {
260 checkDeadZone(event);
261 const SDL_ControllerAxisEvent& a = event.caxis;
262 if (getDeadZone(a.which, a.axis)) {
263 if (event.caxis.value > deadZoneLimit) {
264 setDeadZone(a.which,a.axis,false);
265 return true;
266 }
267 }
268 }
269 return false;
270 }
3030 const int deadZoneLimit = 20000;
3131
3232 void InitGameControllers();
33 void UnInitGameControllers();
34
35 bool isControllerDownEvent(const SDL_Event& event);
36 bool isControllerUpEvent(const SDL_Event& event);
37 bool isControllerLeftEvent(const SDL_Event& event);
38 bool isControllerRightEvent(const SDL_Event& event);
3339
3440 bool isPlayerDownEvent(int playerNumber, const SDL_Event& event);
3541 bool isPlayerUpEvent(int playerNumber, const SDL_Event& event);
3743 bool isPlayerRightEvent(int playerNumber, const SDL_Event& event);
3844 bool isPlayerSwitchEvent(int playerNumber, const SDL_Event& event);
3945 bool isPlayerPushEvent(int playerNumber, const SDL_Event& event);
46 bool isGameControllerConnectionEvent(const SDL_Event& event);
4047 void GameControllerSetVerbose(bool value);
4148 const std::vector<std::string>& GetSupportedControllerNames();
4249
6565 //Loads the levels, if they havn't been loaded:
6666 if (Type == 0) {
6767 LoadPuzzleStages();
68 }
69 if (Type == 0) {
7068 nrOfLevels = PuzzleGetNumberOfPuzzles();
7169 }
7270 if (Type == 1) {
210208 }
211209 DrawBackground(globalData.screen);
212210 return levelNr;
213 }
211 }
7979 *******************************************************************************/
8080 #include "mainVars.inc"
8181
82 using std::string;
83 using std::cerr;
84 using std::cout;
85 using std::exception;
86 using std::vector;
87
8882 GlobalData globalData;
8983
9084 static int InitImages(sago::SagoSpriteHolder& holder);
9185
9286 static void FsSearchParthMainAppend(std::vector<std::string>& paths) {
93 paths.push_back((string)SHAREDIR+"/blockattack.data");
94 paths.push_back((string)PHYSFS_getBaseDir()+"/blockattack.data");
95 paths.push_back((string)PHYSFS_getBaseDir()+"/data");
96 }
97
98 static void PhysFsSetSearchPath(const vector<string>& paths, const string& savepath) {
99 for (const string& path : paths) {
87 paths.push_back((std::string)SHAREDIR+"/blockattack.data");
88 paths.push_back((std::string)PHYSFS_getBaseDir()+"/blockattack.data");
89 paths.push_back((std::string)PHYSFS_getBaseDir()+"/data");
90 }
91
92 static void PhysFsSetSearchPath(const std::vector<std::string>& paths, const std::string& savepath) {
93 for (const std::string& path : paths) {
10094 PHYSFS_mount(path.c_str(), "/", 0);
10195 }
10296 PHYSFS_mount(savepath.c_str(), "/", 0);
336330 //writeScreenShot saves the screen as a bmp file, it uses the time to get a unique filename
337331 void writeScreenShot() {
338332 if (globalData.verboseLevel) {
339 cout << "Saving screenshot" << "\n";
333 std::cout << "Saving screenshot" << "\n";
340334 }
341335 int rightNow = (int)time(nullptr);
342336 SDL_Surface* infoSurface = SDL_GetWindowSurface(sdlWindow);
369363 }
370364
371365 //Function to return the name of a key, to be displayed...
372 string getKeyName(SDL_Keycode key);
366 std::string getKeyName(SDL_Keycode key);
373367
374368
375369 void RunGameState(sago::GameStateInterface& state ) {
488482 DrawBackground(globalData.screen);
489483 theGame->DoPaintJob();
490484 theGame2->DoPaintJob();
491 string strHolder;
485 std::string strHolder;
492486 strHolder = std::to_string(theGame->GetScore()+theGame->GetHandicap());
493487 player1score.SetText(strHolder);
494488 player1score.Draw(globalData.screen, theGame->GetTopX()+310,theGame->GetTopY()+100);
567561 //Blank player2's board:
568562 DrawIMG(backBoard,globalData.screen,theGame2->GetTopX(),theGame2->GetTopY());
569563 //Write a description:
570 string gametypeName;
571 string infostring;
564 std::string gametypeName;
565 std::string infostring;
572566 if (theGame->isTimeTrial()) {
573567 gametypeName = _("Time Trial");
574568 infostring = _("Score as much as possible in 2 minutes");
830824 }
831825
832826 struct globalConfig {
833 string savepath;
834 vector<string> search_paths;
835 string puzzleName;
827 std::string savepath;
828 std::vector<std::string> search_paths;
829 std::string puzzleName;
836830 bool allowResize = true;
837831 bool autoScale = true;
838832 bool softwareRenderer = false;
853847 desc.add_options()
854848 ("help,h", "Displays this message")
855849 ("version", "Display the version information")
856 ("config,c", boost::program_options::value<vector<string> >(), "Read a config file with the values. Can be given multiple times")
850 ("config,c", boost::program_options::value<std::vector<std::string> >(), "Read a config file with the values. Can be given multiple times")
857851 ("nosound", "Disables the sound. Can be used if sound errors prevents you from starting")
858852 ("priority", "Causes the game to not sleep between frames.")
859853 ("software-renderer", "Asks SDL2 to use software renderer")
862856 ("print-search-path", "Prints the search path and quits")
863857 ("no-auto-scale", "Do not automatically auto scale")
864858 ("always-sixteen-nine", "Use 16:9 format even in Window mode")
865 ("puzzle-level-file", boost::program_options::value<string>(), "Sets the default puzzle file to load")
859 ("puzzle-level-file", boost::program_options::value<std::string>(), "Sets the default puzzle file to load")
866860 ("puzzle-single-level", boost::program_options::value<int>(), "Start the specific puzzle level directly")
867861 #ifdef REPLAY_IMPLEMENTED
868 ("play-replay", boost::program_options::value<string>(), "Start a replay")
862 ("play-replay", boost::program_options::value<std::string>(), "Start a replay")
869863 #endif
870 ("bind-text-domain", boost::program_options::value<string>(), SPrintStringF("Overwrites the bind text domain used for finding translations. "
864 ("bind-text-domain", boost::program_options::value<std::string>(), SPrintStringF("Overwrites the bind text domain used for finding translations. "
871865 "Default: \"%s\"", LOCALEDIR).c_str())
872 ("homepath", boost::program_options::value<string>(), SPrintStringF("Set the home folder where settings are saved. The directory will be created if it does not exist."
866 ("homepath", boost::program_options::value<std::string>(), SPrintStringF("Set the home folder where settings are saved. The directory will be created if it does not exist."
873867 " Default: \"%s\"", getPathToSaveFiles().c_str()).c_str())
874868
875869 ;
878872 boost::program_options::store(boost::program_options::parse_command_line(argc, argv, desc), vm);
879873 boost::program_options::notify(vm);
880874 }
881 catch (exception& e) {
882 cerr << e.what() << "\n";
883 cerr << desc << "\n";
875 catch (std::exception& e) {
876 std::cerr << e.what() << "\n";
877 std::cerr << desc << "\n";
884878 throw;
885879 }
886880 if (vm.count("config")) {
887 vector<string> config_filenames = vm["config"].as<vector<string> >();
888 for ( const string& s : config_filenames) {
881 std::vector<std::string> config_filenames = vm["config"].as<std::vector<std::string> >();
882 for ( const std::string& s : config_filenames) {
889883 std::ifstream config_file(s);
890884 store(parse_config_file(config_file, desc), vm);
891885 notify(vm);
892886 }
893887 }
894888 if (vm.count("bind-text-domain")) {
895 string s = vm["bind-text-domain"].as<string>();
889 std::string s = vm["bind-text-domain"].as<std::string>();
896890 bindtextdomain (PACKAGE, s.c_str());
897891 }
898892 if (vm.count("homepath")) {
899 string s = vm["homepath"].as<string>();
893 std::string s = vm["homepath"].as<std::string>();
900894 setPathToSaveFiles(s);
901895 conf.savepath = getPathToSaveFiles();
902896 }
903897 if (vm.count("help")) {
904 cout << SPrintStringF("Block Attack - Rise of the blocks %s\n\n"
905 "Block Attack - Rise of the Blocks is a puzzle/blockfall game inspired by Tetris Attack for the SNES.\n\n"
906 "%s\n\n", VERSION_NUMBER, "www.blockattack.net");
907 cout << "Usage: "<< commandname << " [OPTION]..." << "\n";
908 cout << desc << "\n";
909 cout << "Examples:" << "\n";
910 cout << "\tblockattack \tStart the game normally" << "\n";
911 cout << "\tblockattack --nosound\tStart the game without sound. Can be used if sound problems prevents the game from starting" << "\n";
912 cout << "\tblockattack --puzzle-level-file puzzle.levels --puzzle-single-level 3\tStart the game with the default puzzles in level 3" << "\n";
913 cout << "\tblockattack --bind-text-domain /dev/null\t Disables translations" << "\n";
914 cout << "\n";
915 cout << "Report bugs to the issue tracker here: <https://github.com/blockattack/blockattack-game/issues>" << "\n";
898 std::cout << SPrintStringF("Block Attack - Rise of the blocks %s\n\n"
899 "Block Attack - Rise of the Blocks is a puzzle/blockfall game inspired by Tetris Attack for the SNES.\n\n"
900 "%s\n\n", VERSION_NUMBER, "www.blockattack.net");
901 std::cout << "Usage: "<< commandname << " [OPTION]..." << "\n";
902 std::cout << desc << "\n";
903 std::cout << "Examples:" << "\n";
904 std::cout << "\tblockattack \tStart the game normally" << "\n";
905 std::cout << "\tblockattack --nosound\tStart the game without sound. Can be used if sound problems prevents the game from starting" << "\n";
906 std::cout << "\tblockattack --puzzle-level-file puzzle.levels --puzzle-single-level 3\tStart the game with the default puzzles in level 3" << "\n";
907 std::cout << "\tblockattack --bind-text-domain /dev/null\t Disables translations" << "\n";
908 std::cout << "\n";
909 std::cout << "Report bugs to the issue tracker here: <https://github.com/blockattack/blockattack-game/issues>" << "\n";
916910 exit(0);
917911 }
918912 if (vm.count("version")) {
919 cout << "blockattack " << VERSION_NUMBER << "\n";
920 cout << "\n";
921 cout << "Copyright (C) 2005-2016 Poul Sander" << "\n";
922 cout << "License GPLv2+: GNU GPL version 2 <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html> or later <http://gnu.org/licenses/gpl.html>" << "\n";
923 cout << "This is free software: you are free to change and redistribute it." << "\n";
924 cout << "There is NO WARRANTY, to the extent permitted by law." << "\n";
913 std::cout << "blockattack " << VERSION_NUMBER << "\n";
914 std::cout << "\n";
915 std::cout << "Copyright (C) 2005-2016 Poul Sander" << "\n";
916 std::cout << "License GPLv2+: GNU GPL version 2 <http://www.gnu.org/licenses/old-licenses/gpl-2.0.html> or later <http://gnu.org/licenses/gpl.html>" << "\n";
917 std::cout << "This is free software: you are free to change and redistribute it." << "\n";
918 std::cout << "There is NO WARRANTY, to the extent permitted by law." << "\n";
925919 exit(0);
926920 }
927921 if (vm.count("nosound")) {
940934 GameControllerSetVerbose(true);
941935 }
942936 if (vm.count("print-search-path")) {
943 for (const string& s : conf.search_paths) {
944 cout << s << "\n";
945 }
946 cout << conf.savepath << "\n";
937 for (const std::string& s : conf.search_paths) {
938 std::cout << s << "\n";
939 }
940 std::cout << conf.savepath << "\n";
947941 exit(0);
948942 }
949943 if (vm.count("puzzle-single-level")) {
957951 globalData.alwaysSixteenNine = true;
958952 }
959953 if (vm.count("puzzle-level-file")) {
960 conf.puzzleName = vm["puzzle-level-file"].as<string>();
954 conf.puzzleName = vm["puzzle-level-file"].as<std::string>();
961955 }
962956 if (vm.count("play-replay")) {
963 globalData.replayArgument = vm["play-replay"].as<string>();
957 globalData.replayArgument = vm["play-replay"].as<std::string>();
964958 }
965959
966960 }
1004998 sago::SagoFatalErrorF("Unable to init SDL: %s", SDL_GetError());
1005999 }
10061000 if (SDL_InitSubSystem(SDL_INIT_GAMECONTROLLER ) != 0) {
1007 cerr << "Warning: Game controller failed to initialize. Reason: " << SDL_GetError() << "\n";
1001 std::cerr << "Warning: Game controller failed to initialize. Reason: " << SDL_GetError() << "\n";
10081002 }
10091003 InitGameControllers();
10101004 TTF_Init();
10151009 if (!globalData.NoSound) {
10161010 //If sound has not been disabled, then load the sound system
10171011 if (Mix_OpenAudio(44100, AUDIO_S16SYS, 2, 2048) < 0) {
1018 cerr << "Warning: Couldn't set 44100 Hz 16-bit audio - Reason: " << SDL_GetError() << "\n"
1019 << "Sound will be disabled!" << "\n";
1012 std::cerr << "Warning: Couldn't set 44100 Hz 16-bit audio - Reason: " << SDL_GetError() << "\n"
1013 << "Sound will be disabled!" << "\n";
10201014 globalData.NoSound = true; //Tries to stop all sound from playing/loading
10211015 }
10221016 }
10241018
10251019 if (globalData.verboseLevel) {
10261020 //Copyright notice:
1027 cout << "Block Attack - Rise of the Blocks (" << VERSION_NUMBER << ")" << "\n" << "http://www.blockattack.net" << "\n" << "Copyright 2004-2016 Poul Sander" << "\n" <<
1028 "A SDL2 based game (see www.libsdl.org)" << "\n" <<
1029 "The game is available under the GPL, see COPYING for details." << "\n";
1030 cout << "-------------------------------------------" << "\n";
1021 std::cout << "Block Attack - Rise of the Blocks (" << VERSION_NUMBER << ")" << "\n" << "http://www.blockattack.net" << "\n" << "Copyright 2004-2016 Poul Sander" << "\n" <<
1022 "A SDL2 based game (see www.libsdl.org)" << "\n" <<
1023 "The game is available under the GPL, see COPYING for details." << "\n";
1024 std::cout << "-------------------------------------------" << "\n";
10311025 }
10321026
10331027
11101104 screenHeight = configSettings->getInt("screenHeight");
11111105 }
11121106 if (globalData.verboseLevel) {
1113 cout << "Data loaded from config file" << "\n";
1107 std::cout << "Data loaded from config file" << "\n";
11141108 }
11151109 }
11161110 else {
11171111 if (globalData.verboseLevel) {
1118 cout << "Unable to load options file, using default values" << "\n";
1112 std::cout << "Unable to load options file, using default values" << "\n";
11191113 }
11201114 }
11211115 if (configSettings->getInt("always-software")) {
11571151 if (globalData.verboseLevel) {
11581152 SDL_RendererInfo info;
11591153 SDL_GetRendererInfo(renderer, &info);
1160 cout << "Renderer: " << info.name << "\n";
1154 std::cout << "Renderer: " << info.name << "\n";
11611155 }
11621156 globalData.screen = renderer;
11631157 ResetFullscreen();
11641158 SetSDLIcon(sdlWindow);
11651159
11661160 if (globalData.verboseLevel) {
1167 cout << "Images loaded" << "\n";
1161 std::cout << "Images loaded" << "\n";
11681162 }
11691163
11701164 BlockGameSdl theGame = BlockGameSdl(globalData.xsize/2-426, 100, &globalData.spriteHolder->GetDataHolder()); //creates game objects
12331227
12341228 configSettings->setString("player1name", globalData.player1name);
12351229 configSettings->setString("player2name", globalData.player2name);
1236 if (!globalData.bFullscreen){
1230 if (!globalData.bFullscreen) {
12371231 //Store physical height of window
12381232 int height = 0;
12391233 SDL_GetWindowSize(sdlWindow, nullptr, &height);
12471241 commonTime ct = TimeHandler::ms2ct(SDL_GetTicks());
12481242
12491243 if (globalData.verboseLevel) {
1250 cout << SPrintStringF("Block Attack - Rise of the Blocks ran for: %i hours %i mins and %i secs", ct.hours, ct.minutes, ct.seconds) << "\n";
1244 std::cout << SPrintStringF("Block Attack - Rise of the Blocks ran for: %i hours %i mins and %i secs", ct.hours, ct.minutes, ct.seconds) << "\n";
12511245 }
12521246
12531247 ct = TimeHandler::addTime("totalTime",ct);
12541248 if (globalData.verboseLevel) {
1255 cout << "Total run time is now: " << ct.days << " days " << ct.hours << " hours " << ct.minutes << " mins and " << ct.seconds << " secs" << "\n";
1249 std::cout << "Total run time is now: " << ct.days << " days " << ct.hours << " hours " << ct.minutes << " mins and " << ct.seconds << " secs" << "\n";
12561250 }
12571251
12581252 Stats::getInstance()->save();
12591253 Config::getInstance()->save();
12601254 }
1261 catch (exception& e) {
1255 catch (std::exception& e) {
12621256 sago::SagoFatalError(e.what());
12631257 }
12641258 PHYSFS_delete("gameRunning");
13041298 //game loop
13051299 int done = 0;
13061300 if (globalData.verboseLevel) {
1307 cout << "Starting game loop" << "\n";
1301 std::cout << "Starting game loop" << "\n";
13081302 }
13091303
13101304
13881382 bool mustWriteScreenshot = false;
13891383
13901384 BlockGameAction a;
1391 a.action = BlockGameAction::Action::NONE;
13921385 a.tick = SDL_GetTicks();
13931386 if (true) {
13941387 SDL_Event event;
17681761 a.action = BlockGameAction::Action::SET_WON;
17691762 theGame.DoAction(a);
17701763 }
1771 vector<GarbageStruct> gs;
1764 std::vector<GarbageStruct> gs;
17721765 theGame.PopSendGarbage(gs);
17731766 for (const GarbageStruct& g : gs ) {
17741767 BlockGameAction a;
2929 #include "HelpAboutState.hpp"
3030 #include "ShowFileState.hpp"
3131
32 using std::string;
33 using std::cerr;
34 using std::cout;
35 using std::vector;
3632
3733 #if 0
3834 //Menu
5551 extern control keySettings[3];
5652
5753 //Function to return the name of a key, to be displayed...
58 string getKeyName(SDL_Keycode key) {
59 string keyname(SDL_GetKeyName(key));
54 std::string getKeyName(SDL_Keycode key) {
55 std::string keyname(SDL_GetKeyName(key));
6056 if (key == SDLK_UP) {
6157 keyname = _("Up arrow");
6258 }
9490 keyname = _("Space");
9591 }
9692 if (globalData.verboseLevel) {
97 cout << key << " translated to " << keyname << "\n";
93 std::cout << key << " translated to " << keyname << "\n";
9894 }
9995 return keyname;
10096 }
10298 class Button_changekey : public Button {
10399 private:
104100 SDL_Keycode* m_key2change;
105 string m_keyname;
101 std::string m_keyname;
106102 public:
107 Button_changekey(SDL_Keycode* key, string keyname);
103 Button_changekey(SDL_Keycode* key, const char* keyname);
108104 void doAction();
109105 };
110106
111107
112 Button_changekey::Button_changekey(SDL_Keycode* key, string keyname) {
113 m_key2change = key;
114 m_keyname = keyname;
108 Button_changekey::Button_changekey(SDL_Keycode* key, const char* keyname)
109 : m_key2change{key}, m_keyname{keyname} {
115110 setLabel(m_keyname+" : "+getKeyName(*m_key2change));
116111 }
117112
211206
212207 static void SetAlwaysSoftwareLabel(Button* b) {
213208 b->setLabel(Config::getInstance()->getInt("always-software")?
214 _("Always use software render: On")
215 : _("Always use software render: Off"));
209 _("Always use software render: On")
210 : _("Always use software render: Off"));
216211 }
217212
218213 static void SetMusicLabel (Button* b) {
448443 bOnce.setLabel(_("Use software renderer this time"));
449444 bAlways.setLabel(_("Always use software renderer"));
450445 bOnce.setPopOnRun(true);
451 bAlways.setAction([]() {Config::getInstance()->setInt("always-software", 1); });
446 bAlways.setAction([]() {
447 Config::getInstance()->setInt("always-software", 1);
448 });
452449 bAlways.setPopOnRun(true);
453450 safeMode.addButton(&bOnce);
454451 safeMode.addButton(&bAlways);
2020 ===========================================================================
2121 */
2222
23 #if defined(_WIN32)
23 #ifndef OS_HPP
24 #define OS_HPP
25
26 #if defined(_WIN32)
2427 #include "windows.h"
2528 #include "shlobj.h"
2629 #endif
4043 bool OsPathIsRelative(const std::string& path);
4144
4245 void OsCreateFolder(const std::string& path);
46
47 #endif /* OS_HPP */
2929 #include "cereal/types/vector.hpp"
3030 #include "cereal/archives/json.hpp"
3131 #include "sago/SagoMisc.hpp"
32
33 using std::string;
34 using std::cerr;
35 using std::vector;
3632
3733 const int maxNrOfPuzzleStages = 50; //Maximum number of puzzle stages
3834
3030 #include <memory>
3131 #include <SDL_mixer.h>
3232 #include "SagoMiscSdl2.hpp"
33 #include "SagoMisc.hpp"
3334
3435 #if PHYSFS_VER_MAJOR < 3
3536 #define PHYSFS_readBytes(X,Y,Z) PHYSFS_read(X,Y,1,Z)
114115 if (!PHYSFS_exists(path.c_str())) {
115116 sago::SagoFatalErrorF("getTextureFailed - Texture does not exist: %s", path.c_str());
116117 }
117 PHYSFS_file* myfile = PHYSFS_openRead(path.c_str());
118 unsigned int m_size = PHYSFS_fileLength(myfile);
119 std::unique_ptr<char[]> m_data(new char[m_size]);
120 int length_read = PHYSFS_readBytes (myfile, m_data.get(), m_size);
121 if (length_read != (int)m_size) {
122 PHYSFS_close(myfile);
123 std::cerr << "Error: Corrupt data file: " << path << "\n";
124 return ret;
125 }
126 PHYSFS_close(myfile);
118 unsigned int m_size = 0;
119 std::unique_ptr<char[]> m_data;
120 ReadBytesFromFile(path.c_str(), m_data, m_size);
127121 SDL_RWops* rw = SDL_RWFromMem (m_data.get(), m_size);
128122 //The above might fail an return null.
129123 if (!rw) {
130 PHYSFS_close(myfile);
131124 std::cerr << "Error. Corrupt data file!\n";
132125 return NULL;
133126 }
156149 std::cerr << "getFontPtr - Font does not exists: " << path << "\n";
157150 return ret;
158151 }
159 PHYSFS_file* myfile = PHYSFS_openRead(path.c_str());
160 unsigned int m_size = PHYSFS_fileLength(myfile);
161 std::unique_ptr<char[]> m_data(new char[m_size]);
162 int length_read = PHYSFS_readBytes (myfile, m_data.get(), m_size);
163 if (length_read != (int)m_size) {
164 PHYSFS_close(myfile);
165 std::cerr << "Error: Corrupt data file: " << path << "\n";
166 return ret;
167 }
168 PHYSFS_close(myfile);
152 unsigned int m_size = 0;
153 std::unique_ptr<char[]> m_data;
154 ReadBytesFromFile(path.c_str(), m_data, m_size);
169155
170156 SDL_RWops* rw = SDL_RWFromMem (m_data.get(), m_size);
171157
172158 //The above might fail an return null.
173159 if (!rw) {
174 PHYSFS_close(myfile);
175160 std::cerr << "Error: Corrupt data file!\n";
176161 return ret;
177162 }
199184 std::cerr << "getMusicPtr - Music file does not exists: " << path << "\n";
200185 return ret;
201186 }
202 PHYSFS_file* myfile = PHYSFS_openRead(path.c_str());
203 unsigned int m_size = PHYSFS_fileLength(myfile);
204 std::unique_ptr<char[]> m_data(new char[m_size]);
205 int length_read = PHYSFS_readBytes (myfile, m_data.get(), m_size);
206 if (length_read != (int)m_size) {
207 PHYSFS_close(myfile);
208 std::cerr << "Error: Corrupt data file: " << path << "\n";
209 return ret;
210 }
211 PHYSFS_close(myfile);
187 unsigned int m_size = 0;
188 std::unique_ptr<char[]> m_data;
189 ReadBytesFromFile(path.c_str(), m_data, m_size);
212190 SDL_RWops* rw = SDL_RWFromMem (m_data.get(), m_size);
213191
214192 //The above might fail an return null.
215193 if (!rw) {
216 PHYSFS_close(myfile);
217194 std::cerr << "Error. Corrupt data file!\n";
218195 return NULL;
219196 }
242219 std::cerr << "getSoundPtr - Sound file does not exists: " << path << "\n";
243220 return ret;
244221 }
245 PHYSFS_file* myfile = PHYSFS_openRead(path.c_str());
246 unsigned int m_size = PHYSFS_fileLength(myfile);
247 std::unique_ptr<char[]> m_data(new char[m_size]);
248 int length_read = PHYSFS_readBytes (myfile, m_data.get(), m_size);
249 if (length_read != (int)m_size) {
250 PHYSFS_close(myfile);
251 std::cerr << "Error: Corrupt data file: " << path << "\n";
252 return ret;
253 }
254 PHYSFS_close(myfile);
222 unsigned int m_size = 0;
223 std::unique_ptr<char[]> m_data;
224 ReadBytesFromFile(path.c_str(), m_data, m_size);
255225 SDL_RWops* rw = SDL_RWFromMem (m_data.get(), m_size);
256226
257227 //The above might fail an return null.
258228 if (!rw) {
259 PHYSFS_close(myfile);
260229 std::cerr << "Error. Corrupt data file!\n";
261230 return NULL;
262231 }
8181 */
8282 SagoDataHolder();
8383 explicit SagoDataHolder(SDL_Renderer* renderer);
84
8485 /**
8586 * Return a pointer to the given texture. The pointer is valid for the lifetime of SagoDataHolder object it was taken from or until invalidateAll is called.
8687 * @param textureName Name of the texture
8788 * @return Pointer to the loaded texture
8889 */
8990 SDL_Texture* getTexturePtr(const std::string &textureName) const;
91
9092 TextureHandler getTextureHandler(const std::string &textureName) const;
9193 TTF_Font* getFontPtr(const std::string &fontName, int ptsize) const;
9294 Mix_Music* getMusicPtr(const std::string &musicName) const;
9496 Mix_Chunk* getSoundPtr(const std::string &soundName) const;
9597 SoundHandler getSoundHandler(const std::string &soundName) const;
9698 void setVerbose(bool value);
99
97100 /**
98101 * Invalidates all pointers returned by any of the get variables
99102 */
100103 void invalidateAll();
104
101105 /**
102106 * Invalidates all pointers returned by any of the get variables.
103107 * Also sets a new renderer.
105109 * Setting a new renderer might cause all old textures to no longer match the renderer format.
106110 */
107111 void invalidateAll(SDL_Renderer* renderer);
112
108113 /**
109114 * The version number. Changes everytime the pointers are invalidated.
110115 * Can be used to determen if it is neccecary to get a new pointer.
111116 * @return A globally unique number.
112117 */
113118 Uint64 getVersion() const;
119
114120 ~SagoDataHolder();
115121 private:
116122 SagoDataHolder(const SagoDataHolder& base) = delete;
2626 #include <iostream>
2727 #include <iconv.h>
2828 #include <string.h>
29 #include <memory>
3029
3130 #if PHYSFS_VER_MAJOR < 3
3231 #define PHYSFS_readBytes(X,Y,Z) PHYSFS_read(X,Y,1,Z)
3332 #define PHYSFS_writeBytes(X,Y,Z) PHYSFS_write(X,Y,1,Z)
3433 #endif
3534
36 using std::string;
37 using std::cerr;
38 using std::vector;
39
4035 namespace sago {
4136
4237
4338 std::vector<std::string> GetFileList(const char* dir) {
44 vector<string> ret;
39 std::vector<std::string> ret;
4540 char** rc = PHYSFS_enumerateFiles(dir);
4641 for (char** i = rc; *i != NULL; i++) {
4742 ret.push_back(*i);
5449 return PHYSFS_exists(filename);
5550 }
5651
57 std::string GetFileContent(const char* filename) {
58 string ret;
52 void ReadBytesFromFile(const char* filename, std::unique_ptr<char[]>& dest, unsigned int& bytes) {
53 bytes = 0;
5954 if (!PHYSFS_exists(filename)) {
60 cerr << "GetFileContent - File does not exists: " << filename << "\n";
61 return ret;
55 std::cerr << "ReadBytesFromFile - File does not exists: " << filename << "\n";
56 return;
6257 }
6358 PHYSFS_file* myfile = PHYSFS_openRead(filename);
6459 unsigned int m_size = PHYSFS_fileLength(myfile);
6661 int length_read = PHYSFS_readBytes (myfile, m_data.get(), m_size);
6762 if (length_read != (int)m_size) {
6863 PHYSFS_close(myfile);
69 cerr << "Error: Curropt data file: " << filename << "\n";
64 std::cerr << "Error: Curropt data file: " << filename << "\n";
65 return;
66 }
67 PHYSFS_close(myfile);
68 std::swap(m_data, dest);
69 bytes = m_size;
70 }
71
72 std::string GetFileContent(const char* filename) {
73 std::string ret;
74 if (!PHYSFS_exists(filename)) {
75 std::cerr << "GetFileContent - File does not exists: " << filename << "\n";
7076 return ret;
7177 }
72 PHYSFS_close(myfile);
73 //Now create a std::string
74 ret = string(m_data.get(), m_data.get()+m_size);
78 unsigned int m_size = 0;
79 std::unique_ptr<char[]> m_data;
80 ReadBytesFromFile(filename, m_data, m_size);
81 //Now create a std::string
82 ret = std::string(m_data.get(), m_data.get()+m_size);
7583 return ret;
7684 }
7785
2626
2727 #include <vector>
2828 #include <string>
29 #include <memory>
2930
3031 namespace sago {
3132
3637 * @return A vector with the filenames in the given directory. If empty the directory was empty or did not exist
3738 */
3839 std::vector<std::string> GetFileList(const char* dir);
40
41 /**
42 * Reads an entire file into memory.
43 * PHYSFS must be setup before hand
44 * @param filename The file to read
45 * @param dest The unique pointer in which the bytes will be written
46 * @param bytes Number of bytes written
47 * @return The content of the file. If empty either the file was empty, did not exist or could not be opened
48 */
49 void ReadBytesFromFile(const char* filename, std::unique_ptr<char[]>& dest, unsigned int& bytes);
3950
4051 /**
4152 * Reads an entire file into memory.
2323
2424 #include "SagoSprite.hpp"
2525 #include <iostream>
26
27 #ifndef M_PI
28 // M_PI is a custom extension that most C++ toolchains provide. Out Windows compiler does not provide it.
29 # define M_PI 3.14159265358979323846
30 #endif
2631
2732 namespace sago {
2833
6368 DrawScaled(target, frameTime, x, y, data->imgCord.w, data->imgCord.h);
6469 }
6570
71 void SagoSprite::DrawRotated(SDL_Renderer* target, Sint32 frameTime, int x, int y, const double angleRadian) const {
72 SDL_Point center = {this->data->origin.x, this->data->origin.y};
73 DrawScaledAndRotated(target, frameTime, x, y, data->imgCord.w, data->imgCord.h, angleRadian, &center, SDL_FLIP_NONE);
74 }
75
6676 void SagoSprite::DrawScaled(SDL_Renderer* target, Sint32 frameTime, int x, int y, int w, int h) const {
77 DrawScaledAndRotated(target, frameTime, x, y, w, h, 0.0, nullptr, SDL_FLIP_NONE);
78 }
79
80 void SagoSprite::DrawScaledAndRotated(SDL_Renderer* target, Sint32 frameTime, int x, int y, int w, int h, const double angleRadian, const SDL_Point* center, const SDL_RendererFlip flip) const {
6781 if (!data->tex.get()) {
6882 std::cerr << "Texture is null!\n";
6983 }
7892 if (h > 0) {
7993 pos.h = h;
8094 }
81 SDL_RenderCopy(target, data->tex.get(), &rect, &pos);
95 double angleDegress = angleRadian/M_PI*180.0;
96 SDL_RenderCopyEx(target, data->tex.get(), &rect, &pos, angleDegress, center, flip);
8297 }
8398
8499 void SagoSprite::Draw(SDL_Renderer* target, Sint32 frameTime, int x, int y, const SDL_Rect& part) const {
157172 return data->imgCord.h;
158173 }
159174
160 } //namespace sago
175 } //namespace sago
3232 public:
3333 SagoSprite();
3434 SagoSprite(const SagoDataHolder &texHolder, const std::string &texture,const SDL_Rect& initImage,const int animationFrames, const int animationFrameLength);
35
3536 /**
3637 * Draws the sprite to a given render window
3738 * @param target The render window to draw on
4041 * @param y Place to draw the sprite
4142 */
4243 void Draw(SDL_Renderer* target, Sint32 frameTime, int x, int y) const;
44
45 /**
46 * Draws the sprite to a given render window
47 * @param target The render window to draw on
48 * @param frameTime The time in milliseonds since gamestart. Used to determen the place in the animation
49 * @param x Place to draw the sprite
50 * @param y Place to draw the sprite
51 * @param angleRadian Angle to rotate the sprite around origin before drawing
52 */
53 void DrawRotated(SDL_Renderer* target, Sint32 frameTime, int x, int y, const double angleRadian) const;
54
4355 /**
4456 * Draws part of the sprite to a given render window
4557 * @param target The render window to draw on
4961 * @param part the part of the sprite that should be drawn.
5062 */
5163 void Draw(SDL_Renderer* target, Sint32 frameTime, int x, int y, const SDL_Rect& part) const;
64
5265 /**
5366 * Draws the wprite to the given renderer but makes sure to not draw outside th bounds given
5467 * @param target The render window to draw on
5770 * @param y Place to draw the sprite
5871 * @param bounds A recagular area that we must not draw outside.
5972 */
60 void DrawBounded(SDL_Renderer* target, Sint32 frameTime, int x, int y, const SDL_Rect& bounds) const;/**
73 void DrawBounded(SDL_Renderer* target, Sint32 frameTime, int x, int y, const SDL_Rect& bounds) const;
74
75 /**
6176 * Draws the sprite to a given render window
6277 * @param target The render window to draw on
6378 * @param progress A float with value from 0.0f to 1.0f. Tells how far in the animation that we got
6580 * @param y Place to draw the sprite
6681 */
6782 void DrawProgressive(SDL_Renderer* target, float progress, int x, int y) const;
83
6884 void DrawScaled(SDL_Renderer* target, Sint32 frameTime, int x, int y, int w, int h) const;
85 void DrawScaledAndRotated(SDL_Renderer* target, Sint32 frameTime, int x, int y, int w, int h,
86 const double angleRadian, const SDL_Point* center, const SDL_RendererFlip flip) const;
87
6988 /**
7089 * Set a different origin. Normally it is the top left cornor. But in some cases you might want to center the origin or tranform it for other reasons
7190 * @param newOrigin the coordinates that should be the new origin. Call with {0,0} to reset to default
3030 #include <string.h>
3131 #include <boost/algorithm/string/predicate.hpp>
3232
33 using std::string;
34 using std::cerr;
35 using std::cout;
36 using std::vector;
3733
3834 namespace sago {
3935
7975 }
8076
8177 void SagoSpriteHolder::ReadSpriteFile(const std::string& filename) {
82 string fullfile = "sprites/"+filename;
83 string content = sago::GetFileContent(fullfile.c_str());
78 std::string fullfile = "sprites/"+filename;
79 std::string content = sago::GetFileContent(fullfile.c_str());
8480 rapidjson::Document document;
8581 document.Parse(content.c_str());
8682 if ( !document.IsObject() ) {
87 cerr << "Failed to parse: " << fullfile << "\n";
83 std::cerr << "Failed to parse: " << fullfile << "\n";
8884 return;
8985 }
9086 for (auto& m : document.GetObject()) {
9591 }
9692 continue;
9793 }
98 string textureName = getDefaultValue(m.value, "texture", "fallback");
94 std::string textureName = getDefaultValue(m.value, "texture", "fallback");
9995 int topx = getDefaultValue(m.value, "topx", 0);
10096 int topy = getDefaultValue(m.value, "topy",0);
10197 int height = getDefaultValue(m.value, "height",0);
122118 for (std::string& item : spritefiles ) {
123119 if (boost::algorithm::ends_with(item,".sprite")) {
124120 if (data->verbose) {
125 cout << "Found " << item << "\n";
121 std::cout << "Found " << item << "\n";
126122 }
127123 ReadSpriteFile(item);
128124 }
129125 else {
130126 if (data->verbose) {
131 cout << "Ignoreing " << item << "\n";
127 std::cout << "Ignoreing " << item << "\n";
132128 }
133129 }
134130 }
4646 void SetFont(const char* fontName);
4747 void SetFontSize(int fontSize);
4848 void SetOutline(int outlineSize, const SDL_Color& color);
49
4950 /**
5051 * Sets the max width to generate. SagoTextBox will insert line breaks to keep the width below this number.
5152 * Outline is not included in the width: If you have a 2 pixels outline the rendere may go 2 pixels beyond.
4444 SagoTextField& operator=(const SagoTextField&& base) = delete;
4545 SagoTextField& operator=(const SagoTextField& base) = delete;
4646 ~SagoTextField();
47
4748 /**
4849 * This method creates a copy of a given font.
4950 * The cache will not be copied.
5253 * @return A reference to this object.
5354 */
5455 SagoTextField& CopyFrom(const SagoTextField& base);
56
5557 /**
5658 * Sets the data holder. This is MANDATORY
5759 * @param holder The data holder to fetch the fonts from
5860 */
5961 void SetHolder(const SagoDataHolder* holder);
62
6063 /**
6164 * Set the text to display.
6265 * @param text The actual UTF-8 encoded text
6366 */
6467 void SetText(const char* text);
68
6569 /**
6670 * Set the text to display.
6771 * @param text The actual UTF-8 encoded text
6872 */
6973 void SetText(const std::string& text);
74
7075 void SetColor(const SDL_Color& color);
76
7177 /**
7278 * Set the name of the font. Must be known to the data holder.
7379 * The name could for instance be "freeserif".
7480 * @param fontName Name of the font as required by SagoDataHolder
7581 */
7682 void SetFont(const char* fontName);
83
7784 void SetFontSize(int fontSize);
85
7886 /**
7987 * Enable outline against the font.
8088 * @param outlineSize Number of pixels of outline.
8189 * @param color The color of the outline.
8290 */
8391 void SetOutline(int outlineSize, const SDL_Color& color);
92
8493 /**
8594 * Get the text we are currently drawing
8695 * @return The text
8796 */
8897 const std::string& GetText() const;
98
8999 /**
90100 * A Shorthand for calling TTF_SizeUTF8 on the right font
91101 * The size is measuered WITHOUT the outline!
95105 * @param h Pointer to an int where the hight of the text will be stored. Maybe null.
96106 */
97107 void GetRenderedSize(const char* text, int* w = nullptr, int* h = nullptr);
108
98109 enum class Alignment { left = 0, right=1, center = 2 };
99110 enum class VerticalAlignment { top = 0, center = 1, bottom = 2};
100111 void Draw(SDL_Renderer* target, int x, int y, Alignment alignment = Alignment::left, VerticalAlignment verticalAlignment = VerticalAlignment::top);
112
101113 /**
102114 * Updates the cache.
103115 * You normally do not want to call this from the outside as it is done just in time.
105117 * @param target Target the the text will eventually be rendered to
106118 */
107119 void UpdateCache(SDL_Renderer* target);
120
108121 /**
109122 * Clears the cache and forces the SagoTextField to render it again the next time it is drawn.
110123 * Can be used if you have changed font, color or sizes.
5252 Sint32 totalScore = 0;
5353 Sint32 totalTime = 0;
5454
55 using std::string;
56 using std::cerr;
57 using std::vector;
5855
5956 static void SaveStageClearStages() {
6057 std::stringstream ss;
2626 #include "sago/SagoMisc.hpp"
2727 #include <sstream>
2828
29 using std::string;
30 using std::stringstream;
31 using std::cerr;
32 using std::map;
33 using std::vector;
3429
3530 Stats* Stats::instance = nullptr;
3631
4237 }
4338
4439 void Stats::load() {
45 string fileContent = sago::GetFileContent(statsFileName);
46 stringstream inFile(fileContent);
47 string key;
48 string value;
40 std::string fileContent = sago::GetFileContent(statsFileName);
41 std::stringstream inFile(fileContent);
42 std::string key;
43 std::string value;
4944 if (inFile) {
5045 while (!inFile.eof()) {
5146 inFile >> key; // The key is first on line
6661
6762 void Stats::save() {
6863 std::stringstream outFile;
69 map<string,unsigned int>::iterator iter;
64 std::map<std::string, unsigned int>::iterator iter;
7065 for (iter = statMap.begin(); iter != statMap.end(); ++iter) {
7166 outFile << iter->first << " " << iter->second << "\n";
7267 }
7368 sago::WriteFileContent(statsFileName, outFile.str());
7469 }
7570
76 unsigned int Stats::getNumberOf(const string& statName) {
71 unsigned int Stats::getNumberOf(const std::string& statName) {
7772 if (exists(statName)) {
7873 return statMap[statName];
7974 }
8277 }
8378 }
8479
85 void Stats::addOne(const string& statName) {
86 map<string,unsigned int>::iterator iter = statMap.find(statName);
80 void Stats::addOne(const std::string& statName) {
81 std::map<std::string, unsigned int>::iterator iter = statMap.find(statName);
8782 if (iter == statMap.end()) {
8883 statMap[statName] = 1;
8984 }
9287 }
9388 }
9489
95 bool Stats::exists(const string& statName) {
90 bool Stats::exists(const std::string& statName) {
9691 //Using that 'find' returns an iterator to the end of the map if not found
9792 return statMap.find(statName) != statMap.end();
9893 }
2929 #define GAMENAME "blockattack"
3030
3131 #ifndef VERSION_NUMBER
32 #define VERSION_NUMBER "2.5.0"
32 #define VERSION_NUMBER "2.6.0"
3333 #endif
1414
1515 COPY . /staging/blockattack-game
1616
17 ENV BLOCKATTACK_VERSION 2.5.0
17 ENV BLOCKATTACK_VERSION 2.6.0
1818
1919 RUN cd /staging/blockattack-game && \
2020 ./packdata.sh && \
1414
1515 COPY . /staging/blockattack-game
1616
17 ENV BLOCKATTACK_VERSION 2.5.0
17 ENV BLOCKATTACK_VERSION 2.6.0
1818
1919 RUN cd /staging/blockattack-game && \
2020 ./packdata.sh && \
1515
1616 COPY . /staging/blockattack-game
1717
18 ENV BLOCKATTACK_VERSION 2.5.0
18 ENV BLOCKATTACK_VERSION 2.6.0
1919
2020 RUN cd /staging/blockattack-game && \
2121 ./packdata.sh && \
55
66 COPY . /staging/blockattack-game
77
8 ENV BLOCKATTACK_VERSION 2.5.0
8 ENV BLOCKATTACK_VERSION 2.6.0
99
1010 RUN cd /staging/blockattack-game && \
1111 ./packdata.sh && \
66
77 COPY . /staging/blockattack-game
88
9 ENV BLOCKATTACK_VERSION 2.5.0
9 ENV BLOCKATTACK_VERSION 2.6.0
1010
1111 RUN cd /staging/blockattack-game && \
1212 ./packdata.sh && \
66
77 COPY . /staging/blockattack-game
88
9 ENV BLOCKATTACK_VERSION 2.5.0
9 ENV BLOCKATTACK_VERSION 2.6.0
1010
1111 RUN cd /staging/blockattack-game && \
1212 ./packdata.sh && \
55
66 COPY . /staging/blockattack-game
77
8 ENV BLOCKATTACK_VERSION 2.5.0
8 ENV BLOCKATTACK_VERSION 2.6.0
99
1010 RUN cd /staging/blockattack-game && \
1111 ./packdata.sh && \
77
88 COPY . /staging/blockattack-game
99
10 ENV BLOCKATTACK_VERSION 2.5.0
10 ENV BLOCKATTACK_VERSION 2.6.0
1111
1212 RUN cd /staging/blockattack-game && \
1313 ./packdata.sh && \
2525 cp /staging/blockattack-game/COPYING ./COPYING.txt && \
2626 cp -r /staging/blockattack-game/source/misc/translation/locale ./ && \
2727 echo "[InternetShortcut]" > "Block Attack - Rise Of the Blocks.url" && \
28 echo "URL=http://www.blockattack.net" >> "Block Attack - Rise Of the Blocks.url" && \
28 echo "URL=https://blockattack.net" >> "Block Attack - Rise Of the Blocks.url" && \
2929 cd /staging/package/ && \
3030 zip -r /output/blockattack-${BLOCKATTACK_VERSION}-windows-no-installer.zip "blockattack-${BLOCKATTACK_VERSION}" && \
3131 cd /output && chown nobody * && chmod 666 * && ls -lh
66 Some systems might require the game to be launched from the command line.
77 PulseAudio is required for sound.
88
9 Check www.blockattack.net for more info.
9 Check https://blockattack.net for more info.
11 set -e
22 set -x
33
4 mkdir -p /staging/deps && cd /staging/deps && curl https://libsdl.org/release/SDL2-2.0.9.tar.gz | tar -zx && cd SDL2-2.0.9 && ls -lrt
5 cd /staging/deps/SDL2-2.0.9 && ./configure --enable-shared --enable-static && make && make install
4 mkdir -p /staging/deps && cd /staging/deps && curl https://libsdl.org/release/SDL2-2.0.12.tar.gz | tar -zx && cd SDL2-2.0.12 && ls -lrt
5 cd /staging/deps/SDL2-2.0.12 && ./configure --enable-shared --enable-static && make && make install
66
7 #https://www.libsdl.org/projects/SDL_image/release/SDL2_image-2.0.4.tar.gz
8 mkdir -p /staging/deps && cd /staging/deps && curl https://www.libsdl.org/projects/SDL_image/release/SDL2_image-2.0.4.tar.gz | tar -zx && cd SDL2_image-2.0.4 && ls -lrt
9 cd /staging/deps/SDL2_image-2.0.4 && ./configure --enable-shared --enable-static && make && make install
7 #https://www.libsdl.org/projects/SDL_image/release/SDL2_image-2.0.5.tar.gz
8 mkdir -p /staging/deps && cd /staging/deps && curl https://www.libsdl.org/projects/SDL_image/release/SDL2_image-2.0.5.tar.gz | tar -zx && cd SDL2_image-2.0.5 && ls -lrt
9 cd /staging/deps/SDL2_image-2.0.5 && ./configure --enable-shared --enable-static && make && make install
1010
1111 #https://www.libsdl.org/projects/SDL_mixer/release/SDL2_mixer-2.0.4.tar.gz
1212 mkdir -p /staging/deps && cd /staging/deps && curl https://www.libsdl.org/projects/SDL_mixer/release/SDL2_mixer-2.0.4.tar.gz | tar -zx && cd SDL2_mixer-2.0.4 && ls -lrt
1313 cd /staging/deps/SDL2_mixer-2.0.4 && ./configure --enable-shared --enable-static && make && make install
1414
15 #https://www.libsdl.org/projects/SDL_ttf/release/SDL2_ttf-2.0.14.tar.gz
16 mkdir -p /staging/deps && cd /staging/deps && curl https://www.libsdl.org/projects/SDL_ttf/release/SDL2_ttf-2.0.14.tar.gz | tar -zx && cd SDL2_ttf-2.0.14 && ls -lrt
17 cd /staging/deps/SDL2_ttf-2.0.14 && ./configure --enable-shared --enable-static && make && make install
15 #https://www.libsdl.org/projects/SDL_ttf/release/SDL2_ttf-2.0.15.tar.gz
16 mkdir -p /staging/deps && cd /staging/deps && curl https://www.libsdl.org/projects/SDL_ttf/release/SDL2_ttf-2.0.15.tar.gz | tar -zx && cd SDL2_ttf-2.0.15 && ls -lrt
17 cd /staging/deps/SDL2_ttf-2.0.15 && ./configure --enable-shared --enable-static && make && make install
1818 mkdir -p /staging/blockattack-game
1919
20 mkdir -p /staging/deps && cd /staging/deps && curl http://icculus.org/physfs/downloads/physfs-2.0.3.tar.bz2 | tar -jx && cd physfs-2.0.3 && ls -lrt
21 cd /staging/deps/physfs-2.0.3 && cmake . && make && make install
20 mkdir -p /staging/deps && cd /staging/deps && curl https://icculus.org/physfs/downloads/physfs-3.0.2.tar.bz2 | tar -jx && cd physfs-3.0.2 && ls -lrt
21 cd /staging/deps/physfs-3.0.2 && cmake . && make && make install
2222
2323 # boost
2424 cd ~
44 # Poul Sander <poul@poulsander.com>, 2019. #zanata
55 msgid ""
66 msgstr ""
7 "Project-Id-Version: PACKAGE VERSION\n"
7 "Project-Id-Version: \n"
88 "Report-Msgid-Bugs-To: \n"
9 "POT-Creation-Date: 2019-05-02 19:35+0200\n"
9 "POT-Creation-Date: 2020-06-27 14:06+0200\n"
10 "PO-Revision-Date: 2020-06-27 14:08+0200\n"
11 "Last-Translator: Poul Sander <poul@poulsander.com>\n"
12 "Language-Team: \n"
13 "Language: da\n"
1014 "MIME-Version: 1.0\n"
1115 "Content-Type: text/plain; charset=UTF-8\n"
1216 "Content-Transfer-Encoding: 8bit\n"
13 "PO-Revision-Date: 2019-05-02 05:39+0000\n"
14 "Last-Translator: Poul Sander <poul@poulsander.com>\n"
15 "Language-Team: \n"
16 "Language: da\n"
17 "X-Generator: Zanata 4.6.2\n"
17 "X-Generator: Poedit 2.0.6\n"
1818 "Plural-Forms: nplurals=2; plural=(n != 1);\n"
1919
20 #: ../../code/DialogBox.cpp:92
20 #: ../../code/DialogBox.cpp:94
2121 msgid "Enter to accept"
2222 msgstr "Bekræft med Enter"
2323
24 #: ../../code/DialogBox.cpp:93
24 #: ../../code/DialogBox.cpp:95
2525 msgid "Esc to cancel"
2626 msgstr "Annuller med Esc"
2727
3333 msgid "Name:"
3434 msgstr "Navn:"
3535
36 #: ../../code/HelpAboutState.cpp:71
36 #: ../../code/HelpAboutState.cpp:71 ../../code/main.cpp:329
3737 msgid "Block Attack - Rise of the Blocks"
3838 msgstr "Block Attack - Blokkenes opstand"
3939
169169 msgid "DRAW"
170170 msgstr "UAFGJORT"
171171
172 #: ../../code/main.cpp:487 ../../code/main.cpp:618
172 #: ../../code/main.cpp:497 ../../code/main.cpp:628
173173 msgid "AI"
174174 msgstr "Computer"
175175
176 #: ../../code/main.cpp:490
176 #: ../../code/main.cpp:500
177177 msgid "Playing field"
178178 msgstr "Spilleflade"
179179
180 #: ../../code/main.cpp:564
180 #: ../../code/main.cpp:574
181181 msgid "Time Trial"
182182 msgstr "På tid"
183183
184 #: ../../code/main.cpp:565
184 #: ../../code/main.cpp:575
185185 msgid "Score as much as possible in 2 minutes"
186186 msgstr "Se hvor mange point du kan opnå på 2 minutter"
187187
188 #: ../../code/main.cpp:569
188 #: ../../code/main.cpp:579
189189 msgid "Stage Clear"
190190 msgstr "Stage Clear"
191191
192 #: ../../code/main.cpp:570
192 #: ../../code/main.cpp:580
193193 msgid "You must clear a number of lines. Speed is rapidly increased."
194194 msgstr "Fjern et specifik antal linjer. Hastigheden stiger hurtigt."
195195
196 #: ../../code/main.cpp:573
196 #: ../../code/main.cpp:583
197197 msgid "Puzzle"
198198 msgstr "Gåde"
199199
200 #: ../../code/main.cpp:574
200 #: ../../code/main.cpp:584
201201 msgid "Clear the entire board with a limited number of moves."
202202 msgstr "Fjern alle blokke med et begrænset antal flyt."
203203
204 #: ../../code/main.cpp:577
204 #: ../../code/main.cpp:587
205205 msgid "Endless"
206206 msgstr "Evighed"
207207
208 #: ../../code/main.cpp:578
208 #: ../../code/main.cpp:588
209209 msgid "Score as much as possible. No time limit."
210210 msgstr "Opnå så mange point som muligt. Ingen tidsbegrænsning."
211211
212 #: ../../code/main.cpp:588
212 #: ../../code/main.cpp:598
213213 msgid "Objective:"
214214 msgstr "Formål:"
215215
216 #: ../../code/main.cpp:598
216 #: ../../code/main.cpp:608
217217 msgid "Movement keys:"
218218 msgstr "Bevægelsestaster:"
219219
220 #: ../../code/main.cpp:600
220 #: ../../code/main.cpp:610
221221 msgid "Switch: "
222222 msgstr "Skift: "
223223
224 #: ../../code/main.cpp:602
224 #: ../../code/main.cpp:612
225225 msgid "Restart: "
226226 msgstr "Genstart: "
227227
228 #: ../../code/main.cpp:605
228 #: ../../code/main.cpp:615
229229 msgid "Push line: "
230230 msgstr "Skub linje: "
231231
232 #: ../../code/main.cpp:1040
232 #: ../../code/main.cpp:1050
233233 msgid "Player 2"
234234 msgstr "Spiller 2"
235235
506506 msgstr "Bedste resultater"
507507
508508 #: ../../code/MenuSystem.cpp:159 ../../code/MenuSystem.cpp:167
509 #: ../../code/MenuSystem.cpp:179 ../../code/ScoresDisplay.cpp:216
509 #: ../../code/MenuSystem.cpp:179 ../../code/ScoresDisplay.cpp:220
510510 msgid "Back"
511511 msgstr "Tilbage"
512512
514514 msgid "Exit"
515515 msgstr "Afslut"
516516
517 #: ../../code/os.cpp:99
517 #: ../../code/os.cpp:101
518518 msgid "Player 1"
519519 msgstr "Spiller 1"
520520
521 #: ../../code/ScoresDisplay.cpp:70
521 #: ../../code/ScoresDisplay.cpp:74
522522 msgid "Endless (Fast):"
523523 msgstr "Evighed (Hurtig):"
524524
525 #: ../../code/ScoresDisplay.cpp:73
525 #: ../../code/ScoresDisplay.cpp:77
526526 msgid "Endless (Faster):"
527527 msgstr "Evighed (Hurtigere):"
528528
529 #: ../../code/ScoresDisplay.cpp:76
529 #: ../../code/ScoresDisplay.cpp:80
530530 msgid "Endless (Even faster):"
531531 msgstr "Evighed (Endnu hurtigere):"
532532
533 #: ../../code/ScoresDisplay.cpp:79
533 #: ../../code/ScoresDisplay.cpp:83
534534 msgid "Endless (Fastest):"
535535 msgstr "Evighed (Hurtigst):"
536536
537 #: ../../code/ScoresDisplay.cpp:82
537 #: ../../code/ScoresDisplay.cpp:86
538538 msgid "Endless:"
539539 msgstr "Evighed:"
540540
541 #: ../../code/ScoresDisplay.cpp:87
541 #: ../../code/ScoresDisplay.cpp:91
542542 msgid "Time Trial:"
543543 msgstr "På tid:"
544544
545 #: ../../code/ScoresDisplay.cpp:125
545 #: ../../code/ScoresDisplay.cpp:129
546546 msgid "Stats"
547547 msgstr "Statistik"
548548
549 #: ../../code/ScoresDisplay.cpp:127
549 #: ../../code/ScoresDisplay.cpp:131
550550 msgid "Chains"
551551 msgstr "Kæder"
552552
553 #: ../../code/ScoresDisplay.cpp:135
553 #: ../../code/ScoresDisplay.cpp:139
554554 msgid "Lines Pushed: "
555555 msgstr "Linjer skubbet: "
556556
557 #: ../../code/ScoresDisplay.cpp:140
557 #: ../../code/ScoresDisplay.cpp:144
558558 msgid "Puzzles solved: "
559559 msgstr "Gåder løst: "
560560
561 #: ../../code/ScoresDisplay.cpp:145
561 #: ../../code/ScoresDisplay.cpp:149
562562 msgid "Run time: "
563563 msgstr "Kørselstid: "
564564
565 #: ../../code/ScoresDisplay.cpp:148 ../../code/ScoresDisplay.cpp:161
565 #: ../../code/ScoresDisplay.cpp:152 ../../code/ScoresDisplay.cpp:165
566566 #, c-format
567567 msgid "Days: %i"
568568 msgstr "Dage: %i"
569569
570 #: ../../code/ScoresDisplay.cpp:150 ../../code/ScoresDisplay.cpp:163
570 #: ../../code/ScoresDisplay.cpp:154 ../../code/ScoresDisplay.cpp:167
571571 #, c-format
572572 msgid "Hours: %i"
573573 msgstr "Timer: %i"
574574
575 #: ../../code/ScoresDisplay.cpp:152 ../../code/ScoresDisplay.cpp:165
575 #: ../../code/ScoresDisplay.cpp:156 ../../code/ScoresDisplay.cpp:169
576576 #, c-format
577577 msgid "Minutes: %i"
578578 msgstr "Minutter: %i"
579579
580 #: ../../code/ScoresDisplay.cpp:154 ../../code/ScoresDisplay.cpp:167
580 #: ../../code/ScoresDisplay.cpp:158 ../../code/ScoresDisplay.cpp:171
581581 #, c-format
582582 msgid "Seconds: %i"
583583 msgstr "Sekunder: %i"
584584
585 #: ../../code/ScoresDisplay.cpp:158
585 #: ../../code/ScoresDisplay.cpp:162
586586 msgid "Play time: "
587587 msgstr "Spilletid: "
588588
589 #: ../../code/ScoresDisplay.cpp:171
589 #: ../../code/ScoresDisplay.cpp:175
590590 msgid "VS CPU (win/loss)"
591591 msgstr "Mod computeren (vundet/tabt)"
592592
593 #: ../../code/ScoresDisplay.cpp:220 ../../code/BlockGameSdl.inc:55
593 #: ../../code/ScoresDisplay.cpp:224 ../../code/BlockGameSdl.inc:55
594594 msgid "Next"
595595 msgstr "Næste"
596596
597 #: ../../code/ScoresDisplay.cpp:224
597 #: ../../code/ScoresDisplay.cpp:228
598598 #, c-format
599599 msgid "Page %i of %i"
600600 msgstr "Side %i af %i"
635635 msgid "Last stage"
636636 msgstr "Sidste bane"
637637
638 #: ../../code/DialogBox.hpp:38
639 msgid "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.,:!?+_^@#%&=*"
640 msgstr "ABCDEFGHIJKLMNOPQRSTUVWXYZÆØÅabcdefghijklmnopqrstuvwxyzæøå.,:!?+_^@#%&=*"
641
638642 #: ../../code/ShowFileState.hpp:45
639643 #, c-format
640644 msgid "Showing content of: %s"
641645 msgstr "Viser indhold af: %s"
642
77 msgstr ""
88 "Project-Id-Version: PACKAGE VERSION\n"
99 "Report-Msgid-Bugs-To: \n"
10 "POT-Creation-Date: 2019-05-02 19:35+0200\n"
10 "POT-Creation-Date: 2020-06-27 14:06+0200\n"
1111 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
1212 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
1313 "Language-Team: LANGUAGE <LL@li.org>\n"
1616 "Content-Type: text/plain; charset=CHARSET\n"
1717 "Content-Transfer-Encoding: 8bit\n"
1818
19 #: ../../code/DialogBox.cpp:92
19 #: ../../code/DialogBox.cpp:94
2020 msgid "Enter to accept"
2121 msgstr ""
2222
23 #: ../../code/DialogBox.cpp:93
23 #: ../../code/DialogBox.cpp:95
2424 msgid "Esc to cancel"
2525 msgstr ""
2626
3232 msgid "Name:"
3333 msgstr ""
3434
35 #: ../../code/HelpAboutState.cpp:71
35 #: ../../code/HelpAboutState.cpp:71 ../../code/main.cpp:329
3636 msgid "Block Attack - Rise of the Blocks"
3737 msgstr ""
3838
166166 msgid "DRAW"
167167 msgstr ""
168168
169 #: ../../code/main.cpp:487 ../../code/main.cpp:618
169 #: ../../code/main.cpp:497 ../../code/main.cpp:628
170170 msgid "AI"
171171 msgstr ""
172172
173 #: ../../code/main.cpp:490
173 #: ../../code/main.cpp:500
174174 msgid "Playing field"
175175 msgstr ""
176176
177 #: ../../code/main.cpp:564
177 #: ../../code/main.cpp:574
178178 msgid "Time Trial"
179179 msgstr ""
180180
181 #: ../../code/main.cpp:565
181 #: ../../code/main.cpp:575
182182 msgid "Score as much as possible in 2 minutes"
183183 msgstr ""
184184
185 #: ../../code/main.cpp:569
185 #: ../../code/main.cpp:579
186186 msgid "Stage Clear"
187187 msgstr ""
188188
189 #: ../../code/main.cpp:570
189 #: ../../code/main.cpp:580
190190 msgid "You must clear a number of lines. Speed is rapidly increased."
191191 msgstr ""
192192
193 #: ../../code/main.cpp:573
193 #: ../../code/main.cpp:583
194194 msgid "Puzzle"
195195 msgstr ""
196196
197 #: ../../code/main.cpp:574
197 #: ../../code/main.cpp:584
198198 msgid "Clear the entire board with a limited number of moves."
199199 msgstr ""
200200
201 #: ../../code/main.cpp:577
201 #: ../../code/main.cpp:587
202202 msgid "Endless"
203203 msgstr ""
204204
205 #: ../../code/main.cpp:578
205 #: ../../code/main.cpp:588
206206 msgid "Score as much as possible. No time limit."
207207 msgstr ""
208208
209 #: ../../code/main.cpp:588
209 #: ../../code/main.cpp:598
210210 msgid "Objective:"
211211 msgstr ""
212212
213 #: ../../code/main.cpp:598
213 #: ../../code/main.cpp:608
214214 msgid "Movement keys:"
215215 msgstr ""
216216
217 #: ../../code/main.cpp:600
217 #: ../../code/main.cpp:610
218218 msgid "Switch: "
219219 msgstr ""
220220
221 #: ../../code/main.cpp:602
221 #: ../../code/main.cpp:612
222222 msgid "Restart: "
223223 msgstr ""
224224
225 #: ../../code/main.cpp:605
225 #: ../../code/main.cpp:615
226226 msgid "Push line: "
227227 msgstr ""
228228
229 #: ../../code/main.cpp:1040
229 #: ../../code/main.cpp:1050
230230 msgid "Player 2"
231231 msgstr ""
232232
503503 msgstr ""
504504
505505 #: ../../code/MenuSystem.cpp:159 ../../code/MenuSystem.cpp:167
506 #: ../../code/MenuSystem.cpp:179 ../../code/ScoresDisplay.cpp:216
506 #: ../../code/MenuSystem.cpp:179 ../../code/ScoresDisplay.cpp:220
507507 msgid "Back"
508508 msgstr ""
509509
511511 msgid "Exit"
512512 msgstr ""
513513
514 #: ../../code/os.cpp:99
514 #: ../../code/os.cpp:101
515515 msgid "Player 1"
516516 msgstr ""
517517
518 #: ../../code/ScoresDisplay.cpp:70
518 #: ../../code/ScoresDisplay.cpp:74
519519 msgid "Endless (Fast):"
520520 msgstr ""
521521
522 #: ../../code/ScoresDisplay.cpp:73
522 #: ../../code/ScoresDisplay.cpp:77
523523 msgid "Endless (Faster):"
524524 msgstr ""
525525
526 #: ../../code/ScoresDisplay.cpp:76
526 #: ../../code/ScoresDisplay.cpp:80
527527 msgid "Endless (Even faster):"
528528 msgstr ""
529529
530 #: ../../code/ScoresDisplay.cpp:79
530 #: ../../code/ScoresDisplay.cpp:83
531531 msgid "Endless (Fastest):"
532532 msgstr ""
533533
534 #: ../../code/ScoresDisplay.cpp:82
534 #: ../../code/ScoresDisplay.cpp:86
535535 msgid "Endless:"
536536 msgstr ""
537537
538 #: ../../code/ScoresDisplay.cpp:87
538 #: ../../code/ScoresDisplay.cpp:91
539539 msgid "Time Trial:"
540540 msgstr ""
541541
542 #: ../../code/ScoresDisplay.cpp:125
542 #: ../../code/ScoresDisplay.cpp:129
543543 msgid "Stats"
544544 msgstr ""
545545
546 #: ../../code/ScoresDisplay.cpp:127
546 #: ../../code/ScoresDisplay.cpp:131
547547 msgid "Chains"
548548 msgstr ""
549549
550 #: ../../code/ScoresDisplay.cpp:135
550 #: ../../code/ScoresDisplay.cpp:139
551551 msgid "Lines Pushed: "
552552 msgstr ""
553553
554 #: ../../code/ScoresDisplay.cpp:140
554 #: ../../code/ScoresDisplay.cpp:144
555555 msgid "Puzzles solved: "
556556 msgstr ""
557557
558 #: ../../code/ScoresDisplay.cpp:145
558 #: ../../code/ScoresDisplay.cpp:149
559559 msgid "Run time: "
560560 msgstr ""
561561
562 #: ../../code/ScoresDisplay.cpp:148 ../../code/ScoresDisplay.cpp:161
562 #: ../../code/ScoresDisplay.cpp:152 ../../code/ScoresDisplay.cpp:165
563563 #, c-format
564564 msgid "Days: %i"
565565 msgstr ""
566566
567 #: ../../code/ScoresDisplay.cpp:150 ../../code/ScoresDisplay.cpp:163
567 #: ../../code/ScoresDisplay.cpp:154 ../../code/ScoresDisplay.cpp:167
568568 #, c-format
569569 msgid "Hours: %i"
570570 msgstr ""
571571
572 #: ../../code/ScoresDisplay.cpp:152 ../../code/ScoresDisplay.cpp:165
572 #: ../../code/ScoresDisplay.cpp:156 ../../code/ScoresDisplay.cpp:169
573573 #, c-format
574574 msgid "Minutes: %i"
575575 msgstr ""
576576
577 #: ../../code/ScoresDisplay.cpp:154 ../../code/ScoresDisplay.cpp:167
577 #: ../../code/ScoresDisplay.cpp:158 ../../code/ScoresDisplay.cpp:171
578578 #, c-format
579579 msgid "Seconds: %i"
580580 msgstr ""
581581
582 #: ../../code/ScoresDisplay.cpp:158
582 #: ../../code/ScoresDisplay.cpp:162
583583 msgid "Play time: "
584584 msgstr ""
585585
586 #: ../../code/ScoresDisplay.cpp:171
586 #: ../../code/ScoresDisplay.cpp:175
587587 msgid "VS CPU (win/loss)"
588588 msgstr ""
589589
590 #: ../../code/ScoresDisplay.cpp:220 ../../code/BlockGameSdl.inc:55
590 #: ../../code/ScoresDisplay.cpp:224 ../../code/BlockGameSdl.inc:55
591591 msgid "Next"
592592 msgstr ""
593593
594 #: ../../code/ScoresDisplay.cpp:224
594 #: ../../code/ScoresDisplay.cpp:228
595595 #, c-format
596596 msgid "Page %i of %i"
597597 msgstr ""
632632 msgid "Last stage"
633633 msgstr ""
634634
635 #: ../../code/DialogBox.hpp:38
636 msgid "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz.,:!?+_^@#%&=*"
637 msgstr ""
638
635639 #: ../../code/ShowFileState.hpp:45
636640 #, c-format
637641 msgid "Showing content of: %s"
11
22 ; HM NIS Edit Wizard helper defines
33 !define PRODUCT_NAME "Block Attack - Rise Of the Blocks"
4 !define PRODUCT_VERSION "2.5.0"
4 !define PRODUCT_VERSION "2.6.0"
55 !define PRODUCT_PUBLISHER "Poul Sander"
66 !define PRODUCT_WEB_SITE "http://www.blockattack.net"
77 !define PRODUCT_DIR_REGKEY "Software\Microsoft\Windows\CurrentVersion\App Paths\blockattack.exe"