PiPedal 1.2.33 initial commit

This commit is contained in:
Robin Davies
2024-08-08 12:53:02 -04:00
parent 0e378997a5
commit a3847c8184
255 changed files with 22008 additions and 1791 deletions
+550
View File
@@ -0,0 +1,550 @@
/*
* MIT License
*
* Copyright (c) 2023 Robin E. R. Davies
*
* 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 <vector>
#include <variant>
#include <map>
#include <string>
#include <stdexcept>
#include <utility>
#include "json.hpp"
namespace pipedal
{
class json_null
{
public:
static json_null instance;
bool operator==(const json_null &other) const { return true; }
bool operator!=(const json_null &other) const { return (!((*this) == other)); }
private:
int value = 0;
};
class json_object;
class json_array;
class json_variant
: public JsonSerializable
{
public:
enum class ContentType
{
Null,
Bool,
Number,
String,
Object,
Array
};
using object_ptr = std::shared_ptr<json_object>;
using array_ptr = std::shared_ptr<json_array>;
private:
public:
~json_variant();
json_variant();
json_variant(json_variant &&);
json_variant(const json_variant &);
json_variant(json_null value);
json_variant(bool value);
json_variant(double value);
json_variant(const std::string &value);
json_variant(std::shared_ptr<json_object> &&value);
json_variant(const std::shared_ptr<json_object> &value);
json_variant(std::shared_ptr<json_array> &&value);
json_variant(const std::shared_ptr<json_array> &value);
json_variant(json_array &&array);
json_variant(json_object &&object);
json_variant(const char*sz);
json_variant(const void*) = delete; // do NOT allow implicit conversion of pointers to bool
json_variant &operator=(json_variant &&value);
json_variant &operator=(const json_variant &value);
json_variant &operator=(bool value);
json_variant &operator=(double value);
json_variant &operator=(const std::string &value);
json_variant &operator=(std::string &&value);
json_variant &operator=(json_object &&value);
json_variant &operator=(json_array &&value);
json_variant &operator=(const char*sz) { return (*this) = std::string(sz); }
json_variant &operator=(void*) = delete; // do NOT allow implicit conversion of pointers to bool
void require_type(ContentType content_type) const
{
if (this->content_type != content_type)
{
throw std::logic_error("Content type is not valid.");
}
}
bool is_null() const { return content_type == ContentType::Null; }
bool is_bool() const { return content_type == ContentType::Bool; }
bool is_number() const { return content_type == ContentType::Number; }
bool is_string() const { return content_type == ContentType::String; }
bool is_object() const { return content_type == ContentType::Object; }
bool is_array() const { return content_type == ContentType::Array; }
const json_null &as_null() const
{
require_type(ContentType::Bool);
return json_null::instance;
}
json_null &as_null()
{
require_type(ContentType::Null);
return json_null::instance;
}
bool as_bool() const
{
require_type(ContentType::Bool);
return content.bool_value;
}
bool &as_bool()
{
require_type(ContentType::Bool);
return content.bool_value;
}
double as_number() const
{
require_type(ContentType::Number);
return content.double_value;
}
double &as_number()
{
require_type(ContentType::Number);
return content.double_value;
}
const std::string &as_string() const;
std::string &as_string();
const std::shared_ptr<json_object> &as_object() const;
std::shared_ptr<json_object> &as_object();
const std::shared_ptr<json_array> &as_array() const;
std::shared_ptr<json_array> &as_array();
template <typename U>
U &as() { static_assert("Invalid type."); }
// convenience methods for object and array manipulation.
static json_variant make_object();
static json_variant make_array();
void resize(size_t size);
size_t size() const;
bool contains(const std::string &index) const;
json_variant &at(size_t index);
const json_variant &at(size_t index) const;
json_variant &operator[](size_t index);
const json_variant &operator[](size_t index) const;
json_variant &operator[](const std::string &index);
const json_variant &operator[](const std::string &index) const;
bool operator==(const json_variant &other) const;
bool operator!=(const json_variant &other) const;
std::string to_string() const;
private:
void free();
void write_double_value(json_writer &writer, double value) const;
void write_float_value(json_writer &writer, double value) const;
virtual void read_json(json_reader &reader);
virtual void write_json(json_writer &writer) const;
static constexpr size_t stringSize = sizeof(std::string);
static constexpr size_t objectSize = sizeof(std::shared_ptr<json_variant>);
static constexpr size_t memSize = stringSize > objectSize ? stringSize : objectSize;
union Content
{
bool bool_value;
double double_value;
float float_value;
int32_t int32_value;
uint8_t mem[memSize];
};
ContentType content_type = ContentType::Null;
Content content;
std::string &memString();
object_ptr &memObject();
array_ptr &memArray();
const std::string &memString() const;
const object_ptr &memObject() const;
const array_ptr &memArray() const;
};
class json_array : public JsonSerializable
{
private:
json_array(const json_array&) { } // deleted.
public:
using ptr = std::shared_ptr<json_array>;
json_array() { ++allocation_count_; }
json_array(json_array&&other);
~json_array() { --allocation_count_; }
json_variant &at(size_t index);
const json_variant &at(size_t index) const;
json_variant &operator[](size_t index);
const json_variant &operator[](size_t &index) const;
void resize(size_t size) { values.resize(size); }
size_t size() const { return values.size(); }
void push_back(json_variant &&value) { values.push_back(std::move(value)); }
template <typename U>
void push_back(U &&value) { values.push_back(value); }
void push_back(double value) { values.push_back(json_variant{value}); }
void push_back(const std::string &value) { values.push_back(json_variant{value}); }
void push_back(bool value) { values.push_back(json_variant{value}); }
void push_back(const std::shared_ptr<json_array> &value) { values.push_back(json_variant(value)); }
void push_back(const std::shared_ptr<json_object> &value) { values.push_back(json_variant(value)); }
bool operator==(const json_array &other) const;
bool operator!=(const json_array &other) const { return (!((*this) == other)); }
// Strictly for testing purposes. Not thread-safe.
static int64_t allocation_count()
{
return allocation_count_;
}
using iterator = std::vector<json_variant>::iterator;
using const_iterator = std::vector<json_variant>::const_iterator;
iterator begin() { return values.begin(); }
iterator end() { return values.end(); }
const_iterator begin() const { return values.begin(); }
const_iterator end() const { return values.end(); }
private:
static int64_t allocation_count_; // strictly for testing purposes. not thread safe.
virtual void read_json(json_reader &reader);
virtual void write_json(json_writer &writer) const;
void check_index(size_t size) const;
std::vector<json_variant> values;
};
class json_object : public JsonSerializable
{
private:
json_object(const json_object&) { } // deleted.
public:
using ptr = std::shared_ptr<json_object>;
json_object() { ++ allocation_count_;}
json_object(json_object&&other);
~json_object() { --allocation_count_;}
size_t size() const { return values.size(); }
json_variant &at(const std::string &index);
const json_variant &at(const std::string &index) const;
json_variant &operator[](const std::string &index);
const json_variant &operator[](const std::string &index) const;
bool operator==(const json_object &other) const;
bool operator!=(const json_object &other) const { return (!((*this) == other)); }
bool contains(const std::string &index) const;
using values_t = std::vector< std::pair<std::string, json_variant> >;
using iterator = values_t::iterator;
using const_iterator = values_t::const_iterator;
iterator begin() { return values.begin(); }
iterator end() { return values.end(); }
const_iterator begin() const { return values.begin(); }
const_iterator end() const { return values.end(); }
iterator find(const std::string& key);
const_iterator find(const std::string& key) const;
// strictly for testing purposes. Not thread-safe.
static int64_t allocation_count()
{
return allocation_count_;
}
private:
virtual void read_json(json_reader &reader);
virtual void write_json(json_writer &writer) const;
static int64_t allocation_count_;
values_t values;
};
////////////////////////////////////////////////
inline std::string &json_variant::memString() { return *(std::string *)content.mem; }
inline const std::string &json_variant::memString() const { return *(const std::string *)content.mem; }
template <>
inline json_null &json_variant::as<json_null>() { return as_null(); }
template <>
inline bool &json_variant::as<bool>() { return as_bool(); }
template <>
inline double &json_variant::as<double>() { return as_number(); }
template <>
inline std::string &json_variant::as<std::string>() { return as_string(); }
template <>
inline std::shared_ptr<json_object> &json_variant::as<std::shared_ptr<json_object>>() { return as_object(); }
template <>
inline std::shared_ptr<json_array> &json_variant::as<std::shared_ptr<json_array>>() { return as_array(); }
template <>
inline json_variant &json_variant::as<json_variant>() { return *this; }
inline json_variant::object_ptr &json_variant::memObject()
{
return *(object_ptr *)content.mem;
}
inline json_variant::array_ptr &json_variant::memArray()
{
return *(array_ptr *)content.mem;
}
inline const json_variant::object_ptr &json_variant::memObject() const
{
return *(const object_ptr *)content.mem;
}
inline const json_variant::array_ptr &json_variant::memArray() const
{
return *(const array_ptr *)content.mem;
}
inline json_variant::json_variant(json_array &&array)
{
this->content_type = ContentType::Null;
new (content.mem) std::shared_ptr<json_array>{new json_array(std::move(array))};
this->content_type = ContentType::Array;
}
inline json_variant::json_variant(json_object &&object)
{
this->content_type = ContentType::Null;
new (content.mem) std::shared_ptr<json_object>{new json_object(std::move(object))};
this->content_type = ContentType::Object;
}
inline json_variant::json_variant(const std::string &value)
{
this->content_type = ContentType::Null;
new (content.mem) std::string(value); // placement new.
content_type = ContentType::String;
}
inline json_variant::json_variant(std::shared_ptr<json_object> &&value)
{
this->content_type = ContentType::Null;
new (content.mem) std::shared_ptr<json_object>(std::move(value)); // placement new.
content_type = ContentType::Object;
}
inline json_variant::json_variant(const std::shared_ptr<json_object> &value)
{
// don't deep copy!
std::shared_ptr<json_object> t = const_cast<std::shared_ptr<json_object> &>(value);
this->content_type = ContentType::Null;
new (content.mem) std::shared_ptr<json_object>(t); // placement new.
content_type = ContentType::Object;
}
inline json_variant::json_variant(const std::shared_ptr<json_array> &value)
{
// Make sure we don't deep copy!
std::shared_ptr<json_array> t = const_cast<std::shared_ptr<json_array> &>(value);
this->content_type = ContentType::Null;
new (content.mem) std::shared_ptr<json_array>(t); // placement new.
content_type = ContentType::Array;
}
inline json_variant::json_variant(array_ptr &&value)
{
this->content_type = ContentType::Null;
new (content.mem) std::shared_ptr<json_array>(std::move(value)); // placement new.
content_type = ContentType::Array;
}
inline json_variant::json_variant()
{
content_type = ContentType::Null;
}
inline json_variant::json_variant(json_null value)
{
content_type = ContentType::Null;
}
inline json_variant::json_variant(bool value)
{
content_type = ContentType::Bool;
content.bool_value = value;
}
inline json_variant::json_variant(double value)
{
content_type = ContentType::Number;
content.double_value = value;
}
inline std::string &json_variant::as_string()
{
require_type(ContentType::String);
return memString();
}
inline const std::string &json_variant::as_string() const
{
require_type(ContentType::String);
return memString();
}
inline const json_variant::object_ptr &json_variant::as_object() const
{
require_type(ContentType::Object);
return memObject();
}
inline json_variant::object_ptr &json_variant::as_object()
{
require_type(ContentType::Object);
return memObject();
}
inline const json_variant::array_ptr &json_variant::as_array() const
{
require_type(ContentType::Array);
return memArray();
}
inline json_variant::array_ptr &json_variant::as_array()
{
require_type(ContentType::Array);
return memArray();
}
inline /*static*/ json_variant json_variant::make_object()
{
return json_variant{std::make_shared<json_object>()};
};
inline /*static */ json_variant json_variant::make_array()
{
return json_variant{std::make_shared<json_array>()};
};
inline void json_variant::resize(size_t size)
{
as_array()->resize(size);
}
inline json_variant &json_variant::at(size_t index)
{
return as_array()->at(index);
}
inline const json_variant &json_variant::at(size_t index) const
{
return as_array()->at(index);
}
inline json_variant &json_variant::operator[](size_t index)
{
return as_array()->at(index);
}
inline const json_variant &json_variant::operator[](size_t index) const
{
return as_array()->at(index);
}
inline const json_variant &json_variant::operator[](const std::string &index) const
{
return (*as_object())[index];
}
inline json_variant &json_variant::operator[](const std::string &index)
{
return (*as_object())[index];
}
inline const json_variant &json_array::operator[](size_t &index) const
{
check_index(index);
return values[index];
}
inline json_variant &json_array::operator[](size_t index)
{
return at(index);
}
inline void json_array::check_index(size_t size) const
{
if (size >= values.size())
{
throw std::out_of_range("index out of range.");
}
}
inline bool json_variant::operator!=(const json_variant &other) const
{
return !(*this == other);
}
// Holds a string but is json_read and json_written as an unqoted json object.
class raw_json_string: public JsonSerializable {
public:
raw_json_string() { }
raw_json_string(const std::string &value) : value(value) {}
const std::string& as_string() const { return value; }
void Set(const std::string&value) { this->value = value; }
private:
virtual void write_json(json_writer &writer) const {
writer.write_raw(value.c_str());
}
virtual void read_json(json_reader &reader) {
throw std::logic_error("Not implemented.");
}
std::string value;
};
} // namespace pipedal