Change json::Object's backing store from a list to a map. Cajun used list to preserve order, but json objects do not guarantee that order will be preserved

Originally committed to SVN as r5747.
This commit is contained in:
Thomas Goyne 2011-10-17 21:59:47 +00:00
parent 2f64a116a7
commit 9dc9047c11
10 changed files with 43 additions and 108 deletions

View file

@ -76,20 +76,18 @@ Hotkey::Hotkey(const std::string &file, const std::string &default_config)
json::Object object = hotkey_root; json::Object object = hotkey_root;
for (json::Object::const_iterator index(object.begin()); index != object.end(); index++) { for (json::Object::const_iterator index(object.begin()); index != object.end(); index++) {
const json::Object::Member& member = *index; const json::Object& obj = index->second;
const json::Object& obj = member.element; BuildHotkey(index->first, obj);
BuildHotkey(member.name, obj);
} }
} }
void Hotkey::BuildHotkey(std::string const& context, const json::Object& object) { void Hotkey::BuildHotkey(std::string const& context, const json::Object& object) {
for (json::Object::const_iterator index(object.begin()); index != object.end(); index++) { for (json::Object::const_iterator index(object.begin()); index != object.end(); index++) {
const json::Object::Member& member = *index; const json::Array& array = index->second;
const json::Array& array = member.element;
for (json::Array::const_iterator arr_index(array.begin()); arr_index != array.end(); arr_index++) { for (json::Array::const_iterator arr_index(array.begin()); arr_index != array.end(); arr_index++) {
Combo combo(context, member.name); Combo combo(context, index->first);
const json::Object& obj = *arr_index; const json::Object& obj = *arr_index;

View file

@ -37,11 +37,8 @@ MRUManager::MRUManager(const std::string &config, const std::string &default_con
json::Object::const_iterator index_object(root_new.begin()), index_objectEnd(root_new.end()); json::Object::const_iterator index_object(root_new.begin()), index_objectEnd(root_new.end());
for (; index_object != index_objectEnd; ++index_object) { for (; index_object != index_objectEnd; ++index_object) {
const json::Object::Member& member = *index_object; const std::string &member_name = index_object->first;
const std::string &member_name = member.name; Load(member_name, (json::Array)index_object->second);
const json::UnknownElement& element = member.element;
Load(member_name, (json::Array)element);
} }
} }

View file

@ -239,10 +239,10 @@ 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(json::Object::Member(thispart, json::Object())); pos = obj.insert(make_pair(thispart, json::Object()));
PutOptionVisitor visitor(restpart, value); PutOptionVisitor visitor(restpart, value);
pos->element.Accept(visitor); pos->second.Accept(visitor);
return visitor.result; return visitor.result;
} }
} }

View file

@ -43,9 +43,8 @@ void ConfigVisitor::Visit(const json::Object& object) {
name += "/"; name += "/";
for (; index != index_end; ++index) { for (; index != index_end; ++index) {
const json::Object::Member& member = *index; const std::string &member_name = index->first;
const std::string &member_name = member.name; const json::UnknownElement& element = index->second;
const json::UnknownElement& element = member.element;
ConfigVisitor config_visitor(values, name + member_name); ConfigVisitor config_visitor(values, name + member_name);
@ -61,11 +60,10 @@ void ConfigVisitor::Visit(const json::Array& array) {
for (; index != indexEnd; ++index) { for (; index != indexEnd; ++index) {
const json::Object& index_array = *index; const json::Object& index_array = *index;
json::Object::const_iterator index_object(index_array.begin()), index_objectEnd(index_array.end()); json::Object::const_iterator it(index_array.begin()), index_objectEnd(index_array.end());
for (; index_object != index_objectEnd; ++index_object) { for (; it != index_objectEnd; ++it) {
const json::Object::Member& member = *index_object; const std::string& member_name = it->first;
const std::string& member_name = member.name;
// This can only happen once since a list must always be of the same // This can only happen once since a list must always be of the same
// type, if we try inserting another type into it we want it to fail. // type, if we try inserting another type into it we want it to fail.
@ -86,27 +84,16 @@ void ConfigVisitor::Visit(const json::Array& array) {
} }
try { try {
if (member_name == "string") { if (member_name == "string")
std::string val = (json::String)member.element; array_list->InsertString((json::String)it->second);
array_list->InsertString(val); else if (member_name == "int")
array_list->InsertInt((int64_t)(json::Number)it->second);
} else if (member_name == "int") { else if (member_name == "double")
int64_t val = (int64_t)(json::Number)member.element; array_list->InsertDouble((json::Number)it->second);
array_list->InsertInt(val); else if (member_name == "bool")
array_list->InsertBool((json::Boolean)it->second);
} else if (member_name == "double") { else if (member_name == "colour")
double val = (json::Number)member.element; array_list->InsertColour((std::string)(json::String)it->second);
array_list->InsertDouble(val);
} else if (member_name == "bool") {
bool val = (json::Boolean)member.element;
array_list->InsertBool(val);
} else if (member_name == "colour") {
std::string val = (json::String)member.element;
Colour col(val);
array_list->InsertColour(col);
}
} catch (agi::Exception&) { } catch (agi::Exception&) {
delete array_list; delete array_list;
throw OptionJsonValueArray("Attempt to insert value into array of wrong type"); throw OptionJsonValueArray("Attempt to insert value into array of wrong type");

View file

@ -185,17 +185,7 @@ private:
class Object class Object
{ {
public: public:
struct Member { typedef std::map<std::string, UnknownElement> Members;
Member(const std::string& nameIn = std::string(), const UnknownElement& elementIn = UnknownElement())
: name(nameIn), element(elementIn) { }
bool operator == (const Member& member) const;
std::string name;
UnknownElement element;
};
typedef std::list<Member> Members; // map faster, but does not preserve order
typedef Members::iterator iterator; typedef Members::iterator iterator;
typedef Members::const_iterator const_iterator; typedef Members::const_iterator const_iterator;
@ -209,10 +199,10 @@ public:
size_t size() const { return m_Members.size(); } size_t size() const { return m_Members.size(); }
bool empty() const { return m_Members.empty(); } bool empty() const { return m_Members.empty(); }
iterator find(const std::string& name); iterator find(const std::string& name) { return m_Members.find(name); }
const_iterator find(const std::string& name) const; const_iterator find(const std::string& name) const { return m_Members.find(name); }
iterator insert(const Member& member); iterator insert(std::pair<std::string, UnknownElement> const& ele);
iterator erase(iterator it) { return m_Members.erase(it); } iterator erase(iterator it) { return m_Members.erase(it); }
void clear() { m_Members.clear(); } void clear() { m_Members.clear(); }
@ -220,8 +210,6 @@ public:
const UnknownElement& operator [](const std::string& name) const; const UnknownElement& operator [](const std::string& name) const;
private: private:
class Finder;
Members m_Members; Members m_Members;
}; };

View file

@ -7,18 +7,10 @@ Author: Terry Caton
***********************************************/ ***********************************************/
#include "visitor.h" #include "visitor.h"
#include "reader.h"
#include <cassert> #include <cassert>
#include <algorithm> #include <algorithm>
#include <map> #include <map>
/*
TODO:
* better documentation
*/
namespace json namespace json
{ {
@ -199,40 +191,13 @@ inline bool UnknownElement::operator == (const UnknownElement& element) const
////////////////// //////////////////
// Object members // Object members
inline Object::iterator Object::insert(std::pair<std::string, UnknownElement> const& ele)
inline bool Object::Member::operator == (const Member& member) const
{ {
return name == member.name && element == member.element; iterator it = find(ele.first);
}
class Object::Finder : public std::unary_function<Object::Member, bool>
{
std::string m_name;
public:
Finder(const std::string& name) : m_name(name) {}
bool operator () (const Object::Member& member) {
return member.name == m_name;
}
};
inline Object::iterator Object::find(const std::string& name)
{
return std::find_if(m_Members.begin(), m_Members.end(), Finder(name));
}
inline Object::const_iterator Object::find(const std::string& name) const
{
return std::find_if(m_Members.begin(), m_Members.end(), Finder(name));
}
inline Object::iterator Object::insert(const Member& member)
{
iterator it = find(member.name);
if (it != m_Members.end()) if (it != m_Members.end())
throw Exception("Object member already exists: " + member.name); throw Exception("Object member already exists: " + ele.first);
m_Members.push_back(member); return m_Members.insert(ele).first;
return --it;
} }
inline UnknownElement& Object::operator [](const std::string& name) inline UnknownElement& Object::operator [](const std::string& name)
@ -240,9 +205,9 @@ inline UnknownElement& Object::operator [](const std::string& name)
iterator it = find(name); iterator it = find(name);
if (it == m_Members.end()) if (it == m_Members.end())
{ {
it = insert(Member(name)); it = insert(make_pair(name, UnknownElement()));
} }
return it->element; return it->second;
} }
inline const UnknownElement& Object::operator [](const std::string& name) const inline const UnknownElement& Object::operator [](const std::string& name) const
@ -250,7 +215,7 @@ inline const UnknownElement& Object::operator [](const std::string& name) const
const_iterator it = find(name); const_iterator it = find(name);
if (it == end()) if (it == end())
throw Exception("Object member not found: " + name); throw Exception("Object member not found: " + name);
return it->element; return it->second;
} }
///////////////// /////////////////

View file

@ -402,17 +402,17 @@ 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)
{ {
Object::Member member; 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.name = MatchExpectedToken(Token::TOKEN_STRING, tokenStream); member.first = MatchExpectedToken(Token::TOKEN_STRING, tokenStream);
// ...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.element, tokenStream); Parse(member.second, tokenStream);
// try adding it to the object (this could throw) // try adding it to the object (this could throw)
try try
@ -422,7 +422,7 @@ inline void Reader::Parse(Object& object, Reader::TokenStream& tokenStream)
catch (Exception&) catch (Exception&)
{ {
// must be a duplicate name // must be a duplicate name
throw ParseException("Duplicate object member token: " + member.name, tokenName.locBegin, tokenName.locEnd); throw ParseException("Duplicate object member token: " + member.first, tokenName.locBegin, tokenName.locEnd);
} }
bContinue = (tokenStream.EOS() == false && bContinue = (tokenStream.EOS() == false &&

View file

@ -82,8 +82,8 @@ inline void Writer::Write_i(const Object& object)
Object::const_iterator it(object.begin()), Object::const_iterator it(object.begin()),
itend(object.end()); itend(object.end());
while (it != itend) { while (it != itend) {
m_ostr << std::string(m_nTabDepth, '\t') << '"' << it->name << "\" : "; m_ostr << std::string(m_nTabDepth, '\t') << '"' << it->first << "\" : ";
Write_i(it->element); Write_i(it->second);
if (++it != itend) if (++it != itend)
m_ostr << ','; m_ostr << ',';

View file

@ -231,7 +231,7 @@ struct CommandMenuBar : public wxMenuBar {
bool read_entry(json::Object const& obj, const char *name, std::string *value) { bool read_entry(json::Object const& obj, const char *name, std::string *value) {
json::Object::const_iterator it = obj.find(name); json::Object::const_iterator it = obj.find(name);
if (it == obj.end()) return false; if (it == obj.end()) return false;
*value = static_cast<json::String const&>(it->element); *value = static_cast<json::String const&>(it->second);
return true; return true;
} }
@ -265,7 +265,7 @@ menu_items const& get_menu(std::string const& name) {
menu_map::const_iterator it = root.find(name); menu_map::const_iterator it = root.find(name);
if (it == root.end()) throw menu::UnknownMenu("Menu named " + name + " not found"); if (it == root.end()) throw menu::UnknownMenu("Menu named " + name + " not found");
return it->element; return it->second;
} }
wxMenu *build_menu(std::string const& name, agi::Context *c, CommandManager *cm, wxMenu *menu = 0); wxMenu *build_menu(std::string const& name, agi::Context *c, CommandManager *cm, wxMenu *menu = 0);

View file

@ -100,7 +100,7 @@ namespace {
int icon_size = OPT_GET("App/Toolbar Icon Size")->GetInt(); int icon_size = OPT_GET("App/Toolbar Icon Size")->GetInt();
json::Array arr = it->element; json::Array arr = it->second;
commands.reserve(arr.size()); commands.reserve(arr.size());
bool needs_onidle = false; bool needs_onidle = false;