Last active
September 29, 2022 15:08
-
-
Save dcousens/800cb1d367d203edf37d4198d24800b5 to your computer and use it in GitHub Desktop.
Naive JSON string serialisation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.test.actual | |
test |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{"apples":23,"bananas":-54,"pears":22,"other":{"cocoa":15.54},"lettuce":null,"celery":"yes","vegetables":"probably","icecream":"quite likely","empty":false,"array":[1,2,3,281474976710655,9007199254740996,9007199254740996,9007199254740996]} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{"apples":23,"bananas":-54,"pears":22,"other":{"cocoa":15.54},"lettuce":null,"vegetables":"probably","icecream":"quite likely","empty":false,"array":[1,2,3]} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// MIT License | |
// | |
// Copyright (c) 2022 Daniel Cousens | |
// | |
// Permission is hereby granted, free of charge, to any person obtaining a copy | |
// of this software and associated documentation files (the "Software"), to deal | |
// in the Software without restriction, including without limitation the rights | |
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
// copies of the Software, and to permit persons to whom the Software is | |
// furnished to do so, subject to the following conditions: | |
// | |
// The above copyright notice and this permission notice shall be included in all | |
// copies or substantial portions of the Software. | |
// | |
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | |
// SOFTWARE. | |
#pragma once | |
#include <array> | |
#include <cstdio> // snprintf | |
#include <cmath> | |
#include <initializer_list> | |
#include <string> | |
namespace json { | |
struct raw_t { | |
std::string const value; | |
}; | |
struct value_t { | |
std::string value; | |
value_t () {} | |
value_t (raw_t const x): value(x.value) {} | |
value_t (std::string const x) { | |
auto output = std::string("\""); | |
output.append(x); | |
output.push_back('"'); | |
value = std::move(output); | |
} | |
value_t (char const* x) { | |
auto output = std::string("\""); | |
output.append(x); | |
output.push_back('"'); | |
value = std::move(output); | |
} | |
value_t (bool const x) : value(x ? "true" : "false") {} | |
value_t (uint8_t const x) : value(std::to_string(x)) {} | |
value_t (uint16_t const x) : value(std::to_string(x)) {} | |
value_t (uint32_t const x) : value(std::to_string(x)) {} | |
value_t (int8_t const x) : value(std::to_string(x)) {} | |
value_t (int16_t const x) : value(std::to_string(x)) {} | |
value_t (int32_t const x) : value(std::to_string(x)) {} | |
}; | |
struct pair_t { | |
std::string const left; | |
value_t const right; | |
}; | |
auto const undefined = raw_t{ "undefined" }; | |
auto const null = raw_t{ "null" }; | |
inline bool operator== (value_t const& a, value_t const& b) { | |
return a.value == b.value; | |
} | |
inline bool operator== (pair_t const& a, pair_t const& b) { | |
return a.left == b.left and a.right == b.right; | |
} | |
inline std::string stringify (value_t const& x) { | |
return x.value; | |
} | |
template <typename R = std::initializer_list<value_t>> | |
inline value_t array (R const values) { | |
auto output = std::string("["); | |
auto first = true; | |
for (auto const& x : values) { | |
if (not first) output.push_back(','); | |
first = false; | |
output.append(stringify(x)); | |
} | |
output.push_back(']'); | |
return raw_t{ std::move(output) }; | |
} | |
template <typename R = std::initializer_list<pair_t>> | |
inline value_t object (R const pairs) { | |
auto output = std::string("{"); | |
auto first = true; | |
for (auto const& pair : pairs) { | |
if (pair.right == undefined) continue; | |
if (not first) output.push_back(','); | |
first = false; | |
output.push_back('"'); | |
output.append(pair.left); | |
output.push_back('"'); | |
output.push_back(':'); | |
output.append(stringify(pair.right)); | |
} | |
output.push_back('}'); | |
return raw_t{ std::move(output) }; | |
} | |
inline value_t boolean (bool const x) { return value_t(x); } | |
inline value_t number (uint8_t const x) { return value_t(x); } | |
inline value_t number (uint16_t const x) { return value_t(x); } | |
inline value_t number (uint32_t const x) { return value_t(x); } | |
inline value_t number (int8_t const x) { return value_t(x); } | |
inline value_t number (int16_t const x) { return value_t(x); } | |
inline value_t number (int32_t const x) { return value_t(x); } | |
inline value_t string (const char* const x) { return value_t(x); } | |
inline value_t string (std::string const x) { return value_t(x); } | |
template <size_t N> | |
inline value_t number (double const x) { | |
if (not std::isfinite(x)) return null; | |
if (N == 0) return raw_t{ std::to_string(int64_t(x)) }; | |
static_assert(N <= 4, "Unsupported"); | |
auto b = std::array<char, 14 + N>{}; | |
auto const w = snprintf(b.data(), b.size(), | |
N == 1 ? "%.1f" : | |
N == 2 ? "%.2f" : | |
N == 3 ? "%.3f" : | |
"%.4f", x); | |
if (w < 0 or w >= sizeof(b)) return null; | |
return raw_t{ std::string(b.data(), b.data() + w) }; | |
} | |
inline pair_t pair (pair_t const& x) { | |
return x; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
.PHONY: run-test | |
run-test: test | |
./test | jq | |
./test > .test.actual | |
cmp .test.actual .test.expected | |
test: test.cpp json.hpp | |
clang++ test.cpp -o test |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <array> | |
#include <vector> | |
#include "json.hpp" | |
int main () { | |
std::cout << json::stringify(json::object({ | |
{ "apples", 23 }, | |
{ "bananas", -54 }, | |
{ "pears", json::number<0>(22.064) }, | |
{ "other", json::object({ | |
{ "cacao", true ? json::undefined : json::number(10) }, | |
{ "cocoa", json::number<2>(15.543) }, | |
}) }, | |
{ "lettuce", json::null }, | |
{ "celery", json::raw_t{ "\"yes\"" } }, | |
{ "vegetables", "probably" }, | |
{ "icecream", json::string("quite likely") }, | |
// { "when", json::string(__DATE__ ", " __TIME__) }, | |
{ "empty", false }, | |
{ "array", json::array({ | |
1u, | |
2, | |
json::number<0>(3lu), | |
json::number(4), | |
json::number<0>(281474976710655), | |
json::number<0>(9007199254740995), // rounds to ...996 | |
json::number<0>(9007199254740995.0), // rounds to ...996 | |
json::number<0>(9007199254740997), // rounds to ...996 | |
}) }, | |
})) << std::endl; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment