mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
[upstream_utils] Add jart/json.cpp
This commit is contained in:
@@ -19,6 +19,7 @@ Google Test thirdparty/googletest/include
|
|||||||
thirdparty/googletest/src
|
thirdparty/googletest/src
|
||||||
LLVM wpiutil/src/main/native/thirdparty/llvm
|
LLVM wpiutil/src/main/native/thirdparty/llvm
|
||||||
wpiutil/src/test/native/cpp/llvm/
|
wpiutil/src/test/native/cpp/llvm/
|
||||||
|
JSON for Classic C++ wpiutil/src/main/native/thirdparty/json
|
||||||
libuv wpinet/src/main/native/thirdparty/libuv/
|
libuv wpinet/src/main/native/thirdparty/libuv/
|
||||||
fmtlib wpiutil/src/main/native/thirdparty/fmtlib/
|
fmtlib wpiutil/src/main/native/thirdparty/fmtlib/
|
||||||
sigslot wpiutil/src/main/native/thirdparty/sigslot
|
sigslot wpiutil/src/main/native/thirdparty/sigslot
|
||||||
@@ -368,6 +369,24 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
|
|||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
|
|
||||||
|
|
||||||
|
============================
|
||||||
|
JSON for Classic C++ License
|
||||||
|
============================
|
||||||
|
Copyright 2024 Mozilla Foundation
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
|
||||||
|
|
||||||
==============================================================================
|
==============================================================================
|
||||||
libuv License
|
libuv License
|
||||||
==============================================================================
|
==============================================================================
|
||||||
|
|||||||
54
upstream_utils/json.py
Executable file
54
upstream_utils/json.py
Executable file
@@ -0,0 +1,54 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import shutil
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
from upstream_utils import Lib
|
||||||
|
|
||||||
|
|
||||||
|
def copy_upstream_src(wpilib_root: Path):
|
||||||
|
wpiutil = wpilib_root / "wpiutil"
|
||||||
|
|
||||||
|
# Delete old install
|
||||||
|
for d in [
|
||||||
|
"src/main/native/thirdparty/json/cpp",
|
||||||
|
"src/main/native/thirdparty/json/include",
|
||||||
|
]:
|
||||||
|
shutil.rmtree(wpiutil / d, ignore_errors=True)
|
||||||
|
|
||||||
|
# Create lists of source and destination files
|
||||||
|
src_include_files = ["json.h"]
|
||||||
|
src_src_files = ["json.cpp", "jtckdint.h"]
|
||||||
|
wpiutil_json_root = wpiutil / "src/main/native/thirdparty/json/include/wpi/util"
|
||||||
|
dest_include_files = [wpiutil_json_root / "json.hpp"]
|
||||||
|
|
||||||
|
# Copy json header files into allwpilib
|
||||||
|
for i in range(len(src_include_files)):
|
||||||
|
dest_dir = dest_include_files[i].parent
|
||||||
|
if not dest_dir.exists():
|
||||||
|
dest_dir.mkdir(parents=True)
|
||||||
|
shutil.copyfile(src_include_files[i], dest_include_files[i])
|
||||||
|
|
||||||
|
# Copy json src files into allwpilib
|
||||||
|
for i in range(len(src_src_files)):
|
||||||
|
dest_dir = wpiutil / "src/main/native/thirdparty/json/src"
|
||||||
|
if not dest_dir.exists():
|
||||||
|
dest_dir.mkdir(parents=True)
|
||||||
|
shutil.copyfile(src_src_files[i], dest_dir / src_src_files[i])
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
name = "json"
|
||||||
|
url = "https://github.com/jart/json.cpp.git"
|
||||||
|
tag = "6ec4e44a5bbaadbe677473378c3d2133644c58a1"
|
||||||
|
|
||||||
|
patch_options = {
|
||||||
|
"use_threeway": True,
|
||||||
|
}
|
||||||
|
|
||||||
|
json = Lib(name, url, tag, copy_upstream_src, patch_options)
|
||||||
|
json.main()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
@@ -0,0 +1,48 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Peter Johnson <johnson.peter@gmail.com>
|
||||||
|
Date: Sun, 29 Mar 2026 16:46:09 -0700
|
||||||
|
Subject: [PATCH 01/25] Move to wpi::util namespace
|
||||||
|
|
||||||
|
---
|
||||||
|
json.cpp | 4 ++--
|
||||||
|
json.h | 4 ++--
|
||||||
|
2 files changed, 4 insertions(+), 4 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/json.cpp b/json.cpp
|
||||||
|
index 0b3e3730406ecf3bf283a56d93b7cc8c3052d61d..645266767781cb3ebdb700bf6761e6928806806e 100644
|
||||||
|
--- a/json.cpp
|
||||||
|
+++ b/json.cpp
|
||||||
|
@@ -83,7 +83,7 @@
|
||||||
|
#define ON_LOGIC_ERROR(s) abort()
|
||||||
|
#endif
|
||||||
|
|
||||||
|
-namespace jt {
|
||||||
|
+namespace wpi::util {
|
||||||
|
|
||||||
|
static const char kJsonStr[256] = {
|
||||||
|
1, 1, 1, 1, 1, 1, 1, 1, // 0000 ascii (0)
|
||||||
|
@@ -1313,4 +1313,4 @@ Json::StatusToString(Json::Status status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-} // namespace jt
|
||||||
|
+} // namespace wpi::util
|
||||||
|
diff --git a/json.h b/json.h
|
||||||
|
index 6bb9087f452ae18dfad7c52b95de27c39a886341..c676e651d7c2591a0fb07d8d8b28738cbd1defab 100644
|
||||||
|
--- a/json.h
|
||||||
|
+++ b/json.h
|
||||||
|
@@ -20,7 +20,7 @@
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
-namespace jt {
|
||||||
|
+namespace wpi::util {
|
||||||
|
|
||||||
|
class Json
|
||||||
|
{
|
||||||
|
@@ -221,4 +221,4 @@ class Json
|
||||||
|
static Status parse(Json&, const char*&, const char*, int, int);
|
||||||
|
};
|
||||||
|
|
||||||
|
-} // namespace jt
|
||||||
|
+} // namespace wpi::util
|
||||||
@@ -0,0 +1,599 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Peter Johnson <johnson.peter@gmail.com>
|
||||||
|
Date: Sun, 29 Mar 2026 16:47:26 -0700
|
||||||
|
Subject: [PATCH 02/25] Rename class from Json to json
|
||||||
|
|
||||||
|
---
|
||||||
|
json.cpp | 142 +++++++++++++++++++++++++++----------------------------
|
||||||
|
json.h | 54 ++++++++++-----------
|
||||||
|
2 files changed, 98 insertions(+), 98 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/json.cpp b/json.cpp
|
||||||
|
index 645266767781cb3ebdb700bf6761e6928806806e..3e59a885b55d3fddc418903112595fe5de223f34 100644
|
||||||
|
--- a/json.cpp
|
||||||
|
+++ b/json.cpp
|
||||||
|
@@ -242,7 +242,7 @@ LongToString(char* p, long long x)
|
||||||
|
return UlongToString(p, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
-Json::Json(unsigned long value)
|
||||||
|
+json::json(unsigned long value)
|
||||||
|
{
|
||||||
|
if (value <= LLONG_MAX) {
|
||||||
|
type_ = Long;
|
||||||
|
@@ -253,7 +253,7 @@ Json::Json(unsigned long value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-Json::Json(unsigned long long value)
|
||||||
|
+json::json(unsigned long long value)
|
||||||
|
{
|
||||||
|
if (value <= LLONG_MAX) {
|
||||||
|
type_ = Long;
|
||||||
|
@@ -264,7 +264,7 @@ Json::Json(unsigned long long value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-Json::Json(const char* value)
|
||||||
|
+json::json(const char* value)
|
||||||
|
{
|
||||||
|
if (value) {
|
||||||
|
type_ = String;
|
||||||
|
@@ -274,18 +274,18 @@ Json::Json(const char* value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-Json::Json(const std::string& value) : type_(String), string_value(value)
|
||||||
|
+json::json(const std::string& value) : type_(String), string_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
-Json::~Json()
|
||||||
|
+json::~json()
|
||||||
|
{
|
||||||
|
if (type_ >= String)
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
-Json::clear()
|
||||||
|
+json::clear()
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
case String:
|
||||||
|
@@ -303,7 +303,7 @@ Json::clear()
|
||||||
|
type_ = Null;
|
||||||
|
}
|
||||||
|
|
||||||
|
-Json::Json(const Json& other) : type_(other.type_)
|
||||||
|
+json::json(const json& other) : type_(other.type_)
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
case Null:
|
||||||
|
@@ -324,18 +324,18 @@ Json::Json(const Json& other) : type_(other.type_)
|
||||||
|
new (&string_value) std::string(other.string_value);
|
||||||
|
break;
|
||||||
|
case Array:
|
||||||
|
- new (&array_value) std::vector<Json>(other.array_value);
|
||||||
|
+ new (&array_value) std::vector<json>(other.array_value);
|
||||||
|
break;
|
||||||
|
case Object:
|
||||||
|
- new (&object_value) std::map<std::string, Json>(other.object_value);
|
||||||
|
+ new (&object_value) std::map<std::string, json>(other.object_value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ON_LOGIC_ERROR("Unhandled JSON type.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-Json&
|
||||||
|
-Json::operator=(const Json& other)
|
||||||
|
+json&
|
||||||
|
+json::operator=(const json& other)
|
||||||
|
{
|
||||||
|
if (this != &other) {
|
||||||
|
if (type_ >= String)
|
||||||
|
@@ -360,11 +360,11 @@ Json::operator=(const Json& other)
|
||||||
|
new (&string_value) std::string(other.string_value);
|
||||||
|
break;
|
||||||
|
case Array:
|
||||||
|
- new (&array_value) std::vector<Json>(other.array_value);
|
||||||
|
+ new (&array_value) std::vector<json>(other.array_value);
|
||||||
|
break;
|
||||||
|
case Object:
|
||||||
|
new (&object_value)
|
||||||
|
- std::map<std::string, Json>(other.object_value);
|
||||||
|
+ std::map<std::string, json>(other.object_value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ON_LOGIC_ERROR("Unhandled JSON type.");
|
||||||
|
@@ -373,7 +373,7 @@ Json::operator=(const Json& other)
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
-Json::Json(Json&& other) : type_(other.type_)
|
||||||
|
+json::json(json&& other) : type_(other.type_)
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
case Null:
|
||||||
|
@@ -394,11 +394,11 @@ Json::Json(Json&& other) : type_(other.type_)
|
||||||
|
new (&string_value) std::string(std::move(other.string_value));
|
||||||
|
break;
|
||||||
|
case Array:
|
||||||
|
- new (&array_value) std::vector<Json>(std::move(other.array_value));
|
||||||
|
+ new (&array_value) std::vector<json>(std::move(other.array_value));
|
||||||
|
break;
|
||||||
|
case Object:
|
||||||
|
new (&object_value)
|
||||||
|
- std::map<std::string, Json>(std::move(other.object_value));
|
||||||
|
+ std::map<std::string, json>(std::move(other.object_value));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ON_LOGIC_ERROR("Unhandled JSON type.");
|
||||||
|
@@ -406,8 +406,8 @@ Json::Json(Json&& other) : type_(other.type_)
|
||||||
|
other.type_ = Null;
|
||||||
|
}
|
||||||
|
|
||||||
|
-Json&
|
||||||
|
-Json::operator=(Json&& other)
|
||||||
|
+json&
|
||||||
|
+json::operator=(json&& other)
|
||||||
|
{
|
||||||
|
if (this != &other) {
|
||||||
|
if (type_ >= String)
|
||||||
|
@@ -433,11 +433,11 @@ Json::operator=(Json&& other)
|
||||||
|
break;
|
||||||
|
case Array:
|
||||||
|
new (&array_value)
|
||||||
|
- std::vector<Json>(std::move(other.array_value));
|
||||||
|
+ std::vector<json>(std::move(other.array_value));
|
||||||
|
break;
|
||||||
|
case Object:
|
||||||
|
new (&object_value)
|
||||||
|
- std::map<std::string, Json>(std::move(other.object_value));
|
||||||
|
+ std::map<std::string, json>(std::move(other.object_value));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ON_LOGIC_ERROR("Unhandled JSON type.");;
|
||||||
|
@@ -448,7 +448,7 @@ Json::operator=(Json&& other)
|
||||||
|
}
|
||||||
|
|
||||||
|
double
|
||||||
|
-Json::getNumber() const
|
||||||
|
+json::getNumber() const
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
case Long:
|
||||||
|
@@ -463,7 +463,7 @@ Json::getNumber() const
|
||||||
|
}
|
||||||
|
|
||||||
|
long long
|
||||||
|
-Json::getLong() const
|
||||||
|
+json::getLong() const
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
case Long:
|
||||||
|
@@ -474,7 +474,7 @@ Json::getLong() const
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
-Json::getBool() const
|
||||||
|
+json::getBool() const
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
case Bool:
|
||||||
|
@@ -485,7 +485,7 @@ Json::getBool() const
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
-Json::getFloat() const
|
||||||
|
+json::getFloat() const
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
case Float:
|
||||||
|
@@ -498,7 +498,7 @@ Json::getFloat() const
|
||||||
|
}
|
||||||
|
|
||||||
|
double
|
||||||
|
-Json::getDouble() const
|
||||||
|
+json::getDouble() const
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
case Float:
|
||||||
|
@@ -511,7 +511,7 @@ Json::getDouble() const
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string&
|
||||||
|
-Json::getString()
|
||||||
|
+json::getString()
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
case String:
|
||||||
|
@@ -521,8 +521,8 @@ Json::getString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-std::vector<Json>&
|
||||||
|
-Json::getArray()
|
||||||
|
+std::vector<json>&
|
||||||
|
+json::getArray()
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
case Array:
|
||||||
|
@@ -532,8 +532,8 @@ Json::getArray()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-std::map<std::string, Json>&
|
||||||
|
-Json::getObject()
|
||||||
|
+std::map<std::string, json>&
|
||||||
|
+json::getObject()
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
case Object:
|
||||||
|
@@ -544,33 +544,33 @@ Json::getObject()
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
-Json::setArray()
|
||||||
|
+json::setArray()
|
||||||
|
{
|
||||||
|
if (type_ >= String)
|
||||||
|
clear();
|
||||||
|
type_ = Array;
|
||||||
|
- new (&array_value) std::vector<Json>();
|
||||||
|
+ new (&array_value) std::vector<json>();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
-Json::setObject()
|
||||||
|
+json::setObject()
|
||||||
|
{
|
||||||
|
if (type_ >= String)
|
||||||
|
clear();
|
||||||
|
type_ = Object;
|
||||||
|
- new (&object_value) std::map<std::string, Json>();
|
||||||
|
+ new (&object_value) std::map<std::string, json>();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
-Json::contains(const std::string& key) const
|
||||||
|
+json::contains(const std::string& key) const
|
||||||
|
{
|
||||||
|
if (!isObject())
|
||||||
|
return false;
|
||||||
|
return object_value.find(key) != object_value.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
-Json&
|
||||||
|
-Json::operator[](size_t index)
|
||||||
|
+json&
|
||||||
|
+json::operator[](size_t index)
|
||||||
|
{
|
||||||
|
if (!isArray())
|
||||||
|
setArray();
|
||||||
|
@@ -580,8 +580,8 @@ Json::operator[](size_t index)
|
||||||
|
return array_value[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
-Json&
|
||||||
|
-Json::operator[](const std::string& key)
|
||||||
|
+json&
|
||||||
|
+json::operator[](const std::string& key)
|
||||||
|
{
|
||||||
|
if (!isObject())
|
||||||
|
setObject();
|
||||||
|
@@ -589,7 +589,7 @@ Json::operator[](const std::string& key)
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
-Json::toString() const
|
||||||
|
+json::toString() const
|
||||||
|
{
|
||||||
|
std::string b;
|
||||||
|
marshal(b, false, 0);
|
||||||
|
@@ -597,7 +597,7 @@ Json::toString() const
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
-Json::toStringPretty() const
|
||||||
|
+json::toStringPretty() const
|
||||||
|
{
|
||||||
|
std::string b;
|
||||||
|
marshal(b, true, 0);
|
||||||
|
@@ -605,7 +605,7 @@ Json::toStringPretty() const
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
-Json::marshal(std::string& b, bool pretty, int indent) const
|
||||||
|
+json::marshal(std::string& b, bool pretty, int indent) const
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
case Null:
|
||||||
|
@@ -692,7 +692,7 @@ Json::marshal(std::string& b, bool pretty, int indent) const
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
-Json::stringify(std::string& b, const std::string& s)
|
||||||
|
+json::stringify(std::string& b, const std::string& s)
|
||||||
|
{
|
||||||
|
b += '"';
|
||||||
|
serialize(b, s);
|
||||||
|
@@ -700,7 +700,7 @@ Json::stringify(std::string& b, const std::string& s)
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
-Json::serialize(std::string& sb, const std::string& s)
|
||||||
|
+json::serialize(std::string& sb, const std::string& s)
|
||||||
|
{
|
||||||
|
size_t i, j, m;
|
||||||
|
wint_t x, a, b;
|
||||||
|
@@ -768,8 +768,8 @@ Json::serialize(std::string& sb, const std::string& s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-Json::Status
|
||||||
|
-Json::parse(Json& json, const char*& p, const char* e, int context, int depth)
|
||||||
|
+json::Status
|
||||||
|
+json::parse(json& j, const char*& p, const char* e, int context, int depth)
|
||||||
|
{
|
||||||
|
char w[4];
|
||||||
|
long long x;
|
||||||
|
@@ -818,8 +818,8 @@ Json::parse(Json& json, const char*& p, const char* e, int context, int depth)
|
||||||
|
if (context & (KEY | COLON | COMMA))
|
||||||
|
goto OnColonCommaKey;
|
||||||
|
if (p + 4 <= e && READ32LE(p) == READ32LE("alse")) {
|
||||||
|
- json.type_ = Bool;
|
||||||
|
- json.bool_value = false;
|
||||||
|
+ j.type_ = Bool;
|
||||||
|
+ j.bool_value = false;
|
||||||
|
p += 4;
|
||||||
|
return success;
|
||||||
|
} else {
|
||||||
|
@@ -830,8 +830,8 @@ Json::parse(Json& json, const char*& p, const char* e, int context, int depth)
|
||||||
|
if (context & (KEY | COLON | COMMA))
|
||||||
|
goto OnColonCommaKey;
|
||||||
|
if (p + 3 <= e && READ32LE(p - 1) == READ32LE("true")) {
|
||||||
|
- json.type_ = Bool;
|
||||||
|
- json.bool_value = true;
|
||||||
|
+ j.type_ = Bool;
|
||||||
|
+ j.bool_value = true;
|
||||||
|
p += 3;
|
||||||
|
return success;
|
||||||
|
} else {
|
||||||
|
@@ -873,8 +873,8 @@ Json::parse(Json& json, const char*& p, const char* e, int context, int depth)
|
||||||
|
return unexpected_octal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- json.type_ = Long;
|
||||||
|
- json.long_value = 0;
|
||||||
|
+ j.type_ = Long;
|
||||||
|
+ j.long_value = 0;
|
||||||
|
return success;
|
||||||
|
|
||||||
|
case '1':
|
||||||
|
@@ -905,13 +905,13 @@ Json::parse(Json& json, const char*& p, const char* e, int context, int depth)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- json.type_ = Long;
|
||||||
|
- json.long_value = x;
|
||||||
|
+ j.type_ = Long;
|
||||||
|
+ j.long_value = x;
|
||||||
|
return success;
|
||||||
|
|
||||||
|
UseDubble: // number
|
||||||
|
- json.type_ = Double;
|
||||||
|
- json.double_value = StringToDouble(a, e - a, &c);
|
||||||
|
+ j.type_ = Double;
|
||||||
|
+ j.double_value = StringToDouble(a, e - a, &c);
|
||||||
|
if (c <= 0)
|
||||||
|
return bad_double;
|
||||||
|
if (a + c < e && (a[c] == 'e' || a[c] == 'E'))
|
||||||
|
@@ -922,15 +922,15 @@ Json::parse(Json& json, const char*& p, const char* e, int context, int depth)
|
||||||
|
case '[': { // Array
|
||||||
|
if (context & (COLON | COMMA | KEY))
|
||||||
|
goto OnColonCommaKey;
|
||||||
|
- json.setArray();
|
||||||
|
- Json value;
|
||||||
|
+ j.setArray();
|
||||||
|
+ json value;
|
||||||
|
for (context = ARRAY, i = 0;;) {
|
||||||
|
Status status = parse(value, p, e, context, depth - 1);
|
||||||
|
if (status == absent_value)
|
||||||
|
return success;
|
||||||
|
if (status != success)
|
||||||
|
return status;
|
||||||
|
- json.array_value.emplace_back(std::move(value));
|
||||||
|
+ j.array_value.emplace_back(std::move(value));
|
||||||
|
context = ARRAY | COMMA;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -948,9 +948,9 @@ Json::parse(Json& json, const char*& p, const char* e, int context, int depth)
|
||||||
|
case '{': { // Object
|
||||||
|
if (context & (COLON | COMMA | KEY))
|
||||||
|
goto OnColonCommaKey;
|
||||||
|
- json.setObject();
|
||||||
|
+ j.setObject();
|
||||||
|
context = KEY | OBJECT;
|
||||||
|
- Json key, value;
|
||||||
|
+ json key, value;
|
||||||
|
for (;;) {
|
||||||
|
Status status = parse(key, p, e, context, depth - 1);
|
||||||
|
if (status == absent_value)
|
||||||
|
@@ -964,7 +964,7 @@ Json::parse(Json& json, const char*& p, const char* e, int context, int depth)
|
||||||
|
return object_missing_value;
|
||||||
|
if (status != success)
|
||||||
|
return status;
|
||||||
|
- json.object_value.emplace(std::move(key.string_value),
|
||||||
|
+ j.object_value.emplace(std::move(key.string_value),
|
||||||
|
std::move(value));
|
||||||
|
context = KEY | COMMA | OBJECT;
|
||||||
|
key.clear();
|
||||||
|
@@ -985,8 +985,8 @@ Json::parse(Json& json, const char*& p, const char* e, int context, int depth)
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DQUOTE:
|
||||||
|
- json.type_ = String;
|
||||||
|
- new (&json.string_value) std::string(std::move(b));
|
||||||
|
+ j.type_ = String;
|
||||||
|
+ new (&j.string_value) std::string(std::move(b));
|
||||||
|
return success;
|
||||||
|
|
||||||
|
case BACKSLASH:
|
||||||
|
@@ -1221,16 +1221,16 @@ Json::parse(Json& json, const char*& p, const char* e, int context, int depth)
|
||||||
|
return unexpected_eof;
|
||||||
|
}
|
||||||
|
|
||||||
|
-std::pair<Json::Status, Json>
|
||||||
|
-Json::parse(const std::string& s)
|
||||||
|
+std::pair<json::Status, json>
|
||||||
|
+json::parse(const std::string& s)
|
||||||
|
{
|
||||||
|
- Json::Status s2;
|
||||||
|
- std::pair<Json::Status, Json> res;
|
||||||
|
+ json::Status s2;
|
||||||
|
+ std::pair<json::Status, json> res;
|
||||||
|
const char* p = s.data();
|
||||||
|
const char* e = s.data() + s.size();
|
||||||
|
res.first = parse(res.second, p, e, 0, DEPTH);
|
||||||
|
- if (res.first == Json::success) {
|
||||||
|
- Json j2;
|
||||||
|
+ if (res.first == json::success) {
|
||||||
|
+ json j2;
|
||||||
|
s2 = parse(j2, p, e, 0, DEPTH);
|
||||||
|
if (s2 != absent_value)
|
||||||
|
res.first = trailing_content;
|
||||||
|
@@ -1239,7 +1239,7 @@ Json::parse(const std::string& s)
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
-Json::StatusToString(Json::Status status)
|
||||||
|
+json::StatusToString(json::Status status)
|
||||||
|
{
|
||||||
|
switch (status) {
|
||||||
|
case success:
|
||||||
|
diff --git a/json.h b/json.h
|
||||||
|
index c676e651d7c2591a0fb07d8d8b28738cbd1defab..b1f175cf070c6b0dbebffdc60c38954c14f77745 100644
|
||||||
|
--- a/json.h
|
||||||
|
+++ b/json.h
|
||||||
|
@@ -22,7 +22,7 @@
|
||||||
|
|
||||||
|
namespace wpi::util {
|
||||||
|
|
||||||
|
-class Json
|
||||||
|
+class json
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
enum Type
|
||||||
|
@@ -83,55 +83,55 @@ class Json
|
||||||
|
double double_value;
|
||||||
|
long long long_value;
|
||||||
|
std::string string_value;
|
||||||
|
- std::vector<Json> array_value;
|
||||||
|
- std::map<std::string, Json> object_value;
|
||||||
|
+ std::vector<json> array_value;
|
||||||
|
+ std::map<std::string, json> object_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const char* StatusToString(Status);
|
||||||
|
- static std::pair<Status, Json> parse(const std::string&);
|
||||||
|
+ static std::pair<Status, json> parse(const std::string&);
|
||||||
|
|
||||||
|
- Json(const Json&);
|
||||||
|
- Json(Json&&);
|
||||||
|
- Json(unsigned long);
|
||||||
|
- Json(unsigned long long);
|
||||||
|
- Json(const char*);
|
||||||
|
- Json(const std::string&);
|
||||||
|
- ~Json();
|
||||||
|
+ json(const json&);
|
||||||
|
+ json(json&&);
|
||||||
|
+ json(unsigned long);
|
||||||
|
+ json(unsigned long long);
|
||||||
|
+ json(const char*);
|
||||||
|
+ json(const std::string&);
|
||||||
|
+ ~json();
|
||||||
|
|
||||||
|
- Json(const std::nullptr_t = nullptr) : type_(Null)
|
||||||
|
+ json(const std::nullptr_t = nullptr) : type_(Null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- Json(bool value) : type_(Bool), bool_value(value)
|
||||||
|
+ json(bool value) : type_(Bool), bool_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- Json(int value) : type_(Long), long_value(value)
|
||||||
|
+ json(int value) : type_(Long), long_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- Json(float value) : type_(Float), float_value(value)
|
||||||
|
+ json(float value) : type_(Float), float_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- Json(unsigned value) : type_(Long), long_value(value)
|
||||||
|
+ json(unsigned value) : type_(Long), long_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- Json(long value) : type_(Long), long_value(value)
|
||||||
|
+ json(long value) : type_(Long), long_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- Json(long long value) : type_(Long), long_value(value)
|
||||||
|
+ json(long long value) : type_(Long), long_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- Json(double value) : type_(Double), double_value(value)
|
||||||
|
+ json(double value) : type_(Double), double_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- Json(std::string&& value) : type_(String), string_value(std::move(value))
|
||||||
|
+ json(std::string&& value) : type_(String), string_value(std::move(value))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -191,8 +191,8 @@ class Json
|
||||||
|
double getNumber() const;
|
||||||
|
long long getLong() const;
|
||||||
|
std::string& getString();
|
||||||
|
- std::vector<Json>& getArray();
|
||||||
|
- std::map<std::string, Json>& getObject();
|
||||||
|
+ std::vector<json>& getArray();
|
||||||
|
+ std::map<std::string, json>& getObject();
|
||||||
|
|
||||||
|
bool contains(const std::string&) const;
|
||||||
|
|
||||||
|
@@ -202,11 +202,11 @@ class Json
|
||||||
|
std::string toString() const;
|
||||||
|
std::string toStringPretty() const;
|
||||||
|
|
||||||
|
- Json& operator=(const Json&);
|
||||||
|
- Json& operator=(Json&&);
|
||||||
|
+ json& operator=(const json&);
|
||||||
|
+ json& operator=(json&&);
|
||||||
|
|
||||||
|
- Json& operator[](size_t);
|
||||||
|
- Json& operator[](const std::string&);
|
||||||
|
+ json& operator[](size_t);
|
||||||
|
+ json& operator[](const std::string&);
|
||||||
|
|
||||||
|
operator std::string() const
|
||||||
|
{
|
||||||
|
@@ -218,7 +218,7 @@ class Json
|
||||||
|
void marshal(std::string&, bool, int) const;
|
||||||
|
static void stringify(std::string&, const std::string&);
|
||||||
|
static void serialize(std::string&, const std::string&);
|
||||||
|
- static Status parse(Json&, const char*&, const char*, int, int);
|
||||||
|
+ static Status parse(json&, const char*&, const char*, int, int);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace wpi::util
|
||||||
286
upstream_utils/json_patches/0003-Use-snake_case-names.patch
Normal file
286
upstream_utils/json_patches/0003-Use-snake_case-names.patch
Normal file
@@ -0,0 +1,286 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Peter Johnson <johnson.peter@gmail.com>
|
||||||
|
Date: Sun, 29 Mar 2026 16:50:21 -0700
|
||||||
|
Subject: [PATCH 03/25] Use snake_case names
|
||||||
|
|
||||||
|
---
|
||||||
|
json.cpp | 40 ++++++++++++++++++++--------------------
|
||||||
|
json.h | 48 ++++++++++++++++++++++++------------------------
|
||||||
|
2 files changed, 44 insertions(+), 44 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/json.cpp b/json.cpp
|
||||||
|
index 3e59a885b55d3fddc418903112595fe5de223f34..939efbcf8e550e7c48d180f81be39b476c5990fe 100644
|
||||||
|
--- a/json.cpp
|
||||||
|
+++ b/json.cpp
|
||||||
|
@@ -448,7 +448,7 @@ json::operator=(json&& other)
|
||||||
|
}
|
||||||
|
|
||||||
|
double
|
||||||
|
-json::getNumber() const
|
||||||
|
+json::get_number() const
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
case Long:
|
||||||
|
@@ -463,7 +463,7 @@ json::getNumber() const
|
||||||
|
}
|
||||||
|
|
||||||
|
long long
|
||||||
|
-json::getLong() const
|
||||||
|
+json::get_long() const
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
case Long:
|
||||||
|
@@ -474,7 +474,7 @@ json::getLong() const
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
-json::getBool() const
|
||||||
|
+json::get_bool() const
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
case Bool:
|
||||||
|
@@ -485,7 +485,7 @@ json::getBool() const
|
||||||
|
}
|
||||||
|
|
||||||
|
float
|
||||||
|
-json::getFloat() const
|
||||||
|
+json::get_float() const
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
case Float:
|
||||||
|
@@ -498,7 +498,7 @@ json::getFloat() const
|
||||||
|
}
|
||||||
|
|
||||||
|
double
|
||||||
|
-json::getDouble() const
|
||||||
|
+json::get_double() const
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
case Float:
|
||||||
|
@@ -511,7 +511,7 @@ json::getDouble() const
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string&
|
||||||
|
-json::getString()
|
||||||
|
+json::get_string()
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
case String:
|
||||||
|
@@ -522,7 +522,7 @@ json::getString()
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<json>&
|
||||||
|
-json::getArray()
|
||||||
|
+json::get_array()
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
case Array:
|
||||||
|
@@ -533,7 +533,7 @@ json::getArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::string, json>&
|
||||||
|
-json::getObject()
|
||||||
|
+json::get_object()
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
case Object:
|
||||||
|
@@ -544,7 +544,7 @@ json::getObject()
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
-json::setArray()
|
||||||
|
+json::set_array()
|
||||||
|
{
|
||||||
|
if (type_ >= String)
|
||||||
|
clear();
|
||||||
|
@@ -553,7 +553,7 @@ json::setArray()
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
-json::setObject()
|
||||||
|
+json::set_object()
|
||||||
|
{
|
||||||
|
if (type_ >= String)
|
||||||
|
clear();
|
||||||
|
@@ -564,7 +564,7 @@ json::setObject()
|
||||||
|
bool
|
||||||
|
json::contains(const std::string& key) const
|
||||||
|
{
|
||||||
|
- if (!isObject())
|
||||||
|
+ if (!is_object())
|
||||||
|
return false;
|
||||||
|
return object_value.find(key) != object_value.end();
|
||||||
|
}
|
||||||
|
@@ -572,8 +572,8 @@ json::contains(const std::string& key) const
|
||||||
|
json&
|
||||||
|
json::operator[](size_t index)
|
||||||
|
{
|
||||||
|
- if (!isArray())
|
||||||
|
- setArray();
|
||||||
|
+ if (!is_array())
|
||||||
|
+ set_array();
|
||||||
|
if (index >= array_value.size()) {
|
||||||
|
array_value.resize(index + 1);
|
||||||
|
}
|
||||||
|
@@ -583,13 +583,13 @@ json::operator[](size_t index)
|
||||||
|
json&
|
||||||
|
json::operator[](const std::string& key)
|
||||||
|
{
|
||||||
|
- if (!isObject())
|
||||||
|
- setObject();
|
||||||
|
+ if (!is_object())
|
||||||
|
+ set_object();
|
||||||
|
return object_value[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
-json::toString() const
|
||||||
|
+json::to_string() const
|
||||||
|
{
|
||||||
|
std::string b;
|
||||||
|
marshal(b, false, 0);
|
||||||
|
@@ -597,7 +597,7 @@ json::toString() const
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
-json::toStringPretty() const
|
||||||
|
+json::to_string_pretty() const
|
||||||
|
{
|
||||||
|
std::string b;
|
||||||
|
marshal(b, true, 0);
|
||||||
|
@@ -922,7 +922,7 @@ json::parse(json& j, const char*& p, const char* e, int context, int depth)
|
||||||
|
case '[': { // Array
|
||||||
|
if (context & (COLON | COMMA | KEY))
|
||||||
|
goto OnColonCommaKey;
|
||||||
|
- j.setArray();
|
||||||
|
+ j.set_array();
|
||||||
|
json value;
|
||||||
|
for (context = ARRAY, i = 0;;) {
|
||||||
|
Status status = parse(value, p, e, context, depth - 1);
|
||||||
|
@@ -948,7 +948,7 @@ json::parse(json& j, const char*& p, const char* e, int context, int depth)
|
||||||
|
case '{': { // Object
|
||||||
|
if (context & (COLON | COMMA | KEY))
|
||||||
|
goto OnColonCommaKey;
|
||||||
|
- j.setObject();
|
||||||
|
+ j.set_object();
|
||||||
|
context = KEY | OBJECT;
|
||||||
|
json key, value;
|
||||||
|
for (;;) {
|
||||||
|
@@ -957,7 +957,7 @@ json::parse(json& j, const char*& p, const char* e, int context, int depth)
|
||||||
|
return success;
|
||||||
|
if (status != success)
|
||||||
|
return status;
|
||||||
|
- if (!key.isString())
|
||||||
|
+ if (!key.is_string())
|
||||||
|
return object_key_must_be_string;
|
||||||
|
status = parse(value, p, e, COLON, depth - 1);
|
||||||
|
if (status == absent_value)
|
||||||
|
diff --git a/json.h b/json.h
|
||||||
|
index b1f175cf070c6b0dbebffdc60c38954c14f77745..bf250d3aacb3508601e1e5d61531ec5e8248ebdb 100644
|
||||||
|
--- a/json.h
|
||||||
|
+++ b/json.h
|
||||||
|
@@ -135,72 +135,72 @@ class json
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- Type getType() const
|
||||||
|
+ Type type() const
|
||||||
|
{
|
||||||
|
return type_;
|
||||||
|
}
|
||||||
|
|
||||||
|
- bool isNull() const
|
||||||
|
+ bool is_null() const
|
||||||
|
{
|
||||||
|
return type_ == Null;
|
||||||
|
}
|
||||||
|
|
||||||
|
- bool isBool() const
|
||||||
|
+ bool is_bool() const
|
||||||
|
{
|
||||||
|
return type_ == Bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
- bool isNumber() const
|
||||||
|
+ bool is_number() const
|
||||||
|
{
|
||||||
|
- return isFloat() || isDouble() || isLong();
|
||||||
|
+ return is_float() || is_double() || is_long();
|
||||||
|
}
|
||||||
|
|
||||||
|
- bool isLong() const
|
||||||
|
+ bool is_long() const
|
||||||
|
{
|
||||||
|
return type_ == Long;
|
||||||
|
}
|
||||||
|
|
||||||
|
- bool isFloat() const
|
||||||
|
+ bool is_float() const
|
||||||
|
{
|
||||||
|
return type_ == Float;
|
||||||
|
}
|
||||||
|
|
||||||
|
- bool isDouble() const
|
||||||
|
+ bool is_double() const
|
||||||
|
{
|
||||||
|
return type_ == Double;
|
||||||
|
}
|
||||||
|
|
||||||
|
- bool isString() const
|
||||||
|
+ bool is_string() const
|
||||||
|
{
|
||||||
|
return type_ == String;
|
||||||
|
}
|
||||||
|
|
||||||
|
- bool isArray() const
|
||||||
|
+ bool is_array() const
|
||||||
|
{
|
||||||
|
return type_ == Array;
|
||||||
|
}
|
||||||
|
|
||||||
|
- bool isObject() const
|
||||||
|
+ bool is_object() const
|
||||||
|
{
|
||||||
|
return type_ == Object;
|
||||||
|
}
|
||||||
|
|
||||||
|
- bool getBool() const;
|
||||||
|
- float getFloat() const;
|
||||||
|
- double getDouble() const;
|
||||||
|
- double getNumber() const;
|
||||||
|
- long long getLong() const;
|
||||||
|
- std::string& getString();
|
||||||
|
- std::vector<json>& getArray();
|
||||||
|
- std::map<std::string, json>& getObject();
|
||||||
|
+ bool get_bool() const;
|
||||||
|
+ float get_float() const;
|
||||||
|
+ double get_double() const;
|
||||||
|
+ double get_number() const;
|
||||||
|
+ long long get_long() const;
|
||||||
|
+ std::string& get_string();
|
||||||
|
+ std::vector<json>& get_array();
|
||||||
|
+ std::map<std::string, json>& get_object();
|
||||||
|
|
||||||
|
bool contains(const std::string&) const;
|
||||||
|
|
||||||
|
- void setArray();
|
||||||
|
- void setObject();
|
||||||
|
+ void set_array();
|
||||||
|
+ void set_object();
|
||||||
|
|
||||||
|
- std::string toString() const;
|
||||||
|
- std::string toStringPretty() const;
|
||||||
|
+ std::string to_string() const;
|
||||||
|
+ std::string to_string_pretty() const;
|
||||||
|
|
||||||
|
json& operator=(const json&);
|
||||||
|
json& operator=(json&&);
|
||||||
|
@@ -210,7 +210,7 @@ class json
|
||||||
|
|
||||||
|
operator std::string() const
|
||||||
|
{
|
||||||
|
- return toString();
|
||||||
|
+ return to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Peter Johnson <johnson.peter@gmail.com>
|
||||||
|
Date: Wed, 1 Apr 2026 07:31:40 -0700
|
||||||
|
Subject: [PATCH 04/25] Suppress pedantic warning
|
||||||
|
|
||||||
|
---
|
||||||
|
jtckdint.h | 4 ++++
|
||||||
|
1 file changed, 4 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/jtckdint.h b/jtckdint.h
|
||||||
|
index 4c71d9990ca233017332f3ede71b092da48b474f..ac6a52e5aab04116defe1d06b3831d3509fea8a2 100644
|
||||||
|
--- a/jtckdint.h
|
||||||
|
+++ b/jtckdint.h
|
||||||
|
@@ -57,6 +57,10 @@
|
||||||
|
#ifndef JTCKDINT_H_
|
||||||
|
#define JTCKDINT_H_
|
||||||
|
|
||||||
|
+#ifdef __GNUC__
|
||||||
|
+#pragma GCC diagnostic ignored "-Wpedantic"
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
#ifdef __has_include
|
||||||
|
#define __ckd_has_include(x) __has_include(x)
|
||||||
|
#else
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Peter Johnson <johnson.peter@gmail.com>
|
||||||
|
Date: Wed, 1 Apr 2026 07:32:33 -0700
|
||||||
|
Subject: [PATCH 05/25] Suppress type limits warning
|
||||||
|
|
||||||
|
---
|
||||||
|
json.cpp | 4 ++++
|
||||||
|
1 file changed, 4 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/json.cpp b/json.cpp
|
||||||
|
index 939efbcf8e550e7c48d180f81be39b476c5990fe..8f45bb573deed5b8c7afaf3fe2b6b40fa21555c1 100644
|
||||||
|
--- a/json.cpp
|
||||||
|
+++ b/json.cpp
|
||||||
|
@@ -28,6 +28,10 @@
|
||||||
|
#include "double-conversion/double-to-string.h"
|
||||||
|
#include "double-conversion/string-to-double.h"
|
||||||
|
|
||||||
|
+#ifdef __GNUC__
|
||||||
|
+#pragma GCC diagnostic ignored "-Wtype-limits"
|
||||||
|
+#endif
|
||||||
|
+
|
||||||
|
#define KEY 1
|
||||||
|
#define COMMA 2
|
||||||
|
#define COLON 4
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Peter Johnson <johnson.peter@gmail.com>
|
||||||
|
Date: Wed, 1 Apr 2026 07:33:06 -0700
|
||||||
|
Subject: [PATCH 06/25] Update double-conversion include for wpi
|
||||||
|
|
||||||
|
---
|
||||||
|
json.cpp | 4 ++--
|
||||||
|
1 file changed, 2 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/json.cpp b/json.cpp
|
||||||
|
index 8f45bb573deed5b8c7afaf3fe2b6b40fa21555c1..87433664d2caf96b1c8f5b80eb4f4cc8d3d34f7e 100644
|
||||||
|
--- a/json.cpp
|
||||||
|
+++ b/json.cpp
|
||||||
|
@@ -25,8 +25,8 @@
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
-#include "double-conversion/double-to-string.h"
|
||||||
|
-#include "double-conversion/string-to-double.h"
|
||||||
|
+#include "wpi/double-conversion/double-to-string.h"
|
||||||
|
+#include "wpi/double-conversion/string-to-double.h"
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#pragma GCC diagnostic ignored "-Wtype-limits"
|
||||||
@@ -0,0 +1,155 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Peter Johnson <johnson.peter@gmail.com>
|
||||||
|
Date: Wed, 1 Apr 2026 07:51:30 -0700
|
||||||
|
Subject: [PATCH 07/25] Use typedefs for array and object types
|
||||||
|
|
||||||
|
---
|
||||||
|
json.cpp | 32 ++++++++++++++------------------
|
||||||
|
json.h | 11 +++++++----
|
||||||
|
2 files changed, 21 insertions(+), 22 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/json.cpp b/json.cpp
|
||||||
|
index 87433664d2caf96b1c8f5b80eb4f4cc8d3d34f7e..8fd64748250d9cd71fd31b8caf4281183e31b053 100644
|
||||||
|
--- a/json.cpp
|
||||||
|
+++ b/json.cpp
|
||||||
|
@@ -296,10 +296,10 @@ json::clear()
|
||||||
|
string_value.~basic_string();
|
||||||
|
break;
|
||||||
|
case Array:
|
||||||
|
- array_value.~vector();
|
||||||
|
+ array_value.~array_t();
|
||||||
|
break;
|
||||||
|
case Object:
|
||||||
|
- object_value.~map();
|
||||||
|
+ object_value.~object_t();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
@@ -328,10 +328,10 @@ json::json(const json& other) : type_(other.type_)
|
||||||
|
new (&string_value) std::string(other.string_value);
|
||||||
|
break;
|
||||||
|
case Array:
|
||||||
|
- new (&array_value) std::vector<json>(other.array_value);
|
||||||
|
+ new (&array_value) array_t(other.array_value);
|
||||||
|
break;
|
||||||
|
case Object:
|
||||||
|
- new (&object_value) std::map<std::string, json>(other.object_value);
|
||||||
|
+ new (&object_value) object_t(other.object_value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ON_LOGIC_ERROR("Unhandled JSON type.");
|
||||||
|
@@ -364,11 +364,10 @@ json::operator=(const json& other)
|
||||||
|
new (&string_value) std::string(other.string_value);
|
||||||
|
break;
|
||||||
|
case Array:
|
||||||
|
- new (&array_value) std::vector<json>(other.array_value);
|
||||||
|
+ new (&array_value) array_t(other.array_value);
|
||||||
|
break;
|
||||||
|
case Object:
|
||||||
|
- new (&object_value)
|
||||||
|
- std::map<std::string, json>(other.object_value);
|
||||||
|
+ new (&object_value) object_t(other.object_value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ON_LOGIC_ERROR("Unhandled JSON type.");
|
||||||
|
@@ -398,11 +397,10 @@ json::json(json&& other) : type_(other.type_)
|
||||||
|
new (&string_value) std::string(std::move(other.string_value));
|
||||||
|
break;
|
||||||
|
case Array:
|
||||||
|
- new (&array_value) std::vector<json>(std::move(other.array_value));
|
||||||
|
+ new (&array_value) array_t(std::move(other.array_value));
|
||||||
|
break;
|
||||||
|
case Object:
|
||||||
|
- new (&object_value)
|
||||||
|
- std::map<std::string, json>(std::move(other.object_value));
|
||||||
|
+ new (&object_value) object_t(std::move(other.object_value));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ON_LOGIC_ERROR("Unhandled JSON type.");
|
||||||
|
@@ -436,12 +434,10 @@ json::operator=(json&& other)
|
||||||
|
new (&string_value) std::string(std::move(other.string_value));
|
||||||
|
break;
|
||||||
|
case Array:
|
||||||
|
- new (&array_value)
|
||||||
|
- std::vector<json>(std::move(other.array_value));
|
||||||
|
+ new (&array_value) array_t(std::move(other.array_value));
|
||||||
|
break;
|
||||||
|
case Object:
|
||||||
|
- new (&object_value)
|
||||||
|
- std::map<std::string, json>(std::move(other.object_value));
|
||||||
|
+ new (&object_value) object_t(std::move(other.object_value));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ON_LOGIC_ERROR("Unhandled JSON type.");;
|
||||||
|
@@ -525,7 +521,7 @@ json::get_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-std::vector<json>&
|
||||||
|
+json::array_t&
|
||||||
|
json::get_array()
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
@@ -536,7 +532,7 @@ json::get_array()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-std::map<std::string, json>&
|
||||||
|
+json::object_t&
|
||||||
|
json::get_object()
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
@@ -553,7 +549,7 @@ json::set_array()
|
||||||
|
if (type_ >= String)
|
||||||
|
clear();
|
||||||
|
type_ = Array;
|
||||||
|
- new (&array_value) std::vector<json>();
|
||||||
|
+ new (&array_value) array_t();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
@@ -562,7 +558,7 @@ json::set_object()
|
||||||
|
if (type_ >= String)
|
||||||
|
clear();
|
||||||
|
type_ = Object;
|
||||||
|
- new (&object_value) std::map<std::string, json>();
|
||||||
|
+ new (&object_value) object_t();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
diff --git a/json.h b/json.h
|
||||||
|
index bf250d3aacb3508601e1e5d61531ec5e8248ebdb..e25116a7f7c26525028b11928e665c1883b3ba65 100644
|
||||||
|
--- a/json.h
|
||||||
|
+++ b/json.h
|
||||||
|
@@ -25,6 +25,9 @@ namespace wpi::util {
|
||||||
|
class json
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
+ using array_t = std::vector<json>;
|
||||||
|
+ using object_t = std::map<std::string, json>;
|
||||||
|
+
|
||||||
|
enum Type
|
||||||
|
{
|
||||||
|
Null,
|
||||||
|
@@ -83,8 +86,8 @@ class json
|
||||||
|
double double_value;
|
||||||
|
long long long_value;
|
||||||
|
std::string string_value;
|
||||||
|
- std::vector<json> array_value;
|
||||||
|
- std::map<std::string, json> object_value;
|
||||||
|
+ array_t array_value;
|
||||||
|
+ object_t object_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
@@ -191,8 +194,8 @@ class json
|
||||||
|
double get_number() const;
|
||||||
|
long long get_long() const;
|
||||||
|
std::string& get_string();
|
||||||
|
- std::vector<json>& get_array();
|
||||||
|
- std::map<std::string, json>& get_object();
|
||||||
|
+ array_t& get_array();
|
||||||
|
+ object_t& get_object();
|
||||||
|
|
||||||
|
bool contains(const std::string&) const;
|
||||||
|
|
||||||
@@ -0,0 +1,582 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Peter Johnson <johnson.peter@gmail.com>
|
||||||
|
Date: Wed, 1 Apr 2026 07:56:14 -0700
|
||||||
|
Subject: [PATCH 08/25] Change Type to an enum class
|
||||||
|
|
||||||
|
---
|
||||||
|
json.cpp | 156 +++++++++++++++++++++++++++----------------------------
|
||||||
|
json.h | 36 ++++++-------
|
||||||
|
2 files changed, 96 insertions(+), 96 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/json.cpp b/json.cpp
|
||||||
|
index 8fd64748250d9cd71fd31b8caf4281183e31b053..88ce30f8669a02cdc54e741a2a5a0663953d4acb 100644
|
||||||
|
--- a/json.cpp
|
||||||
|
+++ b/json.cpp
|
||||||
|
@@ -249,10 +249,10 @@ LongToString(char* p, long long x)
|
||||||
|
json::json(unsigned long value)
|
||||||
|
{
|
||||||
|
if (value <= LLONG_MAX) {
|
||||||
|
- type_ = Long;
|
||||||
|
+ type_ = Type::Long;
|
||||||
|
long_value = value;
|
||||||
|
} else {
|
||||||
|
- type_ = Double;
|
||||||
|
+ type_ = Type::Double;
|
||||||
|
double_value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -260,10 +260,10 @@ json::json(unsigned long value)
|
||||||
|
json::json(unsigned long long value)
|
||||||
|
{
|
||||||
|
if (value <= LLONG_MAX) {
|
||||||
|
- type_ = Long;
|
||||||
|
+ type_ = Type::Long;
|
||||||
|
long_value = value;
|
||||||
|
} else {
|
||||||
|
- type_ = Double;
|
||||||
|
+ type_ = Type::Double;
|
||||||
|
double_value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -271,20 +271,20 @@ json::json(unsigned long long value)
|
||||||
|
json::json(const char* value)
|
||||||
|
{
|
||||||
|
if (value) {
|
||||||
|
- type_ = String;
|
||||||
|
+ type_ = Type::String;
|
||||||
|
new (&string_value) std::string(value);
|
||||||
|
} else {
|
||||||
|
- type_ = Null;
|
||||||
|
+ type_ = Type::Null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
-json::json(const std::string& value) : type_(String), string_value(value)
|
||||||
|
+json::json(const std::string& value) : type_(Type::String), string_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
json::~json()
|
||||||
|
{
|
||||||
|
- if (type_ >= String)
|
||||||
|
+ if (type_ >= Type::String)
|
||||||
|
clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -292,45 +292,45 @@ void
|
||||||
|
json::clear()
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
- case String:
|
||||||
|
+ case Type::String:
|
||||||
|
string_value.~basic_string();
|
||||||
|
break;
|
||||||
|
- case Array:
|
||||||
|
+ case Type::Array:
|
||||||
|
array_value.~array_t();
|
||||||
|
break;
|
||||||
|
- case Object:
|
||||||
|
+ case Type::Object:
|
||||||
|
object_value.~object_t();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
- type_ = Null;
|
||||||
|
+ type_ = Type::Null;
|
||||||
|
}
|
||||||
|
|
||||||
|
json::json(const json& other) : type_(other.type_)
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
- case Null:
|
||||||
|
+ case Type::Null:
|
||||||
|
break;
|
||||||
|
- case Bool:
|
||||||
|
+ case Type::Bool:
|
||||||
|
bool_value = other.bool_value;
|
||||||
|
break;
|
||||||
|
- case Long:
|
||||||
|
+ case Type::Long:
|
||||||
|
long_value = other.long_value;
|
||||||
|
break;
|
||||||
|
- case Float:
|
||||||
|
+ case Type::Float:
|
||||||
|
float_value = other.float_value;
|
||||||
|
break;
|
||||||
|
- case Double:
|
||||||
|
+ case Type::Double:
|
||||||
|
double_value = other.double_value;
|
||||||
|
break;
|
||||||
|
- case String:
|
||||||
|
+ case Type::String:
|
||||||
|
new (&string_value) std::string(other.string_value);
|
||||||
|
break;
|
||||||
|
- case Array:
|
||||||
|
+ case Type::Array:
|
||||||
|
new (&array_value) array_t(other.array_value);
|
||||||
|
break;
|
||||||
|
- case Object:
|
||||||
|
+ case Type::Object:
|
||||||
|
new (&object_value) object_t(other.object_value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
@@ -342,31 +342,31 @@ json&
|
||||||
|
json::operator=(const json& other)
|
||||||
|
{
|
||||||
|
if (this != &other) {
|
||||||
|
- if (type_ >= String)
|
||||||
|
+ if (type_ >= Type::String)
|
||||||
|
clear();
|
||||||
|
type_ = other.type_;
|
||||||
|
switch (type_) {
|
||||||
|
- case Null:
|
||||||
|
+ case Type::Null:
|
||||||
|
break;
|
||||||
|
- case Bool:
|
||||||
|
+ case Type::Bool:
|
||||||
|
bool_value = other.bool_value;
|
||||||
|
break;
|
||||||
|
- case Long:
|
||||||
|
+ case Type::Long:
|
||||||
|
long_value = other.long_value;
|
||||||
|
break;
|
||||||
|
- case Float:
|
||||||
|
+ case Type::Float:
|
||||||
|
float_value = other.float_value;
|
||||||
|
break;
|
||||||
|
- case Double:
|
||||||
|
+ case Type::Double:
|
||||||
|
double_value = other.double_value;
|
||||||
|
break;
|
||||||
|
- case String:
|
||||||
|
+ case Type::String:
|
||||||
|
new (&string_value) std::string(other.string_value);
|
||||||
|
break;
|
||||||
|
- case Array:
|
||||||
|
+ case Type::Array:
|
||||||
|
new (&array_value) array_t(other.array_value);
|
||||||
|
break;
|
||||||
|
- case Object:
|
||||||
|
+ case Type::Object:
|
||||||
|
new (&object_value) object_t(other.object_value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
@@ -379,70 +379,70 @@ json::operator=(const json& other)
|
||||||
|
json::json(json&& other) : type_(other.type_)
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
- case Null:
|
||||||
|
+ case Type::Null:
|
||||||
|
break;
|
||||||
|
- case Bool:
|
||||||
|
+ case Type::Bool:
|
||||||
|
bool_value = other.bool_value;
|
||||||
|
break;
|
||||||
|
- case Long:
|
||||||
|
+ case Type::Long:
|
||||||
|
long_value = other.long_value;
|
||||||
|
break;
|
||||||
|
- case Float:
|
||||||
|
+ case Type::Float:
|
||||||
|
float_value = other.float_value;
|
||||||
|
break;
|
||||||
|
- case Double:
|
||||||
|
+ case Type::Double:
|
||||||
|
double_value = other.double_value;
|
||||||
|
break;
|
||||||
|
- case String:
|
||||||
|
+ case Type::String:
|
||||||
|
new (&string_value) std::string(std::move(other.string_value));
|
||||||
|
break;
|
||||||
|
- case Array:
|
||||||
|
+ case Type::Array:
|
||||||
|
new (&array_value) array_t(std::move(other.array_value));
|
||||||
|
break;
|
||||||
|
- case Object:
|
||||||
|
+ case Type::Object:
|
||||||
|
new (&object_value) object_t(std::move(other.object_value));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ON_LOGIC_ERROR("Unhandled JSON type.");
|
||||||
|
}
|
||||||
|
- other.type_ = Null;
|
||||||
|
+ other.type_ = Type::Null;
|
||||||
|
}
|
||||||
|
|
||||||
|
json&
|
||||||
|
json::operator=(json&& other)
|
||||||
|
{
|
||||||
|
if (this != &other) {
|
||||||
|
- if (type_ >= String)
|
||||||
|
+ if (type_ >= Type::String)
|
||||||
|
clear();
|
||||||
|
type_ = other.type_;
|
||||||
|
switch (type_) {
|
||||||
|
- case Null:
|
||||||
|
+ case Type::Null:
|
||||||
|
break;
|
||||||
|
- case Bool:
|
||||||
|
+ case Type::Bool:
|
||||||
|
bool_value = other.bool_value;
|
||||||
|
break;
|
||||||
|
- case Long:
|
||||||
|
+ case Type::Long:
|
||||||
|
long_value = other.long_value;
|
||||||
|
break;
|
||||||
|
- case Float:
|
||||||
|
+ case Type::Float:
|
||||||
|
float_value = other.float_value;
|
||||||
|
break;
|
||||||
|
- case Double:
|
||||||
|
+ case Type::Double:
|
||||||
|
double_value = other.double_value;
|
||||||
|
break;
|
||||||
|
- case String:
|
||||||
|
+ case Type::String:
|
||||||
|
new (&string_value) std::string(std::move(other.string_value));
|
||||||
|
break;
|
||||||
|
- case Array:
|
||||||
|
+ case Type::Array:
|
||||||
|
new (&array_value) array_t(std::move(other.array_value));
|
||||||
|
break;
|
||||||
|
- case Object:
|
||||||
|
+ case Type::Object:
|
||||||
|
new (&object_value) object_t(std::move(other.object_value));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ON_LOGIC_ERROR("Unhandled JSON type.");;
|
||||||
|
}
|
||||||
|
- other.type_ = Null;
|
||||||
|
+ other.type_ = Type::Null;
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
@@ -451,11 +451,11 @@ double
|
||||||
|
json::get_number() const
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
- case Long:
|
||||||
|
+ case Type::Long:
|
||||||
|
return long_value;
|
||||||
|
- case Float:
|
||||||
|
+ case Type::Float:
|
||||||
|
return float_value;
|
||||||
|
- case Double:
|
||||||
|
+ case Type::Double:
|
||||||
|
return double_value;
|
||||||
|
default:
|
||||||
|
ON_LOGIC_ERROR("JSON value is not a number.");
|
||||||
|
@@ -466,7 +466,7 @@ long long
|
||||||
|
json::get_long() const
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
- case Long:
|
||||||
|
+ case Type::Long:
|
||||||
|
return long_value;
|
||||||
|
default:
|
||||||
|
ON_LOGIC_ERROR("JSON value is not a long.");
|
||||||
|
@@ -477,7 +477,7 @@ bool
|
||||||
|
json::get_bool() const
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
- case Bool:
|
||||||
|
+ case Type::Bool:
|
||||||
|
return bool_value;
|
||||||
|
default:
|
||||||
|
ON_LOGIC_ERROR("JSON value is not a bool.");
|
||||||
|
@@ -488,9 +488,9 @@ float
|
||||||
|
json::get_float() const
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
- case Float:
|
||||||
|
+ case Type::Float:
|
||||||
|
return float_value;
|
||||||
|
- case Double:
|
||||||
|
+ case Type::Double:
|
||||||
|
return double_value;
|
||||||
|
default:
|
||||||
|
ON_LOGIC_ERROR("JSON value is not a floating-point number.");
|
||||||
|
@@ -501,9 +501,9 @@ double
|
||||||
|
json::get_double() const
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
- case Float:
|
||||||
|
+ case Type::Float:
|
||||||
|
return float_value;
|
||||||
|
- case Double:
|
||||||
|
+ case Type::Double:
|
||||||
|
return double_value;
|
||||||
|
default:
|
||||||
|
ON_LOGIC_ERROR("JSON value is not a floating-point number.");
|
||||||
|
@@ -514,7 +514,7 @@ std::string&
|
||||||
|
json::get_string()
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
- case String:
|
||||||
|
+ case Type::String:
|
||||||
|
return string_value;
|
||||||
|
default:
|
||||||
|
ON_LOGIC_ERROR("JSON value is not a string.");
|
||||||
|
@@ -525,7 +525,7 @@ json::array_t&
|
||||||
|
json::get_array()
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
- case Array:
|
||||||
|
+ case Type::Array:
|
||||||
|
return array_value;
|
||||||
|
default:
|
||||||
|
ON_LOGIC_ERROR("JSON value is not an array.");
|
||||||
|
@@ -536,7 +536,7 @@ json::object_t&
|
||||||
|
json::get_object()
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
- case Object:
|
||||||
|
+ case Type::Object:
|
||||||
|
return object_value;
|
||||||
|
default:
|
||||||
|
ON_LOGIC_ERROR("JSON value is not an object.");
|
||||||
|
@@ -546,18 +546,18 @@ json::get_object()
|
||||||
|
void
|
||||||
|
json::set_array()
|
||||||
|
{
|
||||||
|
- if (type_ >= String)
|
||||||
|
+ if (type_ >= Type::String)
|
||||||
|
clear();
|
||||||
|
- type_ = Array;
|
||||||
|
+ type_ = Type::Array;
|
||||||
|
new (&array_value) array_t();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
json::set_object()
|
||||||
|
{
|
||||||
|
- if (type_ >= String)
|
||||||
|
+ if (type_ >= Type::String)
|
||||||
|
clear();
|
||||||
|
- type_ = Object;
|
||||||
|
+ type_ = Type::Object;
|
||||||
|
new (&object_value) object_t();
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -608,21 +608,21 @@ void
|
||||||
|
json::marshal(std::string& b, bool pretty, int indent) const
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
- case Null:
|
||||||
|
+ case Type::Null:
|
||||||
|
b += "null";
|
||||||
|
break;
|
||||||
|
- case String:
|
||||||
|
+ case Type::String:
|
||||||
|
stringify(b, string_value);
|
||||||
|
break;
|
||||||
|
- case Bool:
|
||||||
|
+ case Type::Bool:
|
||||||
|
b += bool_value ? "true" : "false";
|
||||||
|
break;
|
||||||
|
- case Long: {
|
||||||
|
+ case Type::Long: {
|
||||||
|
char buf[64];
|
||||||
|
b.append(buf, LongToString(buf, long_value) - buf);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
- case Float: {
|
||||||
|
+ case Type::Float: {
|
||||||
|
char buf[128];
|
||||||
|
double_conversion::StringBuilder db(buf, 128);
|
||||||
|
kDoubleToJson.ToShortestSingle(float_value, &db);
|
||||||
|
@@ -630,7 +630,7 @@ json::marshal(std::string& b, bool pretty, int indent) const
|
||||||
|
b += buf;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
- case Double: {
|
||||||
|
+ case Type::Double: {
|
||||||
|
char buf[128];
|
||||||
|
double_conversion::StringBuilder db(buf, 128);
|
||||||
|
kDoubleToJson.ToShortest(double_value, &db);
|
||||||
|
@@ -638,7 +638,7 @@ json::marshal(std::string& b, bool pretty, int indent) const
|
||||||
|
b += buf;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
- case Array: {
|
||||||
|
+ case Type::Array: {
|
||||||
|
bool once = false;
|
||||||
|
b += '[';
|
||||||
|
for (auto i = array_value.begin(); i != array_value.end(); ++i) {
|
||||||
|
@@ -654,7 +654,7 @@ json::marshal(std::string& b, bool pretty, int indent) const
|
||||||
|
b += ']';
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
- case Object: {
|
||||||
|
+ case Type::Object: {
|
||||||
|
bool once = false;
|
||||||
|
b += '{';
|
||||||
|
for (auto i = object_value.begin(); i != object_value.end(); ++i) {
|
||||||
|
@@ -818,7 +818,7 @@ json::parse(json& j, const char*& p, const char* e, int context, int depth)
|
||||||
|
if (context & (KEY | COLON | COMMA))
|
||||||
|
goto OnColonCommaKey;
|
||||||
|
if (p + 4 <= e && READ32LE(p) == READ32LE("alse")) {
|
||||||
|
- j.type_ = Bool;
|
||||||
|
+ j.type_ = Type::Bool;
|
||||||
|
j.bool_value = false;
|
||||||
|
p += 4;
|
||||||
|
return success;
|
||||||
|
@@ -830,7 +830,7 @@ json::parse(json& j, const char*& p, const char* e, int context, int depth)
|
||||||
|
if (context & (KEY | COLON | COMMA))
|
||||||
|
goto OnColonCommaKey;
|
||||||
|
if (p + 3 <= e && READ32LE(p - 1) == READ32LE("true")) {
|
||||||
|
- j.type_ = Bool;
|
||||||
|
+ j.type_ = Type::Bool;
|
||||||
|
j.bool_value = true;
|
||||||
|
p += 3;
|
||||||
|
return success;
|
||||||
|
@@ -873,7 +873,7 @@ json::parse(json& j, const char*& p, const char* e, int context, int depth)
|
||||||
|
return unexpected_octal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- j.type_ = Long;
|
||||||
|
+ j.type_ = Type::Long;
|
||||||
|
j.long_value = 0;
|
||||||
|
return success;
|
||||||
|
|
||||||
|
@@ -905,12 +905,12 @@ json::parse(json& j, const char*& p, const char* e, int context, int depth)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- j.type_ = Long;
|
||||||
|
+ j.type_ = Type::Long;
|
||||||
|
j.long_value = x;
|
||||||
|
return success;
|
||||||
|
|
||||||
|
UseDubble: // number
|
||||||
|
- j.type_ = Double;
|
||||||
|
+ j.type_ = Type::Double;
|
||||||
|
j.double_value = StringToDouble(a, e - a, &c);
|
||||||
|
if (c <= 0)
|
||||||
|
return bad_double;
|
||||||
|
@@ -985,7 +985,7 @@ json::parse(json& j, const char*& p, const char* e, int context, int depth)
|
||||||
|
break;
|
||||||
|
|
||||||
|
case DQUOTE:
|
||||||
|
- j.type_ = String;
|
||||||
|
+ j.type_ = Type::String;
|
||||||
|
new (&j.string_value) std::string(std::move(b));
|
||||||
|
return success;
|
||||||
|
|
||||||
|
diff --git a/json.h b/json.h
|
||||||
|
index e25116a7f7c26525028b11928e665c1883b3ba65..3d2cb52a1bfeafb5f1a8a1e9c6057a2611cbb41e 100644
|
||||||
|
--- a/json.h
|
||||||
|
+++ b/json.h
|
||||||
|
@@ -28,7 +28,7 @@ class json
|
||||||
|
using array_t = std::vector<json>;
|
||||||
|
using object_t = std::map<std::string, json>;
|
||||||
|
|
||||||
|
- enum Type
|
||||||
|
+ enum class Type
|
||||||
|
{
|
||||||
|
Null,
|
||||||
|
Bool,
|
||||||
|
@@ -102,39 +102,39 @@ class json
|
||||||
|
json(const std::string&);
|
||||||
|
~json();
|
||||||
|
|
||||||
|
- json(const std::nullptr_t = nullptr) : type_(Null)
|
||||||
|
+ json(const std::nullptr_t = nullptr) : type_(Type::Null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- json(bool value) : type_(Bool), bool_value(value)
|
||||||
|
+ json(bool value) : type_(Type::Bool), bool_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- json(int value) : type_(Long), long_value(value)
|
||||||
|
+ json(int value) : type_(Type::Long), long_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- json(float value) : type_(Float), float_value(value)
|
||||||
|
+ json(float value) : type_(Type::Float), float_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- json(unsigned value) : type_(Long), long_value(value)
|
||||||
|
+ json(unsigned value) : type_(Type::Long), long_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- json(long value) : type_(Long), long_value(value)
|
||||||
|
+ json(long value) : type_(Type::Long), long_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- json(long long value) : type_(Long), long_value(value)
|
||||||
|
+ json(long long value) : type_(Type::Long), long_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- json(double value) : type_(Double), double_value(value)
|
||||||
|
+ json(double value) : type_(Type::Double), double_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- json(std::string&& value) : type_(String), string_value(std::move(value))
|
||||||
|
+ json(std::string&& value) : type_(Type::String), string_value(std::move(value))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -145,12 +145,12 @@ class json
|
||||||
|
|
||||||
|
bool is_null() const
|
||||||
|
{
|
||||||
|
- return type_ == Null;
|
||||||
|
+ return type_ == Type::Null;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_bool() const
|
||||||
|
{
|
||||||
|
- return type_ == Bool;
|
||||||
|
+ return type_ == Type::Bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_number() const
|
||||||
|
@@ -160,32 +160,32 @@ class json
|
||||||
|
|
||||||
|
bool is_long() const
|
||||||
|
{
|
||||||
|
- return type_ == Long;
|
||||||
|
+ return type_ == Type::Long;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_float() const
|
||||||
|
{
|
||||||
|
- return type_ == Float;
|
||||||
|
+ return type_ == Type::Float;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_double() const
|
||||||
|
{
|
||||||
|
- return type_ == Double;
|
||||||
|
+ return type_ == Type::Double;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_string() const
|
||||||
|
{
|
||||||
|
- return type_ == String;
|
||||||
|
+ return type_ == Type::String;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_array() const
|
||||||
|
{
|
||||||
|
- return type_ == Array;
|
||||||
|
+ return type_ == Type::Array;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_object() const
|
||||||
|
{
|
||||||
|
- return type_ == Object;
|
||||||
|
+ return type_ == Type::Object;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_bool() const;
|
||||||
183
upstream_utils/json_patches/0009-Rename-long-to-int.patch
Normal file
183
upstream_utils/json_patches/0009-Rename-long-to-int.patch
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Peter Johnson <johnson.peter@gmail.com>
|
||||||
|
Date: Wed, 1 Apr 2026 08:02:21 -0700
|
||||||
|
Subject: [PATCH 09/25] Rename long to int
|
||||||
|
|
||||||
|
---
|
||||||
|
json.cpp | 24 ++++++++++++------------
|
||||||
|
json.h | 18 +++++++++---------
|
||||||
|
2 files changed, 21 insertions(+), 21 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/json.cpp b/json.cpp
|
||||||
|
index 88ce30f8669a02cdc54e741a2a5a0663953d4acb..1266aa36b43155cbab6fe8d918fed2c56596f7a8 100644
|
||||||
|
--- a/json.cpp
|
||||||
|
+++ b/json.cpp
|
||||||
|
@@ -249,7 +249,7 @@ LongToString(char* p, long long x)
|
||||||
|
json::json(unsigned long value)
|
||||||
|
{
|
||||||
|
if (value <= LLONG_MAX) {
|
||||||
|
- type_ = Type::Long;
|
||||||
|
+ type_ = Type::Int;
|
||||||
|
long_value = value;
|
||||||
|
} else {
|
||||||
|
type_ = Type::Double;
|
||||||
|
@@ -260,7 +260,7 @@ json::json(unsigned long value)
|
||||||
|
json::json(unsigned long long value)
|
||||||
|
{
|
||||||
|
if (value <= LLONG_MAX) {
|
||||||
|
- type_ = Type::Long;
|
||||||
|
+ type_ = Type::Int;
|
||||||
|
long_value = value;
|
||||||
|
} else {
|
||||||
|
type_ = Type::Double;
|
||||||
|
@@ -315,7 +315,7 @@ json::json(const json& other) : type_(other.type_)
|
||||||
|
case Type::Bool:
|
||||||
|
bool_value = other.bool_value;
|
||||||
|
break;
|
||||||
|
- case Type::Long:
|
||||||
|
+ case Type::Int:
|
||||||
|
long_value = other.long_value;
|
||||||
|
break;
|
||||||
|
case Type::Float:
|
||||||
|
@@ -351,7 +351,7 @@ json::operator=(const json& other)
|
||||||
|
case Type::Bool:
|
||||||
|
bool_value = other.bool_value;
|
||||||
|
break;
|
||||||
|
- case Type::Long:
|
||||||
|
+ case Type::Int:
|
||||||
|
long_value = other.long_value;
|
||||||
|
break;
|
||||||
|
case Type::Float:
|
||||||
|
@@ -384,7 +384,7 @@ json::json(json&& other) : type_(other.type_)
|
||||||
|
case Type::Bool:
|
||||||
|
bool_value = other.bool_value;
|
||||||
|
break;
|
||||||
|
- case Type::Long:
|
||||||
|
+ case Type::Int:
|
||||||
|
long_value = other.long_value;
|
||||||
|
break;
|
||||||
|
case Type::Float:
|
||||||
|
@@ -421,7 +421,7 @@ json::operator=(json&& other)
|
||||||
|
case Type::Bool:
|
||||||
|
bool_value = other.bool_value;
|
||||||
|
break;
|
||||||
|
- case Type::Long:
|
||||||
|
+ case Type::Int:
|
||||||
|
long_value = other.long_value;
|
||||||
|
break;
|
||||||
|
case Type::Float:
|
||||||
|
@@ -451,7 +451,7 @@ double
|
||||||
|
json::get_number() const
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
- case Type::Long:
|
||||||
|
+ case Type::Int:
|
||||||
|
return long_value;
|
||||||
|
case Type::Float:
|
||||||
|
return float_value;
|
||||||
|
@@ -463,10 +463,10 @@ json::get_number() const
|
||||||
|
}
|
||||||
|
|
||||||
|
long long
|
||||||
|
-json::get_long() const
|
||||||
|
+json::get_int() const
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
- case Type::Long:
|
||||||
|
+ case Type::Int:
|
||||||
|
return long_value;
|
||||||
|
default:
|
||||||
|
ON_LOGIC_ERROR("JSON value is not a long.");
|
||||||
|
@@ -617,7 +617,7 @@ json::marshal(std::string& b, bool pretty, int indent) const
|
||||||
|
case Type::Bool:
|
||||||
|
b += bool_value ? "true" : "false";
|
||||||
|
break;
|
||||||
|
- case Type::Long: {
|
||||||
|
+ case Type::Int: {
|
||||||
|
char buf[64];
|
||||||
|
b.append(buf, LongToString(buf, long_value) - buf);
|
||||||
|
break;
|
||||||
|
@@ -873,7 +873,7 @@ json::parse(json& j, const char*& p, const char* e, int context, int depth)
|
||||||
|
return unexpected_octal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- j.type_ = Type::Long;
|
||||||
|
+ j.type_ = Type::Int;
|
||||||
|
j.long_value = 0;
|
||||||
|
return success;
|
||||||
|
|
||||||
|
@@ -905,7 +905,7 @@ json::parse(json& j, const char*& p, const char* e, int context, int depth)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
- j.type_ = Type::Long;
|
||||||
|
+ j.type_ = Type::Int;
|
||||||
|
j.long_value = x;
|
||||||
|
return success;
|
||||||
|
|
||||||
|
diff --git a/json.h b/json.h
|
||||||
|
index 3d2cb52a1bfeafb5f1a8a1e9c6057a2611cbb41e..d9fdfe40c5cce5b306eee42668f9944e11f6aacd 100644
|
||||||
|
--- a/json.h
|
||||||
|
+++ b/json.h
|
||||||
|
@@ -32,7 +32,7 @@ class json
|
||||||
|
{
|
||||||
|
Null,
|
||||||
|
Bool,
|
||||||
|
- Long,
|
||||||
|
+ Int,
|
||||||
|
Float,
|
||||||
|
Double,
|
||||||
|
String,
|
||||||
|
@@ -110,7 +110,7 @@ class json
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- json(int value) : type_(Type::Long), long_value(value)
|
||||||
|
+ json(int value) : type_(Type::Int), long_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -118,15 +118,15 @@ class json
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- json(unsigned value) : type_(Type::Long), long_value(value)
|
||||||
|
+ json(unsigned value) : type_(Type::Int), long_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- json(long value) : type_(Type::Long), long_value(value)
|
||||||
|
+ json(long value) : type_(Type::Int), long_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- json(long long value) : type_(Type::Long), long_value(value)
|
||||||
|
+ json(long long value) : type_(Type::Int), long_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -155,12 +155,12 @@ class json
|
||||||
|
|
||||||
|
bool is_number() const
|
||||||
|
{
|
||||||
|
- return is_float() || is_double() || is_long();
|
||||||
|
+ return is_float() || is_double() || is_int();
|
||||||
|
}
|
||||||
|
|
||||||
|
- bool is_long() const
|
||||||
|
+ bool is_int() const
|
||||||
|
{
|
||||||
|
- return type_ == Type::Long;
|
||||||
|
+ return type_ == Type::Int;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_float() const
|
||||||
|
@@ -192,7 +192,7 @@ class json
|
||||||
|
float get_float() const;
|
||||||
|
double get_double() const;
|
||||||
|
double get_number() const;
|
||||||
|
- long long get_long() const;
|
||||||
|
+ long long get_int() const;
|
||||||
|
std::string& get_string();
|
||||||
|
array_t& get_array();
|
||||||
|
object_t& get_object();
|
||||||
@@ -0,0 +1,102 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Peter Johnson <johnson.peter@gmail.com>
|
||||||
|
Date: Wed, 1 Apr 2026 08:04:27 -0700
|
||||||
|
Subject: [PATCH 10/25] Make non-object functions constexpr
|
||||||
|
|
||||||
|
---
|
||||||
|
json.h | 30 +++++++++++++++---------------
|
||||||
|
1 file changed, 15 insertions(+), 15 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/json.h b/json.h
|
||||||
|
index d9fdfe40c5cce5b306eee42668f9944e11f6aacd..8b09d001acd0a966328301bc89ff72616f106a4b 100644
|
||||||
|
--- a/json.h
|
||||||
|
+++ b/json.h
|
||||||
|
@@ -102,35 +102,35 @@ class json
|
||||||
|
json(const std::string&);
|
||||||
|
~json();
|
||||||
|
|
||||||
|
- json(const std::nullptr_t = nullptr) : type_(Type::Null)
|
||||||
|
+ constexpr json(const std::nullptr_t = nullptr) : type_(Type::Null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- json(bool value) : type_(Type::Bool), bool_value(value)
|
||||||
|
+ constexpr json(bool value) : type_(Type::Bool), bool_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- json(int value) : type_(Type::Int), long_value(value)
|
||||||
|
+ constexpr json(int value) : type_(Type::Int), long_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- json(float value) : type_(Type::Float), float_value(value)
|
||||||
|
+ constexpr json(float value) : type_(Type::Float), float_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- json(unsigned value) : type_(Type::Int), long_value(value)
|
||||||
|
+ constexpr json(unsigned value) : type_(Type::Int), long_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- json(long value) : type_(Type::Int), long_value(value)
|
||||||
|
+ constexpr json(long value) : type_(Type::Int), long_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- json(long long value) : type_(Type::Int), long_value(value)
|
||||||
|
+ constexpr json(long long value) : type_(Type::Int), long_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- json(double value) : type_(Type::Double), double_value(value)
|
||||||
|
+ constexpr json(double value) : type_(Type::Double), double_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -138,37 +138,37 @@ class json
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- Type type() const
|
||||||
|
+ constexpr Type type() const
|
||||||
|
{
|
||||||
|
return type_;
|
||||||
|
}
|
||||||
|
|
||||||
|
- bool is_null() const
|
||||||
|
+ constexpr bool is_null() const
|
||||||
|
{
|
||||||
|
return type_ == Type::Null;
|
||||||
|
}
|
||||||
|
|
||||||
|
- bool is_bool() const
|
||||||
|
+ constexpr bool is_bool() const
|
||||||
|
{
|
||||||
|
return type_ == Type::Bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
- bool is_number() const
|
||||||
|
+ constexpr bool is_number() const
|
||||||
|
{
|
||||||
|
return is_float() || is_double() || is_int();
|
||||||
|
}
|
||||||
|
|
||||||
|
- bool is_int() const
|
||||||
|
+ constexpr bool is_int() const
|
||||||
|
{
|
||||||
|
return type_ == Type::Int;
|
||||||
|
}
|
||||||
|
|
||||||
|
- bool is_float() const
|
||||||
|
+ constexpr bool is_float() const
|
||||||
|
{
|
||||||
|
return type_ == Type::Float;
|
||||||
|
}
|
||||||
|
|
||||||
|
- bool is_double() const
|
||||||
|
+ constexpr bool is_double() const
|
||||||
|
{
|
||||||
|
return type_ == Type::Double;
|
||||||
|
}
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Peter Johnson <johnson.peter@gmail.com>
|
||||||
|
Date: Wed, 1 Apr 2026 08:13:25 -0700
|
||||||
|
Subject: [PATCH 11/25] Add array and object constructors
|
||||||
|
|
||||||
|
---
|
||||||
|
json.h | 8 ++++++++
|
||||||
|
1 file changed, 8 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/json.h b/json.h
|
||||||
|
index 8b09d001acd0a966328301bc89ff72616f106a4b..9aa5c889932e720746972d9e8ef1dd8b095e0fb1 100644
|
||||||
|
--- a/json.h
|
||||||
|
+++ b/json.h
|
||||||
|
@@ -138,6 +138,14 @@ class json
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
+ json(array_t&& value) : type_(Type::Array), array_value(std::move(value))
|
||||||
|
+ {
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ json(object_t&& value) : type_(Type::Object), object_value(std::move(value))
|
||||||
|
+ {
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
constexpr Type type() const
|
||||||
|
{
|
||||||
|
return type_;
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Peter Johnson <johnson.peter@gmail.com>
|
||||||
|
Date: Wed, 1 Apr 2026 08:15:04 -0700
|
||||||
|
Subject: [PATCH 12/25] Add const getters for string, array, and object
|
||||||
|
|
||||||
|
---
|
||||||
|
json.cpp | 33 +++++++++++++++++++++++++++++++++
|
||||||
|
json.h | 3 +++
|
||||||
|
2 files changed, 36 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/json.cpp b/json.cpp
|
||||||
|
index 1266aa36b43155cbab6fe8d918fed2c56596f7a8..4aebebec76de7628792afbf176f46d61e2f67c43 100644
|
||||||
|
--- a/json.cpp
|
||||||
|
+++ b/json.cpp
|
||||||
|
@@ -521,6 +521,17 @@ json::get_string()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+const std::string&
|
||||||
|
+json::get_string() const
|
||||||
|
+{
|
||||||
|
+ switch (type_) {
|
||||||
|
+ case Type::String:
|
||||||
|
+ return string_value;
|
||||||
|
+ default:
|
||||||
|
+ ON_LOGIC_ERROR("JSON value is not a string.");
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
json::array_t&
|
||||||
|
json::get_array()
|
||||||
|
{
|
||||||
|
@@ -532,6 +543,17 @@ json::get_array()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+const json::array_t&
|
||||||
|
+json::get_array() const
|
||||||
|
+{
|
||||||
|
+ switch (type_) {
|
||||||
|
+ case Type::Array:
|
||||||
|
+ return array_value;
|
||||||
|
+ default:
|
||||||
|
+ ON_LOGIC_ERROR("JSON value is not an array.");
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
json::object_t&
|
||||||
|
json::get_object()
|
||||||
|
{
|
||||||
|
@@ -543,6 +565,17 @@ json::get_object()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+const json::object_t&
|
||||||
|
+json::get_object() const
|
||||||
|
+{
|
||||||
|
+ switch (type_) {
|
||||||
|
+ case Type::Object:
|
||||||
|
+ return object_value;
|
||||||
|
+ default:
|
||||||
|
+ ON_LOGIC_ERROR("JSON value is not an object.");
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
void
|
||||||
|
json::set_array()
|
||||||
|
{
|
||||||
|
diff --git a/json.h b/json.h
|
||||||
|
index 9aa5c889932e720746972d9e8ef1dd8b095e0fb1..2a4c009e4b3cf7f1ccac8b09986853ccd3540f9d 100644
|
||||||
|
--- a/json.h
|
||||||
|
+++ b/json.h
|
||||||
|
@@ -202,8 +202,11 @@ class json
|
||||||
|
double get_number() const;
|
||||||
|
long long get_int() const;
|
||||||
|
std::string& get_string();
|
||||||
|
+ const std::string& get_string() const;
|
||||||
|
array_t& get_array();
|
||||||
|
+ const array_t& get_array() const;
|
||||||
|
object_t& get_object();
|
||||||
|
+ const object_t& get_object() const;
|
||||||
|
|
||||||
|
bool contains(const std::string&) const;
|
||||||
|
|
||||||
35
upstream_utils/json_patches/0013-Use-wpi-StringMap.patch
Normal file
35
upstream_utils/json_patches/0013-Use-wpi-StringMap.patch
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Peter Johnson <johnson.peter@gmail.com>
|
||||||
|
Date: Wed, 1 Apr 2026 08:20:16 -0700
|
||||||
|
Subject: [PATCH 13/25] Use wpi StringMap
|
||||||
|
|
||||||
|
---
|
||||||
|
json.h | 6 ++++--
|
||||||
|
1 file changed, 4 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/json.h b/json.h
|
||||||
|
index 2a4c009e4b3cf7f1ccac8b09986853ccd3540f9d..662a3f2f68a04dc4e7faf5e4bd5a984ffd3705a9 100644
|
||||||
|
--- a/json.h
|
||||||
|
+++ b/json.h
|
||||||
|
@@ -16,17 +16,19 @@
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
-#include <map>
|
||||||
|
+
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
+#include "wpi/util/StringMap.hpp"
|
||||||
|
+
|
||||||
|
namespace wpi::util {
|
||||||
|
|
||||||
|
class json
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using array_t = std::vector<json>;
|
||||||
|
- using object_t = std::map<std::string, json>;
|
||||||
|
+ using object_t = wpi::util::StringMap<json>;
|
||||||
|
|
||||||
|
enum class Type
|
||||||
|
{
|
||||||
128
upstream_utils/json_patches/0014-Use-std-string_view.patch
Normal file
128
upstream_utils/json_patches/0014-Use-std-string_view.patch
Normal file
@@ -0,0 +1,128 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Peter Johnson <johnson.peter@gmail.com>
|
||||||
|
Date: Wed, 1 Apr 2026 08:19:39 -0700
|
||||||
|
Subject: [PATCH 14/25] Use std::string_view
|
||||||
|
|
||||||
|
---
|
||||||
|
json.cpp | 14 +++++++++-----
|
||||||
|
json.h | 12 +++++++-----
|
||||||
|
2 files changed, 16 insertions(+), 10 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/json.cpp b/json.cpp
|
||||||
|
index 4aebebec76de7628792afbf176f46d61e2f67c43..2b4191865e84f4c160450fa8380ad578d37e1cd1 100644
|
||||||
|
--- a/json.cpp
|
||||||
|
+++ b/json.cpp
|
||||||
|
@@ -282,6 +282,10 @@ json::json(const std::string& value) : type_(Type::String), string_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
+json::json(std::string_view value) : type_(Type::String), string_value(value)
|
||||||
|
+{
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
json::~json()
|
||||||
|
{
|
||||||
|
if (type_ >= Type::String)
|
||||||
|
@@ -595,7 +599,7 @@ json::set_object()
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
-json::contains(const std::string& key) const
|
||||||
|
+json::contains(std::string_view key) const
|
||||||
|
{
|
||||||
|
if (!is_object())
|
||||||
|
return false;
|
||||||
|
@@ -614,7 +618,7 @@ json::operator[](size_t index)
|
||||||
|
}
|
||||||
|
|
||||||
|
json&
|
||||||
|
-json::operator[](const std::string& key)
|
||||||
|
+json::operator[](std::string_view key)
|
||||||
|
{
|
||||||
|
if (!is_object())
|
||||||
|
set_object();
|
||||||
|
@@ -725,7 +729,7 @@ json::marshal(std::string& b, bool pretty, int indent) const
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
-json::stringify(std::string& b, const std::string& s)
|
||||||
|
+json::stringify(std::string& b, std::string_view s)
|
||||||
|
{
|
||||||
|
b += '"';
|
||||||
|
serialize(b, s);
|
||||||
|
@@ -733,7 +737,7 @@ json::stringify(std::string& b, const std::string& s)
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
-json::serialize(std::string& sb, const std::string& s)
|
||||||
|
+json::serialize(std::string& sb, std::string_view s)
|
||||||
|
{
|
||||||
|
size_t i, j, m;
|
||||||
|
wint_t x, a, b;
|
||||||
|
@@ -1255,7 +1259,7 @@ json::parse(json& j, const char*& p, const char* e, int context, int depth)
|
||||||
|
}
|
||||||
|
|
||||||
|
std::pair<json::Status, json>
|
||||||
|
-json::parse(const std::string& s)
|
||||||
|
+json::parse(std::string_view s)
|
||||||
|
{
|
||||||
|
json::Status s2;
|
||||||
|
std::pair<json::Status, json> res;
|
||||||
|
diff --git a/json.h b/json.h
|
||||||
|
index 662a3f2f68a04dc4e7faf5e4bd5a984ffd3705a9..1c0dc26a460e17dab44f13d62059cf6e69f355c9 100644
|
||||||
|
--- a/json.h
|
||||||
|
+++ b/json.h
|
||||||
|
@@ -18,6 +18,7 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
+#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "wpi/util/StringMap.hpp"
|
||||||
|
@@ -94,7 +95,7 @@ class json
|
||||||
|
|
||||||
|
public:
|
||||||
|
static const char* StatusToString(Status);
|
||||||
|
- static std::pair<Status, json> parse(const std::string&);
|
||||||
|
+ static std::pair<Status, json> parse(std::string_view);
|
||||||
|
|
||||||
|
json(const json&);
|
||||||
|
json(json&&);
|
||||||
|
@@ -102,6 +103,7 @@ class json
|
||||||
|
json(unsigned long long);
|
||||||
|
json(const char*);
|
||||||
|
json(const std::string&);
|
||||||
|
+ json(std::string_view);
|
||||||
|
~json();
|
||||||
|
|
||||||
|
constexpr json(const std::nullptr_t = nullptr) : type_(Type::Null)
|
||||||
|
@@ -210,7 +212,7 @@ class json
|
||||||
|
object_t& get_object();
|
||||||
|
const object_t& get_object() const;
|
||||||
|
|
||||||
|
- bool contains(const std::string&) const;
|
||||||
|
+ bool contains(std::string_view) const;
|
||||||
|
|
||||||
|
void set_array();
|
||||||
|
void set_object();
|
||||||
|
@@ -222,7 +224,7 @@ class json
|
||||||
|
json& operator=(json&&);
|
||||||
|
|
||||||
|
json& operator[](size_t);
|
||||||
|
- json& operator[](const std::string&);
|
||||||
|
+ json& operator[](std::string_view);
|
||||||
|
|
||||||
|
operator std::string() const
|
||||||
|
{
|
||||||
|
@@ -232,8 +234,8 @@ class json
|
||||||
|
private:
|
||||||
|
void clear();
|
||||||
|
void marshal(std::string&, bool, int) const;
|
||||||
|
- static void stringify(std::string&, const std::string&);
|
||||||
|
- static void serialize(std::string&, const std::string&);
|
||||||
|
+ static void stringify(std::string&, std::string_view);
|
||||||
|
+ static void serialize(std::string&, std::string_view);
|
||||||
|
static Status parse(json&, const char*&, const char*, int, int);
|
||||||
|
};
|
||||||
|
|
||||||
@@ -0,0 +1,93 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Peter Johnson <johnson.peter@gmail.com>
|
||||||
|
Date: Fri, 3 Apr 2026 22:39:28 -0700
|
||||||
|
Subject: [PATCH 15/25] Change parse to return expected with error string
|
||||||
|
|
||||||
|
---
|
||||||
|
json.cpp | 21 +++++++++++----------
|
||||||
|
json.h | 7 ++++---
|
||||||
|
2 files changed, 15 insertions(+), 13 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/json.cpp b/json.cpp
|
||||||
|
index 2b4191865e84f4c160450fa8380ad578d37e1cd1..baefe6317126f95ec75fe9d9a896923d0a90e720 100644
|
||||||
|
--- a/json.cpp
|
||||||
|
+++ b/json.cpp
|
||||||
|
@@ -1258,21 +1258,22 @@ json::parse(json& j, const char*& p, const char* e, int context, int depth)
|
||||||
|
return unexpected_eof;
|
||||||
|
}
|
||||||
|
|
||||||
|
-std::pair<json::Status, json>
|
||||||
|
+wpi::util::expected<json, const char*>
|
||||||
|
json::parse(std::string_view s)
|
||||||
|
{
|
||||||
|
- json::Status s2;
|
||||||
|
- std::pair<json::Status, json> res;
|
||||||
|
const char* p = s.data();
|
||||||
|
const char* e = s.data() + s.size();
|
||||||
|
- res.first = parse(res.second, p, e, 0, DEPTH);
|
||||||
|
- if (res.first == json::success) {
|
||||||
|
- json j2;
|
||||||
|
- s2 = parse(j2, p, e, 0, DEPTH);
|
||||||
|
- if (s2 != absent_value)
|
||||||
|
- res.first = trailing_content;
|
||||||
|
+ json j;
|
||||||
|
+ Status result = parse(j, p, e, 0, DEPTH);
|
||||||
|
+ if (result != success) {
|
||||||
|
+ return wpi::util::unexpected(StatusToString(result));
|
||||||
|
}
|
||||||
|
- return res;
|
||||||
|
+ json j2;
|
||||||
|
+ Status s2 = parse(j2, p, e, 0, DEPTH);
|
||||||
|
+ if (s2 != absent_value) {
|
||||||
|
+ return wpi::util::unexpected(StatusToString(trailing_content));
|
||||||
|
+ }
|
||||||
|
+ return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char*
|
||||||
|
diff --git a/json.h b/json.h
|
||||||
|
index 1c0dc26a460e17dab44f13d62059cf6e69f355c9..d2962c322678b0dd664707f34151094fec90d281 100644
|
||||||
|
--- a/json.h
|
||||||
|
+++ b/json.h
|
||||||
|
@@ -22,6 +22,7 @@
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "wpi/util/StringMap.hpp"
|
||||||
|
+#include "wpi/util/expected"
|
||||||
|
|
||||||
|
namespace wpi::util {
|
||||||
|
|
||||||
|
@@ -43,6 +44,7 @@ class json
|
||||||
|
Object
|
||||||
|
};
|
||||||
|
|
||||||
|
+ private:
|
||||||
|
enum Status
|
||||||
|
{
|
||||||
|
success,
|
||||||
|
@@ -80,7 +82,6 @@ class json
|
||||||
|
non_del_c0_control_code_in_string,
|
||||||
|
};
|
||||||
|
|
||||||
|
- private:
|
||||||
|
Type type_;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
@@ -94,8 +95,7 @@ class json
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
- static const char* StatusToString(Status);
|
||||||
|
- static std::pair<Status, json> parse(std::string_view);
|
||||||
|
+ static wpi::util::expected<json, const char*> parse(std::string_view);
|
||||||
|
|
||||||
|
json(const json&);
|
||||||
|
json(json&&);
|
||||||
|
@@ -232,6 +232,7 @@ class json
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
+ static const char* StatusToString(Status);
|
||||||
|
void clear();
|
||||||
|
void marshal(std::string&, bool, int) const;
|
||||||
|
static void stringify(std::string&, std::string_view);
|
||||||
43
upstream_utils/json_patches/0016-Add-parse_or_throw.patch
Normal file
43
upstream_utils/json_patches/0016-Add-parse_or_throw.patch
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Peter Johnson <johnson.peter@gmail.com>
|
||||||
|
Date: Fri, 3 Apr 2026 22:40:25 -0700
|
||||||
|
Subject: [PATCH 16/25] Add parse_or_throw
|
||||||
|
|
||||||
|
---
|
||||||
|
json.cpp | 10 ++++++++++
|
||||||
|
json.h | 1 +
|
||||||
|
2 files changed, 11 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/json.cpp b/json.cpp
|
||||||
|
index baefe6317126f95ec75fe9d9a896923d0a90e720..49fbf92ea6e67e771f051f10b65ac795351c6f3d 100644
|
||||||
|
--- a/json.cpp
|
||||||
|
+++ b/json.cpp
|
||||||
|
@@ -1276,6 +1276,16 @@ json::parse(std::string_view s)
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
+json
|
||||||
|
+json::parse_or_throw(std::string_view s)
|
||||||
|
+{
|
||||||
|
+ auto result = parse(s);
|
||||||
|
+ if (!result) {
|
||||||
|
+ ON_LOGIC_ERROR(result.error());
|
||||||
|
+ }
|
||||||
|
+ return *result;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
const char*
|
||||||
|
json::StatusToString(json::Status status)
|
||||||
|
{
|
||||||
|
diff --git a/json.h b/json.h
|
||||||
|
index d2962c322678b0dd664707f34151094fec90d281..f42ba9c135cb76a1b0bc31f9e2c03b1ed7dce749 100644
|
||||||
|
--- a/json.h
|
||||||
|
+++ b/json.h
|
||||||
|
@@ -96,6 +96,7 @@ class json
|
||||||
|
|
||||||
|
public:
|
||||||
|
static wpi::util::expected<json, const char*> parse(std::string_view);
|
||||||
|
+ static json parse_or_throw(std::string_view);
|
||||||
|
|
||||||
|
json(const json&);
|
||||||
|
json(json&&);
|
||||||
67
upstream_utils/json_patches/0017-Add-operator.patch
Normal file
67
upstream_utils/json_patches/0017-Add-operator.patch
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Peter Johnson <johnson.peter@gmail.com>
|
||||||
|
Date: Fri, 3 Apr 2026 22:54:14 -0700
|
||||||
|
Subject: [PATCH 17/25] Add operator==
|
||||||
|
|
||||||
|
---
|
||||||
|
json.cpp | 26 ++++++++++++++++++++++++++
|
||||||
|
json.h | 6 ++++++
|
||||||
|
2 files changed, 32 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/json.cpp b/json.cpp
|
||||||
|
index 49fbf92ea6e67e771f051f10b65ac795351c6f3d..40479bc266390f015e291b737b5751522dac76ac 100644
|
||||||
|
--- a/json.cpp
|
||||||
|
+++ b/json.cpp
|
||||||
|
@@ -1361,4 +1361,30 @@ json::StatusToString(json::Status status)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+bool
|
||||||
|
+operator==(const json& lhs, const json& rhs) {
|
||||||
|
+ if (lhs.type_ != rhs.type_)
|
||||||
|
+ return false;
|
||||||
|
+ switch (lhs.type_) {
|
||||||
|
+ case json::Type::Null:
|
||||||
|
+ return true;
|
||||||
|
+ case json::Type::String:
|
||||||
|
+ return lhs.string_value == rhs.string_value;
|
||||||
|
+ case json::Type::Bool:
|
||||||
|
+ return lhs.bool_value == rhs.bool_value;
|
||||||
|
+ case json::Type::Int:
|
||||||
|
+ return lhs.long_value == rhs.long_value;
|
||||||
|
+ case json::Type::Float:
|
||||||
|
+ return lhs.float_value == rhs.float_value;
|
||||||
|
+ case json::Type::Double:
|
||||||
|
+ return lhs.double_value == rhs.double_value;
|
||||||
|
+ case json::Type::Array:
|
||||||
|
+ return lhs.array_value == rhs.array_value;
|
||||||
|
+ case json::Type::Object:
|
||||||
|
+ return lhs.object_value == rhs.object_value;
|
||||||
|
+ default:
|
||||||
|
+ ON_LOGIC_ERROR("Unhandled JSON type during equality comparison.");
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
} // namespace wpi::util
|
||||||
|
diff --git a/json.h b/json.h
|
||||||
|
index f42ba9c135cb76a1b0bc31f9e2c03b1ed7dce749..fbc3fb959f71f6acc344f26247597959807d23bb 100644
|
||||||
|
--- a/json.h
|
||||||
|
+++ b/json.h
|
||||||
|
@@ -28,6 +28,7 @@ namespace wpi::util {
|
||||||
|
|
||||||
|
class json
|
||||||
|
{
|
||||||
|
+ friend bool operator==(const json& lhs, const json& rhs);
|
||||||
|
public:
|
||||||
|
using array_t = std::vector<json>;
|
||||||
|
using object_t = wpi::util::StringMap<json>;
|
||||||
|
@@ -241,4 +242,9 @@ class json
|
||||||
|
static Status parse(json&, const char*&, const char*, int, int);
|
||||||
|
};
|
||||||
|
|
||||||
|
+bool operator==(const json& lhs, const json& rhs);
|
||||||
|
+inline bool operator!=(const json& lhs, const json& rhs) {
|
||||||
|
+ return !(lhs == rhs);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
} // namespace wpi::util
|
||||||
166
upstream_utils/json_patches/0018-Add-container-functions.patch
Normal file
166
upstream_utils/json_patches/0018-Add-container-functions.patch
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Peter Johnson <johnson.peter@gmail.com>
|
||||||
|
Date: Fri, 3 Apr 2026 22:58:18 -0700
|
||||||
|
Subject: [PATCH 18/25] Add container functions
|
||||||
|
|
||||||
|
---
|
||||||
|
json.cpp | 102 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
json.h | 18 ++++++++++
|
||||||
|
2 files changed, 120 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/json.cpp b/json.cpp
|
||||||
|
index 40479bc266390f015e291b737b5751522dac76ac..2307536b15be9aae19da4ec9370a5aa17d5150d1 100644
|
||||||
|
--- a/json.cpp
|
||||||
|
+++ b/json.cpp
|
||||||
|
@@ -606,6 +606,28 @@ json::contains(std::string_view key) const
|
||||||
|
return object_value.find(key) != object_value.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
+json*
|
||||||
|
+json::lookup(std::string_view key)
|
||||||
|
+{
|
||||||
|
+ if (!is_object())
|
||||||
|
+ return nullptr;
|
||||||
|
+ auto i = object_value.find(key);
|
||||||
|
+ if (i == object_value.end())
|
||||||
|
+ return nullptr;
|
||||||
|
+ return &i->second;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+const json*
|
||||||
|
+json::lookup(std::string_view key) const
|
||||||
|
+{
|
||||||
|
+ if (!is_object())
|
||||||
|
+ return nullptr;
|
||||||
|
+ auto i = object_value.find(key);
|
||||||
|
+ if (i == object_value.end())
|
||||||
|
+ return nullptr;
|
||||||
|
+ return &i->second;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
json&
|
||||||
|
json::operator[](size_t index)
|
||||||
|
{
|
||||||
|
@@ -625,6 +647,86 @@ json::operator[](std::string_view key)
|
||||||
|
return object_value[key];
|
||||||
|
}
|
||||||
|
|
||||||
|
+json&
|
||||||
|
+json::at(size_t index) {
|
||||||
|
+ if (!is_array())
|
||||||
|
+ ON_LOGIC_ERROR("JSON value is not an array.");
|
||||||
|
+ return array_value.at(index);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+json&
|
||||||
|
+json::at(std::string_view key) {
|
||||||
|
+ if (!is_object())
|
||||||
|
+ ON_LOGIC_ERROR("JSON value is not an object.");
|
||||||
|
+ return object_value.at(key);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+const json&
|
||||||
|
+json::at(size_t index) const {
|
||||||
|
+ if (!is_array())
|
||||||
|
+ ON_LOGIC_ERROR("JSON value is not an array.");
|
||||||
|
+ return array_value.at(index);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+const json&
|
||||||
|
+json::at(std::string_view key) const {
|
||||||
|
+ if (!is_object())
|
||||||
|
+ ON_LOGIC_ERROR("JSON value is not an object.");
|
||||||
|
+ return object_value.at(key);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+json
|
||||||
|
+json::value(size_t index, json&& default_value) {
|
||||||
|
+ if (!is_array())
|
||||||
|
+ ON_LOGIC_ERROR("JSON value is not an array.");
|
||||||
|
+ if (index < array_value.size())
|
||||||
|
+ return array_value[index];
|
||||||
|
+ return default_value;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+json
|
||||||
|
+json::value(std::string_view key, json&& default_value)
|
||||||
|
+{
|
||||||
|
+ if (!is_object())
|
||||||
|
+ ON_LOGIC_ERROR("JSON value is not an object.");
|
||||||
|
+ auto i = object_value.find(key);
|
||||||
|
+ if (i != object_value.end())
|
||||||
|
+ return i->second;
|
||||||
|
+ return default_value;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+json::erase(std::string_view key)
|
||||||
|
+{
|
||||||
|
+ if (!is_object())
|
||||||
|
+ ON_LOGIC_ERROR("JSON value is not an object.");
|
||||||
|
+ object_value.erase(key);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+json&
|
||||||
|
+json::emplace_back(json&& value)
|
||||||
|
+{
|
||||||
|
+ if (!is_array())
|
||||||
|
+ set_array();
|
||||||
|
+ array_value.emplace_back(std::move(value));
|
||||||
|
+ return array_value.back();
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+bool
|
||||||
|
+json::empty() const
|
||||||
|
+{
|
||||||
|
+ switch (type_) {
|
||||||
|
+ case Type::Null:
|
||||||
|
+ return true;
|
||||||
|
+ case Type::Array:
|
||||||
|
+ return array_value.empty();
|
||||||
|
+ case Type::Object:
|
||||||
|
+ return object_value.empty();
|
||||||
|
+ default:
|
||||||
|
+ return false;
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
std::string
|
||||||
|
json::to_string() const
|
||||||
|
{
|
||||||
|
diff --git a/json.h b/json.h
|
||||||
|
index fbc3fb959f71f6acc344f26247597959807d23bb..62af49cb18b713304ad95e89c52f5cc5bbc4b626 100644
|
||||||
|
--- a/json.h
|
||||||
|
+++ b/json.h
|
||||||
|
@@ -216,6 +216,9 @@ class json
|
||||||
|
|
||||||
|
bool contains(std::string_view) const;
|
||||||
|
|
||||||
|
+ json* lookup(std::string_view);
|
||||||
|
+ const json* lookup(std::string_view) const;
|
||||||
|
+
|
||||||
|
void set_array();
|
||||||
|
void set_object();
|
||||||
|
|
||||||
|
@@ -228,6 +231,21 @@ class json
|
||||||
|
json& operator[](size_t);
|
||||||
|
json& operator[](std::string_view);
|
||||||
|
|
||||||
|
+ json& at(size_t);
|
||||||
|
+ json& at(std::string_view);
|
||||||
|
+
|
||||||
|
+ const json& at(size_t) const;
|
||||||
|
+ const json& at(std::string_view) const;
|
||||||
|
+
|
||||||
|
+ json value(size_t, json&&);
|
||||||
|
+ json value(std::string_view, json&&);
|
||||||
|
+
|
||||||
|
+ void erase(std::string_view);
|
||||||
|
+
|
||||||
|
+ json& emplace_back(json&& value);
|
||||||
|
+
|
||||||
|
+ bool empty() const;
|
||||||
|
+
|
||||||
|
operator std::string() const
|
||||||
|
{
|
||||||
|
return to_string();
|
||||||
@@ -0,0 +1,106 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Peter Johnson <johnson.peter@gmail.com>
|
||||||
|
Date: Fri, 3 Apr 2026 23:01:45 -0700
|
||||||
|
Subject: [PATCH 19/25] Add to_json, from_json, and json_serializer struct
|
||||||
|
|
||||||
|
---
|
||||||
|
json.h | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
|
||||||
|
1 file changed, 65 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/json.h b/json.h
|
||||||
|
index 62af49cb18b713304ad95e89c52f5cc5bbc4b626..e52435a79ee7537928ba59fb146f635fc8511bfc 100644
|
||||||
|
--- a/json.h
|
||||||
|
+++ b/json.h
|
||||||
|
@@ -26,6 +26,35 @@
|
||||||
|
|
||||||
|
namespace wpi::util {
|
||||||
|
|
||||||
|
+class json;
|
||||||
|
+
|
||||||
|
+template <typename T>
|
||||||
|
+struct json_serializer;
|
||||||
|
+
|
||||||
|
+namespace detail {
|
||||||
|
+template <typename T>
|
||||||
|
+concept HasToJson = requires(json& j, const T& val) {
|
||||||
|
+ { to_json(j, val) };
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+template <typename T>
|
||||||
|
+concept HasFromJson = requires(const json& j, T& val) {
|
||||||
|
+ { from_json(j, val) };
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+template <typename T>
|
||||||
|
+concept HasJsonSerializer = requires (json& j, const json& cj, const T& val) {
|
||||||
|
+ typename json_serializer<typename std::remove_cvref_t<T>>;
|
||||||
|
+ { json_serializer<typename std::remove_cvref_t<T>>::to(j, val) };
|
||||||
|
+};
|
||||||
|
+
|
||||||
|
+template <typename T>
|
||||||
|
+concept HasJsonDeserializer = requires (json& j, const json& cj, const T& val) {
|
||||||
|
+ typename json_serializer<typename std::remove_cvref_t<T>>;
|
||||||
|
+ { json_serializer<typename std::remove_cvref_t<T>>::from(cj) } -> std::convertible_to<typename std::remove_cvref_t<T>>;
|
||||||
|
+};
|
||||||
|
+} // namespace detail
|
||||||
|
+
|
||||||
|
class json
|
||||||
|
{
|
||||||
|
friend bool operator==(const json& lhs, const json& rhs);
|
||||||
|
@@ -152,6 +181,18 @@ class json
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
+ template <detail::HasToJson T>
|
||||||
|
+ json(const T& value) : type_(Type::Null)
|
||||||
|
+ {
|
||||||
|
+ to_json(*this, value);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ template <detail::HasJsonSerializer T>
|
||||||
|
+ json(const T& value) : type_(Type::Null)
|
||||||
|
+ {
|
||||||
|
+ json_serializer<T>::to(*this, value);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
constexpr Type type() const
|
||||||
|
{
|
||||||
|
return type_;
|
||||||
|
@@ -214,6 +255,18 @@ class json
|
||||||
|
object_t& get_object();
|
||||||
|
const object_t& get_object() const;
|
||||||
|
|
||||||
|
+ template <detail::HasFromJson T>
|
||||||
|
+ T get() const {
|
||||||
|
+ T value;
|
||||||
|
+ from_json(*this, value);
|
||||||
|
+ return value;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ template <detail::HasJsonDeserializer T>
|
||||||
|
+ T get() const {
|
||||||
|
+ return json_serializer<T>::from(*this);
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
bool contains(std::string_view) const;
|
||||||
|
|
||||||
|
json* lookup(std::string_view);
|
||||||
|
@@ -228,6 +281,18 @@ class json
|
||||||
|
json& operator=(const json&);
|
||||||
|
json& operator=(json&&);
|
||||||
|
|
||||||
|
+ template <detail::HasToJson T>
|
||||||
|
+ json& operator=(const T& value) {
|
||||||
|
+ to_json(*this, value);
|
||||||
|
+ return *this;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ template <detail::HasJsonSerializer T>
|
||||||
|
+ json& operator=(const T& value) {
|
||||||
|
+ json_serializer<T>::to(*this, value);
|
||||||
|
+ return *this;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
json& operator[](size_t);
|
||||||
|
json& operator[](std::string_view);
|
||||||
|
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Peter Johnson <johnson.peter@gmail.com>
|
||||||
|
Date: Fri, 3 Apr 2026 23:05:58 -0700
|
||||||
|
Subject: [PATCH 20/25] Add array and object factory functions
|
||||||
|
|
||||||
|
---
|
||||||
|
json.h | 30 ++++++++++++++++++++++++++++++
|
||||||
|
1 file changed, 30 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/json.h b/json.h
|
||||||
|
index e52435a79ee7537928ba59fb146f635fc8511bfc..6a52615ab3e1799ebcf51a3b5ca445b1e2e64b97 100644
|
||||||
|
--- a/json.h
|
||||||
|
+++ b/json.h
|
||||||
|
@@ -19,6 +19,8 @@
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
+#include <tuple>
|
||||||
|
+#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "wpi/util/StringMap.hpp"
|
||||||
|
@@ -53,6 +55,13 @@ concept HasJsonDeserializer = requires (json& j, const json& cj, const T& val) {
|
||||||
|
typename json_serializer<typename std::remove_cvref_t<T>>;
|
||||||
|
{ json_serializer<typename std::remove_cvref_t<T>>::from(cj) } -> std::convertible_to<typename std::remove_cvref_t<T>>;
|
||||||
|
};
|
||||||
|
+
|
||||||
|
+template <typename F, typename Tuple, size_t... I>
|
||||||
|
+void apply_pairs_helper(F&& f, Tuple&& t, std::index_sequence<I...>) {
|
||||||
|
+ // This fold expression creates a sequence of calls to f for each pair
|
||||||
|
+ (f(std::get<I * 2>(std::forward<Tuple>(t)),
|
||||||
|
+ std::get<I * 2 + 1>(std::forward<Tuple>(t))), ...);
|
||||||
|
+}
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
class json
|
||||||
|
@@ -275,6 +284,27 @@ class json
|
||||||
|
void set_array();
|
||||||
|
void set_object();
|
||||||
|
|
||||||
|
+ template <typename... Args>
|
||||||
|
+ static json array(Args&&... args) {
|
||||||
|
+ json j;
|
||||||
|
+ j.set_array();
|
||||||
|
+ (j.array_value.emplace_back(std::forward<Args>(args)), ...);
|
||||||
|
+ return j;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
+ template <typename... Args>
|
||||||
|
+ static json object(Args&&... args) {
|
||||||
|
+ json j;
|
||||||
|
+ j.set_object();
|
||||||
|
+ detail::apply_pairs_helper(
|
||||||
|
+ [&](auto&& key, auto&& value) {
|
||||||
|
+ j.object_value[std::forward<decltype(key)>(key)] = std::forward<decltype(value)>(value);
|
||||||
|
+ },
|
||||||
|
+ std::forward_as_tuple(args...),
|
||||||
|
+ std::make_index_sequence<sizeof...(Args) / 2>{});
|
||||||
|
+ return j;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
std::string to_string() const;
|
||||||
|
std::string to_string_pretty() const;
|
||||||
|
|
||||||
55
upstream_utils/json_patches/0021-Add-array-constructor.patch
Normal file
55
upstream_utils/json_patches/0021-Add-array-constructor.patch
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Peter Johnson <johnson.peter@gmail.com>
|
||||||
|
Date: Fri, 3 Apr 2026 23:07:20 -0700
|
||||||
|
Subject: [PATCH 21/25] Add array constructor
|
||||||
|
|
||||||
|
---
|
||||||
|
json.h | 21 +++++++++++++++++++++
|
||||||
|
1 file changed, 21 insertions(+)
|
||||||
|
|
||||||
|
diff --git a/json.h b/json.h
|
||||||
|
index 6a52615ab3e1799ebcf51a3b5ca445b1e2e64b97..ef3ea13b7cb147f0b383ff1ead496d495cfece32 100644
|
||||||
|
--- a/json.h
|
||||||
|
+++ b/json.h
|
||||||
|
@@ -17,6 +17,8 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
+#include <concepts>
|
||||||
|
+#include <ranges>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <tuple>
|
||||||
|
@@ -56,6 +58,19 @@ concept HasJsonDeserializer = requires (json& j, const json& cj, const T& val) {
|
||||||
|
{ json_serializer<typename std::remove_cvref_t<T>>::from(cj) } -> std::convertible_to<typename std::remove_cvref_t<T>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
+template <typename T>
|
||||||
|
+concept JsonConvertible =
|
||||||
|
+ HasToJson<T> ||
|
||||||
|
+ HasJsonSerializer<T> ||
|
||||||
|
+ std::is_same_v<T, std::nullptr_t> ||
|
||||||
|
+ std::is_same_v<T, bool> ||
|
||||||
|
+ std::is_floating_point_v<T> ||
|
||||||
|
+ std::is_integral_v<T> ||
|
||||||
|
+ std::convertible_to<T, std::string> ||
|
||||||
|
+ std::convertible_to<T, std::string_view> ||
|
||||||
|
+ std::is_same_v<T, std::vector<json>> ||
|
||||||
|
+ std::is_same_v<T, wpi::util::StringMap<json>>;
|
||||||
|
+
|
||||||
|
template <typename F, typename Tuple, size_t... I>
|
||||||
|
void apply_pairs_helper(F&& f, Tuple&& t, std::index_sequence<I...>) {
|
||||||
|
// This fold expression creates a sequence of calls to f for each pair
|
||||||
|
@@ -190,6 +205,12 @@ class json
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
+ template <std::ranges::input_range R>
|
||||||
|
+ requires detail::JsonConvertible<std::ranges::range_value_t<R>>
|
||||||
|
+ json(const R& range) : type_(Type::Array), array_value(std::ranges::cbegin(range), std::ranges::cend(range))
|
||||||
|
+ {
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
template <detail::HasToJson T>
|
||||||
|
json(const T& value) : type_(Type::Null)
|
||||||
|
{
|
||||||
@@ -0,0 +1,329 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Peter Johnson <johnson.peter@gmail.com>
|
||||||
|
Date: Sat, 4 Apr 2026 12:09:43 -0700
|
||||||
|
Subject: [PATCH 22/25] Improve stringize and marshal and use raw_ostream
|
||||||
|
|
||||||
|
---
|
||||||
|
json.cpp | 202 ++++++++++++++++++++++++++++++++-----------------------
|
||||||
|
json.h | 16 ++++-
|
||||||
|
2 files changed, 131 insertions(+), 87 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/json.cpp b/json.cpp
|
||||||
|
index 2307536b15be9aae19da4ec9370a5aa17d5150d1..1beec7cc30e90ab2e31bc488ee15cedf9a9f32e5 100644
|
||||||
|
--- a/json.cpp
|
||||||
|
+++ b/json.cpp
|
||||||
|
@@ -27,6 +27,7 @@
|
||||||
|
|
||||||
|
#include "wpi/double-conversion/double-to-string.h"
|
||||||
|
#include "wpi/double-conversion/string-to-double.h"
|
||||||
|
+#include "wpi/util/raw_ostream.hpp"
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#pragma GCC diagnostic ignored "-Wtype-limits"
|
||||||
|
@@ -731,7 +732,8 @@ std::string
|
||||||
|
json::to_string() const
|
||||||
|
{
|
||||||
|
std::string b;
|
||||||
|
- marshal(b, false, 0);
|
||||||
|
+ wpi::util::raw_string_ostream os(b);
|
||||||
|
+ marshal(os, false, 0);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -739,107 +741,139 @@ std::string
|
||||||
|
json::to_string_pretty() const
|
||||||
|
{
|
||||||
|
std::string b;
|
||||||
|
- marshal(b, true, 0);
|
||||||
|
+ wpi::util::raw_string_ostream os(b);
|
||||||
|
+ marshal(os, true, 0);
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
-json::marshal(std::string& b, bool pretty, int indent) const
|
||||||
|
+json::marshal(wpi::util::raw_ostream& os, bool pretty, int indent) const
|
||||||
|
{
|
||||||
|
switch (type_) {
|
||||||
|
case Type::Null:
|
||||||
|
- b += "null";
|
||||||
|
+ stringify_null(os);
|
||||||
|
break;
|
||||||
|
case Type::String:
|
||||||
|
- stringify(b, string_value);
|
||||||
|
+ stringify_string(os, string_value);
|
||||||
|
break;
|
||||||
|
case Type::Bool:
|
||||||
|
- b += bool_value ? "true" : "false";
|
||||||
|
+ stringify_bool(os, bool_value);
|
||||||
|
break;
|
||||||
|
- case Type::Int: {
|
||||||
|
- char buf[64];
|
||||||
|
- b.append(buf, LongToString(buf, long_value) - buf);
|
||||||
|
+ case Type::Int:
|
||||||
|
+ stringify_int(os, long_value);
|
||||||
|
break;
|
||||||
|
- }
|
||||||
|
- case Type::Float: {
|
||||||
|
- char buf[128];
|
||||||
|
- double_conversion::StringBuilder db(buf, 128);
|
||||||
|
- kDoubleToJson.ToShortestSingle(float_value, &db);
|
||||||
|
- db.Finalize();
|
||||||
|
- b += buf;
|
||||||
|
+ case Type::Float:
|
||||||
|
+ stringify_float(os, float_value);
|
||||||
|
break;
|
||||||
|
- }
|
||||||
|
- case Type::Double: {
|
||||||
|
- char buf[128];
|
||||||
|
- double_conversion::StringBuilder db(buf, 128);
|
||||||
|
- kDoubleToJson.ToShortest(double_value, &db);
|
||||||
|
- db.Finalize();
|
||||||
|
- b += buf;
|
||||||
|
+ case Type::Double:
|
||||||
|
+ stringify_double(os, double_value);
|
||||||
|
break;
|
||||||
|
- }
|
||||||
|
- case Type::Array: {
|
||||||
|
- bool once = false;
|
||||||
|
- b += '[';
|
||||||
|
- for (auto i = array_value.begin(); i != array_value.end(); ++i) {
|
||||||
|
- if (once) {
|
||||||
|
- b += ',';
|
||||||
|
- if (pretty)
|
||||||
|
- b += ' ';
|
||||||
|
- } else {
|
||||||
|
- once = true;
|
||||||
|
- }
|
||||||
|
- i->marshal(b, pretty, indent);
|
||||||
|
- }
|
||||||
|
- b += ']';
|
||||||
|
+ case Type::Array:
|
||||||
|
+ stringify_array(os, array_value, pretty, indent);
|
||||||
|
break;
|
||||||
|
- }
|
||||||
|
- case Type::Object: {
|
||||||
|
- bool once = false;
|
||||||
|
- b += '{';
|
||||||
|
- for (auto i = object_value.begin(); i != object_value.end(); ++i) {
|
||||||
|
- if (once) {
|
||||||
|
- b += ',';
|
||||||
|
- } else {
|
||||||
|
- once = true;
|
||||||
|
- }
|
||||||
|
- if (pretty && object_value.size() > 1) {
|
||||||
|
- b += '\n';
|
||||||
|
- ++indent;
|
||||||
|
- for (int j = 0; j < indent; ++j)
|
||||||
|
- b += " ";
|
||||||
|
- }
|
||||||
|
- stringify(b, i->first);
|
||||||
|
- b += ':';
|
||||||
|
- if (pretty)
|
||||||
|
- b += ' ';
|
||||||
|
- i->second.marshal(b, pretty, indent);
|
||||||
|
- if (pretty && object_value.size() > 1)
|
||||||
|
- --indent;
|
||||||
|
- }
|
||||||
|
- if (pretty && object_value.size() > 1) {
|
||||||
|
- b += '\n';
|
||||||
|
- for (int j = 0; j < indent; ++j)
|
||||||
|
- b += " ";
|
||||||
|
- ++indent;
|
||||||
|
- }
|
||||||
|
- b += '}';
|
||||||
|
+ case Type::Object:
|
||||||
|
+ stringify_object(os, object_value, pretty, indent);
|
||||||
|
break;
|
||||||
|
- }
|
||||||
|
default:
|
||||||
|
ON_LOGIC_ERROR("Unhandled JSON type.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
-json::stringify(std::string& b, std::string_view s)
|
||||||
|
+json::stringify_null(wpi::util::raw_ostream& os)
|
||||||
|
{
|
||||||
|
- b += '"';
|
||||||
|
- serialize(b, s);
|
||||||
|
- b += '"';
|
||||||
|
+ os << "null";
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+json::stringify_string(wpi::util::raw_ostream& os, std::string_view s)
|
||||||
|
+{
|
||||||
|
+ os << '"';
|
||||||
|
+ serialize(os, s);
|
||||||
|
+ os << '"';
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+json::stringify_bool(wpi::util::raw_ostream& os, bool value) {
|
||||||
|
+ os << (value ? "true" : "false");
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+json::stringify_float(wpi::util::raw_ostream& os, float value) {
|
||||||
|
+ char buf[128];
|
||||||
|
+ double_conversion::StringBuilder db(buf, 128);
|
||||||
|
+ kDoubleToJson.ToShortestSingle(value, &db);
|
||||||
|
+ db.Finalize();
|
||||||
|
+ os << buf;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+json::stringify_double(wpi::util::raw_ostream& os, double value) {
|
||||||
|
+ char buf[128];
|
||||||
|
+ double_conversion::StringBuilder db(buf, 128);
|
||||||
|
+ kDoubleToJson.ToShortest(value, &db);
|
||||||
|
+ db.Finalize();
|
||||||
|
+ os << buf;
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+json::stringify_int(wpi::util::raw_ostream& os, long long value) {
|
||||||
|
+ char buf[64];
|
||||||
|
+ os.write(buf, LongToString(buf, value) - buf);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+json::stringify_array(wpi::util::raw_ostream& os, const array_t& value, bool pretty, int indent) {
|
||||||
|
+ bool once = false;
|
||||||
|
+ os << '[';
|
||||||
|
+ for (auto i = value.begin(); i != value.end(); ++i) {
|
||||||
|
+ if (once) {
|
||||||
|
+ os << ',';
|
||||||
|
+ if (pretty)
|
||||||
|
+ os << ' ';
|
||||||
|
+ } else {
|
||||||
|
+ once = true;
|
||||||
|
+ }
|
||||||
|
+ i->marshal(os, pretty, indent);
|
||||||
|
+ }
|
||||||
|
+ os << ']';
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
+void
|
||||||
|
+json::stringify_object(wpi::util::raw_ostream& os, const object_t& value, bool pretty, int indent) {
|
||||||
|
+ bool once = false;
|
||||||
|
+ os << '{';
|
||||||
|
+ for (auto i = value.begin(); i != value.end(); ++i) {
|
||||||
|
+ if (once) {
|
||||||
|
+ os << ',';
|
||||||
|
+ } else {
|
||||||
|
+ once = true;
|
||||||
|
+ }
|
||||||
|
+ if (pretty && value.size() > 1) {
|
||||||
|
+ os << '\n';
|
||||||
|
+ ++indent;
|
||||||
|
+ for (int j = 0; j < indent; ++j)
|
||||||
|
+ os << " ";
|
||||||
|
+ }
|
||||||
|
+ stringify_string(os, i->first);
|
||||||
|
+ os << ':';
|
||||||
|
+ if (pretty)
|
||||||
|
+ os << ' ';
|
||||||
|
+ i->second.marshal(os, pretty, indent);
|
||||||
|
+ if (pretty && value.size() > 1)
|
||||||
|
+ --indent;
|
||||||
|
+ }
|
||||||
|
+ if (pretty && value.size() > 1) {
|
||||||
|
+ os << '\n';
|
||||||
|
+ for (int j = 0; j < indent; ++j)
|
||||||
|
+ os << " ";
|
||||||
|
+ ++indent;
|
||||||
|
+ }
|
||||||
|
+ os << '}';
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
-json::serialize(std::string& sb, std::string_view s)
|
||||||
|
+json::serialize(wpi::util::raw_ostream& os, std::string_view s)
|
||||||
|
{
|
||||||
|
size_t i, j, m;
|
||||||
|
wint_t x, a, b;
|
||||||
|
@@ -865,28 +899,28 @@ json::serialize(std::string& sb, std::string_view s)
|
||||||
|
}
|
||||||
|
switch (0 <= x && x <= 127 ? kEscapeLiteral[x] : 9) {
|
||||||
|
case 0:
|
||||||
|
- sb += x;
|
||||||
|
+ os << static_cast<char>(x);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
- sb += "\\t";
|
||||||
|
+ os << "\\t";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
- sb += "\\n";
|
||||||
|
+ os << "\\n";
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
- sb += "\\r";
|
||||||
|
+ os << "\\r";
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
- sb += "\\f";
|
||||||
|
+ os << "\\f";
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
- sb += "\\\\";
|
||||||
|
+ os << "\\\\";
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
- sb += "\\/";
|
||||||
|
+ os << "\\/";
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
- sb += "\\\"";
|
||||||
|
+ os << "\\\"";
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
w = EncodeUtf16(x);
|
||||||
|
@@ -898,7 +932,7 @@ json::serialize(std::string& sb, std::string_view s)
|
||||||
|
esc[3] = "0123456789abcdef"[(w & 0x0F00) >> 010];
|
||||||
|
esc[4] = "0123456789abcdef"[(w & 0x00F0) >> 004];
|
||||||
|
esc[5] = "0123456789abcdef"[(w & 0x000F) >> 000];
|
||||||
|
- sb.append(esc, 6);
|
||||||
|
+ os.write(esc, 6);
|
||||||
|
} while ((w >>= 16));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
diff --git a/json.h b/json.h
|
||||||
|
index ef3ea13b7cb147f0b383ff1ead496d495cfece32..e42ee96ac8697eaf17fd9d5298e877a45a4644a0 100644
|
||||||
|
--- a/json.h
|
||||||
|
+++ b/json.h
|
||||||
|
@@ -31,6 +31,7 @@
|
||||||
|
namespace wpi::util {
|
||||||
|
|
||||||
|
class json;
|
||||||
|
+class raw_ostream;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct json_serializer;
|
||||||
|
@@ -367,12 +368,21 @@ class json
|
||||||
|
return to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
+ void marshal(wpi::util::raw_ostream& os, bool pretty = false, int indent = 0) const;
|
||||||
|
+
|
||||||
|
+ static void stringify_null(wpi::util::raw_ostream&);
|
||||||
|
+ static void stringify_string(wpi::util::raw_ostream&, std::string_view);
|
||||||
|
+ static void stringify_bool(wpi::util::raw_ostream&, bool);
|
||||||
|
+ static void stringify_float(wpi::util::raw_ostream&, float);
|
||||||
|
+ static void stringify_double(wpi::util::raw_ostream&, double);
|
||||||
|
+ static void stringify_int(wpi::util::raw_ostream&, long long);
|
||||||
|
+ static void stringify_array(wpi::util::raw_ostream&, const array_t&, bool pretty = false, int indent = 0);
|
||||||
|
+ static void stringify_object(wpi::util::raw_ostream&, const object_t&, bool pretty = false, int indent = 0);
|
||||||
|
+
|
||||||
|
private:
|
||||||
|
static const char* StatusToString(Status);
|
||||||
|
void clear();
|
||||||
|
- void marshal(std::string&, bool, int) const;
|
||||||
|
- static void stringify(std::string&, std::string_view);
|
||||||
|
- static void serialize(std::string&, std::string_view);
|
||||||
|
+ static void serialize(wpi::util::raw_ostream&, std::string_view);
|
||||||
|
static Status parse(json&, const char*&, const char*, int, int);
|
||||||
|
};
|
||||||
|
|
||||||
22
upstream_utils/json_patches/0023-Update-include-path.patch
Normal file
22
upstream_utils/json_patches/0023-Update-include-path.patch
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Peter Johnson <johnson.peter@gmail.com>
|
||||||
|
Date: Sat, 4 Apr 2026 12:24:46 -0700
|
||||||
|
Subject: [PATCH 23/25] Update include path
|
||||||
|
|
||||||
|
---
|
||||||
|
json.cpp | 2 +-
|
||||||
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/json.cpp b/json.cpp
|
||||||
|
index 1beec7cc30e90ab2e31bc488ee15cedf9a9f32e5..f8416f3723df70032d274f32cda36b4ef1c7ed90 100644
|
||||||
|
--- a/json.cpp
|
||||||
|
+++ b/json.cpp
|
||||||
|
@@ -15,7 +15,7 @@
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
-#include "json.h"
|
||||||
|
+#include "wpi/util/json.hpp"
|
||||||
|
#include "jtckdint.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
@@ -0,0 +1,326 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Peter Johnson <johnson.peter@gmail.com>
|
||||||
|
Date: Sun, 5 Apr 2026 17:19:33 -0700
|
||||||
|
Subject: [PATCH 24/25] Add support for unsigned long long values
|
||||||
|
|
||||||
|
Make unsigned constructors constexpr
|
||||||
|
---
|
||||||
|
json.cpp | 115 ++++++++++++++++++++++++++++++++++++++-----------------
|
||||||
|
json.h | 36 +++++++++++++++--
|
||||||
|
2 files changed, 112 insertions(+), 39 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/json.cpp b/json.cpp
|
||||||
|
index f8416f3723df70032d274f32cda36b4ef1c7ed90..7f23ece0e8fa09ccb5fef8226de39c55ef70efdd 100644
|
||||||
|
--- a/json.cpp
|
||||||
|
+++ b/json.cpp
|
||||||
|
@@ -247,28 +247,6 @@ LongToString(char* p, long long x)
|
||||||
|
return UlongToString(p, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
-json::json(unsigned long value)
|
||||||
|
-{
|
||||||
|
- if (value <= LLONG_MAX) {
|
||||||
|
- type_ = Type::Int;
|
||||||
|
- long_value = value;
|
||||||
|
- } else {
|
||||||
|
- type_ = Type::Double;
|
||||||
|
- double_value = value;
|
||||||
|
- }
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
-json::json(unsigned long long value)
|
||||||
|
-{
|
||||||
|
- if (value <= LLONG_MAX) {
|
||||||
|
- type_ = Type::Int;
|
||||||
|
- long_value = value;
|
||||||
|
- } else {
|
||||||
|
- type_ = Type::Double;
|
||||||
|
- double_value = value;
|
||||||
|
- }
|
||||||
|
-}
|
||||||
|
-
|
||||||
|
json::json(const char* value)
|
||||||
|
{
|
||||||
|
if (value) {
|
||||||
|
@@ -323,6 +301,9 @@ json::json(const json& other) : type_(other.type_)
|
||||||
|
case Type::Int:
|
||||||
|
long_value = other.long_value;
|
||||||
|
break;
|
||||||
|
+ case Type::Uint:
|
||||||
|
+ ulong_value = other.ulong_value;
|
||||||
|
+ break;
|
||||||
|
case Type::Float:
|
||||||
|
float_value = other.float_value;
|
||||||
|
break;
|
||||||
|
@@ -359,6 +340,9 @@ json::operator=(const json& other)
|
||||||
|
case Type::Int:
|
||||||
|
long_value = other.long_value;
|
||||||
|
break;
|
||||||
|
+ case Type::Uint:
|
||||||
|
+ ulong_value = other.ulong_value;
|
||||||
|
+ break;
|
||||||
|
case Type::Float:
|
||||||
|
float_value = other.float_value;
|
||||||
|
break;
|
||||||
|
@@ -392,6 +376,9 @@ json::json(json&& other) : type_(other.type_)
|
||||||
|
case Type::Int:
|
||||||
|
long_value = other.long_value;
|
||||||
|
break;
|
||||||
|
+ case Type::Uint:
|
||||||
|
+ ulong_value = other.ulong_value;
|
||||||
|
+ break;
|
||||||
|
case Type::Float:
|
||||||
|
float_value = other.float_value;
|
||||||
|
break;
|
||||||
|
@@ -429,6 +416,9 @@ json::operator=(json&& other)
|
||||||
|
case Type::Int:
|
||||||
|
long_value = other.long_value;
|
||||||
|
break;
|
||||||
|
+ case Type::Uint:
|
||||||
|
+ ulong_value = other.ulong_value;
|
||||||
|
+ break;
|
||||||
|
case Type::Float:
|
||||||
|
float_value = other.float_value;
|
||||||
|
break;
|
||||||
|
@@ -458,6 +448,8 @@ json::get_number() const
|
||||||
|
switch (type_) {
|
||||||
|
case Type::Int:
|
||||||
|
return long_value;
|
||||||
|
+ case Type::Uint:
|
||||||
|
+ return ulong_value;
|
||||||
|
case Type::Float:
|
||||||
|
return float_value;
|
||||||
|
case Type::Double:
|
||||||
|
@@ -478,6 +470,17 @@ json::get_int() const
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
+unsigned long long
|
||||||
|
+json::get_uint() const
|
||||||
|
+{
|
||||||
|
+ switch (type_) {
|
||||||
|
+ case Type::Uint:
|
||||||
|
+ return ulong_value;
|
||||||
|
+ default:
|
||||||
|
+ ON_LOGIC_ERROR("JSON value is not an unsigned long.");
|
||||||
|
+ }
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
bool
|
||||||
|
json::get_bool() const
|
||||||
|
{
|
||||||
|
@@ -762,6 +765,9 @@ json::marshal(wpi::util::raw_ostream& os, bool pretty, int indent) const
|
||||||
|
case Type::Int:
|
||||||
|
stringify_int(os, long_value);
|
||||||
|
break;
|
||||||
|
+ case Type::Uint:
|
||||||
|
+ stringify_uint(os, ulong_value);
|
||||||
|
+ break;
|
||||||
|
case Type::Float:
|
||||||
|
stringify_float(os, float_value);
|
||||||
|
break;
|
||||||
|
@@ -822,6 +828,12 @@ json::stringify_int(wpi::util::raw_ostream& os, long long value) {
|
||||||
|
os.write(buf, LongToString(buf, value) - buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
+void
|
||||||
|
+json::stringify_uint(wpi::util::raw_ostream& os, unsigned long long value) {
|
||||||
|
+ char buf[64];
|
||||||
|
+ os.write(buf, UlongToString(buf, value) - buf);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
void
|
||||||
|
json::stringify_array(wpi::util::raw_ostream& os, const array_t& value, bool pretty, int indent) {
|
||||||
|
bool once = false;
|
||||||
|
@@ -946,6 +958,7 @@ json::parse(json& j, const char*& p, const char* e, int context, int depth)
|
||||||
|
{
|
||||||
|
char w[4];
|
||||||
|
long long x;
|
||||||
|
+ unsigned long long ux;
|
||||||
|
const char* a;
|
||||||
|
int A, B, C, D, c, d, i, u;
|
||||||
|
if (!depth)
|
||||||
|
@@ -1061,25 +1074,53 @@ json::parse(json& j, const char*& p, const char* e, int context, int depth)
|
||||||
|
case '9': // integer
|
||||||
|
if (context & (COLON | COMMA | KEY))
|
||||||
|
goto OnColonCommaKey;
|
||||||
|
- for (x = (c - '0') * d; p < e; ++p) {
|
||||||
|
- c = *p & 255;
|
||||||
|
- if (isdigit(c)) {
|
||||||
|
- if (ckd_mul(&x, x, 10) ||
|
||||||
|
- ckd_add(&x, x, (c - '0') * d)) {
|
||||||
|
+ if (d > 0) {
|
||||||
|
+ for (ux = c - '0'; p < e; ++p) {
|
||||||
|
+ c = *p & 255;
|
||||||
|
+ if (isdigit(c)) {
|
||||||
|
+ if (ckd_mul(&ux, ux, 10u) ||
|
||||||
|
+ ckd_add(&ux, ux,
|
||||||
|
+ static_cast<unsigned long long>(c - '0'))) {
|
||||||
|
+ goto UseDubble;
|
||||||
|
+ }
|
||||||
|
+ } else if (c == '.') {
|
||||||
|
+ if (p + 1 == e || !isdigit(p[1]))
|
||||||
|
+ return bad_double;
|
||||||
|
+ goto UseDubble;
|
||||||
|
+ } else if (c == 'e' || c == 'E') {
|
||||||
|
goto UseDubble;
|
||||||
|
+ } else {
|
||||||
|
+ break;
|
||||||
|
}
|
||||||
|
- } else if (c == '.') {
|
||||||
|
- if (p + 1 == e || !isdigit(p[1]))
|
||||||
|
- return bad_double;
|
||||||
|
- goto UseDubble;
|
||||||
|
- } else if (c == 'e' || c == 'E') {
|
||||||
|
- goto UseDubble;
|
||||||
|
+ }
|
||||||
|
+ if (ux <= static_cast<unsigned long long>(LLONG_MAX)) {
|
||||||
|
+ j.type_ = Type::Int;
|
||||||
|
+ j.long_value = ux;
|
||||||
|
} else {
|
||||||
|
- break;
|
||||||
|
+ j.type_ = Type::Uint;
|
||||||
|
+ j.ulong_value = ux;
|
||||||
|
+ }
|
||||||
|
+ } else {
|
||||||
|
+ for (x = (c - '0') * d; p < e; ++p) {
|
||||||
|
+ c = *p & 255;
|
||||||
|
+ if (isdigit(c)) {
|
||||||
|
+ if (ckd_mul(&x, x, 10) ||
|
||||||
|
+ ckd_add(&x, x, (c - '0') * d)) {
|
||||||
|
+ goto UseDubble;
|
||||||
|
+ }
|
||||||
|
+ } else if (c == '.') {
|
||||||
|
+ if (p + 1 == e || !isdigit(p[1]))
|
||||||
|
+ return bad_double;
|
||||||
|
+ goto UseDubble;
|
||||||
|
+ } else if (c == 'e' || c == 'E') {
|
||||||
|
+ goto UseDubble;
|
||||||
|
+ } else {
|
||||||
|
+ break;
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
+ j.type_ = Type::Int;
|
||||||
|
+ j.long_value = x;
|
||||||
|
}
|
||||||
|
- j.type_ = Type::Int;
|
||||||
|
- j.long_value = x;
|
||||||
|
return success;
|
||||||
|
|
||||||
|
UseDubble: // number
|
||||||
|
@@ -1510,6 +1551,8 @@ operator==(const json& lhs, const json& rhs) {
|
||||||
|
return lhs.bool_value == rhs.bool_value;
|
||||||
|
case json::Type::Int:
|
||||||
|
return lhs.long_value == rhs.long_value;
|
||||||
|
+ case json::Type::Uint:
|
||||||
|
+ return lhs.ulong_value == rhs.ulong_value;
|
||||||
|
case json::Type::Float:
|
||||||
|
return lhs.float_value == rhs.float_value;
|
||||||
|
case json::Type::Double:
|
||||||
|
diff --git a/json.h b/json.h
|
||||||
|
index e42ee96ac8697eaf17fd9d5298e877a45a4644a0..31c5ea39b67286df158a9d6e13ab5073498126b8 100644
|
||||||
|
--- a/json.h
|
||||||
|
+++ b/json.h
|
||||||
|
@@ -17,6 +17,7 @@
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
+#include <climits>
|
||||||
|
#include <concepts>
|
||||||
|
#include <ranges>
|
||||||
|
#include <string>
|
||||||
|
@@ -92,6 +93,7 @@ class json
|
||||||
|
Null,
|
||||||
|
Bool,
|
||||||
|
Int,
|
||||||
|
+ Uint,
|
||||||
|
Float,
|
||||||
|
Double,
|
||||||
|
String,
|
||||||
|
@@ -144,6 +146,7 @@ class json
|
||||||
|
float float_value;
|
||||||
|
double double_value;
|
||||||
|
long long long_value;
|
||||||
|
+ unsigned long long ulong_value;
|
||||||
|
std::string string_value;
|
||||||
|
array_t array_value;
|
||||||
|
object_t object_value;
|
||||||
|
@@ -155,8 +158,6 @@ class json
|
||||||
|
|
||||||
|
json(const json&);
|
||||||
|
json(json&&);
|
||||||
|
- json(unsigned long);
|
||||||
|
- json(unsigned long long);
|
||||||
|
json(const char*);
|
||||||
|
json(const std::string&);
|
||||||
|
json(std::string_view);
|
||||||
|
@@ -186,10 +187,32 @@ class json
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
+ constexpr json(unsigned long value)
|
||||||
|
+ {
|
||||||
|
+ if (value <= LLONG_MAX) {
|
||||||
|
+ type_ = Type::Int;
|
||||||
|
+ long_value = value;
|
||||||
|
+ } else {
|
||||||
|
+ type_ = Type::Uint;
|
||||||
|
+ ulong_value = value;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
constexpr json(long long value) : type_(Type::Int), long_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
+ constexpr json(unsigned long long value)
|
||||||
|
+ {
|
||||||
|
+ if (value <= LLONG_MAX) {
|
||||||
|
+ type_ = Type::Int;
|
||||||
|
+ long_value = value;
|
||||||
|
+ } else {
|
||||||
|
+ type_ = Type::Uint;
|
||||||
|
+ ulong_value = value;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
constexpr json(double value) : type_(Type::Double), double_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
@@ -241,7 +264,7 @@ class json
|
||||||
|
|
||||||
|
constexpr bool is_number() const
|
||||||
|
{
|
||||||
|
- return is_float() || is_double() || is_int();
|
||||||
|
+ return is_float() || is_double() || is_int() || is_uint();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool is_int() const
|
||||||
|
@@ -249,6 +272,11 @@ class json
|
||||||
|
return type_ == Type::Int;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ constexpr bool is_uint() const
|
||||||
|
+ {
|
||||||
|
+ return type_ == Type::Uint;
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
constexpr bool is_float() const
|
||||||
|
{
|
||||||
|
return type_ == Type::Float;
|
||||||
|
@@ -279,6 +307,7 @@ class json
|
||||||
|
double get_double() const;
|
||||||
|
double get_number() const;
|
||||||
|
long long get_int() const;
|
||||||
|
+ unsigned long long get_uint() const;
|
||||||
|
std::string& get_string();
|
||||||
|
const std::string& get_string() const;
|
||||||
|
array_t& get_array();
|
||||||
|
@@ -376,6 +405,7 @@ class json
|
||||||
|
static void stringify_float(wpi::util::raw_ostream&, float);
|
||||||
|
static void stringify_double(wpi::util::raw_ostream&, double);
|
||||||
|
static void stringify_int(wpi::util::raw_ostream&, long long);
|
||||||
|
+ static void stringify_uint(wpi::util::raw_ostream&, unsigned long long);
|
||||||
|
static void stringify_array(wpi::util::raw_ostream&, const array_t&, bool pretty = false, int indent = 0);
|
||||||
|
static void stringify_object(wpi::util::raw_ostream&, const object_t&, bool pretty = false, int indent = 0);
|
||||||
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
|
||||||
|
From: Peter Johnson <johnson.peter@gmail.com>
|
||||||
|
Date: Mon, 6 Apr 2026 17:49:08 -0700
|
||||||
|
Subject: [PATCH 25/25] Make bool constructor safe
|
||||||
|
|
||||||
|
---
|
||||||
|
json.h | 2 +-
|
||||||
|
1 file changed, 1 insertion(+), 1 deletion(-)
|
||||||
|
|
||||||
|
diff --git a/json.h b/json.h
|
||||||
|
index 31c5ea39b67286df158a9d6e13ab5073498126b8..2746badf92a5bb4de6c38007d8e6dcfbed5b47eb 100644
|
||||||
|
--- a/json.h
|
||||||
|
+++ b/json.h
|
||||||
|
@@ -167,7 +167,7 @@ class json
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
- constexpr json(bool value) : type_(Type::Bool), bool_value(value)
|
||||||
|
+ constexpr json(std::same_as<bool> auto value) : type_(Type::Bool), bool_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
@@ -122,6 +122,7 @@ third_party_cc_lib_helper(
|
|||||||
third_party_cc_lib_helper(
|
third_party_cc_lib_helper(
|
||||||
name = "json",
|
name = "json",
|
||||||
include_root = "src/main/native/thirdparty/json/include",
|
include_root = "src/main/native/thirdparty/json/include",
|
||||||
|
src_root = "src/main/native/thirdparty/json/src",
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -189,13 +190,13 @@ wpilib_cc_library(
|
|||||||
third_party_header_only_libraries = [
|
third_party_header_only_libraries = [
|
||||||
":argparse",
|
":argparse",
|
||||||
":expected",
|
":expected",
|
||||||
":json",
|
|
||||||
":sigslot",
|
":sigslot",
|
||||||
],
|
],
|
||||||
third_party_libraries = [
|
third_party_libraries = [
|
||||||
":debugging",
|
":debugging",
|
||||||
":double-conversion",
|
":double-conversion",
|
||||||
":fmtlib",
|
":fmtlib",
|
||||||
|
":json",
|
||||||
":llvm",
|
":llvm",
|
||||||
":mpack",
|
":mpack",
|
||||||
":nanopb",
|
":nanopb",
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ file(
|
|||||||
src/main/native/cpp/*.cpp
|
src/main/native/cpp/*.cpp
|
||||||
src/main/native/thirdparty/debugging/src/*.cpp
|
src/main/native/thirdparty/debugging/src/*.cpp
|
||||||
src/main/native/thirdparty/double-conversion/src/*.cpp
|
src/main/native/thirdparty/double-conversion/src/*.cpp
|
||||||
src/main/native/thirdparty/json/cpp/*.cpp
|
src/main/native/thirdparty/json/src/*.cpp
|
||||||
src/main/native/thirdparty/llvm/cpp/*.cpp
|
src/main/native/thirdparty/llvm/cpp/*.cpp
|
||||||
src/main/native/thirdparty/mpack/src/*.cpp
|
src/main/native/thirdparty/mpack/src/*.cpp
|
||||||
src/main/native/thirdparty/nanopb/src/*.cpp
|
src/main/native/thirdparty/nanopb/src/*.cpp
|
||||||
|
|||||||
@@ -44,11 +44,11 @@ ext {
|
|||||||
}
|
}
|
||||||
jsonCpp(CppSourceSet) {
|
jsonCpp(CppSourceSet) {
|
||||||
source {
|
source {
|
||||||
srcDirs 'src/main/native/thirdparty/json/cpp'
|
srcDirs 'src/main/native/thirdparty/json/src'
|
||||||
include '*.cpp'
|
include '**/*.cpp'
|
||||||
}
|
}
|
||||||
exportedHeaders {
|
exportedHeaders {
|
||||||
srcDirs 'src/main/native/thirdparty/json/include'
|
srcDirs 'src/main/native/include', 'src/main/native/thirdparty/double-conversion/include', 'src/main/native/thirdparty/expected/include', 'src/main/native/thirdparty/llvm/include', 'src/main/native/thirdparty/json/include'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
llvmCpp(CppSourceSet) {
|
llvmCpp(CppSourceSet) {
|
||||||
@@ -210,7 +210,7 @@ cppSourcesZip {
|
|||||||
from('src/main/native/thirdparty/fmtlib/src') {
|
from('src/main/native/thirdparty/fmtlib/src') {
|
||||||
into '/'
|
into '/'
|
||||||
}
|
}
|
||||||
from('src/main/native/thirdparty/json/cpp') {
|
from('src/main/native/thirdparty/json/src') {
|
||||||
into '/'
|
into '/'
|
||||||
}
|
}
|
||||||
from('src/main/native/thirdparty/llvm/cpp') {
|
from('src/main/native/thirdparty/llvm/cpp') {
|
||||||
|
|||||||
424
wpiutil/src/main/native/thirdparty/json/include/wpi/util/json.hpp
vendored
Normal file
424
wpiutil/src/main/native/thirdparty/json/include/wpi/util/json.hpp
vendored
Normal file
@@ -0,0 +1,424 @@
|
|||||||
|
// -*- mode:c++;indent-tabs-mode:nil;c-basic-offset:4;coding:utf-8 -*-
|
||||||
|
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
|
||||||
|
//
|
||||||
|
// Copyright 2024 Mozilla Foundation
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <climits>
|
||||||
|
#include <concepts>
|
||||||
|
#include <ranges>
|
||||||
|
#include <string>
|
||||||
|
#include <string_view>
|
||||||
|
#include <tuple>
|
||||||
|
#include <utility>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#include "wpi/util/StringMap.hpp"
|
||||||
|
#include "wpi/util/expected"
|
||||||
|
|
||||||
|
namespace wpi::util {
|
||||||
|
|
||||||
|
class json;
|
||||||
|
class raw_ostream;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct json_serializer;
|
||||||
|
|
||||||
|
namespace detail {
|
||||||
|
template <typename T>
|
||||||
|
concept HasToJson = requires(json& j, const T& val) {
|
||||||
|
{ to_json(j, val) };
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept HasFromJson = requires(const json& j, T& val) {
|
||||||
|
{ from_json(j, val) };
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept HasJsonSerializer = requires (json& j, const json& cj, const T& val) {
|
||||||
|
typename json_serializer<typename std::remove_cvref_t<T>>;
|
||||||
|
{ json_serializer<typename std::remove_cvref_t<T>>::to(j, val) };
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept HasJsonDeserializer = requires (json& j, const json& cj, const T& val) {
|
||||||
|
typename json_serializer<typename std::remove_cvref_t<T>>;
|
||||||
|
{ json_serializer<typename std::remove_cvref_t<T>>::from(cj) } -> std::convertible_to<typename std::remove_cvref_t<T>>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept JsonConvertible =
|
||||||
|
HasToJson<T> ||
|
||||||
|
HasJsonSerializer<T> ||
|
||||||
|
std::is_same_v<T, std::nullptr_t> ||
|
||||||
|
std::is_same_v<T, bool> ||
|
||||||
|
std::is_floating_point_v<T> ||
|
||||||
|
std::is_integral_v<T> ||
|
||||||
|
std::convertible_to<T, std::string> ||
|
||||||
|
std::convertible_to<T, std::string_view> ||
|
||||||
|
std::is_same_v<T, std::vector<json>> ||
|
||||||
|
std::is_same_v<T, wpi::util::StringMap<json>>;
|
||||||
|
|
||||||
|
template <typename F, typename Tuple, size_t... I>
|
||||||
|
void apply_pairs_helper(F&& f, Tuple&& t, std::index_sequence<I...>) {
|
||||||
|
// This fold expression creates a sequence of calls to f for each pair
|
||||||
|
(f(std::get<I * 2>(std::forward<Tuple>(t)),
|
||||||
|
std::get<I * 2 + 1>(std::forward<Tuple>(t))), ...);
|
||||||
|
}
|
||||||
|
} // namespace detail
|
||||||
|
|
||||||
|
class json
|
||||||
|
{
|
||||||
|
friend bool operator==(const json& lhs, const json& rhs);
|
||||||
|
public:
|
||||||
|
using array_t = std::vector<json>;
|
||||||
|
using object_t = wpi::util::StringMap<json>;
|
||||||
|
|
||||||
|
enum class Type
|
||||||
|
{
|
||||||
|
Null,
|
||||||
|
Bool,
|
||||||
|
Int,
|
||||||
|
Uint,
|
||||||
|
Float,
|
||||||
|
Double,
|
||||||
|
String,
|
||||||
|
Array,
|
||||||
|
Object
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum Status
|
||||||
|
{
|
||||||
|
success,
|
||||||
|
bad_double,
|
||||||
|
absent_value,
|
||||||
|
bad_negative,
|
||||||
|
bad_exponent,
|
||||||
|
missing_comma,
|
||||||
|
missing_colon,
|
||||||
|
malformed_utf8,
|
||||||
|
depth_exceeded,
|
||||||
|
stack_overflow,
|
||||||
|
unexpected_eof,
|
||||||
|
overlong_ascii,
|
||||||
|
unexpected_comma,
|
||||||
|
unexpected_colon,
|
||||||
|
unexpected_octal,
|
||||||
|
trailing_content,
|
||||||
|
illegal_character,
|
||||||
|
invalid_hex_escape,
|
||||||
|
overlong_utf8_0x7ff,
|
||||||
|
overlong_utf8_0xffff,
|
||||||
|
object_missing_value,
|
||||||
|
illegal_utf8_character,
|
||||||
|
invalid_unicode_escape,
|
||||||
|
utf16_surrogate_in_utf8,
|
||||||
|
unexpected_end_of_array,
|
||||||
|
hex_escape_not_printable,
|
||||||
|
invalid_escape_character,
|
||||||
|
utf8_exceeds_utf16_range,
|
||||||
|
unexpected_end_of_string,
|
||||||
|
unexpected_end_of_object,
|
||||||
|
object_key_must_be_string,
|
||||||
|
c1_control_code_in_string,
|
||||||
|
non_del_c0_control_code_in_string,
|
||||||
|
};
|
||||||
|
|
||||||
|
Type type_;
|
||||||
|
union
|
||||||
|
{
|
||||||
|
bool bool_value;
|
||||||
|
float float_value;
|
||||||
|
double double_value;
|
||||||
|
long long long_value;
|
||||||
|
unsigned long long ulong_value;
|
||||||
|
std::string string_value;
|
||||||
|
array_t array_value;
|
||||||
|
object_t object_value;
|
||||||
|
};
|
||||||
|
|
||||||
|
public:
|
||||||
|
static wpi::util::expected<json, const char*> parse(std::string_view);
|
||||||
|
static json parse_or_throw(std::string_view);
|
||||||
|
|
||||||
|
json(const json&);
|
||||||
|
json(json&&);
|
||||||
|
json(const char*);
|
||||||
|
json(const std::string&);
|
||||||
|
json(std::string_view);
|
||||||
|
~json();
|
||||||
|
|
||||||
|
constexpr json(const std::nullptr_t = nullptr) : type_(Type::Null)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr json(std::same_as<bool> auto value) : type_(Type::Bool), bool_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr json(int value) : type_(Type::Int), long_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr json(float value) : type_(Type::Float), float_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr json(unsigned value) : type_(Type::Int), long_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr json(long value) : type_(Type::Int), long_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr json(unsigned long value)
|
||||||
|
{
|
||||||
|
if (value <= LLONG_MAX) {
|
||||||
|
type_ = Type::Int;
|
||||||
|
long_value = value;
|
||||||
|
} else {
|
||||||
|
type_ = Type::Uint;
|
||||||
|
ulong_value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr json(long long value) : type_(Type::Int), long_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr json(unsigned long long value)
|
||||||
|
{
|
||||||
|
if (value <= LLONG_MAX) {
|
||||||
|
type_ = Type::Int;
|
||||||
|
long_value = value;
|
||||||
|
} else {
|
||||||
|
type_ = Type::Uint;
|
||||||
|
ulong_value = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr json(double value) : type_(Type::Double), double_value(value)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
json(std::string&& value) : type_(Type::String), string_value(std::move(value))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
json(array_t&& value) : type_(Type::Array), array_value(std::move(value))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
json(object_t&& value) : type_(Type::Object), object_value(std::move(value))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::ranges::input_range R>
|
||||||
|
requires detail::JsonConvertible<std::ranges::range_value_t<R>>
|
||||||
|
json(const R& range) : type_(Type::Array), array_value(std::ranges::cbegin(range), std::ranges::cend(range))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <detail::HasToJson T>
|
||||||
|
json(const T& value) : type_(Type::Null)
|
||||||
|
{
|
||||||
|
to_json(*this, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <detail::HasJsonSerializer T>
|
||||||
|
json(const T& value) : type_(Type::Null)
|
||||||
|
{
|
||||||
|
json_serializer<T>::to(*this, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr Type type() const
|
||||||
|
{
|
||||||
|
return type_;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool is_null() const
|
||||||
|
{
|
||||||
|
return type_ == Type::Null;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool is_bool() const
|
||||||
|
{
|
||||||
|
return type_ == Type::Bool;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool is_number() const
|
||||||
|
{
|
||||||
|
return is_float() || is_double() || is_int() || is_uint();
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool is_int() const
|
||||||
|
{
|
||||||
|
return type_ == Type::Int;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool is_uint() const
|
||||||
|
{
|
||||||
|
return type_ == Type::Uint;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool is_float() const
|
||||||
|
{
|
||||||
|
return type_ == Type::Float;
|
||||||
|
}
|
||||||
|
|
||||||
|
constexpr bool is_double() const
|
||||||
|
{
|
||||||
|
return type_ == Type::Double;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_string() const
|
||||||
|
{
|
||||||
|
return type_ == Type::String;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_array() const
|
||||||
|
{
|
||||||
|
return type_ == Type::Array;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_object() const
|
||||||
|
{
|
||||||
|
return type_ == Type::Object;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool get_bool() const;
|
||||||
|
float get_float() const;
|
||||||
|
double get_double() const;
|
||||||
|
double get_number() const;
|
||||||
|
long long get_int() const;
|
||||||
|
unsigned long long get_uint() const;
|
||||||
|
std::string& get_string();
|
||||||
|
const std::string& get_string() const;
|
||||||
|
array_t& get_array();
|
||||||
|
const array_t& get_array() const;
|
||||||
|
object_t& get_object();
|
||||||
|
const object_t& get_object() const;
|
||||||
|
|
||||||
|
template <detail::HasFromJson T>
|
||||||
|
T get() const {
|
||||||
|
T value;
|
||||||
|
from_json(*this, value);
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <detail::HasJsonDeserializer T>
|
||||||
|
T get() const {
|
||||||
|
return json_serializer<T>::from(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool contains(std::string_view) const;
|
||||||
|
|
||||||
|
json* lookup(std::string_view);
|
||||||
|
const json* lookup(std::string_view) const;
|
||||||
|
|
||||||
|
void set_array();
|
||||||
|
void set_object();
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
static json array(Args&&... args) {
|
||||||
|
json j;
|
||||||
|
j.set_array();
|
||||||
|
(j.array_value.emplace_back(std::forward<Args>(args)), ...);
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename... Args>
|
||||||
|
static json object(Args&&... args) {
|
||||||
|
json j;
|
||||||
|
j.set_object();
|
||||||
|
detail::apply_pairs_helper(
|
||||||
|
[&](auto&& key, auto&& value) {
|
||||||
|
j.object_value[std::forward<decltype(key)>(key)] = std::forward<decltype(value)>(value);
|
||||||
|
},
|
||||||
|
std::forward_as_tuple(args...),
|
||||||
|
std::make_index_sequence<sizeof...(Args) / 2>{});
|
||||||
|
return j;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string to_string() const;
|
||||||
|
std::string to_string_pretty() const;
|
||||||
|
|
||||||
|
json& operator=(const json&);
|
||||||
|
json& operator=(json&&);
|
||||||
|
|
||||||
|
template <detail::HasToJson T>
|
||||||
|
json& operator=(const T& value) {
|
||||||
|
to_json(*this, value);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <detail::HasJsonSerializer T>
|
||||||
|
json& operator=(const T& value) {
|
||||||
|
json_serializer<T>::to(*this, value);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
json& operator[](size_t);
|
||||||
|
json& operator[](std::string_view);
|
||||||
|
|
||||||
|
json& at(size_t);
|
||||||
|
json& at(std::string_view);
|
||||||
|
|
||||||
|
const json& at(size_t) const;
|
||||||
|
const json& at(std::string_view) const;
|
||||||
|
|
||||||
|
json value(size_t, json&&);
|
||||||
|
json value(std::string_view, json&&);
|
||||||
|
|
||||||
|
void erase(std::string_view);
|
||||||
|
|
||||||
|
json& emplace_back(json&& value);
|
||||||
|
|
||||||
|
bool empty() const;
|
||||||
|
|
||||||
|
operator std::string() const
|
||||||
|
{
|
||||||
|
return to_string();
|
||||||
|
}
|
||||||
|
|
||||||
|
void marshal(wpi::util::raw_ostream& os, bool pretty = false, int indent = 0) const;
|
||||||
|
|
||||||
|
static void stringify_null(wpi::util::raw_ostream&);
|
||||||
|
static void stringify_string(wpi::util::raw_ostream&, std::string_view);
|
||||||
|
static void stringify_bool(wpi::util::raw_ostream&, bool);
|
||||||
|
static void stringify_float(wpi::util::raw_ostream&, float);
|
||||||
|
static void stringify_double(wpi::util::raw_ostream&, double);
|
||||||
|
static void stringify_int(wpi::util::raw_ostream&, long long);
|
||||||
|
static void stringify_uint(wpi::util::raw_ostream&, unsigned long long);
|
||||||
|
static void stringify_array(wpi::util::raw_ostream&, const array_t&, bool pretty = false, int indent = 0);
|
||||||
|
static void stringify_object(wpi::util::raw_ostream&, const object_t&, bool pretty = false, int indent = 0);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const char* StatusToString(Status);
|
||||||
|
void clear();
|
||||||
|
static void serialize(wpi::util::raw_ostream&, std::string_view);
|
||||||
|
static Status parse(json&, const char*&, const char*, int, int);
|
||||||
|
};
|
||||||
|
|
||||||
|
bool operator==(const json& lhs, const json& rhs);
|
||||||
|
inline bool operator!=(const json& lhs, const json& rhs) {
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace wpi::util
|
||||||
1569
wpiutil/src/main/native/thirdparty/json/src/json.cpp
vendored
Normal file
1569
wpiutil/src/main/native/thirdparty/json/src/json.cpp
vendored
Normal file
File diff suppressed because it is too large
Load Diff
670
wpiutil/src/main/native/thirdparty/json/src/jtckdint.h
vendored
Normal file
670
wpiutil/src/main/native/thirdparty/json/src/jtckdint.h
vendored
Normal file
@@ -0,0 +1,670 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2023 Justine Alexandra Roberts Tunney
|
||||||
|
*
|
||||||
|
* Permission to use, copy, modify, and/or distribute this software for
|
||||||
|
* any purpose with or without fee is hereby granted, provided that the
|
||||||
|
* above copyright notice and this permission notice appear in all copies.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
|
||||||
|
* WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
|
||||||
|
* AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||||
|
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
|
||||||
|
* TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||||
|
* PERFORMANCE OF THIS SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @fileoverview C23 Checked Arithmetic
|
||||||
|
*
|
||||||
|
* This header defines three type generic functions:
|
||||||
|
*
|
||||||
|
* - `bool ckd_add(res, a, b)`
|
||||||
|
* - `bool ckd_sub(res, a, b)`
|
||||||
|
* - `bool ckd_mul(res, a, b)`
|
||||||
|
*
|
||||||
|
* Which allow integer arithmetic errors to be detected. There are many
|
||||||
|
* kinds of integer errors, e.g. overflow, truncation, etc. These funcs
|
||||||
|
* catch them all. Here's an example of how it works:
|
||||||
|
*
|
||||||
|
* uint32_t c;
|
||||||
|
* int32_t a = 0x7fffffff;
|
||||||
|
* int32_t b = 2;
|
||||||
|
* assert(!ckd_add(&c, a, b));
|
||||||
|
* assert(c == 0x80000001u);
|
||||||
|
*
|
||||||
|
* Experienced C / C++ users should find this example counter-intuitive
|
||||||
|
* because the expression `0x7fffffff + 2` not only overflows it's also
|
||||||
|
* undefined behavior. However here we see it's specified, and does not
|
||||||
|
* result in an error. That's because C23 checked arithmetic is not the
|
||||||
|
* arithmetic you're used to. The new standard changes the mathematics.
|
||||||
|
*
|
||||||
|
* C23 checked arithmetic is defined as performing the arithmetic using
|
||||||
|
* infinite precision and then checking if the resulting value will fit
|
||||||
|
* in the output type. Our example above did not result in an error due
|
||||||
|
* to `0x80000001` being a legal value for `uint32_t`.
|
||||||
|
*
|
||||||
|
* This implementation will use the GNU compiler builtins, when they're
|
||||||
|
* available, only if you don't use build flags like `-std=c11` because
|
||||||
|
* they define `__STRICT_ANSI__` and GCC extensions aren't really ANSI.
|
||||||
|
* Instead, you'll get a pretty good pure C11 and C++11 implementation.
|
||||||
|
*
|
||||||
|
* @see https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3096.pdf
|
||||||
|
* @version 1.0 (2024-12-07)
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef JTCKDINT_H_
|
||||||
|
#define JTCKDINT_H_
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#pragma GCC diagnostic ignored "-Wpedantic"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __has_include
|
||||||
|
#define __ckd_has_include(x) __has_include(x)
|
||||||
|
#else
|
||||||
|
#define __ckd_has_include(x) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if __ckd_has_include(<stdckdint.h>) && !defined(__cplusplus)
|
||||||
|
#include <stdckdint.h>
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define __STDC_VERSION_STDCKDINT_H__ 202311L
|
||||||
|
|
||||||
|
#if (!defined(__STRICT_ANSI__) && defined(__SIZEOF_INT128__))
|
||||||
|
#define __ckd_have_int128
|
||||||
|
#define __ckd_intmax __int128
|
||||||
|
#elif ((defined(__cplusplus) && __cplusplus >= 201103L) || \
|
||||||
|
(defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L))
|
||||||
|
#define __ckd_intmax long long
|
||||||
|
#else
|
||||||
|
#define __ckd_intmax long
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef signed __ckd_intmax __ckd_intmax_t;
|
||||||
|
typedef unsigned __ckd_intmax __ckd_uintmax_t;
|
||||||
|
|
||||||
|
#ifdef __has_builtin
|
||||||
|
#define __ckd_has_builtin(x) __has_builtin(x)
|
||||||
|
#else
|
||||||
|
#define __ckd_has_builtin(x) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (!defined(__STRICT_ANSI__) && \
|
||||||
|
((defined(__GNUC__) && __GNUC__ >= 5 && !defined(__ICC)) || \
|
||||||
|
(__ckd_has_builtin(__builtin_add_overflow) && \
|
||||||
|
__ckd_has_builtin(__builtin_sub_overflow) && \
|
||||||
|
__ckd_has_builtin(__builtin_mul_overflow))))
|
||||||
|
#define ckd_add(res, x, y) __builtin_add_overflow((x), (y), (res))
|
||||||
|
#define ckd_sub(res, x, y) __builtin_sub_overflow((x), (y), (res))
|
||||||
|
#define ckd_mul(res, x, y) __builtin_mul_overflow((x), (y), (res))
|
||||||
|
|
||||||
|
#elif (defined(__cplusplus) && \
|
||||||
|
(__cplusplus >= 201103L || \
|
||||||
|
(defined(_MSC_VER) && __cplusplus >= 199711L && \
|
||||||
|
__ckd_has_include(<type_traits>) && __ckd_has_include(<limits>))))
|
||||||
|
#include <limits>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
template<typename __T, typename __U, typename __V>
|
||||||
|
inline bool
|
||||||
|
ckd_add(__T* __res, __U __a, __V __b)
|
||||||
|
{
|
||||||
|
static_assert(std::is_integral<__T>::value &&
|
||||||
|
std::is_integral<__U>::value &&
|
||||||
|
std::is_integral<__V>::value,
|
||||||
|
"non-integral types not allowed");
|
||||||
|
static_assert(!std::is_same<__T, bool>::value &&
|
||||||
|
!std::is_same<__U, bool>::value &&
|
||||||
|
!std::is_same<__V, bool>::value,
|
||||||
|
"checked booleans not supported");
|
||||||
|
static_assert(!std::is_same<__T, char>::value &&
|
||||||
|
!std::is_same<__U, char>::value &&
|
||||||
|
!std::is_same<__V, char>::value,
|
||||||
|
"unqualified char type is ambiguous");
|
||||||
|
__ckd_uintmax_t __x = __a;
|
||||||
|
__ckd_uintmax_t __y = __b;
|
||||||
|
__ckd_uintmax_t __z = __x + __y;
|
||||||
|
*__res = __z;
|
||||||
|
if (sizeof(__z) > sizeof(__U) && sizeof(__z) > sizeof(__V)) {
|
||||||
|
if (sizeof(__z) > sizeof(__T) || std::is_signed<__T>::value) {
|
||||||
|
return static_cast<__ckd_intmax_t>(__z) != static_cast<__T>(__z);
|
||||||
|
} else if (!std::is_same<__T, __ckd_uintmax_t>::value) {
|
||||||
|
return (
|
||||||
|
__z != static_cast<__T>(__z) ||
|
||||||
|
((std::is_signed<__U>::value || std::is_signed<__V>::value) &&
|
||||||
|
static_cast<__ckd_intmax_t>(__z) < 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
bool __truncated = false;
|
||||||
|
if (sizeof(__T) < sizeof(__ckd_intmax_t)) {
|
||||||
|
__truncated =
|
||||||
|
__z != static_cast<__ckd_uintmax_t>(static_cast<__T>(__z));
|
||||||
|
}
|
||||||
|
switch (std::is_signed<__T>::value << 2 | //
|
||||||
|
std::is_signed<__U>::value << 1 | //
|
||||||
|
std::is_signed<__V>::value) {
|
||||||
|
case 0: // u = u + u
|
||||||
|
return __truncated | (__z < __x);
|
||||||
|
case 1: // u = u + s
|
||||||
|
__y ^= std::numeric_limits<__ckd_intmax_t>::min();
|
||||||
|
return __truncated |
|
||||||
|
(static_cast<__ckd_intmax_t>((__z ^ __x) & (__z ^ __y)) < 0);
|
||||||
|
case 2: // u = s + u
|
||||||
|
__x ^= std::numeric_limits<__ckd_intmax_t>::min();
|
||||||
|
return __truncated |
|
||||||
|
(static_cast<__ckd_intmax_t>((__z ^ __x) & (__z ^ __y)) < 0);
|
||||||
|
case 3: // u = s + s
|
||||||
|
return __truncated |
|
||||||
|
(static_cast<__ckd_intmax_t>(((__z | __x) & __y) |
|
||||||
|
((__z & __x) & ~__y)) < 0);
|
||||||
|
case 4: // s = u + u
|
||||||
|
return __truncated | (__z < __x) |
|
||||||
|
(static_cast<__ckd_intmax_t>(__z) < 0);
|
||||||
|
case 5: // s = u + s
|
||||||
|
__y ^= std::numeric_limits<__ckd_intmax_t>::min();
|
||||||
|
return __truncated | (__x + __y < __y);
|
||||||
|
case 6: // s = s + u
|
||||||
|
__x ^= std::numeric_limits<__ckd_intmax_t>::min();
|
||||||
|
return __truncated | (__x + __y < __x);
|
||||||
|
case 7: // s = s + s
|
||||||
|
return __truncated |
|
||||||
|
(static_cast<__ckd_intmax_t>((__z ^ __x) & (__z ^ __y)) < 0);
|
||||||
|
default:
|
||||||
|
for (;;)
|
||||||
|
(void)0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __T, typename __U, typename __V>
|
||||||
|
inline bool
|
||||||
|
ckd_sub(__T* __res, __U __a, __V __b)
|
||||||
|
{
|
||||||
|
static_assert(std::is_integral<__T>::value &&
|
||||||
|
std::is_integral<__U>::value &&
|
||||||
|
std::is_integral<__V>::value,
|
||||||
|
"non-integral types not allowed");
|
||||||
|
static_assert(!std::is_same<__T, bool>::value &&
|
||||||
|
!std::is_same<__U, bool>::value &&
|
||||||
|
!std::is_same<__V, bool>::value,
|
||||||
|
"checked booleans not supported");
|
||||||
|
static_assert(!std::is_same<__T, char>::value &&
|
||||||
|
!std::is_same<__U, char>::value &&
|
||||||
|
!std::is_same<__V, char>::value,
|
||||||
|
"unqualified char type is ambiguous");
|
||||||
|
__ckd_uintmax_t __x = __a;
|
||||||
|
__ckd_uintmax_t __y = __b;
|
||||||
|
__ckd_uintmax_t __z = __x - __y;
|
||||||
|
*__res = __z;
|
||||||
|
bool __truncated = false;
|
||||||
|
if (sizeof(__T) < sizeof(__ckd_intmax_t)) {
|
||||||
|
__truncated =
|
||||||
|
__z != static_cast<__ckd_uintmax_t>(static_cast<__T>(__z));
|
||||||
|
}
|
||||||
|
switch (std::is_signed<__T>::value << 2 | //
|
||||||
|
std::is_signed<__U>::value << 1 | //
|
||||||
|
std::is_signed<__V>::value) {
|
||||||
|
case 0: // u = u - u
|
||||||
|
return __truncated | (__x < __y);
|
||||||
|
case 1: // u = u - s
|
||||||
|
__y ^= std::numeric_limits<__ckd_intmax_t>::min();
|
||||||
|
return __truncated |
|
||||||
|
(static_cast<__ckd_intmax_t>((__x ^ __y) & (__z ^ __x)) < 0);
|
||||||
|
case 2: // u = s - u
|
||||||
|
return __truncated | (__y > __x) |
|
||||||
|
(static_cast<__ckd_intmax_t>(__x) < 0);
|
||||||
|
case 3: // u = s - s
|
||||||
|
return __truncated |
|
||||||
|
(static_cast<__ckd_intmax_t>(((__z & __x) & __y) |
|
||||||
|
((__z | __x) & ~__y)) < 0);
|
||||||
|
case 4: // s = u - u
|
||||||
|
return __truncated |
|
||||||
|
((__x < __y) ^ (static_cast<__ckd_intmax_t>(__z) < 0));
|
||||||
|
case 5: // s = u - s
|
||||||
|
__y ^= std::numeric_limits<__ckd_intmax_t>::min();
|
||||||
|
return __truncated | (__x >= __y);
|
||||||
|
case 6: // s = s - u
|
||||||
|
__x ^= std::numeric_limits<__ckd_intmax_t>::min();
|
||||||
|
return __truncated | (__x < __y);
|
||||||
|
case 7: // s = s - s
|
||||||
|
return __truncated |
|
||||||
|
(static_cast<__ckd_intmax_t>((__x ^ __y) & (__z ^ __x)) < 0);
|
||||||
|
default:
|
||||||
|
for (;;)
|
||||||
|
(void)0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename __T, typename __U, typename __V>
|
||||||
|
inline bool
|
||||||
|
ckd_mul(__T* __res, __U __a, __V __b)
|
||||||
|
{
|
||||||
|
static_assert(std::is_integral<__T>::value &&
|
||||||
|
std::is_integral<__U>::value &&
|
||||||
|
std::is_integral<__V>::value,
|
||||||
|
"non-integral types not allowed");
|
||||||
|
static_assert(!std::is_same<__T, bool>::value &&
|
||||||
|
!std::is_same<__U, bool>::value &&
|
||||||
|
!std::is_same<__V, bool>::value,
|
||||||
|
"checked booleans not supported");
|
||||||
|
static_assert(!std::is_same<__T, char>::value &&
|
||||||
|
!std::is_same<__U, char>::value &&
|
||||||
|
!std::is_same<__V, char>::value,
|
||||||
|
"unqualified char type is ambiguous");
|
||||||
|
__ckd_uintmax_t __x = __a;
|
||||||
|
__ckd_uintmax_t __y = __b;
|
||||||
|
if ((sizeof(__U) * 8 - std::is_signed<__U>::value) +
|
||||||
|
(sizeof(__V) * 8 - std::is_signed<__V>::value) <=
|
||||||
|
(sizeof(__T) * 8 - std::is_signed<__T>::value)) {
|
||||||
|
if (sizeof(__ckd_uintmax_t) > sizeof(__T) ||
|
||||||
|
std::is_signed<__T>::value) {
|
||||||
|
__ckd_intmax_t __z = __x * __y;
|
||||||
|
return __z != (*__res = __z);
|
||||||
|
} else if (!std::is_same<__T, __ckd_uintmax_t>::value) {
|
||||||
|
__ckd_uintmax_t __z = __x * __y;
|
||||||
|
*__res = __z;
|
||||||
|
return (
|
||||||
|
__z != static_cast<__T>(__z) ||
|
||||||
|
((std::is_signed<__U>::value || std::is_signed<__V>::value) &&
|
||||||
|
static_cast<__ckd_intmax_t>(__z) < 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (std::is_signed<__T>::value << 2 | //
|
||||||
|
std::is_signed<__U>::value << 1 | //
|
||||||
|
std::is_signed<__V>::value) {
|
||||||
|
case 0: { // u = u * u
|
||||||
|
__ckd_uintmax_t __z = __x * __y;
|
||||||
|
int __o = __x && __z / __x != __y;
|
||||||
|
*__res = __z;
|
||||||
|
return __o | (sizeof(__T) < sizeof(__z) &&
|
||||||
|
__z != static_cast<__ckd_uintmax_t>(*__res));
|
||||||
|
}
|
||||||
|
case 1: { // u = u * s
|
||||||
|
__ckd_uintmax_t __z = __x * __y;
|
||||||
|
int __o = __x && __z / __x != __y;
|
||||||
|
*__res = __z;
|
||||||
|
return (__o | ((static_cast<__ckd_intmax_t>(__y) < 0) & !!__x) |
|
||||||
|
(sizeof(__T) < sizeof(__z) &&
|
||||||
|
__z != static_cast<__ckd_uintmax_t>(*__res)));
|
||||||
|
}
|
||||||
|
case 2: { // u = s * u
|
||||||
|
__ckd_uintmax_t __z = __x * __y;
|
||||||
|
int __o = __x && __z / __x != __y;
|
||||||
|
*__res = __z;
|
||||||
|
return (__o | ((static_cast<__ckd_intmax_t>(__x) < 0) & !!__y) |
|
||||||
|
(sizeof(__T) < sizeof(__z) &&
|
||||||
|
__z != static_cast<__ckd_uintmax_t>(*__res)));
|
||||||
|
}
|
||||||
|
case 3: { // u = s * s
|
||||||
|
int __o = false;
|
||||||
|
if (static_cast<__ckd_intmax_t>(__x & __y) < 0) {
|
||||||
|
__x = 0 - __x;
|
||||||
|
__y = 0 - __y;
|
||||||
|
} else if (static_cast<__ckd_intmax_t>(__x ^ __y) < 0) {
|
||||||
|
__o = __x && __y;
|
||||||
|
}
|
||||||
|
__ckd_uintmax_t __z = __x * __y;
|
||||||
|
__o |= __x && __z / __x != __y;
|
||||||
|
*__res = __z;
|
||||||
|
return __o | (sizeof(__T) < sizeof(__z) &&
|
||||||
|
__z != static_cast<__ckd_uintmax_t>(*__res));
|
||||||
|
}
|
||||||
|
case 4: { // s = u * u
|
||||||
|
__ckd_uintmax_t __z = __x * __y;
|
||||||
|
int __o = __x && __z / __x != __y;
|
||||||
|
*__res = __z;
|
||||||
|
return (__o | (static_cast<__ckd_intmax_t>(__z) < 0) |
|
||||||
|
(sizeof(__T) < sizeof(__z) &&
|
||||||
|
__z != static_cast<__ckd_uintmax_t>(*__res)));
|
||||||
|
}
|
||||||
|
case 5: { // s = u * s
|
||||||
|
__ckd_uintmax_t __t = 0 - __y;
|
||||||
|
__t = static_cast<__ckd_intmax_t>(__t) < 0 ? __y : __t;
|
||||||
|
__ckd_uintmax_t __p = __t * __x;
|
||||||
|
int __o = __t && __p / __t != __x;
|
||||||
|
int __n = static_cast<__ckd_intmax_t>(__y) < 0;
|
||||||
|
__ckd_uintmax_t __z = __n ? 0 - __p : __p;
|
||||||
|
*__res = __z;
|
||||||
|
__ckd_uintmax_t __m = std::numeric_limits<__ckd_intmax_t>::max();
|
||||||
|
return (__o | (__p > __m + __n) |
|
||||||
|
(sizeof(__T) < sizeof(__z) &&
|
||||||
|
__z != static_cast<__ckd_uintmax_t>(*__res)));
|
||||||
|
}
|
||||||
|
case 6: { // s = s * u
|
||||||
|
__ckd_uintmax_t __t = 0 - __x;
|
||||||
|
__t = static_cast<__ckd_intmax_t>(__t) < 0 ? __x : __t;
|
||||||
|
__ckd_uintmax_t __p = __t * __y;
|
||||||
|
int __o = __t && __p / __t != __y;
|
||||||
|
int __n = static_cast<__ckd_intmax_t>(__x) < 0;
|
||||||
|
__ckd_uintmax_t __z = __n ? 0 - __p : __p;
|
||||||
|
*__res = __z;
|
||||||
|
__ckd_uintmax_t __m = std::numeric_limits<__ckd_intmax_t>::max();
|
||||||
|
return (__o | (__p > __m + __n) |
|
||||||
|
(sizeof(__T) < sizeof(__z) &&
|
||||||
|
__z != static_cast<__ckd_uintmax_t>(*__res)));
|
||||||
|
}
|
||||||
|
case 7: { // s = s * s
|
||||||
|
__ckd_uintmax_t __z = __x * __y;
|
||||||
|
*__res = __z;
|
||||||
|
return ((((static_cast<__ckd_intmax_t>(__y) < 0) &&
|
||||||
|
(static_cast<__ckd_intmax_t>(__x) ==
|
||||||
|
std::numeric_limits<__ckd_intmax_t>::min())) ||
|
||||||
|
(__y && ((static_cast<__ckd_intmax_t>(__z) /
|
||||||
|
static_cast<__ckd_intmax_t>(__y)) !=
|
||||||
|
static_cast<__ckd_intmax_t>(__x)))) |
|
||||||
|
(sizeof(__T) < sizeof(__z) &&
|
||||||
|
__z != static_cast<__ckd_uintmax_t>(*__res)));
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
for (;;)
|
||||||
|
(void)0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
|
||||||
|
|
||||||
|
#define ckd_add(res, a, b) __ckd_expr(add, (res), (a), (b))
|
||||||
|
#define ckd_sub(res, a, b) __ckd_expr(sub, (res), (a), (b))
|
||||||
|
#define ckd_mul(res, a, b) __ckd_expr(mul, (res), (a), (b))
|
||||||
|
|
||||||
|
#if defined(__GNUC__) || defined(__llvm__)
|
||||||
|
#define __ckd_inline \
|
||||||
|
extern __inline \
|
||||||
|
__attribute__((__gnu_inline__, __always_inline__, __artificial__))
|
||||||
|
#else
|
||||||
|
#define __ckd_inline static inline
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __ckd_have_int128
|
||||||
|
#define __ckd_generic_int128(x, y) \
|
||||||
|
, \
|
||||||
|
signed __int128 \
|
||||||
|
: x \
|
||||||
|
, unsigned __int128 : y
|
||||||
|
#else
|
||||||
|
#define __ckd_generic_int128(x, y)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define __ckd_sign(T) ((T)1 << (sizeof(T) * 8 - 1))
|
||||||
|
|
||||||
|
#define __ckd_is_signed(x) \
|
||||||
|
_Generic(x, \
|
||||||
|
signed char: 1, \
|
||||||
|
unsigned char: 0, \
|
||||||
|
signed short: 1, \
|
||||||
|
unsigned short: 0, \
|
||||||
|
signed int: 1, \
|
||||||
|
unsigned int: 0, \
|
||||||
|
signed long: 1, \
|
||||||
|
unsigned long: 0, \
|
||||||
|
signed long long: 1, \
|
||||||
|
unsigned long long: 0 __ckd_generic_int128(1, 0))
|
||||||
|
|
||||||
|
#define __ckd_expr(op, res, a, b) \
|
||||||
|
(_Generic(*res, \
|
||||||
|
signed char: __ckd_##op##_schar, \
|
||||||
|
unsigned char: __ckd_##op##_uchar, \
|
||||||
|
signed short: __ckd_##op##_sshort, \
|
||||||
|
unsigned short: __ckd_##op##_ushort, \
|
||||||
|
signed int: __ckd_##op##_sint, \
|
||||||
|
unsigned int: __ckd_##op##_uint, \
|
||||||
|
signed long: __ckd_##op##_slong, \
|
||||||
|
unsigned long: __ckd_##op##_ulong, \
|
||||||
|
signed long long: __ckd_##op##_slonger, \
|
||||||
|
unsigned long long: __ckd_##op##_ulonger __ckd_generic_int128( \
|
||||||
|
__ckd_##op##_sint128, __ckd_##op##_uint128))( \
|
||||||
|
res, a, b, __ckd_is_signed(a), __ckd_is_signed(b)))
|
||||||
|
|
||||||
|
#define __ckd_declare_add(S, T) \
|
||||||
|
__ckd_inline char S(void* __res, \
|
||||||
|
__ckd_uintmax_t __x, \
|
||||||
|
__ckd_uintmax_t __y, \
|
||||||
|
char __a_signed, \
|
||||||
|
char __b_signed) \
|
||||||
|
{ \
|
||||||
|
__ckd_uintmax_t __z = __x + __y; \
|
||||||
|
*(T*)__res = __z; \
|
||||||
|
char __truncated = 0; \
|
||||||
|
if (sizeof(T) < sizeof(__ckd_intmax_t)) { \
|
||||||
|
__truncated = __z != (__ckd_uintmax_t)(T)__z; \
|
||||||
|
} \
|
||||||
|
switch (__ckd_is_signed((T)0) << 2 | __a_signed << 1 | __b_signed) { \
|
||||||
|
case 0: /* u = u + u */ \
|
||||||
|
return __truncated | (__z < __x); \
|
||||||
|
case 1: /* u = u + s */ \
|
||||||
|
__y ^= __ckd_sign(__ckd_uintmax_t); \
|
||||||
|
return __truncated | \
|
||||||
|
((__ckd_intmax_t)((__z ^ __x) & (__z ^ __y)) < 0); \
|
||||||
|
case 2: /* u = s + u */ \
|
||||||
|
__x ^= __ckd_sign(__ckd_uintmax_t); \
|
||||||
|
return __truncated | \
|
||||||
|
((__ckd_intmax_t)((__z ^ __x) & (__z ^ __y)) < 0); \
|
||||||
|
case 3: /* u = s + s */ \
|
||||||
|
return __truncated | \
|
||||||
|
((__ckd_intmax_t)(((__z | __x) & __y) | \
|
||||||
|
((__z & __x) & ~__y)) < 0); \
|
||||||
|
case 4: /* s = u + u */ \
|
||||||
|
return __truncated | (__z < __x) | ((__ckd_intmax_t)__z < 0); \
|
||||||
|
case 5: /* s = u + s */ \
|
||||||
|
__y ^= __ckd_sign(__ckd_uintmax_t); \
|
||||||
|
return __truncated | (__x + __y < __y); \
|
||||||
|
case 6: /* s = s + u */ \
|
||||||
|
__x ^= __ckd_sign(__ckd_uintmax_t); \
|
||||||
|
return __truncated | (__x + __y < __x); \
|
||||||
|
case 7: /* s = s + s */ \
|
||||||
|
return __truncated | \
|
||||||
|
((__ckd_intmax_t)((__z ^ __x) & (__z ^ __y)) < 0); \
|
||||||
|
default: \
|
||||||
|
for (;;) \
|
||||||
|
(void)0; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
__ckd_declare_add(__ckd_add_schar,
|
||||||
|
signed char) __ckd_declare_add(__ckd_add_uchar, unsigned char)
|
||||||
|
__ckd_declare_add(__ckd_add_sshort, signed short) __ckd_declare_add(
|
||||||
|
__ckd_add_ushort,
|
||||||
|
unsigned short) __ckd_declare_add(__ckd_add_sint, signed int)
|
||||||
|
__ckd_declare_add(__ckd_add_uint, unsigned int) __ckd_declare_add(
|
||||||
|
__ckd_add_slong,
|
||||||
|
signed long) __ckd_declare_add(__ckd_add_ulong, unsigned long)
|
||||||
|
__ckd_declare_add(__ckd_add_slonger,
|
||||||
|
signed long long) __ckd_declare_add(__ckd_add_ulonger,
|
||||||
|
unsigned long long)
|
||||||
|
#ifdef __ckd_have_int128
|
||||||
|
__ckd_declare_add(__ckd_add_sint128,
|
||||||
|
signed __int128) __ckd_declare_add(__ckd_add_uint128,
|
||||||
|
unsigned __int128)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define __ckd_declare_sub(S, T) \
|
||||||
|
__ckd_inline char S(void* __res, \
|
||||||
|
__ckd_uintmax_t __x, \
|
||||||
|
__ckd_uintmax_t __y, \
|
||||||
|
char __a_signed, \
|
||||||
|
char __b_signed) \
|
||||||
|
{ \
|
||||||
|
__ckd_uintmax_t __z = __x - __y; \
|
||||||
|
*(T*)__res = __z; \
|
||||||
|
char __truncated = 0; \
|
||||||
|
if (sizeof(T) < sizeof(__ckd_intmax_t)) { \
|
||||||
|
__truncated = __z != (__ckd_uintmax_t)(T)__z; \
|
||||||
|
} \
|
||||||
|
switch (__ckd_is_signed((T)0) << 2 | __a_signed << 1 | __b_signed) { \
|
||||||
|
case 0: /* u = u - u */ \
|
||||||
|
return __truncated | (__x < __y); \
|
||||||
|
case 1: /* u = u - s */ \
|
||||||
|
__y ^= __ckd_sign(__ckd_uintmax_t); \
|
||||||
|
return __truncated | \
|
||||||
|
((__ckd_intmax_t)((__x ^ __y) & (__z ^ __x)) < 0); \
|
||||||
|
case 2: /* u = s - u */ \
|
||||||
|
return __truncated | (__y > __x) | ((__ckd_intmax_t)__x < 0); \
|
||||||
|
case 3: /* u = s - s */ \
|
||||||
|
return __truncated | \
|
||||||
|
((__ckd_intmax_t)(((__z & __x) & __y) | \
|
||||||
|
((__z | __x) & ~__y)) < 0); \
|
||||||
|
case 4: /* s = u - u */ \
|
||||||
|
return __truncated | \
|
||||||
|
((__x < __y) ^ ((__ckd_intmax_t)__z < 0)); \
|
||||||
|
case 5: /* s = u - s */ \
|
||||||
|
__y ^= __ckd_sign(__ckd_uintmax_t); \
|
||||||
|
return __truncated | (__x >= __y); \
|
||||||
|
case 6: /* s = s - u */ \
|
||||||
|
__x ^= __ckd_sign(__ckd_uintmax_t); \
|
||||||
|
return __truncated | (__x < __y); \
|
||||||
|
case 7: /* s = s - s */ \
|
||||||
|
return __truncated | \
|
||||||
|
((__ckd_intmax_t)((__x ^ __y) & (__z ^ __x)) < 0); \
|
||||||
|
default: \
|
||||||
|
for (;;) \
|
||||||
|
(void)0; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
__ckd_declare_sub(__ckd_sub_schar, signed char) __ckd_declare_sub(
|
||||||
|
__ckd_sub_uchar,
|
||||||
|
unsigned char) __ckd_declare_sub(__ckd_sub_sshort, signed short)
|
||||||
|
__ckd_declare_sub(__ckd_sub_ushort,
|
||||||
|
unsigned short) __ckd_declare_sub(__ckd_sub_sint,
|
||||||
|
signed int)
|
||||||
|
__ckd_declare_sub(__ckd_sub_uint, unsigned int) __ckd_declare_sub(
|
||||||
|
__ckd_sub_slong,
|
||||||
|
signed long) __ckd_declare_sub(__ckd_sub_ulong, unsigned long)
|
||||||
|
__ckd_declare_sub(__ckd_sub_slonger, signed long long)
|
||||||
|
__ckd_declare_sub(__ckd_sub_ulonger, unsigned long long)
|
||||||
|
#ifdef __ckd_have_int128
|
||||||
|
__ckd_declare_sub(__ckd_sub_sint128, signed __int128)
|
||||||
|
__ckd_declare_sub(__ckd_sub_uint128, unsigned __int128)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define __ckd_declare_mul(S, T) \
|
||||||
|
__ckd_inline char S(void* __res, \
|
||||||
|
__ckd_uintmax_t __x, \
|
||||||
|
__ckd_uintmax_t __y, \
|
||||||
|
char __a_signed, \
|
||||||
|
char __b_signed) \
|
||||||
|
{ \
|
||||||
|
switch (__ckd_is_signed((T)0) << 2 | __a_signed << 1 | __b_signed) { \
|
||||||
|
case 0: { /* u = u * u */ \
|
||||||
|
__ckd_uintmax_t __z = __x * __y; \
|
||||||
|
int __o = __x && __z / __x != __y; \
|
||||||
|
*(T*)__res = __z; \
|
||||||
|
return __o | (sizeof(T) < sizeof(__z) && \
|
||||||
|
__z != (__ckd_uintmax_t) * (T*)__res); \
|
||||||
|
} \
|
||||||
|
case 1: { /* u = u * s */ \
|
||||||
|
__ckd_uintmax_t __z = __x * __y; \
|
||||||
|
int __o = __x && __z / __x != __y; \
|
||||||
|
*(T*)__res = __z; \
|
||||||
|
return (__o | (((__ckd_intmax_t)__y < 0) & !!__x) | \
|
||||||
|
(sizeof(T) < sizeof(__z) && \
|
||||||
|
__z != (__ckd_uintmax_t) * (T*)__res)); \
|
||||||
|
} \
|
||||||
|
case 2: { /* u = s * u */ \
|
||||||
|
__ckd_uintmax_t __z = __x * __y; \
|
||||||
|
int __o = __x && __z / __x != __y; \
|
||||||
|
*(T*)__res = __z; \
|
||||||
|
return (__o | (((__ckd_intmax_t)__x < 0) & !!__y) | \
|
||||||
|
(sizeof(T) < sizeof(__z) && \
|
||||||
|
__z != (__ckd_uintmax_t) * (T*)__res)); \
|
||||||
|
} \
|
||||||
|
case 3: { /* u = s * s */ \
|
||||||
|
int __o = 0; \
|
||||||
|
if ((__ckd_intmax_t)(__x & __y) < 0) { \
|
||||||
|
__x = 0 - __x; \
|
||||||
|
__y = 0 - __y; \
|
||||||
|
} else if ((__ckd_intmax_t)(__x ^ __y) < 0) { \
|
||||||
|
__o = __x && __y; \
|
||||||
|
} \
|
||||||
|
__ckd_uintmax_t __z = __x * __y; \
|
||||||
|
__o |= __x && __z / __x != __y; \
|
||||||
|
*(T*)__res = __z; \
|
||||||
|
return __o | (sizeof(T) < sizeof(__z) && \
|
||||||
|
__z != (__ckd_uintmax_t) * (T*)__res); \
|
||||||
|
} \
|
||||||
|
case 4: { /* s = u * u */ \
|
||||||
|
__ckd_uintmax_t __z = __x * __y; \
|
||||||
|
int __o = __x && __z / __x != __y; \
|
||||||
|
*(T*)__res = __z; \
|
||||||
|
return (__o | ((__ckd_intmax_t)(__z) < 0) | \
|
||||||
|
(sizeof(T) < sizeof(__z) && \
|
||||||
|
__z != (__ckd_uintmax_t) * (T*)__res)); \
|
||||||
|
} \
|
||||||
|
case 5: { /* s = u * s */ \
|
||||||
|
__ckd_uintmax_t __t = 0 - __y; \
|
||||||
|
__t = (__ckd_intmax_t)(__t) < 0 ? __y : __t; \
|
||||||
|
__ckd_uintmax_t __p = __t * __x; \
|
||||||
|
int __o = __t && __p / __t != __x; \
|
||||||
|
int __n = (__ckd_intmax_t)__y < 0; \
|
||||||
|
__ckd_uintmax_t __z = __n ? 0 - __p : __p; \
|
||||||
|
*(T*)__res = __z; \
|
||||||
|
__ckd_uintmax_t __m = __ckd_sign(__ckd_uintmax_t) - 1; \
|
||||||
|
return (__o | (__p > __m + __n) | \
|
||||||
|
(sizeof(T) < sizeof(__z) && \
|
||||||
|
__z != (__ckd_uintmax_t) * (T*)__res)); \
|
||||||
|
} \
|
||||||
|
case 6: { /* s = s * u */ \
|
||||||
|
__ckd_uintmax_t __t = 0 - __x; \
|
||||||
|
__t = (__ckd_intmax_t)(__t) < 0 ? __x : __t; \
|
||||||
|
__ckd_uintmax_t __p = __t * __y; \
|
||||||
|
int __o = __t && __p / __t != __y; \
|
||||||
|
int __n = (__ckd_intmax_t)__x < 0; \
|
||||||
|
__ckd_uintmax_t __z = __n ? 0 - __p : __p; \
|
||||||
|
*(T*)__res = __z; \
|
||||||
|
__ckd_uintmax_t __m = __ckd_sign(__ckd_uintmax_t) - 1; \
|
||||||
|
return (__o | (__p > __m + __n) | \
|
||||||
|
(sizeof(T) < sizeof(__z) && \
|
||||||
|
__z != (__ckd_uintmax_t) * (T*)__res)); \
|
||||||
|
} \
|
||||||
|
case 7: { /* s = s * s */ \
|
||||||
|
__ckd_uintmax_t __z = __x * __y; \
|
||||||
|
*(T*)__res = __z; \
|
||||||
|
return ( \
|
||||||
|
((((__ckd_intmax_t)__y < 0) && \
|
||||||
|
(__x == __ckd_sign(__ckd_uintmax_t))) || \
|
||||||
|
(__y && (((__ckd_intmax_t)__z / (__ckd_intmax_t)__y) != \
|
||||||
|
(__ckd_intmax_t)__x))) | \
|
||||||
|
(sizeof(T) < sizeof(__z) && \
|
||||||
|
__z != (__ckd_uintmax_t) * (T*)__res)); \
|
||||||
|
} \
|
||||||
|
default: \
|
||||||
|
for (;;) \
|
||||||
|
(void)0; \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
__ckd_declare_mul(__ckd_mul_schar, signed char)
|
||||||
|
__ckd_declare_mul(__ckd_mul_uchar, unsigned char)
|
||||||
|
__ckd_declare_mul(
|
||||||
|
__ckd_mul_sshort,
|
||||||
|
signed short) __ckd_declare_mul(__ckd_mul_ushort,
|
||||||
|
unsigned short)
|
||||||
|
__ckd_declare_mul(__ckd_mul_sint, signed int)
|
||||||
|
__ckd_declare_mul(__ckd_mul_uint, unsigned int)
|
||||||
|
__ckd_declare_mul(__ckd_mul_slong,
|
||||||
|
signed long)
|
||||||
|
__ckd_declare_mul(__ckd_mul_ulong,
|
||||||
|
unsigned long)
|
||||||
|
__ckd_declare_mul(__ckd_mul_slonger,
|
||||||
|
signed long long)
|
||||||
|
__ckd_declare_mul(__ckd_mul_ulonger,
|
||||||
|
unsigned long long)
|
||||||
|
#ifdef __ckd_have_int128
|
||||||
|
__ckd_declare_mul(__ckd_mul_sint128,
|
||||||
|
signed __int128)
|
||||||
|
__ckd_declare_mul(__ckd_mul_uint128,
|
||||||
|
unsigned __int128)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#else
|
||||||
|
#pragma message "checked integer arithmetic unsupported in this environment"
|
||||||
|
|
||||||
|
#define ckd_add(res, x, y) (*(res) = (x) + (y), 0)
|
||||||
|
#define ckd_sub(res, x, y) (*(res) = (x) - (y), 0)
|
||||||
|
#define ckd_mul(res, x, y) (*(res) = (x) * (y), 0)
|
||||||
|
|
||||||
|
#endif /* GNU */
|
||||||
|
#endif /* stdckdint.h */
|
||||||
|
#endif /* JTCKDINT_H_ */
|
||||||
59
wpiutil/src/test/native/cpp/json_test.cpp
Normal file
59
wpiutil/src/test/native/cpp/json_test.cpp
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
// Copyright (c) FIRST and other WPILib contributors.
|
||||||
|
// Open Source Software; you can modify and/or share it under the terms of
|
||||||
|
// the WPILib BSD license file in the root directory of this project.
|
||||||
|
|
||||||
|
#include "wpi/util/json.hpp"
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
|
||||||
|
namespace wpi::util {
|
||||||
|
|
||||||
|
TEST(JsonTest, ParseMaxUint64) {
|
||||||
|
auto j = json::parse_or_throw("18446744073709551615");
|
||||||
|
EXPECT_TRUE(j.is_uint());
|
||||||
|
EXPECT_EQ(j.get_uint(), 18446744073709551615ull);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(JsonTest, MarshalMaxUint64) {
|
||||||
|
json j{18446744073709551615ull};
|
||||||
|
EXPECT_EQ(j.to_string(), "18446744073709551615");
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(JsonTest, AssignBool) {
|
||||||
|
json j;
|
||||||
|
j = true;
|
||||||
|
ASSERT_TRUE(j.is_bool());
|
||||||
|
EXPECT_TRUE(j.get_bool());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(JsonTest, AssignBoolToMap) {
|
||||||
|
json j;
|
||||||
|
j["key"] = true;
|
||||||
|
ASSERT_TRUE(j["key"].is_bool());
|
||||||
|
EXPECT_TRUE(j["key"].get_bool());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(JsonTest, AssignBoolToArray) {
|
||||||
|
json j;
|
||||||
|
j.emplace_back(true);
|
||||||
|
ASSERT_TRUE(j[0].is_bool());
|
||||||
|
EXPECT_TRUE(j[0].get_bool());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(JsonTest, BoolObject) {
|
||||||
|
json j = json::object("key", true);
|
||||||
|
ASSERT_TRUE(j["key"].is_bool());
|
||||||
|
EXPECT_TRUE(j["key"].get_bool());
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(JsonTest, BoolArray) {
|
||||||
|
json j = json::array(true, false, true);
|
||||||
|
ASSERT_TRUE(j[0].is_bool());
|
||||||
|
EXPECT_TRUE(j[0].get_bool());
|
||||||
|
ASSERT_TRUE(j[1].is_bool());
|
||||||
|
EXPECT_FALSE(j[1].get_bool());
|
||||||
|
ASSERT_TRUE(j[2].is_bool());
|
||||||
|
EXPECT_TRUE(j[2].get_bool());
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace wpi::util
|
||||||
Reference in New Issue
Block a user