This commit is contained in:
Nick Bopp 2020-03-02 13:15:02 -08:00 коммит произвёл GitHub
Родитель 20e2b2760e
Коммит aa1b358538
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
11 изменённых файлов: 4768 добавлений и 4768 удалений

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
Просмотреть файл

@ -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})

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -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)

Разница между файлами не показана из-за своего большого размера Загрузить разницу