2010-05-21 03:13:36 +02:00
|
|
|
/**********************************************
|
|
|
|
|
|
|
|
License: BSD
|
|
|
|
Project Webpage: http://cajun-jsonapi.sourceforge.net/
|
|
|
|
Author: Terry Caton
|
|
|
|
|
|
|
|
***********************************************/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <deque>
|
|
|
|
#include <list>
|
|
|
|
#include <string>
|
|
|
|
#include <stdexcept>
|
|
|
|
|
|
|
|
namespace json
|
|
|
|
{
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////
|
|
|
|
// forward declarations (more info further below)
|
|
|
|
class Visitor;
|
|
|
|
class ConstVisitor;
|
|
|
|
|
|
|
|
template <typename ValueTypeT>
|
|
|
|
class TrivialType_T;
|
|
|
|
|
2011-10-17 23:59:59 +02:00
|
|
|
typedef double Number;
|
|
|
|
typedef bool Boolean;
|
|
|
|
typedef std::string String;
|
2010-05-21 03:13:36 +02:00
|
|
|
|
|
|
|
class Object;
|
|
|
|
class Array;
|
|
|
|
class Null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
// Exception - base class for all JSON-related runtime errors
|
|
|
|
class Exception : public std::runtime_error
|
|
|
|
{
|
|
|
|
public:
|
2011-10-17 23:59:35 +02:00
|
|
|
Exception(const std::string& sMessage) : std::runtime_error(sMessage) { }
|
2010-05-21 03:13:36 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////
|
|
|
|
// UnknownElement - provides a typesafe surrogate for any of the JSON-
|
|
|
|
// sanctioned element types. This class allows the Array and Object
|
|
|
|
// class to effectively contain a heterogeneous set of child elements.
|
|
|
|
// The cast operators provide convenient implicit downcasting, while
|
|
|
|
// preserving dynamic type safety by throwing an exception during a
|
2011-10-17 23:59:35 +02:00
|
|
|
// a bad cast.
|
2010-05-21 03:13:36 +02:00
|
|
|
// The object & array element index operators (operators [std::string]
|
|
|
|
// and [size_t]) provide convenient, quick access to child elements.
|
|
|
|
// They are a logical extension of the cast operators. These child
|
|
|
|
// element accesses can be chained together, allowing the following
|
|
|
|
// (when document structure is well-known):
|
|
|
|
// String str = objInvoices[1]["Customer"]["Company"];
|
|
|
|
|
|
|
|
|
|
|
|
class UnknownElement
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
UnknownElement();
|
|
|
|
UnknownElement(const UnknownElement& unknown);
|
|
|
|
UnknownElement(const Object& object);
|
|
|
|
UnknownElement(const Array& array);
|
|
|
|
UnknownElement(const Number& number);
|
|
|
|
UnknownElement(const Boolean& boolean);
|
|
|
|
UnknownElement(const String& string);
|
|
|
|
UnknownElement(const Null& null);
|
|
|
|
|
|
|
|
~UnknownElement();
|
|
|
|
|
|
|
|
UnknownElement& operator = (const UnknownElement& unknown);
|
|
|
|
|
|
|
|
// implicit cast to actual element type. throws on failure
|
|
|
|
operator const Object& () const;
|
|
|
|
operator const Array& () const;
|
|
|
|
operator const Number& () const;
|
|
|
|
operator const Boolean& () const;
|
|
|
|
operator const String& () const;
|
|
|
|
operator const Null& () const;
|
|
|
|
|
|
|
|
// implicit cast to actual element type. *converts* on failure, and always returns success
|
|
|
|
operator Object& ();
|
|
|
|
operator Array& ();
|
|
|
|
operator Number& ();
|
|
|
|
operator Boolean& ();
|
|
|
|
operator String& ();
|
|
|
|
operator Null& ();
|
|
|
|
|
|
|
|
// provides quick access to children when real element type is object
|
2011-10-17 23:59:59 +02:00
|
|
|
UnknownElement& operator[] (const char *key) { return operator[](std::string(key)); }
|
|
|
|
const UnknownElement& operator[] (const char *key) const { return operator[](std::string(key)); }
|
2010-05-21 03:13:36 +02:00
|
|
|
UnknownElement& operator[] (const std::string& key);
|
|
|
|
const UnknownElement& operator[] (const std::string& key) const;
|
|
|
|
|
|
|
|
// provides quick access to children when real element type is array
|
|
|
|
UnknownElement& operator[] (size_t index);
|
|
|
|
const UnknownElement& operator[] (size_t index) const;
|
|
|
|
|
|
|
|
// implements visitor pattern
|
|
|
|
void Accept(ConstVisitor& visitor) const;
|
|
|
|
void Accept(Visitor& visitor);
|
|
|
|
|
|
|
|
// tests equality. first checks type, then value if possible
|
|
|
|
bool operator == (const UnknownElement& element) const;
|
|
|
|
|
|
|
|
private:
|
|
|
|
class Imp;
|
|
|
|
|
|
|
|
template <typename ElementTypeT>
|
|
|
|
class Imp_T;
|
|
|
|
|
|
|
|
class CastVisitor;
|
|
|
|
class ConstCastVisitor;
|
2011-10-17 23:59:35 +02:00
|
|
|
|
2010-05-21 03:13:36 +02:00
|
|
|
template <typename ElementTypeT>
|
|
|
|
class CastVisitor_T;
|
|
|
|
|
|
|
|
template <typename ElementTypeT>
|
|
|
|
class ConstCastVisitor_T;
|
|
|
|
|
|
|
|
template <typename ElementTypeT>
|
|
|
|
const ElementTypeT& CastTo() const;
|
|
|
|
|
|
|
|
template <typename ElementTypeT>
|
|
|
|
ElementTypeT& ConvertTo();
|
|
|
|
|
|
|
|
Imp* m_pImp;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
2011-10-17 23:59:35 +02:00
|
|
|
// Array - mimics std::deque<UnknownElement>. The array contents are effectively
|
|
|
|
// heterogeneous thanks to the ElementUnknown class.
|
2010-05-21 03:13:36 +02:00
|
|
|
class Array
|
|
|
|
{
|
|
|
|
public:
|
2011-10-17 23:59:35 +02:00
|
|
|
typedef std::deque<UnknownElement> elements;
|
|
|
|
typedef elements::iterator iterator;
|
|
|
|
typedef elements::const_iterator const_iterator;
|
|
|
|
|
|
|
|
iterator begin() { return m_Elements.begin(); }
|
|
|
|
iterator end() { return m_Elements.end(); }
|
|
|
|
const_iterator begin() const { return m_Elements.begin(); }
|
|
|
|
const_iterator end() const { return m_Elements.end(); }
|
|
|
|
|
|
|
|
iterator insert(iterator it, const UnknownElement& element) { m_Elements.insert(it, element); }
|
|
|
|
void push_back(const UnknownElement& element) { m_Elements.push_back(element); }
|
|
|
|
iterator erase(iterator it) { return m_Elements.erase(it); }
|
|
|
|
void resize(size_t newsize) { m_Elements.resize(newsize); }
|
|
|
|
void clear() { m_Elements.clear(); }
|
|
|
|
|
|
|
|
size_t size() const { return m_Elements.size(); }
|
|
|
|
bool empty() const { return m_Elements.empty(); }
|
|
|
|
|
|
|
|
UnknownElement& front() { return m_Elements.front(); }
|
|
|
|
const UnknownElement& front() const { return m_Elements.front(); }
|
|
|
|
UnknownElement& back() { return m_Elements.back(); }
|
|
|
|
const UnknownElement& back() const { return m_Elements.back(); }
|
2010-05-21 03:13:36 +02:00
|
|
|
|
|
|
|
UnknownElement& operator[] (size_t index);
|
|
|
|
const UnknownElement& operator[] (size_t index) const;
|
|
|
|
|
2011-10-17 23:59:35 +02:00
|
|
|
bool operator == (const Array& array) const { return m_Elements == array.m_Elements; }
|
2010-05-21 03:13:36 +02:00
|
|
|
|
|
|
|
private:
|
2011-10-17 23:59:35 +02:00
|
|
|
elements m_Elements;
|
2010-05-21 03:13:36 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
2011-10-17 23:59:35 +02:00
|
|
|
// Object - mimics std::map<std::string, UnknownElement>. The member value
|
2010-05-21 03:13:36 +02:00
|
|
|
// contents are effectively heterogeneous thanks to the UnknownElement class
|
|
|
|
|
|
|
|
class Object
|
|
|
|
{
|
|
|
|
public:
|
2011-10-17 23:59:47 +02:00
|
|
|
typedef std::map<std::string, UnknownElement> Members;
|
2010-05-21 03:13:36 +02:00
|
|
|
typedef Members::iterator iterator;
|
|
|
|
typedef Members::const_iterator const_iterator;
|
|
|
|
|
2011-10-17 23:59:35 +02:00
|
|
|
bool operator == (const Object& object) const { return m_Members == object.m_Members; }
|
2010-05-21 03:13:36 +02:00
|
|
|
|
2011-10-17 23:59:35 +02:00
|
|
|
iterator begin() { return m_Members.begin(); }
|
|
|
|
iterator end() { return m_Members.end(); }
|
|
|
|
const_iterator begin() const { return m_Members.begin(); }
|
|
|
|
const_iterator end() const { return m_Members.end(); }
|
2010-05-21 03:13:36 +02:00
|
|
|
|
2011-10-17 23:59:35 +02:00
|
|
|
size_t size() const { return m_Members.size(); }
|
|
|
|
bool empty() const { return m_Members.empty(); }
|
2010-05-21 03:13:36 +02:00
|
|
|
|
2011-10-17 23:59:47 +02:00
|
|
|
iterator find(const std::string& name) { return m_Members.find(name); }
|
|
|
|
const_iterator find(const std::string& name) const { return m_Members.find(name); }
|
2010-05-21 03:13:36 +02:00
|
|
|
|
2011-10-17 23:59:47 +02:00
|
|
|
iterator insert(std::pair<std::string, UnknownElement> const& ele);
|
2011-10-17 23:59:35 +02:00
|
|
|
iterator erase(iterator it) { return m_Members.erase(it); }
|
|
|
|
void clear() { m_Members.clear(); }
|
2010-05-21 03:13:36 +02:00
|
|
|
|
|
|
|
UnknownElement& operator [](const std::string& name);
|
|
|
|
const UnknownElement& operator [](const std::string& name) const;
|
|
|
|
|
|
|
|
private:
|
|
|
|
Members m_Members;
|
|
|
|
};
|
|
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////////
|
|
|
|
// Null - doesn't do much of anything but satisfy the JSON spec. It is the default
|
|
|
|
// element type of UnknownElement
|
|
|
|
class Null
|
|
|
|
{
|
|
|
|
public:
|
2011-10-17 23:59:59 +02:00
|
|
|
bool operator == (const Null& trivial) const { return true; }
|
2010-05-21 03:13:36 +02:00
|
|
|
};
|
|
|
|
|
2011-10-17 23:59:35 +02:00
|
|
|
} // end namespace
|
2010-05-21 03:13:36 +02:00
|
|
|
|
|
|
|
|
|
|
|
#include "elements.inl"
|