mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-02 16:26:48 +00:00
680 lines
16 KiB
C++
680 lines
16 KiB
C++
#pragma once
|
|
|
|
#include <xrpl/basics/Number.h>
|
|
#include <xrpl/json/json_forwards.h>
|
|
|
|
#include <cstring>
|
|
#include <limits>
|
|
#include <map>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
/** \brief JSON (JavaScript Object Notation).
|
|
*/
|
|
namespace json {
|
|
|
|
/** \brief Type of the value held by a Value object.
|
|
*/
|
|
enum class ValueType {
|
|
Null = 0, ///< 'null' value
|
|
Int, ///< signed integer value
|
|
UInt, ///< unsigned integer value
|
|
Real, ///< double value
|
|
String, ///< UTF-8 string value
|
|
Boolean, ///< bool value
|
|
Array, ///< array value (ordered list)
|
|
Object ///< object value (collection of name/value pairs).
|
|
};
|
|
|
|
/** \brief Lightweight wrapper to tag static string.
|
|
*
|
|
* Value constructor and ValueType::Object member assignment takes advantage of the
|
|
* StaticString and avoid the cost of string duplication when storing the
|
|
* string or the member name.
|
|
*
|
|
* Example of usage:
|
|
* \code
|
|
* json::Value aValue( StaticString("some text") );
|
|
* json::Value object;
|
|
* static const StaticString code("code");
|
|
* object[code] = 1234;
|
|
* \endcode
|
|
*/
|
|
class StaticString
|
|
{
|
|
public:
|
|
constexpr explicit StaticString(char const* czString) : str_(czString)
|
|
{
|
|
}
|
|
|
|
constexpr
|
|
operator char const*() const
|
|
{
|
|
return str_;
|
|
}
|
|
|
|
[[nodiscard]] constexpr char const*
|
|
cStr() const
|
|
{
|
|
return str_;
|
|
}
|
|
|
|
private:
|
|
char const* str_;
|
|
};
|
|
|
|
inline bool
|
|
operator==(StaticString x, StaticString y)
|
|
{
|
|
return strcmp(x.cStr(), y.cStr()) == 0;
|
|
}
|
|
|
|
inline bool
|
|
operator!=(StaticString x, StaticString y)
|
|
{
|
|
return !(x == y);
|
|
}
|
|
|
|
inline bool
|
|
operator==(std::string const& x, StaticString y)
|
|
{
|
|
return strcmp(x.c_str(), y.cStr()) == 0;
|
|
}
|
|
|
|
inline bool
|
|
operator!=(std::string const& x, StaticString y)
|
|
{
|
|
return !(x == y);
|
|
}
|
|
|
|
inline bool
|
|
operator==(StaticString x, std::string const& y)
|
|
{
|
|
return y == x;
|
|
}
|
|
|
|
inline bool
|
|
operator!=(StaticString x, std::string const& y)
|
|
{
|
|
return !(y == x);
|
|
}
|
|
|
|
/** \brief Represents a <a HREF="http://www.json.org">JSON</a> value.
|
|
*
|
|
* This class is a discriminated union wrapper that can represent a:
|
|
* - signed integer [range: Value::kMinInt - Value::kMaxInt]
|
|
* - unsigned integer (range: 0 - Value::kMaxUInt)
|
|
* - double
|
|
* - UTF-8 string
|
|
* - boolean
|
|
* - 'null'
|
|
* - an ordered list of Value
|
|
* - collection of name/value pairs (javascript object)
|
|
*
|
|
* The type of the held value is represented by a #ValueType and
|
|
* can be obtained using type().
|
|
*
|
|
* values of an ValueType::Object or ValueType::Array can be accessed using operator[]()
|
|
* methods. Non const methods will automatically create the a ValueType::Null element
|
|
* if it does not exist.
|
|
* The sequence of an ValueType::Array will be automatically resize and initialized
|
|
* with ValueType::Null. resize() can be used to enlarge or truncate an ValueType::Array.
|
|
*
|
|
* The get() methods can be used to obtain a default value in the case the
|
|
* required element does not exist.
|
|
*
|
|
* It is possible to iterate over the list of a ValueType::Object values using
|
|
* the getMemberNames() method.
|
|
*/
|
|
class Value
|
|
{
|
|
friend class ValueIteratorBase;
|
|
|
|
public:
|
|
using Members = std::vector<std::string>;
|
|
using iterator = ValueIterator;
|
|
using const_iterator = ValueConstIterator;
|
|
using UInt = json::UInt;
|
|
using Int = json::Int;
|
|
using ArrayIndex = UInt;
|
|
|
|
static Value const kNull;
|
|
static constexpr Int kMinInt = std::numeric_limits<Int>::min();
|
|
static constexpr Int kMaxInt = std::numeric_limits<Int>::max();
|
|
static constexpr UInt kMaxUInt = std::numeric_limits<UInt>::max();
|
|
|
|
private:
|
|
class CZString
|
|
{
|
|
public:
|
|
enum class DuplicationPolicy { NoDuplication = 0, Duplicate, DuplicateOnCopy };
|
|
|
|
CZString(int index);
|
|
CZString(char const* cstr, DuplicationPolicy allocate);
|
|
CZString(CZString const& other);
|
|
~CZString();
|
|
CZString&
|
|
operator=(CZString const& other) = delete;
|
|
bool
|
|
operator<(CZString const& other) const;
|
|
bool
|
|
operator==(CZString const& other) const;
|
|
[[nodiscard]] int
|
|
index() const;
|
|
[[nodiscard]] char const*
|
|
cStr() const;
|
|
[[nodiscard]] bool
|
|
isStaticString() const;
|
|
|
|
private:
|
|
char const* cstr_;
|
|
int index_;
|
|
};
|
|
|
|
public:
|
|
using ObjectValues = std::map<CZString, Value>;
|
|
|
|
public:
|
|
/** \brief Create a default Value of the given type.
|
|
|
|
This is a very useful constructor.
|
|
To create an empty array, pass ValueType::Array.
|
|
To create an empty object, pass ValueType::Object.
|
|
Another Value can then be set to this one by assignment.
|
|
This is useful since clear() and resize() will not alter types.
|
|
|
|
Examples:
|
|
\code
|
|
json::Value null_value; // null
|
|
json::Value arr_value(json::ValueType::Array); // []
|
|
json::Value obj_value(json::ValueType::Object); // {}
|
|
\endcode
|
|
*/
|
|
Value(ValueType type = ValueType::Null);
|
|
Value(Int value);
|
|
Value(UInt value);
|
|
Value(double value);
|
|
Value(char const* value);
|
|
Value(xrpl::Number const& value);
|
|
/** \brief Constructs a value from a static string.
|
|
|
|
* Like other value string constructor but do not duplicate the string for
|
|
* internal storage. The given string must remain alive after the call to
|
|
this
|
|
* constructor.
|
|
* Example of usage:
|
|
* \code
|
|
* json::Value aValue( StaticString("some text") );
|
|
* \endcode
|
|
*/
|
|
Value(StaticString const& value);
|
|
Value(std::string const& value);
|
|
Value(bool value);
|
|
Value(Value const& other);
|
|
~Value();
|
|
|
|
Value&
|
|
operator=(Value const& other);
|
|
Value&
|
|
operator=(Value&& other);
|
|
|
|
Value(Value&& other) noexcept;
|
|
|
|
/// Swap values.
|
|
void
|
|
swap(Value& other) noexcept;
|
|
|
|
[[nodiscard]] ValueType
|
|
type() const;
|
|
|
|
[[nodiscard]] char const*
|
|
asCString() const;
|
|
/** Returns the unquoted string value. */
|
|
[[nodiscard]] std::string
|
|
asString() const;
|
|
[[nodiscard]] Int
|
|
asInt() const;
|
|
[[nodiscard]] UInt
|
|
asUInt() const;
|
|
[[nodiscard]] double
|
|
asDouble() const;
|
|
[[nodiscard]] bool
|
|
asBool() const;
|
|
|
|
/** Correct absolute value from int or unsigned int */
|
|
[[nodiscard]] UInt
|
|
asAbsUInt() const;
|
|
|
|
// TODO: What is the "empty()" method this docstring mentions?
|
|
/** isNull() tests to see if this field is null. Don't use this method to
|
|
test for emptiness: use empty(). */
|
|
[[nodiscard]] bool
|
|
isNull() const;
|
|
[[nodiscard]] bool
|
|
isBool() const;
|
|
[[nodiscard]] bool
|
|
isInt() const;
|
|
[[nodiscard]] bool
|
|
isUInt() const;
|
|
[[nodiscard]] bool
|
|
isIntegral() const;
|
|
[[nodiscard]] bool
|
|
isDouble() const;
|
|
[[nodiscard]] bool
|
|
isNumeric() const;
|
|
[[nodiscard]] bool
|
|
isString() const;
|
|
[[nodiscard]] bool
|
|
isArray() const;
|
|
[[nodiscard]] bool
|
|
isArrayOrNull() const;
|
|
[[nodiscard]] bool
|
|
isObject() const;
|
|
[[nodiscard]] bool
|
|
isObjectOrNull() const;
|
|
|
|
[[nodiscard]] bool
|
|
isConvertibleTo(ValueType other) const;
|
|
|
|
/// Number of values in array or object
|
|
[[nodiscard]] UInt
|
|
size() const;
|
|
|
|
/** Returns false if this is an empty array, empty object, empty string,
|
|
or null. */
|
|
explicit
|
|
operator bool() const;
|
|
|
|
/// Remove all object members and array elements.
|
|
/// \pre type() is ValueType::Array, ValueType::Object, or ValueType::Null
|
|
/// \post type() is unchanged
|
|
void
|
|
clear();
|
|
|
|
/// Access an array element (zero based index ).
|
|
/// If the array contains less than index element, then null value are
|
|
/// inserted in the array so that its size is index+1. (You may need to say
|
|
/// 'value[0u]' to get your compiler to distinguish
|
|
/// this from the operator[] which takes a string.)
|
|
Value&
|
|
operator[](UInt index);
|
|
/// Access an array element (zero based index )
|
|
/// (You may need to say 'value[0u]' to get your compiler to distinguish
|
|
/// this from the operator[] which takes a string.)
|
|
Value const&
|
|
operator[](UInt index) const;
|
|
/// If the array contains at least index+1 elements, returns the element
|
|
/// value, otherwise returns defaultValue.
|
|
[[nodiscard]] Value
|
|
get(UInt index, Value const& defaultValue) const;
|
|
/// Return true if index < size().
|
|
[[nodiscard]] bool
|
|
isValidIndex(UInt index) const;
|
|
/// \brief Append value to array at the end.
|
|
///
|
|
/// Equivalent to jsonvalue[jsonvalue.size()] = value;
|
|
Value&
|
|
append(Value const& value);
|
|
Value&
|
|
append(Value&& value);
|
|
|
|
/// Access an object value by name, create a null member if it does not
|
|
/// exist.
|
|
Value&
|
|
operator[](char const* key);
|
|
/// Access an object value by name, returns null if there is no member with
|
|
/// that name.
|
|
Value const&
|
|
operator[](char const* key) const;
|
|
/// Access an object value by name, create a null member if it does not
|
|
/// exist.
|
|
Value&
|
|
operator[](std::string const& key);
|
|
/// Access an object value by name, returns null if there is no member with
|
|
/// that name.
|
|
Value const&
|
|
operator[](std::string const& key) const;
|
|
/** \brief Access an object value by name, create a null member if it does
|
|
not exist.
|
|
|
|
* If the object as no entry for that name, then the member name used to
|
|
store
|
|
* the new entry is not duplicated.
|
|
* Example of use:
|
|
* \code
|
|
* json::Value object;
|
|
* static const StaticString code("code");
|
|
* object[code] = 1234;
|
|
* \endcode
|
|
*/
|
|
Value&
|
|
operator[](StaticString const& key);
|
|
Value const&
|
|
operator[](StaticString const& key) const;
|
|
|
|
/// Return the member named key if it exist, defaultValue otherwise.
|
|
Value
|
|
get(char const* key, Value const& defaultValue) const;
|
|
/// Return the member named key if it exist, defaultValue otherwise.
|
|
[[nodiscard]] Value
|
|
get(std::string const& key, Value const& defaultValue) const;
|
|
|
|
/// \brief Remove and return the named member.
|
|
///
|
|
/// Do nothing if it did not exist.
|
|
/// \return the removed Value, or null.
|
|
/// \pre type() is ValueType::Object or ValueType::Null
|
|
/// \post type() is unchanged
|
|
Value
|
|
removeMember(char const* key);
|
|
/// Same as removeMember(const char*)
|
|
Value
|
|
removeMember(std::string const& key);
|
|
|
|
/// Return true if the object has a member named key.
|
|
bool
|
|
isMember(char const* key) const;
|
|
/// Return true if the object has a member named key.
|
|
[[nodiscard]] bool
|
|
isMember(std::string const& key) const;
|
|
/// Return true if the object has a member named key.
|
|
[[nodiscard]] bool
|
|
isMember(StaticString const& key) const;
|
|
|
|
/// \brief Return a list of the member names.
|
|
///
|
|
/// If null, return an empty list.
|
|
/// \pre type() is ValueType::Object or ValueType::Null
|
|
/// \post if type() was ValueType::Null, it remains ValueType::Null
|
|
[[nodiscard]] Members
|
|
getMemberNames() const;
|
|
|
|
[[nodiscard]] std::string
|
|
toStyledString() const;
|
|
|
|
[[nodiscard]] const_iterator
|
|
begin() const;
|
|
[[nodiscard]] const_iterator
|
|
end() const;
|
|
|
|
iterator
|
|
begin();
|
|
iterator
|
|
end();
|
|
|
|
friend bool
|
|
operator==(Value const&, Value const&);
|
|
friend bool
|
|
operator<(Value const&, Value const&);
|
|
|
|
private:
|
|
Value&
|
|
resolveReference(char const* key, bool isStatic);
|
|
|
|
private:
|
|
union ValueHolder
|
|
{
|
|
Int intVal;
|
|
UInt uintVal;
|
|
double realVal;
|
|
bool boolVal;
|
|
char* stringVal;
|
|
ObjectValues* mapVal{nullptr};
|
|
} value_;
|
|
ValueType type_ : 8;
|
|
int allocated_ : 1 {}; // Notes: if declared as bool, bitfield is useless.
|
|
};
|
|
|
|
inline Value
|
|
toJson(xrpl::Number const& number)
|
|
{
|
|
return to_string(number);
|
|
}
|
|
|
|
bool
|
|
operator==(Value const&, Value const&);
|
|
|
|
inline bool
|
|
operator!=(Value const& x, Value const& y)
|
|
{
|
|
return !(x == y);
|
|
}
|
|
|
|
bool
|
|
operator<(Value const&, Value const&);
|
|
|
|
inline bool
|
|
operator<=(Value const& x, Value const& y)
|
|
{
|
|
return !(y < x);
|
|
}
|
|
|
|
inline bool
|
|
operator>(Value const& x, Value const& y)
|
|
{
|
|
return y < x;
|
|
}
|
|
|
|
inline bool
|
|
operator>=(Value const& x, Value const& y)
|
|
{
|
|
return !(x < y);
|
|
}
|
|
|
|
/** \brief Experimental do not use: Allocator to customize member name and
|
|
* string value memory management done by Value.
|
|
*
|
|
* - makeMemberName() and releaseMemberName() are called to respectively
|
|
* duplicate and free an json::ValueType::Object member name.
|
|
* - duplicateStringValue() and releaseStringValue() are called similarly to
|
|
* duplicate and free a json::ValueType::String value.
|
|
*/
|
|
class ValueAllocator
|
|
{
|
|
public:
|
|
static constexpr auto kUnknown = (unsigned)-1;
|
|
|
|
virtual ~ValueAllocator() = default;
|
|
|
|
virtual char*
|
|
makeMemberName(char const* memberName) = 0;
|
|
virtual void
|
|
releaseMemberName(char* memberName) = 0;
|
|
virtual char*
|
|
duplicateStringValue(char const* value, unsigned int length = kUnknown) = 0;
|
|
virtual void
|
|
releaseStringValue(char* value) = 0;
|
|
};
|
|
|
|
/** \brief base class for Value iterators.
|
|
*
|
|
*/
|
|
class ValueIteratorBase
|
|
{
|
|
public:
|
|
using size_t = unsigned int;
|
|
using difference_type = int;
|
|
using SelfType = ValueIteratorBase;
|
|
|
|
ValueIteratorBase();
|
|
|
|
explicit ValueIteratorBase(Value::ObjectValues::iterator const& current);
|
|
|
|
bool
|
|
operator==(SelfType const& other) const
|
|
{
|
|
return isEqual(other);
|
|
}
|
|
|
|
bool
|
|
operator!=(SelfType const& other) const
|
|
{
|
|
return !isEqual(other);
|
|
}
|
|
|
|
/// Return either the index or the member name of the referenced value as a
|
|
/// Value.
|
|
[[nodiscard]] Value
|
|
key() const;
|
|
|
|
/// Return the index of the referenced Value. -1 if it is not an ValueType::Array.
|
|
[[nodiscard]] UInt
|
|
index() const;
|
|
|
|
/// Return the member name of the referenced Value. "" if it is not an
|
|
/// ValueType::Object.
|
|
[[nodiscard]] char const*
|
|
memberName() const;
|
|
|
|
protected:
|
|
[[nodiscard]] Value&
|
|
deref() const;
|
|
|
|
void
|
|
increment();
|
|
|
|
void
|
|
decrement();
|
|
|
|
[[nodiscard]] difference_type
|
|
computeDistance(SelfType const& other) const;
|
|
|
|
[[nodiscard]] bool
|
|
isEqual(SelfType const& other) const;
|
|
|
|
void
|
|
copy(SelfType const& other);
|
|
|
|
private:
|
|
Value::ObjectValues::iterator current_;
|
|
// Indicates that iterator is for a null value.
|
|
bool isNull_;
|
|
};
|
|
|
|
/** \brief const iterator for object and array value.
|
|
*
|
|
*/
|
|
class ValueConstIterator : public ValueIteratorBase
|
|
{
|
|
friend class Value;
|
|
|
|
public:
|
|
using size_t = unsigned int;
|
|
using difference_type = int;
|
|
using reference = Value const&;
|
|
using pointer = Value const*;
|
|
using SelfType = ValueConstIterator;
|
|
|
|
ValueConstIterator() = default;
|
|
|
|
private:
|
|
/*! \internal Use by Value to create an iterator.
|
|
*/
|
|
explicit ValueConstIterator(Value::ObjectValues::iterator const& current);
|
|
|
|
public:
|
|
SelfType&
|
|
operator=(ValueIteratorBase const& other);
|
|
|
|
SelfType
|
|
operator++(int)
|
|
{
|
|
SelfType temp(*this);
|
|
++*this;
|
|
return temp;
|
|
}
|
|
|
|
SelfType
|
|
operator--(int)
|
|
{
|
|
SelfType temp(*this);
|
|
--*this;
|
|
return temp;
|
|
}
|
|
|
|
SelfType&
|
|
operator--()
|
|
{
|
|
decrement();
|
|
return *this;
|
|
}
|
|
|
|
SelfType&
|
|
operator++()
|
|
{
|
|
increment();
|
|
return *this;
|
|
}
|
|
|
|
reference
|
|
operator*() const
|
|
{
|
|
return deref();
|
|
}
|
|
};
|
|
|
|
/** \brief Iterator for object and array value.
|
|
*/
|
|
class ValueIterator : public ValueIteratorBase
|
|
{
|
|
friend class Value;
|
|
|
|
public:
|
|
using size_t = unsigned int;
|
|
using difference_type = int;
|
|
using reference = Value&;
|
|
using pointer = Value*;
|
|
using SelfType = ValueIterator;
|
|
|
|
ValueIterator() = default;
|
|
ValueIterator(ValueConstIterator const& other);
|
|
ValueIterator(ValueIterator const& other);
|
|
|
|
private:
|
|
/*! \internal Use by Value to create an iterator.
|
|
*/
|
|
explicit ValueIterator(Value::ObjectValues::iterator const& current);
|
|
|
|
public:
|
|
SelfType&
|
|
operator=(SelfType const& other);
|
|
|
|
SelfType
|
|
operator++(int)
|
|
{
|
|
SelfType const temp(*this);
|
|
++*this;
|
|
return temp;
|
|
}
|
|
|
|
SelfType
|
|
operator--(int)
|
|
{
|
|
SelfType const temp(*this);
|
|
--*this;
|
|
return temp;
|
|
}
|
|
|
|
SelfType&
|
|
operator--()
|
|
{
|
|
decrement();
|
|
return *this;
|
|
}
|
|
|
|
SelfType&
|
|
operator++()
|
|
{
|
|
increment();
|
|
return *this;
|
|
}
|
|
|
|
reference
|
|
operator*() const
|
|
{
|
|
return deref();
|
|
}
|
|
};
|
|
|
|
} // namespace json
|