forked from mia/Aegisub
Completely ditch json::Array and json::Object's custom implementations and switch to typedefs to STL types.
Originally committed to SVN as r5752.
This commit is contained in:
parent
4e8848c110
commit
dd46c7af7f
7 changed files with 56 additions and 189 deletions
|
@ -228,7 +228,7 @@ bool Options::PutOption(json::Object &obj, const std::string &path, const json::
|
||||||
|
|
||||||
// New key, make object.
|
// New key, make object.
|
||||||
if (pos == obj.end())
|
if (pos == obj.end())
|
||||||
pos = obj.insert(make_pair(thispart, json::Object()));
|
pos = obj.insert(make_pair(thispart, json::Object())).first;
|
||||||
|
|
||||||
PutOptionVisitor visitor(restpart, value);
|
PutOptionVisitor visitor(restpart, value);
|
||||||
pos->second.Accept(visitor);
|
pos->second.Accept(visitor);
|
||||||
|
|
|
@ -20,6 +20,7 @@ namespace json
|
||||||
// forward declarations (more info further below)
|
// forward declarations (more info further below)
|
||||||
class Visitor;
|
class Visitor;
|
||||||
class ConstVisitor;
|
class ConstVisitor;
|
||||||
|
class UnknownElement;
|
||||||
|
|
||||||
template <typename ValueTypeT>
|
template <typename ValueTypeT>
|
||||||
class TrivialType_T;
|
class TrivialType_T;
|
||||||
|
@ -27,9 +28,9 @@ class TrivialType_T;
|
||||||
typedef double Number;
|
typedef double Number;
|
||||||
typedef bool Boolean;
|
typedef bool Boolean;
|
||||||
typedef std::string String;
|
typedef std::string String;
|
||||||
|
typedef std::deque<UnknownElement> Array;
|
||||||
|
typedef std::map<std::string, UnknownElement> Object;
|
||||||
|
|
||||||
class Object;
|
|
||||||
class Array;
|
|
||||||
class Null;
|
class Null;
|
||||||
|
|
||||||
|
|
||||||
|
@ -130,75 +131,6 @@ private:
|
||||||
Imp* m_pImp;
|
Imp* m_pImp;
|
||||||
};
|
};
|
||||||
|
|
||||||
class Array : private std::deque<UnknownElement>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
using std::deque<UnknownElement>::back;
|
|
||||||
using std::deque<UnknownElement>::begin;
|
|
||||||
using std::deque<UnknownElement>::clear;
|
|
||||||
using std::deque<UnknownElement>::const_iterator;
|
|
||||||
using std::deque<UnknownElement>::const_reference;
|
|
||||||
using std::deque<UnknownElement>::const_reverse_iterator;
|
|
||||||
using std::deque<UnknownElement>::difference_type;
|
|
||||||
using std::deque<UnknownElement>::empty;
|
|
||||||
using std::deque<UnknownElement>::end;
|
|
||||||
using std::deque<UnknownElement>::front;
|
|
||||||
using std::deque<UnknownElement>::iterator;
|
|
||||||
using std::deque<UnknownElement>::max_size;
|
|
||||||
using std::deque<UnknownElement>::pointer;
|
|
||||||
using std::deque<UnknownElement>::pop_back;
|
|
||||||
using std::deque<UnknownElement>::pop_front;
|
|
||||||
using std::deque<UnknownElement>::push_back;
|
|
||||||
using std::deque<UnknownElement>::push_front;
|
|
||||||
using std::deque<UnknownElement>::rbegin;
|
|
||||||
using std::deque<UnknownElement>::reference;
|
|
||||||
using std::deque<UnknownElement>::rend;
|
|
||||||
using std::deque<UnknownElement>::reverse_iterator;
|
|
||||||
using std::deque<UnknownElement>::size;
|
|
||||||
using std::deque<UnknownElement>::size_type;
|
|
||||||
using std::deque<UnknownElement>::swap;
|
|
||||||
using std::deque<UnknownElement>::value_type;
|
|
||||||
|
|
||||||
UnknownElement& operator[](size_t idx);
|
|
||||||
const UnknownElement& operator[](size_t idx) const;
|
|
||||||
bool operator==(Array const& rgt) const;
|
|
||||||
};
|
|
||||||
|
|
||||||
/////////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Object - mimics std::map<std::string, UnknownElement>. The member value
|
|
||||||
// contents are effectively heterogeneous thanks to the UnknownElement class
|
|
||||||
|
|
||||||
class Object
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef std::map<std::string, UnknownElement> Members;
|
|
||||||
typedef Members::iterator iterator;
|
|
||||||
typedef Members::const_iterator const_iterator;
|
|
||||||
|
|
||||||
bool operator == (const Object& object) const { return m_Members == object.m_Members; }
|
|
||||||
|
|
||||||
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(); }
|
|
||||||
|
|
||||||
size_t size() const { return m_Members.size(); }
|
|
||||||
bool empty() const { return m_Members.empty(); }
|
|
||||||
|
|
||||||
iterator find(const std::string& name) { return m_Members.find(name); }
|
|
||||||
const_iterator find(const std::string& name) const { return m_Members.find(name); }
|
|
||||||
|
|
||||||
iterator insert(std::pair<std::string, UnknownElement> const& ele);
|
|
||||||
iterator erase(iterator it) { return m_Members.erase(it); }
|
|
||||||
void clear() { m_Members.clear(); }
|
|
||||||
|
|
||||||
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
|
// Null - doesn't do much of anything but satisfy the JSON spec. It is the default
|
||||||
// element type of UnknownElement
|
// element type of UnknownElement
|
||||||
|
|
|
@ -138,7 +138,11 @@ inline UnknownElement& UnknownElement::operator[] (const std::string& key)
|
||||||
inline const UnknownElement& UnknownElement::operator[] (const std::string& key) const
|
inline const UnknownElement& UnknownElement::operator[] (const std::string& key) const
|
||||||
{
|
{
|
||||||
// throws if we aren't an object
|
// throws if we aren't an object
|
||||||
return CastTo<Object>()[key];
|
Object const& obj = CastTo<Object>();
|
||||||
|
Object::const_iterator it = obj.find(key);
|
||||||
|
if (it == obj.end())
|
||||||
|
throw Exception("Object member not found: " + key);
|
||||||
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline UnknownElement& UnknownElement::operator[] (size_t index)
|
inline UnknownElement& UnknownElement::operator[] (size_t index)
|
||||||
|
@ -191,51 +195,4 @@ inline bool UnknownElement::operator == (const UnknownElement& element) const
|
||||||
return m_pImp->Compare(*element.m_pImp);
|
return m_pImp->Compare(*element.m_pImp);
|
||||||
}
|
}
|
||||||
|
|
||||||
//////////////////
|
|
||||||
// Object members
|
|
||||||
inline Object::iterator Object::insert(std::pair<std::string, UnknownElement> const& ele)
|
|
||||||
{
|
|
||||||
iterator it = find(ele.first);
|
|
||||||
if (it != m_Members.end())
|
|
||||||
throw Exception("Object member already exists: " + ele.first);
|
|
||||||
|
|
||||||
return m_Members.insert(ele).first;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline UnknownElement& Object::operator [](const std::string& name)
|
|
||||||
{
|
|
||||||
iterator it = find(name);
|
|
||||||
if (it == m_Members.end())
|
|
||||||
{
|
|
||||||
it = insert(make_pair(name, UnknownElement()));
|
|
||||||
}
|
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const UnknownElement& Object::operator [](const std::string& name) const
|
|
||||||
{
|
|
||||||
const_iterator it = find(name);
|
|
||||||
if (it == end())
|
|
||||||
throw Exception("Object member not found: " + name);
|
|
||||||
return it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
/////////////////
|
|
||||||
// Array members
|
|
||||||
inline UnknownElement& Array::operator[](size_t idx) {
|
|
||||||
if (idx >= size())
|
|
||||||
resize(idx + 1);
|
|
||||||
return std::deque<UnknownElement>::operator[](idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const UnknownElement& Array::operator[](size_t idx) const {
|
|
||||||
if (idx >= size())
|
|
||||||
throw Exception("Array out of bounds");
|
|
||||||
return std::deque<UnknownElement>::operator[](idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool Array::operator==(Array const& rgt) const {
|
|
||||||
return *static_cast<const std::deque<UnknownElement> *>(this) == rgt;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // end namespace
|
} // end namespace
|
||||||
|
|
|
@ -22,7 +22,7 @@ namespace json
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
inline std::istream& operator >> (std::istream& istr, UnknownElement& elementRoot) {
|
inline std::istream& operator >> (std::istream& istr, UnknownElement& elementRoot) {
|
||||||
Reader::Read(elementRoot, istr);
|
Reader::Read(elementRoot, istr);
|
||||||
return istr;
|
return istr;
|
||||||
}
|
}
|
||||||
|
@ -87,39 +87,28 @@ inline char Reader::InputStream::Get()
|
||||||
|
|
||||||
class Reader::TokenStream
|
class Reader::TokenStream
|
||||||
{
|
{
|
||||||
public:
|
|
||||||
TokenStream(const Tokens& tokens);
|
|
||||||
|
|
||||||
const Token& Peek();
|
|
||||||
const Token& Get();
|
|
||||||
|
|
||||||
bool EOS() const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
const Tokens& m_Tokens;
|
const Tokens& m_Tokens;
|
||||||
Tokens::const_iterator m_itCurrent;
|
Tokens::const_iterator m_itCurrent;
|
||||||
|
|
||||||
|
public:
|
||||||
|
TokenStream(const Tokens& tokens)
|
||||||
|
: m_Tokens(tokens), m_itCurrent(tokens.begin())
|
||||||
|
{ }
|
||||||
|
|
||||||
|
const Token& Peek() {
|
||||||
|
assert(m_itCurrent != m_Tokens.end());
|
||||||
|
return *(m_itCurrent);
|
||||||
|
}
|
||||||
|
const Token& Get() {
|
||||||
|
assert(m_itCurrent != m_Tokens.end());
|
||||||
|
return *(m_itCurrent++);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool EOS() const {
|
||||||
|
return m_itCurrent == m_Tokens.end();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
inline Reader::TokenStream::TokenStream(const Tokens& tokens) :
|
|
||||||
m_Tokens(tokens),
|
|
||||||
m_itCurrent(tokens.begin())
|
|
||||||
{}
|
|
||||||
|
|
||||||
inline const Reader::Token& Reader::TokenStream::Peek() {
|
|
||||||
assert(m_itCurrent != m_Tokens.end());
|
|
||||||
return *(m_itCurrent);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline const Reader::Token& Reader::TokenStream::Get() {
|
|
||||||
assert(m_itCurrent != m_Tokens.end());
|
|
||||||
return *(m_itCurrent++);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool Reader::TokenStream::EOS() const {
|
|
||||||
return m_itCurrent == m_Tokens.end();
|
|
||||||
}
|
|
||||||
|
|
||||||
///////////////////
|
///////////////////
|
||||||
// Reader (finally)
|
// Reader (finally)
|
||||||
|
|
||||||
|
@ -148,8 +137,7 @@ void Reader::Read_i(ElementTypeT& element, std::istream& istr)
|
||||||
if (tokenStream.EOS() == false)
|
if (tokenStream.EOS() == false)
|
||||||
{
|
{
|
||||||
const Token& token = tokenStream.Peek();
|
const Token& token = tokenStream.Peek();
|
||||||
std::string sMessage = "Expected End of token stream; found " + token.sValue;
|
throw ParseException("Expected End of token stream; found " + token.sValue, token.locBegin, token.locEnd);
|
||||||
throw ParseException(sMessage, token.locBegin, token.locEnd);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -244,8 +232,7 @@ inline void Reader::Scan(Tokens& tokens, InputStream& inputStream)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default: {
|
default: {
|
||||||
std::string sErrorMessage = "Unexpected character in stream: " + sChar;
|
throw ScanException("Unexpected character in stream: " + sChar, inputStream.GetLocation());
|
||||||
throw ScanException(sErrorMessage, inputStream.GetLocation());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -270,8 +257,7 @@ inline void Reader::MatchExpectedString(const std::string& sExpected, InputStrea
|
||||||
if (inputStream.EOS() || // did we reach the end before finding what we're looking for...
|
if (inputStream.EOS() || // did we reach the end before finding what we're looking for...
|
||||||
inputStream.Get() != *it) // ...or did we find something different?
|
inputStream.Get() != *it) // ...or did we find something different?
|
||||||
{
|
{
|
||||||
std::string sMessage = "Expected string: " + sExpected;
|
throw ScanException("Expected string: " + sExpected, inputStream.GetLocation());
|
||||||
throw ScanException(sMessage, inputStream.GetLocation());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -303,10 +289,8 @@ inline void Reader::MatchString(std::string& string, InputStream& inputStream)
|
||||||
case 'r': string.push_back('\r'); break;
|
case 'r': string.push_back('\r'); break;
|
||||||
case 't': string.push_back('\t'); break;
|
case 't': string.push_back('\t'); break;
|
||||||
case 'u': // TODO: what do we do with this?
|
case 'u': // TODO: what do we do with this?
|
||||||
default: {
|
default:
|
||||||
std::string sMessage = "Unrecognized escape sequence found in string: \\" + c;
|
throw ScanException("Unrecognized escape sequence found in string: \\" + c, inputStream.GetLocation());
|
||||||
throw ScanException(sMessage, inputStream.GetLocation());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -328,7 +312,7 @@ inline void Reader::MatchNumber(std::string& sNumber, InputStream& inputStream)
|
||||||
while (inputStream.EOS() == false &&
|
while (inputStream.EOS() == false &&
|
||||||
numericChars.find(inputStream.Peek()) != numericChars.end())
|
numericChars.find(inputStream.Peek()) != numericChars.end())
|
||||||
{
|
{
|
||||||
sNumber.push_back(inputStream.Get());
|
sNumber.push_back(inputStream.Get());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -336,8 +320,7 @@ inline void Reader::MatchNumber(std::string& sNumber, InputStream& inputStream)
|
||||||
inline void Reader::Parse(UnknownElement& element, Reader::TokenStream& tokenStream)
|
inline void Reader::Parse(UnknownElement& element, Reader::TokenStream& tokenStream)
|
||||||
{
|
{
|
||||||
if (tokenStream.EOS()) {
|
if (tokenStream.EOS()) {
|
||||||
std::string sMessage = "Unexpected end of token stream";
|
throw ParseException("Unexpected end of token stream", Location(), Location()); // nowhere to point to
|
||||||
throw ParseException(sMessage, Location(), Location()); // nowhere to point to
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Token& token = tokenStream.Peek();
|
const Token& token = tokenStream.Peek();
|
||||||
|
@ -387,8 +370,7 @@ inline void Reader::Parse(UnknownElement& element, Reader::TokenStream& tokenStr
|
||||||
|
|
||||||
default:
|
default:
|
||||||
{
|
{
|
||||||
std::string sMessage = "Unexpected token: " + token.sValue;
|
throw ParseException("Unexpected token: " + token.sValue, token.locBegin, token.locEnd);
|
||||||
throw ParseException(sMessage, token.locBegin, token.locEnd);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -402,28 +384,23 @@ inline void Reader::Parse(Object& object, Reader::TokenStream& tokenStream)
|
||||||
tokenStream.Peek().nType != Token::TOKEN_OBJECT_END);
|
tokenStream.Peek().nType != Token::TOKEN_OBJECT_END);
|
||||||
while (bContinue)
|
while (bContinue)
|
||||||
{
|
{
|
||||||
std::pair<std::string, UnknownElement> member;
|
|
||||||
|
|
||||||
// first the member name. save the token in case we have to throw an exception
|
// first the member name. save the token in case we have to throw an exception
|
||||||
const Token& tokenName = tokenStream.Peek();
|
const Token& tokenName = tokenStream.Peek();
|
||||||
member.first = MatchExpectedToken(Token::TOKEN_STRING, tokenStream);
|
std::string const& name = MatchExpectedToken(Token::TOKEN_STRING, tokenStream);
|
||||||
|
|
||||||
|
if (object.count(name))
|
||||||
|
{
|
||||||
|
throw ParseException("Duplicate object member token: " + name, tokenName.locBegin, tokenName.locEnd);
|
||||||
|
}
|
||||||
|
|
||||||
// ...then the key/value separator...
|
// ...then the key/value separator...
|
||||||
MatchExpectedToken(Token::TOKEN_MEMBER_ASSIGN, tokenStream);
|
MatchExpectedToken(Token::TOKEN_MEMBER_ASSIGN, tokenStream);
|
||||||
|
|
||||||
// ...then the value itself (can be anything).
|
// ...then the value itself (can be anything).
|
||||||
Parse(member.second, tokenStream);
|
UnknownElement value;
|
||||||
|
Parse(value, tokenStream);
|
||||||
|
|
||||||
// try adding it to the object (this could throw)
|
object[name] = value;
|
||||||
try
|
|
||||||
{
|
|
||||||
object.insert(member);
|
|
||||||
}
|
|
||||||
catch (Exception&)
|
|
||||||
{
|
|
||||||
// must be a duplicate name
|
|
||||||
throw ParseException("Duplicate object member token: " + member.first, tokenName.locBegin, tokenName.locEnd);
|
|
||||||
}
|
|
||||||
|
|
||||||
bContinue = (tokenStream.EOS() == false &&
|
bContinue = (tokenStream.EOS() == false &&
|
||||||
tokenStream.Peek().nType == Token::TOKEN_NEXT_ELEMENT);
|
tokenStream.Peek().nType == Token::TOKEN_NEXT_ELEMENT);
|
||||||
|
@ -476,8 +453,7 @@ inline void Reader::Parse(Number& number, Reader::TokenStream& tokenStream)
|
||||||
// did we consume all characters in the token?
|
// did we consume all characters in the token?
|
||||||
if (iStr.eof() == false)
|
if (iStr.eof() == false)
|
||||||
{
|
{
|
||||||
std::string sMessage = "Unexpected character in NUMBER token: " + iStr.peek();
|
throw ParseException("Unexpected character in NUMBER token: " + iStr.peek(), currentToken.locBegin, currentToken.locEnd);
|
||||||
throw ParseException(sMessage, currentToken.locBegin, currentToken.locEnd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
number = dValue;
|
number = dValue;
|
||||||
|
@ -487,7 +463,7 @@ inline void Reader::Parse(Number& number, Reader::TokenStream& tokenStream)
|
||||||
inline void Reader::Parse(Boolean& boolean, Reader::TokenStream& tokenStream)
|
inline void Reader::Parse(Boolean& boolean, Reader::TokenStream& tokenStream)
|
||||||
{
|
{
|
||||||
const std::string& sValue = MatchExpectedToken(Token::TOKEN_BOOLEAN, tokenStream);
|
const std::string& sValue = MatchExpectedToken(Token::TOKEN_BOOLEAN, tokenStream);
|
||||||
boolean = (sValue == "true" ? true : false);
|
boolean = (sValue == "true");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -501,15 +477,13 @@ inline const std::string& Reader::MatchExpectedToken(Token::Type nExpected, Read
|
||||||
{
|
{
|
||||||
if (tokenStream.EOS())
|
if (tokenStream.EOS())
|
||||||
{
|
{
|
||||||
std::string sMessage = "Unexpected End of token stream";
|
throw ParseException("Unexpected End of token stream", Location(), Location()); // nowhere to point to
|
||||||
throw ParseException(sMessage, Location(), Location()); // nowhere to point to
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Token& token = tokenStream.Get();
|
const Token& token = tokenStream.Get();
|
||||||
if (token.nType != nExpected)
|
if (token.nType != nExpected)
|
||||||
{
|
{
|
||||||
std::string sMessage = "Unexpected token: " + token.sValue;
|
throw ParseException("Unexpected token: " + token.sValue, token.locBegin, token.locEnd);
|
||||||
throw ParseException(sMessage, token.locBegin, token.locEnd);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return token.sValue;
|
return token.sValue;
|
||||||
|
|
|
@ -26,7 +26,10 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace json { class Object; }
|
namespace json {
|
||||||
|
class UnknownElement;
|
||||||
|
typedef std::map<std::string, UnknownElement> Object;
|
||||||
|
}
|
||||||
|
|
||||||
namespace agi {
|
namespace agi {
|
||||||
namespace hotkey {
|
namespace hotkey {
|
||||||
|
|
|
@ -27,7 +27,8 @@
|
||||||
#include <libaegisub/exception.h>
|
#include <libaegisub/exception.h>
|
||||||
|
|
||||||
namespace json {
|
namespace json {
|
||||||
class Array;
|
class UnknownElement;
|
||||||
|
typedef std::deque<UnknownElement> Array;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace agi {
|
namespace agi {
|
||||||
|
|
|
@ -28,8 +28,8 @@
|
||||||
#include <libaegisub/exception.h>
|
#include <libaegisub/exception.h>
|
||||||
|
|
||||||
namespace json {
|
namespace json {
|
||||||
class Object;
|
|
||||||
class UnknownElement;
|
class UnknownElement;
|
||||||
|
typedef std::map<std::string, UnknownElement> Object;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace agi {
|
namespace agi {
|
||||||
|
|
Loading…
Reference in a new issue