mirror of
https://github.com/pocoproject/poco.git
synced 2024-12-12 18:20:26 +01:00
603 lines
12 KiB
C++
603 lines
12 KiB
C++
//
|
|
// Array.h
|
|
//
|
|
// Library: JSON
|
|
// Package: JSON
|
|
// Module: Array
|
|
//
|
|
// Definition of the Array class.
|
|
//
|
|
// Copyright (c) 2012, Applied Informatics Software Engineering GmbH.
|
|
// and Contributors.
|
|
//
|
|
// SPDX-License-Identifier: BSL-1.0
|
|
//
|
|
|
|
|
|
#ifndef JSON_Array_INCLUDED
|
|
#define JSON_Array_INCLUDED
|
|
|
|
|
|
#include "Poco/JSON/JSON.h"
|
|
#include "Poco/SharedPtr.h"
|
|
#include "Poco/Dynamic/Var.h"
|
|
#include <vector>
|
|
#include <sstream>
|
|
|
|
|
|
namespace Poco {
|
|
|
|
namespace JSON {
|
|
|
|
class JSON_API Array;
|
|
|
|
}
|
|
|
|
|
|
#if defined(POCO_OS_FAMILY_WINDOWS)
|
|
// Explicitly instantiated shared pointer in JSON library
|
|
extern template class Poco::SharedPtr<Poco::JSON::Array>;
|
|
#else
|
|
// Explicitly instantiated shared pointer in JSON library
|
|
extern template class JSON_API Poco::SharedPtr<Poco::JSON::Array>;
|
|
#endif
|
|
|
|
namespace JSON {
|
|
|
|
class Object;
|
|
|
|
|
|
class JSON_API Array
|
|
/// Represents a JSON array. Array provides a representation
|
|
/// based on shared pointers and optimized for performance. It is possible to
|
|
/// convert Array to Poco::Dynamic::Array. Conversion requires copying and therefore
|
|
/// has performance penalty; the benefit is in improved syntax, eg:
|
|
///
|
|
/// // use pointers to avoid copying
|
|
/// using namespace Poco::JSON;
|
|
/// std::string json = "[ {\"test\" : 0}, { \"test1\" : [1, 2, 3], \"test2\" : 4 } ]";
|
|
/// Parser parser;
|
|
/// Var result = parser.parse(json);
|
|
/// Array::Ptr arr = result.extract<Array::Ptr>();
|
|
/// Object::Ptr object = arr->getObject(0); // object == {\"test\" : 0}
|
|
/// int i = object->getElement<int>("test"); // i == 0;
|
|
/// Object::Ptr subObject = arr->getObject(1); // subObject == {\"test\" : 0}
|
|
/// Array subArr::Ptr = subObject->getArray("test1"); // subArr == [1, 2, 3]
|
|
/// i = result = subArr->get(0); // i == 1;
|
|
///
|
|
/// // copy/convert to Poco::Dynamic::Array
|
|
/// Poco::Dynamic::Array da = *arr;
|
|
/// i = da[0]["test"]; // i == 0
|
|
/// i = da[1]["test1"][1]; // i == 2
|
|
/// i = da[1]["test2"]; // i == 4
|
|
/// ----
|
|
{
|
|
public:
|
|
using ValueVec = std::vector<Dynamic::Var>;
|
|
using Iterator = std::vector<Dynamic::Var>::iterator;
|
|
using ConstIterator = std::vector<Dynamic::Var>::const_iterator;
|
|
using Ptr = SharedPtr<Array>;
|
|
|
|
Array(int options = 0);
|
|
/// Creates an empty Array.
|
|
///
|
|
/// If JSON_ESCAPE_UNICODE is specified, when the object is
|
|
/// stringified, all unicode characters will be escaped in the
|
|
/// resulting string.
|
|
|
|
Array(const Array& copy);
|
|
/// Creates an Array by copying another one.
|
|
|
|
Array(Array&& other) noexcept;
|
|
/// Move constructor
|
|
|
|
Array& operator = (const Array& other);
|
|
/// Assignment operator.
|
|
|
|
Array& operator = (Array&& other) noexcept;
|
|
/// Move assignment operator.
|
|
|
|
~Array();
|
|
/// Destroys the Array.
|
|
|
|
void setEscapeUnicode(bool escape = true);
|
|
/// Sets the flag for escaping unicode.
|
|
|
|
bool getEscapeUnicode() const;
|
|
/// Returns the flag for escaping unicode.
|
|
|
|
void setLowercaseHex(bool lowercaseHex);
|
|
/// Sets the flag for using lowercase hex numbers
|
|
|
|
bool getLowercaseHex() const;
|
|
/// Returns the flag for using lowercase hex numbers
|
|
|
|
ValueVec::const_iterator begin() const;
|
|
/// Returns the begin iterator for values.
|
|
|
|
ValueVec::const_iterator end() const;
|
|
/// Returns the end iterator for values.
|
|
|
|
Dynamic::Var get(unsigned int index) const;
|
|
/// Retrieves the element at the given index.
|
|
/// Will return an empty value when the element doesn't exist.
|
|
|
|
Array::Ptr getArray(unsigned int index) const;
|
|
/// Retrieves an array. When the element is not
|
|
/// an Array or doesn't exist, an empty SharedPtr is returned.
|
|
|
|
template<typename T>
|
|
T getElement(unsigned int index) const
|
|
/// Retrieves an element and tries to convert it to the
|
|
/// template type. The convert<T> method of
|
|
/// Dynamic is called which can also throw
|
|
/// exceptions for invalid values.
|
|
/// Note: This will not work for an array or an object.
|
|
{
|
|
Dynamic::Var value = get(index);
|
|
return value.convert<T>();
|
|
}
|
|
|
|
SharedPtr<Object> getObject(unsigned int index) const;
|
|
/// Retrieves an object. When the element is not
|
|
/// an object or doesn't exist, an empty SharedPtr is returned.
|
|
|
|
std::size_t size() const;
|
|
/// Returns the size of the array.
|
|
|
|
bool empty() const;
|
|
/// Returns true if the array is empty, false otherwise.
|
|
|
|
bool isArray(unsigned int index) const;
|
|
/// Returns true when the element is an array.
|
|
|
|
bool isArray(const Dynamic::Var& value) const;
|
|
/// Returns true when the element is an array.
|
|
|
|
bool isArray(ConstIterator& value) const;
|
|
/// Returns true when the element is an array.
|
|
|
|
bool isNull(unsigned int index) const;
|
|
/// Returns true when the element is null or
|
|
/// when the element doesn't exist.
|
|
|
|
bool isObject(unsigned int index) const;
|
|
/// Returns true when the element is an object.
|
|
|
|
bool isObject(const Dynamic::Var& value) const;
|
|
/// Returns true when the element is an object.
|
|
|
|
bool isObject(ConstIterator& value) const;
|
|
/// Returns true when the element is an object.
|
|
|
|
template<typename T>
|
|
T optElement(unsigned int index, const T& def) const
|
|
/// Returns the element at the given index. When
|
|
/// the element is null, doesn't exist or can't
|
|
/// be converted to the given type, the default
|
|
/// value will be returned
|
|
{
|
|
T value = def;
|
|
if (index < _values.size())
|
|
{
|
|
try
|
|
{
|
|
value = _values[index].convert<T>();
|
|
}
|
|
catch (...)
|
|
{
|
|
// Default value is returned.
|
|
}
|
|
}
|
|
return value;
|
|
}
|
|
|
|
Array& add(const Dynamic::Var& value);
|
|
/// Add the given value to the array
|
|
|
|
Array& set(unsigned int index, const Dynamic::Var& value);
|
|
/// Update the element on the given index to specified value
|
|
|
|
void stringify(std::ostream& out, unsigned int indent = 0, int step = -1) const;
|
|
/// Prints the array to out. When indent has zero value,
|
|
/// the array will be printed without newline breaks and spaces between elements.
|
|
|
|
void remove(unsigned int index);
|
|
/// Removes the element on the given index.
|
|
|
|
operator const Poco::Dynamic::Array& () const;
|
|
/// Conversion operator to Dynamic::Array.
|
|
|
|
static Poco::Dynamic::Array makeArray(const JSON::Array::Ptr& arr);
|
|
/// Utility function for creation of array.
|
|
|
|
void clear();
|
|
/// Clears the contents of the array.
|
|
|
|
private:
|
|
void resetDynArray() const;
|
|
|
|
using ArrayPtr = SharedPtr<Poco::Dynamic::Array>;
|
|
|
|
ValueVec _values;
|
|
mutable ArrayPtr _pArray;
|
|
mutable bool _modified;
|
|
// Note:
|
|
// The reason we have this flag here (rather than as argument to stringify())
|
|
// is because Array can be returned stringified from a Dynamic::Var:toString(),
|
|
// so it must know whether to escape unicode or not.
|
|
bool _escapeUnicode;
|
|
bool _lowercaseHex;
|
|
};
|
|
|
|
|
|
//
|
|
// inlines
|
|
//
|
|
|
|
inline void Array::setEscapeUnicode(bool escape)
|
|
{
|
|
_escapeUnicode = escape;
|
|
}
|
|
|
|
|
|
inline bool Array::getEscapeUnicode() const
|
|
{
|
|
return _escapeUnicode;
|
|
}
|
|
|
|
inline void Array::setLowercaseHex(bool lowercaseHex)
|
|
{
|
|
_lowercaseHex = lowercaseHex;
|
|
}
|
|
|
|
|
|
inline bool Array::getLowercaseHex() const
|
|
{
|
|
return _lowercaseHex;
|
|
}
|
|
|
|
|
|
inline Array::ValueVec::const_iterator Array::begin() const
|
|
{
|
|
return _values.begin();
|
|
}
|
|
|
|
|
|
inline Array::ValueVec::const_iterator Array::end() const
|
|
|
|
{
|
|
return _values.end();
|
|
}
|
|
|
|
|
|
inline std::size_t Array::size() const
|
|
{
|
|
return static_cast<std::size_t>(_values.size());
|
|
}
|
|
|
|
|
|
inline bool Array::empty() const
|
|
{
|
|
return _values.empty();
|
|
}
|
|
|
|
|
|
inline bool Array::isArray(unsigned int index) const
|
|
{
|
|
Dynamic::Var value = get(index);
|
|
return isArray(value);
|
|
}
|
|
|
|
|
|
inline bool Array::isArray(const Dynamic::Var& value) const
|
|
{
|
|
return value.type() == typeid(Array::Ptr);
|
|
}
|
|
|
|
|
|
inline bool Array::isArray(ConstIterator& it) const
|
|
{
|
|
return it!= end() && isArray(*it);
|
|
}
|
|
|
|
|
|
inline Array& Array::add(const Dynamic::Var& value)
|
|
{
|
|
_values.push_back(value);
|
|
_modified = true;
|
|
return *this;
|
|
}
|
|
|
|
|
|
inline Array& Array::set(unsigned int index, const Dynamic::Var& value)
|
|
{
|
|
if (index >= _values.size()) _values.resize(index + 1);
|
|
_values[index] = value;
|
|
_modified = true;
|
|
return *this;
|
|
}
|
|
|
|
|
|
inline void Array::remove(unsigned int index)
|
|
{
|
|
_values.erase(_values.begin() + index);
|
|
}
|
|
|
|
|
|
} } // namespace Poco::JSON
|
|
|
|
|
|
namespace Poco {
|
|
namespace Dynamic {
|
|
|
|
|
|
template <>
|
|
class VarHolderImpl<JSON::Array::Ptr>: public VarHolder
|
|
{
|
|
public:
|
|
VarHolderImpl(const JSON::Array::Ptr& val): _val(val)
|
|
{
|
|
}
|
|
|
|
~VarHolderImpl() override = default;
|
|
|
|
const std::type_info& type() const override
|
|
{
|
|
return typeid(JSON::Array::Ptr);
|
|
}
|
|
|
|
void convert(Int8&) const override
|
|
{
|
|
throw BadCastException();
|
|
}
|
|
|
|
void convert(Int16&) const override
|
|
{
|
|
throw BadCastException();
|
|
}
|
|
|
|
void convert(Int32&) const override
|
|
{
|
|
throw BadCastException();
|
|
}
|
|
|
|
void convert(Int64&) const override
|
|
{
|
|
throw BadCastException();
|
|
}
|
|
|
|
void convert(UInt8&) const override
|
|
{
|
|
throw BadCastException();
|
|
}
|
|
|
|
void convert(UInt16&) const override
|
|
{
|
|
throw BadCastException();
|
|
}
|
|
|
|
void convert(UInt32&) const override
|
|
{
|
|
throw BadCastException();
|
|
}
|
|
|
|
void convert(UInt64&) const override
|
|
{
|
|
throw BadCastException();
|
|
}
|
|
|
|
void convert(bool& value) const override
|
|
{
|
|
value = !_val.isNull() && _val->size() > 0;
|
|
}
|
|
|
|
void convert(float&) const override
|
|
{
|
|
throw BadCastException();
|
|
}
|
|
|
|
void convert(double&) const override
|
|
{
|
|
throw BadCastException();
|
|
}
|
|
|
|
void convert(char&) const override
|
|
{
|
|
throw BadCastException();
|
|
}
|
|
|
|
void convert(std::string& s) const override
|
|
{
|
|
std::ostringstream oss;
|
|
_val->stringify(oss);
|
|
s = oss.str();
|
|
}
|
|
|
|
void convert(DateTime& /*val*/) const override
|
|
{
|
|
throw BadCastException("Cannot convert Array to DateTime");
|
|
}
|
|
|
|
void convert(LocalDateTime& /*ldt*/) const override
|
|
{
|
|
throw BadCastException("Cannot convert Array to LocalDateTime");
|
|
}
|
|
|
|
void convert(Timestamp& /*ts*/) const override
|
|
{
|
|
throw BadCastException("Cannot convert Array to Timestamp");
|
|
}
|
|
|
|
VarHolder* clone(Placeholder<VarHolder>* pVarHolder = nullptr) const override
|
|
{
|
|
return cloneHolder(pVarHolder, _val);
|
|
}
|
|
|
|
const JSON::Array::Ptr& value() const
|
|
{
|
|
return _val;
|
|
}
|
|
|
|
bool isInteger() const override
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool isSigned() const override
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool isNumeric() const override
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool isString() const override
|
|
{
|
|
return false;
|
|
}
|
|
|
|
private:
|
|
JSON::Array::Ptr _val;
|
|
};
|
|
|
|
|
|
template <>
|
|
class VarHolderImpl<JSON::Array>: public VarHolder
|
|
{
|
|
public:
|
|
VarHolderImpl(const JSON::Array& val): _val(val)
|
|
{
|
|
}
|
|
|
|
~VarHolderImpl() override = default;
|
|
|
|
const std::type_info& type() const override
|
|
{
|
|
return typeid(JSON::Array);
|
|
}
|
|
|
|
void convert(Int8&) const override
|
|
{
|
|
throw BadCastException();
|
|
}
|
|
|
|
void convert(Int16&) const override
|
|
{
|
|
throw BadCastException();
|
|
}
|
|
|
|
void convert(Int32&) const override
|
|
{
|
|
throw BadCastException();
|
|
}
|
|
|
|
void convert(Int64&) const override
|
|
{
|
|
throw BadCastException();
|
|
}
|
|
|
|
void convert(UInt8&) const override
|
|
{
|
|
throw BadCastException();
|
|
}
|
|
|
|
void convert(UInt16&) const override
|
|
{
|
|
throw BadCastException();
|
|
}
|
|
|
|
void convert(UInt32&) const override
|
|
{
|
|
throw BadCastException();
|
|
}
|
|
|
|
void convert(UInt64&) const override
|
|
{
|
|
throw BadCastException();
|
|
}
|
|
|
|
void convert(bool& value) const override
|
|
{
|
|
value = _val.size() > 0;
|
|
}
|
|
|
|
void convert(float&) const override
|
|
{
|
|
throw BadCastException();
|
|
}
|
|
|
|
void convert(double&) const override
|
|
{
|
|
throw BadCastException();
|
|
}
|
|
|
|
void convert(char&) const override
|
|
{
|
|
throw BadCastException();
|
|
}
|
|
|
|
void convert(std::string& s) const override
|
|
{
|
|
std::ostringstream oss;
|
|
_val.stringify(oss);
|
|
s = oss.str();
|
|
}
|
|
|
|
void convert(DateTime& /*val*/) const override
|
|
{
|
|
throw BadCastException("Cannot convert Array to DateTime");
|
|
}
|
|
|
|
void convert(LocalDateTime& /*ldt*/) const override
|
|
{
|
|
throw BadCastException("Cannot convert Array to LocalDateTime");
|
|
}
|
|
|
|
void convert(Timestamp& /*ts*/) const override
|
|
{
|
|
throw BadCastException("Cannot convert Array to Timestamp");
|
|
}
|
|
|
|
VarHolder* clone(Placeholder<VarHolder>* pVarHolder = nullptr) const override
|
|
{
|
|
return cloneHolder(pVarHolder, _val);
|
|
}
|
|
|
|
const JSON::Array& value() const
|
|
{
|
|
return _val;
|
|
}
|
|
|
|
bool isInteger() const override
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool isSigned() const override
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool isNumeric() const override
|
|
{
|
|
return false;
|
|
}
|
|
|
|
bool isString() const override
|
|
{
|
|
return false;
|
|
}
|
|
|
|
private:
|
|
JSON::Array _val;
|
|
};
|
|
|
|
|
|
} } // namespace Poco::Dynamic
|
|
|
|
|
|
#endif // JSON_Array_INCLUDED
|