Fix line endings (#15)
This commit is contained in:
Родитель
20e2b2760e
Коммит
aa1b358538
42
LICENSE
42
LICENSE
|
@ -1,22 +1,22 @@
|
|||
JsonBuilder
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
JsonBuilder
|
||||
Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE
|
282
README.md
282
README.md
|
@ -1,142 +1,142 @@
|
|||
[![Build Status](https://dev.azure.com/ms/JsonBuilder/_apis/build/status/microsoft.JsonBuilder?branchName=master)](https://dev.azure.com/ms/JsonBuilder/_build/latest?definitionId=148&branchName=master)
|
||||
|
||||
# JsonBuilder
|
||||
|
||||
JsonBuilder is a small C++ library for building a space-efficient binary representation of structured data and, when ready, rendering it to JSON. The library offers STL-like syntax for adding and finding data as well as STL-like iterators for efficiently tracking location.
|
||||
|
||||
## Examples
|
||||
|
||||
### Building structured data
|
||||
|
||||
Let's try to build the following JSON up using the JsonBuilder interface:
|
||||
|
||||
```json
|
||||
{
|
||||
"e": 2.718,
|
||||
"enabled": true,
|
||||
"user": "john",
|
||||
"resolution": {
|
||||
"x": 1024,
|
||||
"y": 768
|
||||
},
|
||||
"colors": [
|
||||
"Red",
|
||||
"Green",
|
||||
"Blue"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The code to do so would look like this:
|
||||
|
||||
```cpp
|
||||
JsonBuilder jb;
|
||||
jb.push_back(jb.end(), "e", 2.718);
|
||||
jb.push_back(jb.end(), "enabled", true);
|
||||
jb.push_back(jb.end(), "user", "john");
|
||||
|
||||
JsonIterator resolutionItr = jb.push_back(jb.end(), "resolution", JsonObject);
|
||||
jb.push_back(resolutionItr, "x", 1024);
|
||||
jb.push_back(resolutionItr, "y", 768);
|
||||
|
||||
JsonIterator colorIterator = jb.push_back(jb.end(), "colors", JsonArray);
|
||||
jb.push_back(colorIterator, "", "Red");
|
||||
jb.push_back(colorIterator, "", "Green");
|
||||
jb.push_back(colorIterator, "", "Blue");
|
||||
```
|
||||
|
||||
### Getting an iterator to existing data
|
||||
|
||||
Using the built JsonBuilder object above as a starting point:
|
||||
|
||||
```cpp
|
||||
// Float
|
||||
JsonConstIterator eItr = jb.find("e");
|
||||
float e = eItr->GetUnchecked<float>();
|
||||
std::cout << e << std::endl;
|
||||
|
||||
// Object
|
||||
JsonConstIterator resolutionItr = jb.find("resolution");
|
||||
for (JsonConstIterator beginItr = resolutionItr.begin(),
|
||||
endItr = resolutionItr.end();
|
||||
beginItr != endItr;
|
||||
++beginItr)
|
||||
{
|
||||
std::string name(beginItr->Name().data(), beginItr->Name().length());
|
||||
std::cout << name << " " << beginItr->GetUnchecked<int64_t>()
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
// Array
|
||||
JsonConstIterator colorsItr = jb.find("colors");
|
||||
for (JsonConstIterator beginItr = colorsItr.begin(), endItr = colorsItr.end();
|
||||
beginItr != endItr;
|
||||
++beginItr)
|
||||
{
|
||||
auto color = beginItr->GetUnchecked<std::string_view>();
|
||||
std::cout << color << std::endl;
|
||||
}
|
||||
```
|
||||
|
||||
### Rendering to JSON
|
||||
|
||||
Using the built JsonBuilder object above as a starting point:
|
||||
|
||||
```cpp
|
||||
// Create a renderer and reserve 2048 bytes up front
|
||||
JsonRenderer renderer;
|
||||
renderer.Reserve(2048);
|
||||
|
||||
// Render a json builder object to a string
|
||||
std::string_view result = renderer.Render(_jsonBuilder);
|
||||
std::string stl_string(result.data(), result.size());
|
||||
std::cout << stl_string.c_str() << std::endl;
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
This project carries a dependency on the uuid library. To develop with this project, install the development version of the library:
|
||||
|
||||
```bash
|
||||
sudo apt-get install uuid-dev
|
||||
```
|
||||
|
||||
If you checkout with submodules, you will receive a version of Catch2 for testing that can be used automatically. If you do not checkout
|
||||
this submodule, the build system will instead search for an installed version of Catch2 and use that.
|
||||
|
||||
## Integration
|
||||
|
||||
JsonBuilder builds as a static library and requires C++11. The project creates a CMake compatible 'jsonbuilder' target which you can use for linking against the library.
|
||||
|
||||
1. Add this project as a subdirectory in your project, either as a git submodule or copying the code directly.
|
||||
2. Add that directory to your top-level CMakeLists.txt with 'add_subdirectory'. This will make the 'jsonbuilder' target available.
|
||||
3. Add the 'jsonbuilder' target to the target_link_libraries of any target that will use the JsonBuilder library.
|
||||
|
||||
## Reporting Security Issues
|
||||
|
||||
Security issues and bugs should be reported privately, via email, to the
|
||||
Microsoft Security Response Center (MSRC) at <[secure@microsoft.com](mailto:secure@microsoft.com)>.
|
||||
You should receive a response within 24 hours. If for some reason you do not, please follow up via
|
||||
email to ensure we received your original message. Further information, including the
|
||||
[MSRC PGP](https://technet.microsoft.com/en-us/security/dn606155) key, can be found in the
|
||||
[Security TechCenter](https://technet.microsoft.com/en-us/security/default).
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
||||
|
||||
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
|
||||
## Contributing
|
||||
|
||||
Want to contribute? The team encourages community feedback and contributions. Please follow our [contributing guidelines](CONTRIBUTING.md).
|
||||
|
||||
We also welcome [issues submitted on GitHub](https://github.com/Microsoft/JsonBuilder/issues).
|
||||
|
||||
## Project Status
|
||||
|
||||
This project is currently in active development.
|
||||
|
||||
## Contact
|
||||
|
||||
[![Build Status](https://dev.azure.com/ms/JsonBuilder/_apis/build/status/microsoft.JsonBuilder?branchName=master)](https://dev.azure.com/ms/JsonBuilder/_build/latest?definitionId=148&branchName=master)
|
||||
|
||||
# JsonBuilder
|
||||
|
||||
JsonBuilder is a small C++ library for building a space-efficient binary representation of structured data and, when ready, rendering it to JSON. The library offers STL-like syntax for adding and finding data as well as STL-like iterators for efficiently tracking location.
|
||||
|
||||
## Examples
|
||||
|
||||
### Building structured data
|
||||
|
||||
Let's try to build the following JSON up using the JsonBuilder interface:
|
||||
|
||||
```json
|
||||
{
|
||||
"e": 2.718,
|
||||
"enabled": true,
|
||||
"user": "john",
|
||||
"resolution": {
|
||||
"x": 1024,
|
||||
"y": 768
|
||||
},
|
||||
"colors": [
|
||||
"Red",
|
||||
"Green",
|
||||
"Blue"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
The code to do so would look like this:
|
||||
|
||||
```cpp
|
||||
JsonBuilder jb;
|
||||
jb.push_back(jb.end(), "e", 2.718);
|
||||
jb.push_back(jb.end(), "enabled", true);
|
||||
jb.push_back(jb.end(), "user", "john");
|
||||
|
||||
JsonIterator resolutionItr = jb.push_back(jb.end(), "resolution", JsonObject);
|
||||
jb.push_back(resolutionItr, "x", 1024);
|
||||
jb.push_back(resolutionItr, "y", 768);
|
||||
|
||||
JsonIterator colorIterator = jb.push_back(jb.end(), "colors", JsonArray);
|
||||
jb.push_back(colorIterator, "", "Red");
|
||||
jb.push_back(colorIterator, "", "Green");
|
||||
jb.push_back(colorIterator, "", "Blue");
|
||||
```
|
||||
|
||||
### Getting an iterator to existing data
|
||||
|
||||
Using the built JsonBuilder object above as a starting point:
|
||||
|
||||
```cpp
|
||||
// Float
|
||||
JsonConstIterator eItr = jb.find("e");
|
||||
float e = eItr->GetUnchecked<float>();
|
||||
std::cout << e << std::endl;
|
||||
|
||||
// Object
|
||||
JsonConstIterator resolutionItr = jb.find("resolution");
|
||||
for (JsonConstIterator beginItr = resolutionItr.begin(),
|
||||
endItr = resolutionItr.end();
|
||||
beginItr != endItr;
|
||||
++beginItr)
|
||||
{
|
||||
std::string name(beginItr->Name().data(), beginItr->Name().length());
|
||||
std::cout << name << " " << beginItr->GetUnchecked<int64_t>()
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
// Array
|
||||
JsonConstIterator colorsItr = jb.find("colors");
|
||||
for (JsonConstIterator beginItr = colorsItr.begin(), endItr = colorsItr.end();
|
||||
beginItr != endItr;
|
||||
++beginItr)
|
||||
{
|
||||
auto color = beginItr->GetUnchecked<std::string_view>();
|
||||
std::cout << color << std::endl;
|
||||
}
|
||||
```
|
||||
|
||||
### Rendering to JSON
|
||||
|
||||
Using the built JsonBuilder object above as a starting point:
|
||||
|
||||
```cpp
|
||||
// Create a renderer and reserve 2048 bytes up front
|
||||
JsonRenderer renderer;
|
||||
renderer.Reserve(2048);
|
||||
|
||||
// Render a json builder object to a string
|
||||
std::string_view result = renderer.Render(_jsonBuilder);
|
||||
std::string stl_string(result.data(), result.size());
|
||||
std::cout << stl_string.c_str() << std::endl;
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
This project carries a dependency on the uuid library. To develop with this project, install the development version of the library:
|
||||
|
||||
```bash
|
||||
sudo apt-get install uuid-dev
|
||||
```
|
||||
|
||||
If you checkout with submodules, you will receive a version of Catch2 for testing that can be used automatically. If you do not checkout
|
||||
this submodule, the build system will instead search for an installed version of Catch2 and use that.
|
||||
|
||||
## Integration
|
||||
|
||||
JsonBuilder builds as a static library and requires C++11. The project creates a CMake compatible 'jsonbuilder' target which you can use for linking against the library.
|
||||
|
||||
1. Add this project as a subdirectory in your project, either as a git submodule or copying the code directly.
|
||||
2. Add that directory to your top-level CMakeLists.txt with 'add_subdirectory'. This will make the 'jsonbuilder' target available.
|
||||
3. Add the 'jsonbuilder' target to the target_link_libraries of any target that will use the JsonBuilder library.
|
||||
|
||||
## Reporting Security Issues
|
||||
|
||||
Security issues and bugs should be reported privately, via email, to the
|
||||
Microsoft Security Response Center (MSRC) at <[secure@microsoft.com](mailto:secure@microsoft.com)>.
|
||||
You should receive a response within 24 hours. If for some reason you do not, please follow up via
|
||||
email to ensure we received your original message. Further information, including the
|
||||
[MSRC PGP](https://technet.microsoft.com/en-us/security/dn606155) key, can be found in the
|
||||
[Security TechCenter](https://technet.microsoft.com/en-us/security/default).
|
||||
|
||||
## Code of Conduct
|
||||
|
||||
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
|
||||
|
||||
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
|
||||
|
||||
## Contributing
|
||||
|
||||
Want to contribute? The team encourages community feedback and contributions. Please follow our [contributing guidelines](CONTRIBUTING.md).
|
||||
|
||||
We also welcome [issues submitted on GitHub](https://github.com/Microsoft/JsonBuilder/issues).
|
||||
|
||||
## Project Status
|
||||
|
||||
This project is currently in active development.
|
||||
|
||||
## Contact
|
||||
|
||||
The easiest way to contact us is via the [Issues](https://github.com/microsoft/JsonBuilder/issues) page.
|
|
@ -1,40 +1,40 @@
|
|||
# Output target
|
||||
# uuid::uuid
|
||||
|
||||
include(AliasPkgConfigTarget)
|
||||
|
||||
if (TARGET uuid::uuid)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# First try and find with PkgConfig
|
||||
find_package(PkgConfig QUIET)
|
||||
if (PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(uuid REQUIRED IMPORTED_TARGET uuid)
|
||||
if (TARGET PkgConfig::uuid)
|
||||
alias_pkg_config_target(uuid::uuid PkgConfig::uuid)
|
||||
return()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
# If that doesn't work, try again with old fashioned path lookup, with some caching
|
||||
if (NOT (uuid_INCLUDE_DIR AND uuid_LIBRARY))
|
||||
find_path(uuid_INCLUDE_DIR
|
||||
NAMES uuid/uuid.h)
|
||||
find_library(uuid_LIBRARY
|
||||
NAMES uuid)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(uuid DEFAULT_MSG
|
||||
uuid_LIBRARY
|
||||
uuid_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(uuid_LIBRARY uuid_INCLUDE_DIR)
|
||||
endif()
|
||||
|
||||
add_library(uuid::uuid UNKNOWN IMPORTED)
|
||||
set_target_properties(uuid::uuid PROPERTIES
|
||||
IMPORTED_LOCATION "${uuid_LIBRARY}"
|
||||
IMPORTED_INCLUDE_DIRECTORIES "${uuid_INCLUDE_DIR}")
|
||||
|
||||
set(uuid_FOUND TRUE)
|
||||
# Output target
|
||||
# uuid::uuid
|
||||
|
||||
include(AliasPkgConfigTarget)
|
||||
|
||||
if (TARGET uuid::uuid)
|
||||
return()
|
||||
endif()
|
||||
|
||||
# First try and find with PkgConfig
|
||||
find_package(PkgConfig QUIET)
|
||||
if (PKG_CONFIG_FOUND)
|
||||
pkg_check_modules(uuid REQUIRED IMPORTED_TARGET uuid)
|
||||
if (TARGET PkgConfig::uuid)
|
||||
alias_pkg_config_target(uuid::uuid PkgConfig::uuid)
|
||||
return()
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
# If that doesn't work, try again with old fashioned path lookup, with some caching
|
||||
if (NOT (uuid_INCLUDE_DIR AND uuid_LIBRARY))
|
||||
find_path(uuid_INCLUDE_DIR
|
||||
NAMES uuid/uuid.h)
|
||||
find_library(uuid_LIBRARY
|
||||
NAMES uuid)
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(uuid DEFAULT_MSG
|
||||
uuid_LIBRARY
|
||||
uuid_INCLUDE_DIR)
|
||||
|
||||
mark_as_advanced(uuid_LIBRARY uuid_INCLUDE_DIR)
|
||||
endif()
|
||||
|
||||
add_library(uuid::uuid UNKNOWN IMPORTED)
|
||||
set_target_properties(uuid::uuid PROPERTIES
|
||||
IMPORTED_LOCATION "${uuid_LIBRARY}"
|
||||
IMPORTED_INCLUDE_DIRECTORIES "${uuid_INCLUDE_DIR}")
|
||||
|
||||
set(uuid_FOUND TRUE)
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,278 +1,278 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
JsonRenderer converts JsonBuilder trees into utf8 JSON text.
|
||||
|
||||
Summary:
|
||||
- JsonRenderer
|
||||
- JsonRenderBool
|
||||
- JsonRenderFalse
|
||||
- JsonRenderTime
|
||||
- JsonRenderFloat
|
||||
- JsonRenderInt
|
||||
- JsonRenderNull
|
||||
- JsonRenderTrue
|
||||
- JsonRenderUInt
|
||||
- JsonRenderUuid
|
||||
- JsonRenderUuidWithBraces
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <jsonbuilder/JsonBuilder.h>
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
|
||||
namespace jsonbuilder {
|
||||
/*
|
||||
Converts JsonBuilder data into utf-8 JSON text.
|
||||
Recognizes the built-in JsonType types. To support other (custom) types,
|
||||
derive from JsonRenderer and override RenderCustom.
|
||||
*/
|
||||
class JsonRenderer
|
||||
{
|
||||
protected:
|
||||
typedef JsonInternal::PodVector<char> RenderBuffer;
|
||||
typedef JsonBuilder::const_iterator iterator;
|
||||
|
||||
private:
|
||||
RenderBuffer m_renderBuffer;
|
||||
std::string_view m_newLine;
|
||||
unsigned m_indentSpaces;
|
||||
unsigned m_indent;
|
||||
bool m_pretty;
|
||||
|
||||
public:
|
||||
typedef JsonInternal::PodVector<char>::size_type size_type;
|
||||
|
||||
/*
|
||||
Initializes a new instance of the JsonRenderer class.
|
||||
Optionally sets the initial value of the formatting properties.
|
||||
*/
|
||||
explicit JsonRenderer(
|
||||
bool pretty = false,
|
||||
std::string_view const& newLine = "\n",
|
||||
unsigned indentSpaces = 2) throw();
|
||||
|
||||
/*
|
||||
Preallocates memory in the rendering buffer (increases capacity).
|
||||
*/
|
||||
void Reserve(size_type cb); // may throw bad_alloc, length_error
|
||||
|
||||
/*
|
||||
Gets the current size of the rendering buffer, in bytes.
|
||||
*/
|
||||
size_type Size() const throw();
|
||||
|
||||
/*
|
||||
Gets the current capacity of the rendering buffer (how large it can grow
|
||||
without allocating additional memory), in bytes.
|
||||
*/
|
||||
size_type Capacity() const throw();
|
||||
|
||||
/*
|
||||
Gets a value indicating whether the output will be formatted nicely.
|
||||
If true, insignificant whitespace (spaces and newlines) will be added to
|
||||
improve readability by humans and to put each value on its own line.
|
||||
If false, all insignificant whitespace will be omitted.
|
||||
Default value is false.
|
||||
*/
|
||||
bool Pretty() const throw();
|
||||
|
||||
/*
|
||||
Set a value indicating whether the output will be formatted nicely.
|
||||
If true, insignificant whitespace (spaces and newlines) will be added to
|
||||
improve readability by humans and to put each value on its own line.
|
||||
If false, all insignificant whitespace will be omitted.
|
||||
Default value is false.
|
||||
*/
|
||||
void Pretty(bool) throw();
|
||||
|
||||
/*
|
||||
Gets the string that is used for newline when Pretty() is true.
|
||||
Default value is "\r\n".
|
||||
*/
|
||||
std::string_view const& NewLine() const throw();
|
||||
|
||||
/*
|
||||
Sets the string that is used for newline when Pretty() is true.
|
||||
Note that the JsonRenderer will store a copy of the string_view, but it
|
||||
does not make a copy of the actual string. The string passed in here must
|
||||
be valid for as long as the JsonRenderer exists.
|
||||
Default value is "\r\n".
|
||||
*/
|
||||
void NewLine(std::string_view const&) throw();
|
||||
|
||||
/*
|
||||
Gets the number of spaces per indent level. Default value is 2.
|
||||
*/
|
||||
unsigned IndentSpaces() const throw();
|
||||
|
||||
/*
|
||||
Sets the number of spaces per indent level. Default value is 2.
|
||||
*/
|
||||
void IndentSpaces(unsigned) throw();
|
||||
|
||||
/*
|
||||
Renders the contents of the specified JsonBuilder as utf-8 JSON, starting
|
||||
at the root value.
|
||||
Returns a string_view with the resulting JSON string. The returned string
|
||||
is nul-terminated, but the nul is not included as part of the string_view
|
||||
itself, so return.data()[return.size()] == '\0'.
|
||||
The returned string_view is valid until the next call to Render or until
|
||||
this JsonBuilder is destroyed.
|
||||
*/
|
||||
std::string_view Render(JsonBuilder const& builder); // may throw
|
||||
// bad_alloc,
|
||||
// length_error
|
||||
|
||||
/*
|
||||
Renders the contents of a JsonBuilder as utf-8 JSON, starting at the
|
||||
specified value.
|
||||
Returns a string_view with the resulting JSON string. The returned string
|
||||
is nul-terminated, but the nul is not included as part of the string_view
|
||||
itself, so return.data()[return.size()] == '\0'.
|
||||
The returned string_view is valid until the next call to Render or until
|
||||
this JsonBuilder is destroyed.
|
||||
*/
|
||||
std::string_view
|
||||
Render(JsonBuilder::const_iterator const& it); // may throw bad_alloc,
|
||||
// length_error
|
||||
|
||||
protected:
|
||||
/*
|
||||
Override this method to provide rendering behavior for custom value types.
|
||||
The utf-8 representation of the value referenced by itValue should be
|
||||
appended to the end of buffer by calling buffer.push_back with the bytes
|
||||
of the utf-8 representation.
|
||||
*/
|
||||
virtual void RenderCustom(
|
||||
RenderBuffer& buffer,
|
||||
iterator const& itValue); // may throw bad_alloc, length_error
|
||||
|
||||
private:
|
||||
/*
|
||||
Renders any value and its children by dispatching to the appropriate
|
||||
subroutine.
|
||||
CANNOT RENDER THE ROOT! (Don't call this if it.IsRoot() is true.)
|
||||
*/
|
||||
void RenderValue(iterator const& it);
|
||||
|
||||
/*
|
||||
Renders an object/array value and its children.
|
||||
itParent must be an array or object.
|
||||
Set showNames = true for object. Set showNames = false for array.
|
||||
Can be called with itParent == end() to render the root.
|
||||
Example output: {"ObjectName":{"ArrayName":[7]}}
|
||||
*/
|
||||
void RenderStructure(iterator const& itParent, bool showNames);
|
||||
|
||||
/*
|
||||
Renders value as floating-point. Requires that cb be 4 or 8. Data will be
|
||||
interpreted as a little-endian float or double.
|
||||
Example output: 123.45
|
||||
*/
|
||||
void RenderFloat(double const& value);
|
||||
|
||||
/*
|
||||
Renders value as signed integer. Requires that cb be 1, 2, 4 or 8. Data will
|
||||
be interpreted as a little-endian signed integer.
|
||||
Example output: -12345
|
||||
*/
|
||||
void RenderInt(long long signed const& value);
|
||||
|
||||
/*
|
||||
Renders value as unsigned integer. Requires that cb be 1, 2, 4 or 8. Data
|
||||
will be interpreted as a little-endian unsigned integer.
|
||||
Example output: 12345
|
||||
*/
|
||||
void RenderUInt(long long unsigned const& value);
|
||||
|
||||
/*
|
||||
Renders value as time. Requires that cb be 8. Data will be interpreted as
|
||||
number of 100ns intervals since 1601-01-01T00:00:00Z.
|
||||
Example output: "2015-04-02T02:09:14.7927652Z".
|
||||
*/
|
||||
void RenderTime(std::chrono::system_clock::time_point const& value);
|
||||
|
||||
/*
|
||||
Renders value as UUID. Requires that cb be 16.
|
||||
Example output: "CD8D0A5E-6409-4B8E-9366-B815CEF0E35D".
|
||||
*/
|
||||
void RenderUuid(uuid_t const& value);
|
||||
|
||||
/*
|
||||
Renders value as a string. Converts pch to utf-8, escapes any control
|
||||
characters, and adds quotes around the result. Example output: "String\n"
|
||||
*/
|
||||
void RenderString(std::string_view const& value);
|
||||
|
||||
/*
|
||||
If pretty-printing is disabled, has no effect.
|
||||
If pretty-printing is enabled, writes m_newLine followed by
|
||||
(m_indent * m_indentSpaces) space characters.
|
||||
*/
|
||||
void RenderNewline();
|
||||
};
|
||||
|
||||
/*
|
||||
Renders the given value as an unsigned decimal integer, e.g. "123".
|
||||
Returns the number of characters written, not counting the nul-termination.
|
||||
*/
|
||||
unsigned JsonRenderUInt(long long unsigned n, char* pBuffer) throw();
|
||||
|
||||
/*
|
||||
Renders the given value as a signed decimal integer, e.g. "-123".
|
||||
Returns the number of characters written, not counting the nul-termination.
|
||||
*/
|
||||
unsigned JsonRenderInt(long long signed n, char* pBuffer) throw();
|
||||
|
||||
/*
|
||||
Renders the given value as a signed floating-point, e.g. "-123.1", or "null"
|
||||
if the value is not finite.
|
||||
Returns the number of characters written, not counting the nul-termination.
|
||||
*/
|
||||
unsigned JsonRenderFloat(double n, char* pBuffer) throw();
|
||||
|
||||
/*
|
||||
Renders the string "true" or "false".
|
||||
Returns the number of characters written, not counting the nul-termination.
|
||||
(Always returns 4 or 5.)
|
||||
*/
|
||||
unsigned JsonRenderBool(bool b, char* pBuffer) throw();
|
||||
|
||||
/*
|
||||
Renders the string "null".
|
||||
Returns the number of characters written, not counting the nul-termination.
|
||||
(Always returns 4.)
|
||||
*/
|
||||
unsigned JsonRenderNull(char* pBuffer) throw();
|
||||
|
||||
/*
|
||||
Renders the given FILETIME value (uint64) as an ISO 8601 string, e.g.
|
||||
"2015-04-02T02:09:14.7927652Z".
|
||||
Returns the number of characters written, not counting the nul-termination.
|
||||
(Always returns 28.)
|
||||
*/
|
||||
unsigned JsonRenderTime(
|
||||
std::chrono::system_clock::time_point const& ft,
|
||||
char* pBuffer) throw();
|
||||
|
||||
/*
|
||||
Renders the given GUID value as a string in uppercase without braces, e.g.
|
||||
"CD8D0A5E-6409-4B8E-9366-B815CEF0E35D".
|
||||
Returns the number of characters written, not counting the nul-termination.
|
||||
(Always returns 36.)
|
||||
*/
|
||||
unsigned JsonRenderUuid(uuid_t const& g, char* pBuffer) throw();
|
||||
|
||||
/*
|
||||
Renders the given GUID value as a string in uppercase with braces, e.g.
|
||||
"{CD8D0A5E-6409-4B8E-9366-B815CEF0E35D}".
|
||||
Returns the number of characters written, not counting the nul-termination.
|
||||
(Always returns 38.)
|
||||
*/
|
||||
unsigned JsonRenderUuidWithBraces(uuid_t const& g, char* pBuffer) throw();
|
||||
|
||||
} // namespace jsonbuilder
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
/*
|
||||
JsonRenderer converts JsonBuilder trees into utf8 JSON text.
|
||||
|
||||
Summary:
|
||||
- JsonRenderer
|
||||
- JsonRenderBool
|
||||
- JsonRenderFalse
|
||||
- JsonRenderTime
|
||||
- JsonRenderFloat
|
||||
- JsonRenderInt
|
||||
- JsonRenderNull
|
||||
- JsonRenderTrue
|
||||
- JsonRenderUInt
|
||||
- JsonRenderUuid
|
||||
- JsonRenderUuidWithBraces
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <jsonbuilder/JsonBuilder.h>
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
|
||||
namespace jsonbuilder {
|
||||
/*
|
||||
Converts JsonBuilder data into utf-8 JSON text.
|
||||
Recognizes the built-in JsonType types. To support other (custom) types,
|
||||
derive from JsonRenderer and override RenderCustom.
|
||||
*/
|
||||
class JsonRenderer
|
||||
{
|
||||
protected:
|
||||
typedef JsonInternal::PodVector<char> RenderBuffer;
|
||||
typedef JsonBuilder::const_iterator iterator;
|
||||
|
||||
private:
|
||||
RenderBuffer m_renderBuffer;
|
||||
std::string_view m_newLine;
|
||||
unsigned m_indentSpaces;
|
||||
unsigned m_indent;
|
||||
bool m_pretty;
|
||||
|
||||
public:
|
||||
typedef JsonInternal::PodVector<char>::size_type size_type;
|
||||
|
||||
/*
|
||||
Initializes a new instance of the JsonRenderer class.
|
||||
Optionally sets the initial value of the formatting properties.
|
||||
*/
|
||||
explicit JsonRenderer(
|
||||
bool pretty = false,
|
||||
std::string_view const& newLine = "\n",
|
||||
unsigned indentSpaces = 2) throw();
|
||||
|
||||
/*
|
||||
Preallocates memory in the rendering buffer (increases capacity).
|
||||
*/
|
||||
void Reserve(size_type cb); // may throw bad_alloc, length_error
|
||||
|
||||
/*
|
||||
Gets the current size of the rendering buffer, in bytes.
|
||||
*/
|
||||
size_type Size() const throw();
|
||||
|
||||
/*
|
||||
Gets the current capacity of the rendering buffer (how large it can grow
|
||||
without allocating additional memory), in bytes.
|
||||
*/
|
||||
size_type Capacity() const throw();
|
||||
|
||||
/*
|
||||
Gets a value indicating whether the output will be formatted nicely.
|
||||
If true, insignificant whitespace (spaces and newlines) will be added to
|
||||
improve readability by humans and to put each value on its own line.
|
||||
If false, all insignificant whitespace will be omitted.
|
||||
Default value is false.
|
||||
*/
|
||||
bool Pretty() const throw();
|
||||
|
||||
/*
|
||||
Set a value indicating whether the output will be formatted nicely.
|
||||
If true, insignificant whitespace (spaces and newlines) will be added to
|
||||
improve readability by humans and to put each value on its own line.
|
||||
If false, all insignificant whitespace will be omitted.
|
||||
Default value is false.
|
||||
*/
|
||||
void Pretty(bool) throw();
|
||||
|
||||
/*
|
||||
Gets the string that is used for newline when Pretty() is true.
|
||||
Default value is "\r\n".
|
||||
*/
|
||||
std::string_view const& NewLine() const throw();
|
||||
|
||||
/*
|
||||
Sets the string that is used for newline when Pretty() is true.
|
||||
Note that the JsonRenderer will store a copy of the string_view, but it
|
||||
does not make a copy of the actual string. The string passed in here must
|
||||
be valid for as long as the JsonRenderer exists.
|
||||
Default value is "\r\n".
|
||||
*/
|
||||
void NewLine(std::string_view const&) throw();
|
||||
|
||||
/*
|
||||
Gets the number of spaces per indent level. Default value is 2.
|
||||
*/
|
||||
unsigned IndentSpaces() const throw();
|
||||
|
||||
/*
|
||||
Sets the number of spaces per indent level. Default value is 2.
|
||||
*/
|
||||
void IndentSpaces(unsigned) throw();
|
||||
|
||||
/*
|
||||
Renders the contents of the specified JsonBuilder as utf-8 JSON, starting
|
||||
at the root value.
|
||||
Returns a string_view with the resulting JSON string. The returned string
|
||||
is nul-terminated, but the nul is not included as part of the string_view
|
||||
itself, so return.data()[return.size()] == '\0'.
|
||||
The returned string_view is valid until the next call to Render or until
|
||||
this JsonBuilder is destroyed.
|
||||
*/
|
||||
std::string_view Render(JsonBuilder const& builder); // may throw
|
||||
// bad_alloc,
|
||||
// length_error
|
||||
|
||||
/*
|
||||
Renders the contents of a JsonBuilder as utf-8 JSON, starting at the
|
||||
specified value.
|
||||
Returns a string_view with the resulting JSON string. The returned string
|
||||
is nul-terminated, but the nul is not included as part of the string_view
|
||||
itself, so return.data()[return.size()] == '\0'.
|
||||
The returned string_view is valid until the next call to Render or until
|
||||
this JsonBuilder is destroyed.
|
||||
*/
|
||||
std::string_view
|
||||
Render(JsonBuilder::const_iterator const& it); // may throw bad_alloc,
|
||||
// length_error
|
||||
|
||||
protected:
|
||||
/*
|
||||
Override this method to provide rendering behavior for custom value types.
|
||||
The utf-8 representation of the value referenced by itValue should be
|
||||
appended to the end of buffer by calling buffer.push_back with the bytes
|
||||
of the utf-8 representation.
|
||||
*/
|
||||
virtual void RenderCustom(
|
||||
RenderBuffer& buffer,
|
||||
iterator const& itValue); // may throw bad_alloc, length_error
|
||||
|
||||
private:
|
||||
/*
|
||||
Renders any value and its children by dispatching to the appropriate
|
||||
subroutine.
|
||||
CANNOT RENDER THE ROOT! (Don't call this if it.IsRoot() is true.)
|
||||
*/
|
||||
void RenderValue(iterator const& it);
|
||||
|
||||
/*
|
||||
Renders an object/array value and its children.
|
||||
itParent must be an array or object.
|
||||
Set showNames = true for object. Set showNames = false for array.
|
||||
Can be called with itParent == end() to render the root.
|
||||
Example output: {"ObjectName":{"ArrayName":[7]}}
|
||||
*/
|
||||
void RenderStructure(iterator const& itParent, bool showNames);
|
||||
|
||||
/*
|
||||
Renders value as floating-point. Requires that cb be 4 or 8. Data will be
|
||||
interpreted as a little-endian float or double.
|
||||
Example output: 123.45
|
||||
*/
|
||||
void RenderFloat(double const& value);
|
||||
|
||||
/*
|
||||
Renders value as signed integer. Requires that cb be 1, 2, 4 or 8. Data will
|
||||
be interpreted as a little-endian signed integer.
|
||||
Example output: -12345
|
||||
*/
|
||||
void RenderInt(long long signed const& value);
|
||||
|
||||
/*
|
||||
Renders value as unsigned integer. Requires that cb be 1, 2, 4 or 8. Data
|
||||
will be interpreted as a little-endian unsigned integer.
|
||||
Example output: 12345
|
||||
*/
|
||||
void RenderUInt(long long unsigned const& value);
|
||||
|
||||
/*
|
||||
Renders value as time. Requires that cb be 8. Data will be interpreted as
|
||||
number of 100ns intervals since 1601-01-01T00:00:00Z.
|
||||
Example output: "2015-04-02T02:09:14.7927652Z".
|
||||
*/
|
||||
void RenderTime(std::chrono::system_clock::time_point const& value);
|
||||
|
||||
/*
|
||||
Renders value as UUID. Requires that cb be 16.
|
||||
Example output: "CD8D0A5E-6409-4B8E-9366-B815CEF0E35D".
|
||||
*/
|
||||
void RenderUuid(uuid_t const& value);
|
||||
|
||||
/*
|
||||
Renders value as a string. Converts pch to utf-8, escapes any control
|
||||
characters, and adds quotes around the result. Example output: "String\n"
|
||||
*/
|
||||
void RenderString(std::string_view const& value);
|
||||
|
||||
/*
|
||||
If pretty-printing is disabled, has no effect.
|
||||
If pretty-printing is enabled, writes m_newLine followed by
|
||||
(m_indent * m_indentSpaces) space characters.
|
||||
*/
|
||||
void RenderNewline();
|
||||
};
|
||||
|
||||
/*
|
||||
Renders the given value as an unsigned decimal integer, e.g. "123".
|
||||
Returns the number of characters written, not counting the nul-termination.
|
||||
*/
|
||||
unsigned JsonRenderUInt(long long unsigned n, char* pBuffer) throw();
|
||||
|
||||
/*
|
||||
Renders the given value as a signed decimal integer, e.g. "-123".
|
||||
Returns the number of characters written, not counting the nul-termination.
|
||||
*/
|
||||
unsigned JsonRenderInt(long long signed n, char* pBuffer) throw();
|
||||
|
||||
/*
|
||||
Renders the given value as a signed floating-point, e.g. "-123.1", or "null"
|
||||
if the value is not finite.
|
||||
Returns the number of characters written, not counting the nul-termination.
|
||||
*/
|
||||
unsigned JsonRenderFloat(double n, char* pBuffer) throw();
|
||||
|
||||
/*
|
||||
Renders the string "true" or "false".
|
||||
Returns the number of characters written, not counting the nul-termination.
|
||||
(Always returns 4 or 5.)
|
||||
*/
|
||||
unsigned JsonRenderBool(bool b, char* pBuffer) throw();
|
||||
|
||||
/*
|
||||
Renders the string "null".
|
||||
Returns the number of characters written, not counting the nul-termination.
|
||||
(Always returns 4.)
|
||||
*/
|
||||
unsigned JsonRenderNull(char* pBuffer) throw();
|
||||
|
||||
/*
|
||||
Renders the given FILETIME value (uint64) as an ISO 8601 string, e.g.
|
||||
"2015-04-02T02:09:14.7927652Z".
|
||||
Returns the number of characters written, not counting the nul-termination.
|
||||
(Always returns 28.)
|
||||
*/
|
||||
unsigned JsonRenderTime(
|
||||
std::chrono::system_clock::time_point const& ft,
|
||||
char* pBuffer) throw();
|
||||
|
||||
/*
|
||||
Renders the given GUID value as a string in uppercase without braces, e.g.
|
||||
"CD8D0A5E-6409-4B8E-9366-B815CEF0E35D".
|
||||
Returns the number of characters written, not counting the nul-termination.
|
||||
(Always returns 36.)
|
||||
*/
|
||||
unsigned JsonRenderUuid(uuid_t const& g, char* pBuffer) throw();
|
||||
|
||||
/*
|
||||
Renders the given GUID value as a string in uppercase with braces, e.g.
|
||||
"{CD8D0A5E-6409-4B8E-9366-B815CEF0E35D}".
|
||||
Returns the number of characters written, not counting the nul-termination.
|
||||
(Always returns 38.)
|
||||
*/
|
||||
unsigned JsonRenderUuidWithBraces(uuid_t const& g, char* pBuffer) throw();
|
||||
|
||||
} // namespace jsonbuilder
|
||||
|
|
|
@ -1,40 +1,40 @@
|
|||
cmake_minimum_required(VERSION 3.7)
|
||||
|
||||
add_library(jsonbuilder
|
||||
JsonBuilder.cpp
|
||||
JsonRenderer.cpp
|
||||
PodVector.cpp)
|
||||
|
||||
target_include_directories(jsonbuilder
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:include>)
|
||||
|
||||
target_link_libraries(jsonbuilder PUBLIC uuid::uuid)
|
||||
target_compile_features(jsonbuilder PUBLIC cxx_std_17)
|
||||
|
||||
set_property(TARGET jsonbuilder PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
set_property(TARGET jsonbuilder PROPERTY SOVERSION 0)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
install(TARGETS jsonbuilder
|
||||
EXPORT jsonbuilder-export
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
INCLUDES DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
|
||||
add_library(jsonbuilder::jsonbuilder ALIAS jsonbuilder)
|
||||
|
||||
install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
|
||||
set(JSONBUILDER_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/jsonbuilder)
|
||||
|
||||
install(EXPORT jsonbuilder-export
|
||||
FILE jsonbuilderTargets.cmake
|
||||
NAMESPACE jsonbuilder::
|
||||
DESTINATION ${JSONBUILDER_CMAKE_DIR})
|
||||
|
||||
install(FILES ${PROJECT_SOURCE_DIR}/cmake/modules/jsonbuilderConfig.cmake
|
||||
DESTINATION ${JSONBUILDER_CMAKE_DIR})
|
||||
cmake_minimum_required(VERSION 3.7)
|
||||
|
||||
add_library(jsonbuilder
|
||||
JsonBuilder.cpp
|
||||
JsonRenderer.cpp
|
||||
PodVector.cpp)
|
||||
|
||||
target_include_directories(jsonbuilder
|
||||
PUBLIC
|
||||
$<BUILD_INTERFACE:${PROJECT_SOURCE_DIR}/include>
|
||||
$<INSTALL_INTERFACE:include>)
|
||||
|
||||
target_link_libraries(jsonbuilder PUBLIC uuid::uuid)
|
||||
target_compile_features(jsonbuilder PUBLIC cxx_std_17)
|
||||
|
||||
set_property(TARGET jsonbuilder PROPERTY POSITION_INDEPENDENT_CODE ON)
|
||||
set_property(TARGET jsonbuilder PROPERTY SOVERSION 0)
|
||||
|
||||
include(GNUInstallDirs)
|
||||
|
||||
install(TARGETS jsonbuilder
|
||||
EXPORT jsonbuilder-export
|
||||
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
INCLUDES DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
|
||||
add_library(jsonbuilder::jsonbuilder ALIAS jsonbuilder)
|
||||
|
||||
install(DIRECTORY ${PROJECT_SOURCE_DIR}/include/ DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
|
||||
|
||||
set(JSONBUILDER_CMAKE_DIR ${CMAKE_INSTALL_LIBDIR}/cmake/jsonbuilder)
|
||||
|
||||
install(EXPORT jsonbuilder-export
|
||||
FILE jsonbuilderTargets.cmake
|
||||
NAMESPACE jsonbuilder::
|
||||
DESTINATION ${JSONBUILDER_CMAKE_DIR})
|
||||
|
||||
install(FILES ${PROJECT_SOURCE_DIR}/cmake/modules/jsonbuilderConfig.cmake
|
||||
DESTINATION ${JSONBUILDER_CMAKE_DIR})
|
||||
|
|
2846
src/JsonBuilder.cpp
2846
src/JsonBuilder.cpp
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -1,486 +1,486 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
|
||||
#include <jsonbuilder/JsonRenderer.h>
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
#define WriteChar(ch) m_renderBuffer.push_back(ch)
|
||||
#define WriteChars(pch, cch) m_renderBuffer.append(pch, cch)
|
||||
|
||||
namespace jsonbuilder {
|
||||
/*
|
||||
Efficiently multiply two 32-bit unsigned integers to get a 64-bit result.
|
||||
(The current VC compiler does not optimize this -- if we don't use an
|
||||
intrinsic, it makes a call to _aullmul.)
|
||||
*/
|
||||
#if defined(_M_ARM) || defined(_M_ARM64)
|
||||
# define UMul64(a, b) _arm_umull(a, b)
|
||||
#elif defined(_M_IX86) || defined(_M_X64)
|
||||
# define UMul64(a, b) __emulu(a, b)
|
||||
#else
|
||||
static long long unsigned UMul64(unsigned a, unsigned b)
|
||||
{
|
||||
return static_cast<long long unsigned>(a) * b;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
Given a number from 0..15, returns the corresponding uppercase hex digit,
|
||||
i.e. '0'..'F'. Note: it is an error to pass a value larger than 15.
|
||||
*/
|
||||
static inline constexpr char u4_to_hex_upper(char unsigned _Val4)
|
||||
{
|
||||
return ("0123456789ABCDEF")[_Val4];
|
||||
}
|
||||
|
||||
/*
|
||||
Multiply two 64-bit unsigned integers to get a 128-bit result. Return the high
|
||||
64 bits of the answer.
|
||||
*/
|
||||
__attribute__((unused)) static long long unsigned
|
||||
UMul128Hi(long long unsigned a, long long unsigned b)
|
||||
{
|
||||
#if defined(_M_X64) || defined(_M_ARM64)
|
||||
long long unsigned const high = __umulh(a, b);
|
||||
#else
|
||||
long long unsigned const mid =
|
||||
UMul64(static_cast<unsigned>(a), static_cast<unsigned>(b >> 32)) +
|
||||
(UMul64(static_cast<unsigned>(a), static_cast<unsigned>(b)) >> 32);
|
||||
long long unsigned const high =
|
||||
UMul64(static_cast<unsigned>(a >> 32), static_cast<unsigned>(b >> 32)) +
|
||||
(mid >> 32) +
|
||||
((UMul64(static_cast<unsigned>(a >> 32), static_cast<unsigned>(b)) +
|
||||
static_cast<unsigned>(mid)) >>
|
||||
32);
|
||||
#endif
|
||||
return high;
|
||||
}
|
||||
|
||||
/*
|
||||
Formats a uint32 with leading 0s. Always writes cch characters.
|
||||
*/
|
||||
static void FormatUint(unsigned n, char* pch, unsigned cch)
|
||||
{
|
||||
do
|
||||
{
|
||||
--cch;
|
||||
pch[cch] = '0' + (n % 10);
|
||||
n = n / 10;
|
||||
} while (cch != 0);
|
||||
}
|
||||
|
||||
template<unsigned CB, class N>
|
||||
static unsigned JsonRenderXInt(N const& n, char* pBuffer)
|
||||
{
|
||||
// TODO: Why can't we use std::to_wchars when we're using c++17?
|
||||
std::string result = std::to_string(n);
|
||||
std::size_t const cch =
|
||||
std::min(result.size(), static_cast<std::size_t>(CB - 1));
|
||||
strncpy(pBuffer, result.c_str(), cch);
|
||||
pBuffer[cch] = 0;
|
||||
|
||||
pBuffer[cch] = 0;
|
||||
return static_cast<unsigned>(cch);
|
||||
}
|
||||
|
||||
unsigned JsonRenderUInt(long long unsigned n, char* pBuffer) throw()
|
||||
{
|
||||
return JsonRenderXInt<21>(n, pBuffer);
|
||||
}
|
||||
|
||||
unsigned JsonRenderInt(long long signed n, char* pBuffer) throw()
|
||||
{
|
||||
return JsonRenderXInt<21>(n, pBuffer);
|
||||
}
|
||||
|
||||
unsigned JsonRenderFloat(double n, char* pBuffer) throw()
|
||||
{
|
||||
unsigned cch;
|
||||
|
||||
if (std::isfinite(n))
|
||||
{
|
||||
cch = static_cast<unsigned>(snprintf(pBuffer, 31, "%.17g", n));
|
||||
if (cch > 31)
|
||||
{
|
||||
cch = 31;
|
||||
}
|
||||
pBuffer[cch] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cch = JsonRenderNull(pBuffer);
|
||||
}
|
||||
|
||||
return cch;
|
||||
}
|
||||
|
||||
unsigned JsonRenderBool(bool b, char* pBuffer) throw()
|
||||
{
|
||||
unsigned cch;
|
||||
if (b)
|
||||
{
|
||||
strcpy(pBuffer, "true");
|
||||
cch = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(pBuffer, "false");
|
||||
cch = 5;
|
||||
}
|
||||
return cch;
|
||||
}
|
||||
|
||||
unsigned JsonRenderNull(char* pBuffer) throw()
|
||||
{
|
||||
strcpy(pBuffer, "null");
|
||||
return 4;
|
||||
}
|
||||
|
||||
unsigned JsonRenderTime(
|
||||
std::chrono::system_clock::time_point const& timePoint,
|
||||
char* pBuffer) throw()
|
||||
{
|
||||
time_t printableTime = std::chrono::system_clock::to_time_t(timePoint);
|
||||
tm timeStruct = tm();
|
||||
gmtime_r(&printableTime, &timeStruct);
|
||||
|
||||
auto subsecondDuration =
|
||||
timePoint.time_since_epoch() % std::chrono::seconds{ 1 };
|
||||
auto subsecondNanos =
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(subsecondDuration);
|
||||
|
||||
FormatUint(static_cast<unsigned>(timeStruct.tm_year + 1900), pBuffer + 0, 4);
|
||||
pBuffer[4] = '-';
|
||||
FormatUint(static_cast<unsigned>(timeStruct.tm_mon + 1), pBuffer + 5, 2);
|
||||
pBuffer[7] = '-';
|
||||
FormatUint(static_cast<unsigned>(timeStruct.tm_mday), pBuffer + 8, 2);
|
||||
pBuffer[10] = 'T';
|
||||
FormatUint(static_cast<unsigned>(timeStruct.tm_hour), pBuffer + 11, 2);
|
||||
pBuffer[13] = ':';
|
||||
FormatUint(static_cast<unsigned>(timeStruct.tm_min), pBuffer + 14, 2);
|
||||
pBuffer[16] = ':';
|
||||
FormatUint(static_cast<unsigned>(timeStruct.tm_sec), pBuffer + 17, 2);
|
||||
pBuffer[19] = '.';
|
||||
FormatUint(
|
||||
static_cast<unsigned>(subsecondNanos.count() / 100), pBuffer + 20, 7);
|
||||
pBuffer[27] = 'Z';
|
||||
pBuffer[28] = 0;
|
||||
return 28;
|
||||
}
|
||||
|
||||
unsigned JsonRenderUuid(uuid_t const& g, char* pBuffer) throw()
|
||||
{
|
||||
uuid_unparse_upper(g, pBuffer);
|
||||
return 36;
|
||||
}
|
||||
|
||||
unsigned JsonRenderUuidWithBraces(uuid_t const& g, char* pBuffer) throw()
|
||||
{
|
||||
pBuffer[0] = '{';
|
||||
JsonRenderUuid(g, pBuffer + 1);
|
||||
pBuffer[37] = '}';
|
||||
pBuffer[38] = 0;
|
||||
return 38;
|
||||
}
|
||||
|
||||
JsonRenderer::JsonRenderer(
|
||||
bool pretty,
|
||||
std::string_view const& newLine,
|
||||
unsigned indentSpaces) throw()
|
||||
: m_newLine(newLine), m_indentSpaces(indentSpaces), m_pretty(pretty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void JsonRenderer::Reserve(size_type cb)
|
||||
{
|
||||
m_renderBuffer.reserve(cb);
|
||||
}
|
||||
|
||||
JsonRenderer::size_type JsonRenderer::Size() const throw()
|
||||
{
|
||||
return m_renderBuffer.size();
|
||||
}
|
||||
|
||||
JsonRenderer::size_type JsonRenderer::Capacity() const throw()
|
||||
{
|
||||
return m_renderBuffer.capacity();
|
||||
}
|
||||
|
||||
bool JsonRenderer::Pretty() const throw()
|
||||
{
|
||||
return m_pretty;
|
||||
}
|
||||
|
||||
void JsonRenderer::Pretty(bool value) throw()
|
||||
{
|
||||
m_pretty = value;
|
||||
}
|
||||
|
||||
std::string_view const& JsonRenderer::NewLine() const throw()
|
||||
{
|
||||
return m_newLine;
|
||||
}
|
||||
|
||||
void JsonRenderer::NewLine(std::string_view const& value) throw()
|
||||
{
|
||||
m_newLine = value;
|
||||
}
|
||||
|
||||
unsigned JsonRenderer::IndentSpaces() const throw()
|
||||
{
|
||||
return m_indentSpaces;
|
||||
}
|
||||
|
||||
void JsonRenderer::IndentSpaces(unsigned value) throw()
|
||||
{
|
||||
m_indentSpaces = value;
|
||||
}
|
||||
|
||||
std::string_view JsonRenderer::Render(JsonBuilder const& builder)
|
||||
{
|
||||
auto itRoot = builder.root();
|
||||
m_renderBuffer.clear();
|
||||
m_indent = 0;
|
||||
RenderStructure(itRoot, true);
|
||||
WriteChar('\0');
|
||||
return std::string_view(m_renderBuffer.data(), m_renderBuffer.size() - 1);
|
||||
}
|
||||
|
||||
std::string_view JsonRenderer::Render(JsonBuilder::const_iterator const& it)
|
||||
{
|
||||
m_renderBuffer.clear();
|
||||
m_indent = 0;
|
||||
if (it.IsRoot())
|
||||
{
|
||||
RenderStructure(it, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderValue(it);
|
||||
}
|
||||
WriteChar('\0');
|
||||
return std::string_view(m_renderBuffer.data(), m_renderBuffer.size() - 1);
|
||||
}
|
||||
|
||||
void JsonRenderer::RenderCustom(RenderBuffer&, iterator const& it)
|
||||
{
|
||||
auto const cchMax = 32u;
|
||||
auto pch = m_renderBuffer.GetAppendPointer(cchMax);
|
||||
unsigned cch =
|
||||
static_cast<unsigned>(snprintf(pch, cchMax, "\"Custom#%u\"", it->Type()));
|
||||
pch += cch > cchMax ? cchMax : cch;
|
||||
m_renderBuffer.SetEndPointer(pch);
|
||||
}
|
||||
|
||||
void JsonRenderer::RenderValue(iterator const& it)
|
||||
{
|
||||
assert(!it.IsRoot());
|
||||
switch (it->Type())
|
||||
{
|
||||
case JsonObject:
|
||||
RenderStructure(it, true);
|
||||
break;
|
||||
case JsonArray:
|
||||
RenderStructure(it, false);
|
||||
break;
|
||||
case JsonNull:
|
||||
WriteChars("null", 4);
|
||||
break;
|
||||
case JsonBool:
|
||||
if (it->GetUnchecked<bool>())
|
||||
{
|
||||
WriteChars("true", 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteChars("false", 5);
|
||||
}
|
||||
break;
|
||||
case JsonUtf8:
|
||||
RenderString(it->GetUnchecked<std::string_view>());
|
||||
break;
|
||||
case JsonFloat:
|
||||
RenderFloat(it->GetUnchecked<double>());
|
||||
break;
|
||||
case JsonInt:
|
||||
RenderInt(it->GetUnchecked<long long signed>());
|
||||
break;
|
||||
case JsonUInt:
|
||||
RenderUInt(it->GetUnchecked<long long unsigned>());
|
||||
break;
|
||||
case JsonTime:
|
||||
RenderTime(it->GetUnchecked<std::chrono::system_clock::time_point>());
|
||||
break;
|
||||
case JsonUuid:
|
||||
RenderUuid(it->GetUnchecked<UuidStruct>().Data);
|
||||
break;
|
||||
default:
|
||||
RenderCustom(m_renderBuffer, it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void JsonRenderer::RenderStructure(iterator const& itParent, bool showNames)
|
||||
{
|
||||
WriteChar(showNames ? '{' : '[');
|
||||
|
||||
auto it = itParent.begin();
|
||||
auto itEnd = itParent.end();
|
||||
if (it != itEnd)
|
||||
{
|
||||
m_indent += m_indentSpaces;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (m_pretty)
|
||||
{
|
||||
RenderNewline();
|
||||
}
|
||||
|
||||
if (showNames)
|
||||
{
|
||||
RenderString(it->Name());
|
||||
WriteChar(':');
|
||||
|
||||
if (m_pretty)
|
||||
{
|
||||
WriteChar(' ');
|
||||
}
|
||||
}
|
||||
|
||||
RenderValue(it);
|
||||
|
||||
++it;
|
||||
if (it == itEnd)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
WriteChar(',');
|
||||
}
|
||||
|
||||
m_indent -= m_indentSpaces;
|
||||
|
||||
if (m_pretty)
|
||||
{
|
||||
RenderNewline();
|
||||
}
|
||||
}
|
||||
|
||||
WriteChar(showNames ? '}' : ']');
|
||||
}
|
||||
|
||||
void JsonRenderer::RenderFloat(double const& value)
|
||||
{
|
||||
auto pch = m_renderBuffer.GetAppendPointer(32);
|
||||
pch += JsonRenderFloat(value, pch);
|
||||
m_renderBuffer.SetEndPointer(pch);
|
||||
}
|
||||
|
||||
void JsonRenderer::RenderInt(long long signed const& value)
|
||||
{
|
||||
auto const cchMax = 20u;
|
||||
auto pch = m_renderBuffer.GetAppendPointer(cchMax);
|
||||
|
||||
// TODO: Why can't we use std::to_wchars when we're using c++17?
|
||||
unsigned cch = static_cast<unsigned>(snprintf(pch, cchMax, "%lld", value));
|
||||
pch += cch > cchMax ? cchMax : cch;
|
||||
m_renderBuffer.SetEndPointer(pch);
|
||||
}
|
||||
|
||||
void JsonRenderer::RenderUInt(long long unsigned const& value)
|
||||
{
|
||||
auto const cchMax = 20u;
|
||||
auto pch = m_renderBuffer.GetAppendPointer(cchMax);
|
||||
|
||||
// TODO: Why can't we use std::to_wchars when we're using c++17?
|
||||
unsigned cch = static_cast<unsigned>(snprintf(pch, cchMax, "%llu", value));
|
||||
pch += cch > cchMax ? cchMax : cch;
|
||||
m_renderBuffer.SetEndPointer(pch);
|
||||
}
|
||||
|
||||
void JsonRenderer::RenderTime(std::chrono::system_clock::time_point const& value)
|
||||
{
|
||||
auto pch = m_renderBuffer.GetAppendPointer(32);
|
||||
*pch++ = '"';
|
||||
pch += JsonRenderTime(value, pch);
|
||||
*pch++ = '"';
|
||||
m_renderBuffer.SetEndPointer(pch);
|
||||
}
|
||||
|
||||
void JsonRenderer::RenderUuid(uuid_t const& value)
|
||||
{
|
||||
auto pch = m_renderBuffer.GetAppendPointer(38);
|
||||
*pch++ = '"';
|
||||
pch += JsonRenderUuid(value, pch);
|
||||
*pch++ = '"';
|
||||
m_renderBuffer.SetEndPointer(pch);
|
||||
}
|
||||
|
||||
void JsonRenderer::RenderString(std::string_view const& value)
|
||||
{
|
||||
WriteChar('"');
|
||||
for (auto ch : value)
|
||||
{
|
||||
if (static_cast<unsigned char>(ch) < 0x20)
|
||||
{
|
||||
// Control character - must be escaped.
|
||||
switch (ch)
|
||||
{
|
||||
case 8:
|
||||
WriteChar('\\');
|
||||
WriteChar('b');
|
||||
break;
|
||||
case 9:
|
||||
WriteChar('\\');
|
||||
WriteChar('t');
|
||||
break;
|
||||
case 10:
|
||||
WriteChar('\\');
|
||||
WriteChar('n');
|
||||
break;
|
||||
case 12:
|
||||
WriteChar('\\');
|
||||
WriteChar('f');
|
||||
break;
|
||||
case 13:
|
||||
WriteChar('\\');
|
||||
WriteChar('r');
|
||||
break;
|
||||
default:
|
||||
auto p = m_renderBuffer.GetAppendPointer(6);
|
||||
*p++ = '\\';
|
||||
*p++ = 'u';
|
||||
*p++ = '0';
|
||||
*p++ = '0';
|
||||
*p++ = u4_to_hex_upper((ch >> 4) & 0xf);
|
||||
*p++ = u4_to_hex_upper(ch & 0xf);
|
||||
m_renderBuffer.SetEndPointer(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (ch == '"' || ch == '\\')
|
||||
{
|
||||
// ASCII character - pass through (escape quote and backslash)
|
||||
WriteChar('\\');
|
||||
WriteChar(ch);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteChar(ch);
|
||||
}
|
||||
}
|
||||
WriteChar('"');
|
||||
}
|
||||
|
||||
void JsonRenderer::RenderNewline()
|
||||
{
|
||||
WriteChars(m_newLine.data(), static_cast<unsigned>(m_newLine.size()));
|
||||
m_renderBuffer.append(m_indent, ' ');
|
||||
}
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include <cassert>
|
||||
#include <cmath>
|
||||
#include <string>
|
||||
|
||||
#include <jsonbuilder/JsonRenderer.h>
|
||||
#include <uuid/uuid.h>
|
||||
|
||||
#define WriteChar(ch) m_renderBuffer.push_back(ch)
|
||||
#define WriteChars(pch, cch) m_renderBuffer.append(pch, cch)
|
||||
|
||||
namespace jsonbuilder {
|
||||
/*
|
||||
Efficiently multiply two 32-bit unsigned integers to get a 64-bit result.
|
||||
(The current VC compiler does not optimize this -- if we don't use an
|
||||
intrinsic, it makes a call to _aullmul.)
|
||||
*/
|
||||
#if defined(_M_ARM) || defined(_M_ARM64)
|
||||
# define UMul64(a, b) _arm_umull(a, b)
|
||||
#elif defined(_M_IX86) || defined(_M_X64)
|
||||
# define UMul64(a, b) __emulu(a, b)
|
||||
#else
|
||||
static long long unsigned UMul64(unsigned a, unsigned b)
|
||||
{
|
||||
return static_cast<long long unsigned>(a) * b;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
Given a number from 0..15, returns the corresponding uppercase hex digit,
|
||||
i.e. '0'..'F'. Note: it is an error to pass a value larger than 15.
|
||||
*/
|
||||
static inline constexpr char u4_to_hex_upper(char unsigned _Val4)
|
||||
{
|
||||
return ("0123456789ABCDEF")[_Val4];
|
||||
}
|
||||
|
||||
/*
|
||||
Multiply two 64-bit unsigned integers to get a 128-bit result. Return the high
|
||||
64 bits of the answer.
|
||||
*/
|
||||
__attribute__((unused)) static long long unsigned
|
||||
UMul128Hi(long long unsigned a, long long unsigned b)
|
||||
{
|
||||
#if defined(_M_X64) || defined(_M_ARM64)
|
||||
long long unsigned const high = __umulh(a, b);
|
||||
#else
|
||||
long long unsigned const mid =
|
||||
UMul64(static_cast<unsigned>(a), static_cast<unsigned>(b >> 32)) +
|
||||
(UMul64(static_cast<unsigned>(a), static_cast<unsigned>(b)) >> 32);
|
||||
long long unsigned const high =
|
||||
UMul64(static_cast<unsigned>(a >> 32), static_cast<unsigned>(b >> 32)) +
|
||||
(mid >> 32) +
|
||||
((UMul64(static_cast<unsigned>(a >> 32), static_cast<unsigned>(b)) +
|
||||
static_cast<unsigned>(mid)) >>
|
||||
32);
|
||||
#endif
|
||||
return high;
|
||||
}
|
||||
|
||||
/*
|
||||
Formats a uint32 with leading 0s. Always writes cch characters.
|
||||
*/
|
||||
static void FormatUint(unsigned n, char* pch, unsigned cch)
|
||||
{
|
||||
do
|
||||
{
|
||||
--cch;
|
||||
pch[cch] = '0' + (n % 10);
|
||||
n = n / 10;
|
||||
} while (cch != 0);
|
||||
}
|
||||
|
||||
template<unsigned CB, class N>
|
||||
static unsigned JsonRenderXInt(N const& n, char* pBuffer)
|
||||
{
|
||||
// TODO: Why can't we use std::to_wchars when we're using c++17?
|
||||
std::string result = std::to_string(n);
|
||||
std::size_t const cch =
|
||||
std::min(result.size(), static_cast<std::size_t>(CB - 1));
|
||||
strncpy(pBuffer, result.c_str(), cch);
|
||||
pBuffer[cch] = 0;
|
||||
|
||||
pBuffer[cch] = 0;
|
||||
return static_cast<unsigned>(cch);
|
||||
}
|
||||
|
||||
unsigned JsonRenderUInt(long long unsigned n, char* pBuffer) throw()
|
||||
{
|
||||
return JsonRenderXInt<21>(n, pBuffer);
|
||||
}
|
||||
|
||||
unsigned JsonRenderInt(long long signed n, char* pBuffer) throw()
|
||||
{
|
||||
return JsonRenderXInt<21>(n, pBuffer);
|
||||
}
|
||||
|
||||
unsigned JsonRenderFloat(double n, char* pBuffer) throw()
|
||||
{
|
||||
unsigned cch;
|
||||
|
||||
if (std::isfinite(n))
|
||||
{
|
||||
cch = static_cast<unsigned>(snprintf(pBuffer, 31, "%.17g", n));
|
||||
if (cch > 31)
|
||||
{
|
||||
cch = 31;
|
||||
}
|
||||
pBuffer[cch] = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
cch = JsonRenderNull(pBuffer);
|
||||
}
|
||||
|
||||
return cch;
|
||||
}
|
||||
|
||||
unsigned JsonRenderBool(bool b, char* pBuffer) throw()
|
||||
{
|
||||
unsigned cch;
|
||||
if (b)
|
||||
{
|
||||
strcpy(pBuffer, "true");
|
||||
cch = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
strcpy(pBuffer, "false");
|
||||
cch = 5;
|
||||
}
|
||||
return cch;
|
||||
}
|
||||
|
||||
unsigned JsonRenderNull(char* pBuffer) throw()
|
||||
{
|
||||
strcpy(pBuffer, "null");
|
||||
return 4;
|
||||
}
|
||||
|
||||
unsigned JsonRenderTime(
|
||||
std::chrono::system_clock::time_point const& timePoint,
|
||||
char* pBuffer) throw()
|
||||
{
|
||||
time_t printableTime = std::chrono::system_clock::to_time_t(timePoint);
|
||||
tm timeStruct = tm();
|
||||
gmtime_r(&printableTime, &timeStruct);
|
||||
|
||||
auto subsecondDuration =
|
||||
timePoint.time_since_epoch() % std::chrono::seconds{ 1 };
|
||||
auto subsecondNanos =
|
||||
std::chrono::duration_cast<std::chrono::nanoseconds>(subsecondDuration);
|
||||
|
||||
FormatUint(static_cast<unsigned>(timeStruct.tm_year + 1900), pBuffer + 0, 4);
|
||||
pBuffer[4] = '-';
|
||||
FormatUint(static_cast<unsigned>(timeStruct.tm_mon + 1), pBuffer + 5, 2);
|
||||
pBuffer[7] = '-';
|
||||
FormatUint(static_cast<unsigned>(timeStruct.tm_mday), pBuffer + 8, 2);
|
||||
pBuffer[10] = 'T';
|
||||
FormatUint(static_cast<unsigned>(timeStruct.tm_hour), pBuffer + 11, 2);
|
||||
pBuffer[13] = ':';
|
||||
FormatUint(static_cast<unsigned>(timeStruct.tm_min), pBuffer + 14, 2);
|
||||
pBuffer[16] = ':';
|
||||
FormatUint(static_cast<unsigned>(timeStruct.tm_sec), pBuffer + 17, 2);
|
||||
pBuffer[19] = '.';
|
||||
FormatUint(
|
||||
static_cast<unsigned>(subsecondNanos.count() / 100), pBuffer + 20, 7);
|
||||
pBuffer[27] = 'Z';
|
||||
pBuffer[28] = 0;
|
||||
return 28;
|
||||
}
|
||||
|
||||
unsigned JsonRenderUuid(uuid_t const& g, char* pBuffer) throw()
|
||||
{
|
||||
uuid_unparse_upper(g, pBuffer);
|
||||
return 36;
|
||||
}
|
||||
|
||||
unsigned JsonRenderUuidWithBraces(uuid_t const& g, char* pBuffer) throw()
|
||||
{
|
||||
pBuffer[0] = '{';
|
||||
JsonRenderUuid(g, pBuffer + 1);
|
||||
pBuffer[37] = '}';
|
||||
pBuffer[38] = 0;
|
||||
return 38;
|
||||
}
|
||||
|
||||
JsonRenderer::JsonRenderer(
|
||||
bool pretty,
|
||||
std::string_view const& newLine,
|
||||
unsigned indentSpaces) throw()
|
||||
: m_newLine(newLine), m_indentSpaces(indentSpaces), m_pretty(pretty)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void JsonRenderer::Reserve(size_type cb)
|
||||
{
|
||||
m_renderBuffer.reserve(cb);
|
||||
}
|
||||
|
||||
JsonRenderer::size_type JsonRenderer::Size() const throw()
|
||||
{
|
||||
return m_renderBuffer.size();
|
||||
}
|
||||
|
||||
JsonRenderer::size_type JsonRenderer::Capacity() const throw()
|
||||
{
|
||||
return m_renderBuffer.capacity();
|
||||
}
|
||||
|
||||
bool JsonRenderer::Pretty() const throw()
|
||||
{
|
||||
return m_pretty;
|
||||
}
|
||||
|
||||
void JsonRenderer::Pretty(bool value) throw()
|
||||
{
|
||||
m_pretty = value;
|
||||
}
|
||||
|
||||
std::string_view const& JsonRenderer::NewLine() const throw()
|
||||
{
|
||||
return m_newLine;
|
||||
}
|
||||
|
||||
void JsonRenderer::NewLine(std::string_view const& value) throw()
|
||||
{
|
||||
m_newLine = value;
|
||||
}
|
||||
|
||||
unsigned JsonRenderer::IndentSpaces() const throw()
|
||||
{
|
||||
return m_indentSpaces;
|
||||
}
|
||||
|
||||
void JsonRenderer::IndentSpaces(unsigned value) throw()
|
||||
{
|
||||
m_indentSpaces = value;
|
||||
}
|
||||
|
||||
std::string_view JsonRenderer::Render(JsonBuilder const& builder)
|
||||
{
|
||||
auto itRoot = builder.root();
|
||||
m_renderBuffer.clear();
|
||||
m_indent = 0;
|
||||
RenderStructure(itRoot, true);
|
||||
WriteChar('\0');
|
||||
return std::string_view(m_renderBuffer.data(), m_renderBuffer.size() - 1);
|
||||
}
|
||||
|
||||
std::string_view JsonRenderer::Render(JsonBuilder::const_iterator const& it)
|
||||
{
|
||||
m_renderBuffer.clear();
|
||||
m_indent = 0;
|
||||
if (it.IsRoot())
|
||||
{
|
||||
RenderStructure(it, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderValue(it);
|
||||
}
|
||||
WriteChar('\0');
|
||||
return std::string_view(m_renderBuffer.data(), m_renderBuffer.size() - 1);
|
||||
}
|
||||
|
||||
void JsonRenderer::RenderCustom(RenderBuffer&, iterator const& it)
|
||||
{
|
||||
auto const cchMax = 32u;
|
||||
auto pch = m_renderBuffer.GetAppendPointer(cchMax);
|
||||
unsigned cch =
|
||||
static_cast<unsigned>(snprintf(pch, cchMax, "\"Custom#%u\"", it->Type()));
|
||||
pch += cch > cchMax ? cchMax : cch;
|
||||
m_renderBuffer.SetEndPointer(pch);
|
||||
}
|
||||
|
||||
void JsonRenderer::RenderValue(iterator const& it)
|
||||
{
|
||||
assert(!it.IsRoot());
|
||||
switch (it->Type())
|
||||
{
|
||||
case JsonObject:
|
||||
RenderStructure(it, true);
|
||||
break;
|
||||
case JsonArray:
|
||||
RenderStructure(it, false);
|
||||
break;
|
||||
case JsonNull:
|
||||
WriteChars("null", 4);
|
||||
break;
|
||||
case JsonBool:
|
||||
if (it->GetUnchecked<bool>())
|
||||
{
|
||||
WriteChars("true", 4);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteChars("false", 5);
|
||||
}
|
||||
break;
|
||||
case JsonUtf8:
|
||||
RenderString(it->GetUnchecked<std::string_view>());
|
||||
break;
|
||||
case JsonFloat:
|
||||
RenderFloat(it->GetUnchecked<double>());
|
||||
break;
|
||||
case JsonInt:
|
||||
RenderInt(it->GetUnchecked<long long signed>());
|
||||
break;
|
||||
case JsonUInt:
|
||||
RenderUInt(it->GetUnchecked<long long unsigned>());
|
||||
break;
|
||||
case JsonTime:
|
||||
RenderTime(it->GetUnchecked<std::chrono::system_clock::time_point>());
|
||||
break;
|
||||
case JsonUuid:
|
||||
RenderUuid(it->GetUnchecked<UuidStruct>().Data);
|
||||
break;
|
||||
default:
|
||||
RenderCustom(m_renderBuffer, it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void JsonRenderer::RenderStructure(iterator const& itParent, bool showNames)
|
||||
{
|
||||
WriteChar(showNames ? '{' : '[');
|
||||
|
||||
auto it = itParent.begin();
|
||||
auto itEnd = itParent.end();
|
||||
if (it != itEnd)
|
||||
{
|
||||
m_indent += m_indentSpaces;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (m_pretty)
|
||||
{
|
||||
RenderNewline();
|
||||
}
|
||||
|
||||
if (showNames)
|
||||
{
|
||||
RenderString(it->Name());
|
||||
WriteChar(':');
|
||||
|
||||
if (m_pretty)
|
||||
{
|
||||
WriteChar(' ');
|
||||
}
|
||||
}
|
||||
|
||||
RenderValue(it);
|
||||
|
||||
++it;
|
||||
if (it == itEnd)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
WriteChar(',');
|
||||
}
|
||||
|
||||
m_indent -= m_indentSpaces;
|
||||
|
||||
if (m_pretty)
|
||||
{
|
||||
RenderNewline();
|
||||
}
|
||||
}
|
||||
|
||||
WriteChar(showNames ? '}' : ']');
|
||||
}
|
||||
|
||||
void JsonRenderer::RenderFloat(double const& value)
|
||||
{
|
||||
auto pch = m_renderBuffer.GetAppendPointer(32);
|
||||
pch += JsonRenderFloat(value, pch);
|
||||
m_renderBuffer.SetEndPointer(pch);
|
||||
}
|
||||
|
||||
void JsonRenderer::RenderInt(long long signed const& value)
|
||||
{
|
||||
auto const cchMax = 20u;
|
||||
auto pch = m_renderBuffer.GetAppendPointer(cchMax);
|
||||
|
||||
// TODO: Why can't we use std::to_wchars when we're using c++17?
|
||||
unsigned cch = static_cast<unsigned>(snprintf(pch, cchMax, "%lld", value));
|
||||
pch += cch > cchMax ? cchMax : cch;
|
||||
m_renderBuffer.SetEndPointer(pch);
|
||||
}
|
||||
|
||||
void JsonRenderer::RenderUInt(long long unsigned const& value)
|
||||
{
|
||||
auto const cchMax = 20u;
|
||||
auto pch = m_renderBuffer.GetAppendPointer(cchMax);
|
||||
|
||||
// TODO: Why can't we use std::to_wchars when we're using c++17?
|
||||
unsigned cch = static_cast<unsigned>(snprintf(pch, cchMax, "%llu", value));
|
||||
pch += cch > cchMax ? cchMax : cch;
|
||||
m_renderBuffer.SetEndPointer(pch);
|
||||
}
|
||||
|
||||
void JsonRenderer::RenderTime(std::chrono::system_clock::time_point const& value)
|
||||
{
|
||||
auto pch = m_renderBuffer.GetAppendPointer(32);
|
||||
*pch++ = '"';
|
||||
pch += JsonRenderTime(value, pch);
|
||||
*pch++ = '"';
|
||||
m_renderBuffer.SetEndPointer(pch);
|
||||
}
|
||||
|
||||
void JsonRenderer::RenderUuid(uuid_t const& value)
|
||||
{
|
||||
auto pch = m_renderBuffer.GetAppendPointer(38);
|
||||
*pch++ = '"';
|
||||
pch += JsonRenderUuid(value, pch);
|
||||
*pch++ = '"';
|
||||
m_renderBuffer.SetEndPointer(pch);
|
||||
}
|
||||
|
||||
void JsonRenderer::RenderString(std::string_view const& value)
|
||||
{
|
||||
WriteChar('"');
|
||||
for (auto ch : value)
|
||||
{
|
||||
if (static_cast<unsigned char>(ch) < 0x20)
|
||||
{
|
||||
// Control character - must be escaped.
|
||||
switch (ch)
|
||||
{
|
||||
case 8:
|
||||
WriteChar('\\');
|
||||
WriteChar('b');
|
||||
break;
|
||||
case 9:
|
||||
WriteChar('\\');
|
||||
WriteChar('t');
|
||||
break;
|
||||
case 10:
|
||||
WriteChar('\\');
|
||||
WriteChar('n');
|
||||
break;
|
||||
case 12:
|
||||
WriteChar('\\');
|
||||
WriteChar('f');
|
||||
break;
|
||||
case 13:
|
||||
WriteChar('\\');
|
||||
WriteChar('r');
|
||||
break;
|
||||
default:
|
||||
auto p = m_renderBuffer.GetAppendPointer(6);
|
||||
*p++ = '\\';
|
||||
*p++ = 'u';
|
||||
*p++ = '0';
|
||||
*p++ = '0';
|
||||
*p++ = u4_to_hex_upper((ch >> 4) & 0xf);
|
||||
*p++ = u4_to_hex_upper(ch & 0xf);
|
||||
m_renderBuffer.SetEndPointer(p);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (ch == '"' || ch == '\\')
|
||||
{
|
||||
// ASCII character - pass through (escape quote and backslash)
|
||||
WriteChar('\\');
|
||||
WriteChar(ch);
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteChar(ch);
|
||||
}
|
||||
}
|
||||
WriteChar('"');
|
||||
}
|
||||
|
||||
void JsonRenderer::RenderNewline()
|
||||
{
|
||||
WriteChars(m_newLine.data(), static_cast<unsigned>(m_newLine.size()));
|
||||
m_renderBuffer.append(m_indent, ' ');
|
||||
}
|
||||
} // namespace jsonbuilder
|
|
@ -1,118 +1,118 @@
|
|||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <jsonbuilder/JsonBuilder.h>
|
||||
|
||||
namespace jsonbuilder { namespace JsonInternal {
|
||||
|
||||
static inline unsigned char
|
||||
BitScanReverse(unsigned long* Index, unsigned long Mask)
|
||||
{
|
||||
if (Mask == 0 || Index == 0)
|
||||
return 0;
|
||||
|
||||
int ii = 0;
|
||||
for (ii = ((sizeof(Mask) * 8) - 1); ii >= 0; --ii)
|
||||
{
|
||||
unsigned long tempMask = 1ul << ii;
|
||||
if ((Mask & tempMask) != 0)
|
||||
{
|
||||
*Index = ii;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (ii >= 0 ? (unsigned char) 1 : (unsigned char) 0);
|
||||
}
|
||||
|
||||
void PodVectorBase::CheckOffset(size_type index, size_type currentSize) throw()
|
||||
{
|
||||
(void) index; // Unreferenced parameter
|
||||
(void) currentSize; // Unreferenced parameter
|
||||
assert(index < currentSize);
|
||||
}
|
||||
|
||||
void PodVectorBase::CheckRange(void const* p1, void const* p2, void const* p3) throw()
|
||||
{
|
||||
(void) p1; // Unreferenced parameter
|
||||
(void) p2; // Unreferenced parameter
|
||||
(void) p3; // Unreferenced parameter
|
||||
assert(p1 <= p2 && p2 <= p3);
|
||||
}
|
||||
|
||||
PodVectorBase::size_type PodVectorBase::CheckedAdd(size_type a, size_type b)
|
||||
{
|
||||
size_type c = a + b;
|
||||
if (c < a)
|
||||
{
|
||||
throw std::length_error("JsonVector - exceeded maximum capacity");
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
void PodVectorBase::InitData(void* pDest, void const* pSource, size_t cb) throw()
|
||||
{
|
||||
memcpy(pDest, pSource, cb);
|
||||
}
|
||||
|
||||
PodVectorBase::size_type
|
||||
PodVectorBase::GetNewCapacity(size_type minCapacity, size_type maxCapacity)
|
||||
{
|
||||
size_type cap;
|
||||
if (minCapacity <= 15)
|
||||
{
|
||||
cap = 15;
|
||||
}
|
||||
else
|
||||
{
|
||||
long unsigned index = 0;
|
||||
if (!BitScanReverse(&index, minCapacity))
|
||||
{
|
||||
std::terminate();
|
||||
}
|
||||
cap = static_cast<uint32_t>((2 << index) - 1);
|
||||
}
|
||||
|
||||
if (maxCapacity < cap)
|
||||
{
|
||||
if (maxCapacity < minCapacity)
|
||||
{
|
||||
throw std::length_error("JsonVector - exceeded maximum capacity");
|
||||
}
|
||||
|
||||
cap = maxCapacity;
|
||||
}
|
||||
|
||||
assert(15 <= cap);
|
||||
assert(minCapacity <= cap);
|
||||
assert(cap <= maxCapacity);
|
||||
return cap;
|
||||
}
|
||||
|
||||
void* PodVectorBase::Reallocate(void* pb, size_t cb, bool zeroInitializeMemory)
|
||||
{
|
||||
void* const pbNew = pb ? realloc(pb, cb) : malloc(cb);
|
||||
|
||||
if (pbNew == nullptr)
|
||||
{
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
if (zeroInitializeMemory)
|
||||
{
|
||||
memset(pbNew, 0, cb);
|
||||
}
|
||||
|
||||
return pbNew;
|
||||
}
|
||||
|
||||
void PodVectorBase::Deallocate(void* pb) throw()
|
||||
{
|
||||
if (pb)
|
||||
{
|
||||
free(pb);
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
// Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
// Licensed under the MIT License.
|
||||
|
||||
#include <cassert>
|
||||
|
||||
#include <jsonbuilder/JsonBuilder.h>
|
||||
|
||||
namespace jsonbuilder { namespace JsonInternal {
|
||||
|
||||
static inline unsigned char
|
||||
BitScanReverse(unsigned long* Index, unsigned long Mask)
|
||||
{
|
||||
if (Mask == 0 || Index == 0)
|
||||
return 0;
|
||||
|
||||
int ii = 0;
|
||||
for (ii = ((sizeof(Mask) * 8) - 1); ii >= 0; --ii)
|
||||
{
|
||||
unsigned long tempMask = 1ul << ii;
|
||||
if ((Mask & tempMask) != 0)
|
||||
{
|
||||
*Index = ii;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (ii >= 0 ? (unsigned char) 1 : (unsigned char) 0);
|
||||
}
|
||||
|
||||
void PodVectorBase::CheckOffset(size_type index, size_type currentSize) throw()
|
||||
{
|
||||
(void) index; // Unreferenced parameter
|
||||
(void) currentSize; // Unreferenced parameter
|
||||
assert(index < currentSize);
|
||||
}
|
||||
|
||||
void PodVectorBase::CheckRange(void const* p1, void const* p2, void const* p3) throw()
|
||||
{
|
||||
(void) p1; // Unreferenced parameter
|
||||
(void) p2; // Unreferenced parameter
|
||||
(void) p3; // Unreferenced parameter
|
||||
assert(p1 <= p2 && p2 <= p3);
|
||||
}
|
||||
|
||||
PodVectorBase::size_type PodVectorBase::CheckedAdd(size_type a, size_type b)
|
||||
{
|
||||
size_type c = a + b;
|
||||
if (c < a)
|
||||
{
|
||||
throw std::length_error("JsonVector - exceeded maximum capacity");
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
void PodVectorBase::InitData(void* pDest, void const* pSource, size_t cb) throw()
|
||||
{
|
||||
memcpy(pDest, pSource, cb);
|
||||
}
|
||||
|
||||
PodVectorBase::size_type
|
||||
PodVectorBase::GetNewCapacity(size_type minCapacity, size_type maxCapacity)
|
||||
{
|
||||
size_type cap;
|
||||
if (minCapacity <= 15)
|
||||
{
|
||||
cap = 15;
|
||||
}
|
||||
else
|
||||
{
|
||||
long unsigned index = 0;
|
||||
if (!BitScanReverse(&index, minCapacity))
|
||||
{
|
||||
std::terminate();
|
||||
}
|
||||
cap = static_cast<uint32_t>((2 << index) - 1);
|
||||
}
|
||||
|
||||
if (maxCapacity < cap)
|
||||
{
|
||||
if (maxCapacity < minCapacity)
|
||||
{
|
||||
throw std::length_error("JsonVector - exceeded maximum capacity");
|
||||
}
|
||||
|
||||
cap = maxCapacity;
|
||||
}
|
||||
|
||||
assert(15 <= cap);
|
||||
assert(minCapacity <= cap);
|
||||
assert(cap <= maxCapacity);
|
||||
return cap;
|
||||
}
|
||||
|
||||
void* PodVectorBase::Reallocate(void* pb, size_t cb, bool zeroInitializeMemory)
|
||||
{
|
||||
void* const pbNew = pb ? realloc(pb, cb) : malloc(cb);
|
||||
|
||||
if (pbNew == nullptr)
|
||||
{
|
||||
throw std::bad_alloc();
|
||||
}
|
||||
|
||||
if (zeroInitializeMemory)
|
||||
{
|
||||
memset(pbNew, 0, cb);
|
||||
}
|
||||
|
||||
return pbNew;
|
||||
}
|
||||
|
||||
void PodVectorBase::Deallocate(void* pb) throw()
|
||||
{
|
||||
if (pb)
|
||||
{
|
||||
free(pb);
|
||||
}
|
||||
}
|
||||
|
||||
}}
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
cmake_minimum_required(VERSION 3.7)
|
||||
|
||||
# Add source to this project's executable.
|
||||
add_executable(jsonbuilderTest CatchMain.cpp TestBuilder.cpp TestRenderer.cpp)
|
||||
target_compile_features(jsonbuilderTest PRIVATE cxx_std_17)
|
||||
target_link_libraries(jsonbuilderTest PRIVATE jsonbuilder Catch2::Catch2)
|
||||
|
||||
include(CTest)
|
||||
include(Catch)
|
||||
catch_discover_tests(jsonbuilderTest)
|
||||
cmake_minimum_required(VERSION 3.7)
|
||||
|
||||
# Add source to this project's executable.
|
||||
add_executable(jsonbuilderTest CatchMain.cpp TestBuilder.cpp TestRenderer.cpp)
|
||||
target_compile_features(jsonbuilderTest PRIVATE cxx_std_17)
|
||||
target_link_libraries(jsonbuilderTest PRIVATE jsonbuilder Catch2::Catch2)
|
||||
|
||||
include(CTest)
|
||||
include(Catch)
|
||||
catch_discover_tests(jsonbuilderTest)
|
||||
|
|
1232
test/TestBuilder.cpp
1232
test/TestBuilder.cpp
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
Загрузка…
Ссылка в новой задаче