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:
Thomas Goyne 2011-10-17 22:00:38 +00:00
parent 4e8848c110
commit dd46c7af7f
7 changed files with 56 additions and 189 deletions

View File

@ -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);

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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 {

View File

@ -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 {

View File

@ -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 {