text: //
  // 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 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.
  
  	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 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;
  
  	typedef SharedPtr<Poco::Dynamic::Array> ArrayPtr;
  
  	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;
  };
  
  
  //
  // inlines
  //
  
  inline void Array::setEscapeUnicode(bool escape)
  {
  	_escapeUnicode = escape;
  }
  
  
  inline bool Array::getEscapeUnicode() const
  {
  	return _escapeUnicode;
  }
  
  
  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::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()
  	{
  	}
  
  	const std::type_info& type() const
  	{
  		return typeid(JSON::Array::Ptr);
  	}
  
  	void convert(Int8&) const
  	{
  		throw BadCastException();
  	}
  
  	void convert(Int16&) const
  	{
  		throw BadCastException();
  	}
  
  	void convert(Int32&) const
  	{
  		throw BadCastException();
  	}
  
  	void convert(Int64&) const
  	{
  		throw BadCastException();
  	}
  
  	void convert(UInt8&) const
  	{
  		throw BadCastException();
  	}
  
  	void convert(UInt16&) const
  	{
  		throw BadCastException();
  	}
  
  	void convert(UInt32&) const
  	{
  		throw BadCastException();
  	}
  
  	void convert(UInt64&) const
  	{
  		throw BadCastException();
  	}
  
  	void convert(bool& value) const
  	{
  		value = !_val.isNull() && _val->size() > 0;
  	}
  
  	void convert(float&) const
  	{
  		throw BadCastException();
  	}
  
  	void convert(double&) const
  	{
  		throw BadCastException();
  	}
  
  	void convert(char&) const
  	{
  		throw BadCastException();
  	}
  
  	void convert(std::string& s) const
  	{
  		std::ostringstream oss;
  		_val->stringify(oss, 2);
  		s = oss.str();
  	}
  
  	void convert(DateTime& /*val*/) const
  	{
  		throw BadCastException("Cannot convert Array to DateTime");
  	}
  
  	void convert(LocalDateTime& /*ldt*/) const
  	{
  		throw BadCastException("Cannot convert Array to LocalDateTime");
  	}
  
  	void convert(Timestamp& /*ts*/) const
  	{
  		throw BadCastException("Cannot convert Array to Timestamp");
  	}
  
  	VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
  	{
  		return cloneHolder(pVarHolder, _val);
  	}
  
  	const JSON::Array::Ptr& value() const
  	{
  		return _val;
  	}
  
  	bool isInteger() const
  	{
  		return false;
  	}
  
  	bool isSigned() const
  	{
  		return false;
  	}
  
  	bool isNumeric() const
  	{
  		return false;
  	}
  
  	bool isString() const
  	{
  		return false;
  	}
  
  private:
  	JSON::Array::Ptr _val;
  };
  
  
  template <>
  class VarHolderImpl<JSON::Array>: public VarHolder
  {
  public:
  	VarHolderImpl(const JSON::Array& val): _val(val)
  	{
  	}
  
  	~VarHolderImpl()
  	{
  	}
  
  	const std::type_info& type() const
  	{
  		return typeid(JSON::Array);
  	}
  
  	void convert(Int8&) const
  	{
  		throw BadCastException();
  	}
  
  	void convert(Int16&) const
  	{
  		throw BadCastException();
  	}
  
  	void convert(Int32&) const
  	{
  		throw BadCastException();
  	}
  
  	void convert(Int64&) const
  	{
  		throw BadCastException();
  	}
  
  	void convert(UInt8&) const
  	{
  		throw BadCastException();
  	}
  
  	void convert(UInt16&) const
  	{
  		throw BadCastException();
  	}
  
  	void convert(UInt32&) const
  	{
  		throw BadCastException();
  	}
  
  	void convert(UInt64&) const
  	{
  		throw BadCastException();
  	}
  
  	void convert(bool& value) const
  	{
  		value = _val.size() > 0;
  	}
  
  	void convert(float&) const
  	{
  		throw BadCastException();
  	}
  
  	void convert(double&) const
  	{
  		throw BadCastException();
  	}
  
  	void convert(char&) const
  	{
  		throw BadCastException();
  	}
  
  	void convert(std::string& s) const
  	{
  		std::ostringstream oss;
  		_val.stringify(oss, 2);
  		s = oss.str();
  	}
  
  	void convert(DateTime& /*val*/) const
  	{
  		throw BadCastException("Cannot convert Array to DateTime");
  	}
  
  	void convert(LocalDateTime& /*ldt*/) const
  	{
  		throw BadCastException("Cannot convert Array to LocalDateTime");
  	}
  
  	void convert(Timestamp& /*ts*/) const
  	{
  		throw BadCastException("Cannot convert Array to Timestamp");
  	}
  
  	VarHolder* clone(Placeholder<VarHolder>* pVarHolder = 0) const
  	{
  		return cloneHolder(pVarHolder, _val);
  	}
  
  	const JSON::Array& value() const
  	{
  		return _val;
  	}
  
  	bool isInteger() const
  	{
  		return false;
  	}
  
  	bool isSigned() const
  	{
  		return false;
  	}
  
  	bool isNumeric() const
  	{
  		return false;
  	}
  
  	bool isString() const
  	{
  		return false;
  	}
  
  private:
  	JSON::Array _val;
  };
  
  
  } } // namespace Poco::Dynamic
  
  
  #endif // JSON_Array_INCLUDED
  