Skip to content

Commit

Permalink
Breaking changes!
Browse files Browse the repository at this point in the history
Entity no longer contains the map since it was adding overhead to anything
that derived from it.

The create_map function has now been replaced with a map function that
returns a mapping object. Added << operator overloads to allow for a tidier
mapping syntax along with macros that help with automatic naming.

Moved the "to_tree" and "from_tree" to "to" and "from" overloads.

Const'd a lot of stuff to make it easier to pass temporaries about.

Renamed the map.h to vmap.h to match the class names inside.
  • Loading branch information
parnham committed Aug 2, 2013
1 parent f6fd688 commit 09dc3c2
Show file tree
Hide file tree
Showing 11 changed files with 205 additions and 179 deletions.
31 changes: 17 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@ Warning
-------

This library should be considered alpha and as such is not suitable for production
environments. However, the API for the
[entity](https://github.com/emergent-design/libentity/wiki/Entity) base class is
extremely simple and therefore unlikely to change.
environments.


Parsers
Expand Down Expand Up @@ -62,18 +60,16 @@ using namespace std;
using namespace ent;


// A structure with simple members that is derived from entity
// A structure with simple members, derived from entity
struct Simple : entity
{
string name = "default";
bool flag = false;
int integer = 0;

void create_map()
mapping map()
{
automap(name); // Uses parameter name (avoid "this->")
map("flag", this->flag); // Uses explicit name ("this->" is safe)
map("int", this->integer); // Uses an alternative name
return mapping() << ref(name) << ref(flag) << ref("int", integer);
}
};

Expand Down Expand Up @@ -116,12 +112,13 @@ g++ -std=c++11 simple.cpp -lentity
Any class or struct that descends from
[entity](https://github.com/emergent-design/libentity/wiki/Entity)
must implement the
[create_map](https://github.com/emergent-design/libentity/wiki/Entity#create-map)
[map](https://github.com/emergent-design/libentity/wiki/Entity#map)
function which allows the library to do its magic without the need for a
pre-compilation step. The macro ```automap``` simply expands to call the
```map(name, reference)``` function where the name matches that of the parameter.
You can use the map function directly if the names must differ when
serialised or deserialised.
pre-compilation step. The macro ```ref``` simply expands to a
```mapping::reference``` instance and if no name is provided it will
automagically use the parameter name (so avoid using ```this->```).
By allowing the name to be specified, as in the "int" example above, it can map a
value from a third-party system where the names may differ.


Installation
Expand All @@ -137,4 +134,10 @@ and, with some tweaking of the build process, it should also be possible to
compile for Windows/OSX since it has no dependencies other than a modern compiler
that supports C++11.

[Changelog](https://github.com/emergent-design/libentity/blob/master/packages/debian/changelog)
---

<div style="text-align:center">
<a href="https://github.com/emergent-design/libentity/blob/master/packages/debian/changelog">
Changelog
</a>
</div>
65 changes: 17 additions & 48 deletions include/entity/entity.h
Original file line number Diff line number Diff line change
@@ -1,79 +1,48 @@
#pragma once

#include <entity/map.h>
#include <entity/tree.h>
#include <entity/mapping.h>


namespace ent
{
// Utility macro to invoke the map function using the name of
// the parameter as the mapping name.
#define automap(reference) map(#reference, reference)


// The abstract base class for serialisable objects.
// Inherit from this, implement the create_map function correctly,
// Inherit from this, implement the map function correctly,
// and your class will become serialisable.
class entity
{
public:

// Convenience function that invokes the appropriate
// methods to serialise this instance.
template <class T> std::string to(bool pretty = false)
// Uses the mapping to convert this object instance
// into a tree structure for easier parsing.
tree to()
{
return this->to_tree().to<T>(pretty);
return this->map().to();
}

// Convenience function that invokes the appropriate
// methods to deserialise this instance.
template <class T> void from(const std::string &value)
// Convenience functions to serialise this instance.
template <class T> std::string to(bool pretty = false)
{
tree t = T::from(value);
this->from_tree(t);
return this->map().to().to<T>(pretty);
}

// Uses the mapping to convert this object instance
// into a tree structure for easier parsing.
tree to_tree();

// Uses the mapping to pull the relevant values
// out of a tree and into this object instance.
void from_tree(tree &tree);


protected:

// Create a mapping instance for a singular value
template <class T> void map(std::string name, T &reference)
void from(const tree &tree)
{
this->mapping[name] = std::make_shared<vmap<T>>(reference);
return this->map().from(tree);
}

// Create a mapping instance for an array
template <class T> void map(std::string name, std::vector<T> &reference)
// Convenience function to deserialise this instance.
template <class T> void from(const std::string &value)
{
this->mapping[name] = std::make_shared<vmap<T>>(reference);
this->map().from(T::from(value));
}

// Create a mapping instance for a dictionary
template <class T> void map(std::string name, std::map<std::string, T> &reference)
{
this->mapping[name] = std::make_shared<vmap<T>>(reference);
}

protected:

// Abstract function that must be implemented by
// any objects to be serialised/deserialised.
virtual void create_map() = 0;


private:

// This holds the map that links object property names to
// actual instance members.
std::map<std::string, std::shared_ptr<vmapbase>> mapping;
virtual mapping map() = 0;
};

// Special case to bypass the vector<T> template
template <> void entity::map(std::string name, std::vector<byte> &reference);
}
73 changes: 73 additions & 0 deletions include/entity/mapping.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
#pragma once

#include <entity/vmap.h>
#include <entity/tree.h>


namespace ent
{
// Utility macros for invoking the appropriate reference constructor
// If one argument is passed then string name of that argument is used as the mapping key
// If two arguments are passed then the supplied name is used as the mapping key
#ifndef ent_ref
#define ent_get_ref(_1, _2, name, ...) name
#define ent_auto_ref(item) mapping::reference(#item, item)
#define ent_man_ref(name, item) mapping::reference(name, item)
#define ent_ref(...) ent_get_ref(__VA_ARGS__, ent_man_ref, ent_auto_ref)(__VA_ARGS__)

// Concise call to ent_ref, disable if it conflicts and use ent_ref instead
#define ref ent_ref
#endif


// Storage for the mapping lookup table
class mapping
{
public:

// Reference to a mapped variable
struct reference
{
std::string name;
std::shared_ptr<vmapbase> item;

// Create a mapping reference for a singular value
template <class T> reference(std::string name, T &item) : name(name), item(std::make_shared<vmap<T>>(item)) {}

// Create a mapping reference for an array (except vector<byte>)
template <class T, class = typename std::enable_if<!std::is_same<T, byte>::value>::type>
reference(std::string name, std::vector<T> &item) : name(name), item(std::make_shared<vmap<T>>(item)) {}

// Create a mapping reference for a dictionary
template <class T> reference(std::string name, std::map<std::string, T> &item) : name(name), item(std::make_shared<vmap<T>>(item)) {}
};


// Default
mapping() {}

// Construct from a single reference
mapping(const reference &item);

// Construct from a list of references
mapping(std::initializer_list<reference> items);

// Add a reference to the mapping
mapping &operator<<(const reference &item);

// Add a list of references to the mapping
mapping &operator<<(std::initializer_list<reference> items);

// Traverses the map to generate a tree
tree to();

// Traverses the map and updates with values from the tree
void from(const tree &tree);

private:

// This holds the map that links object property names to
// actual instance members.
std::map<std::string, std::shared_ptr<vmapbase>> lookup;
};
}
18 changes: 8 additions & 10 deletions include/entity/tree.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ namespace ent

// Get property by name where the value is an object and therefore
// represented by another tree.
tree get(const std::string name);
tree get(const std::string name) const;

// Set the value of a property to null
tree &set(const std::string name);
Expand All @@ -30,13 +30,13 @@ namespace ent
tree &set(const std::string name, const std::vector<tree> &items);

// Get property by name where the value is an array of objects
std::vector<tree> array(const std::string name);
std::vector<tree> array(const std::string name) const;


// Get property by name where the value is a simple scalar (string, number, boolean, null)
template <class T> T get(const std::string name, T defaultValue = T())
template <class T> T get(const std::string name, T defaultValue = T()) const
{
return this->properties.count(name) ? this->properties[name].get(defaultValue) : defaultValue;
return this->properties.count(name) ? this->properties.at(name).get(defaultValue) : defaultValue;
}


Expand All @@ -49,13 +49,13 @@ namespace ent


// Get property by name where the value is an array of simple scalar values
template <class T> std::vector<T> array(const std::string name)
template <class T> std::vector<T> array(const std::string name) const
{
std::vector<T> result;

if (this->properties.count(name))
{
auto &p = this->properties[name];
auto &p = this->properties.at(name);

if (p.get_type() == value::Type::Array)
{
Expand All @@ -74,8 +74,6 @@ namespace ent
template <class T> tree &set(std::string name, const std::vector<T> &items)
{
std::vector<value> result(items.size());
//value result(vtype::Array);
//result.array.resize(items.size());

std::transform(items.begin(), items.end(), result.begin(), [](const T &v) {
return value(v);
Expand All @@ -88,13 +86,13 @@ namespace ent


// Get property by name where the value is an object and return as a map
template <class T> std::map<std::string, T> map(const std::string name)
template <class T> std::map<std::string, T> map(const std::string name) const
{
std::map<std::string, T> result;

if (this->properties.count(name))
{
auto &p = this->properties[name];
auto &p = this->properties.at(name);

if (p.get_type() == value::Type::Object)
{
Expand Down
22 changes: 11 additions & 11 deletions include/entity/map.h → include/entity/vmap.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ namespace ent
struct vmapbase
{
virtual value to() = 0;
virtual void from(value &value) = 0;
virtual void from(const value &value) = 0;
};


Expand Down Expand Up @@ -53,7 +53,7 @@ namespace ent
std::vector<value> result(array->size());

std::transform(array->begin(), array->end(), result.begin(), [](T &v) {
return value(std::make_shared<tree>(v.to_tree()));
return value(std::make_shared<tree>(v.to()));
});

return value(result);
Expand All @@ -62,11 +62,11 @@ namespace ent
{
auto result = std::make_shared<tree>();

for (auto &i : *map) result->set(i.first, i.second.to_tree());
for (auto &i : *map) result->set(i.first, i.second.to());

return value(result);
}
else if (reference) return value(std::make_shared<tree>(reference->to_tree()));
else if (reference) return value(std::make_shared<tree>(reference->to()));

return value();
}
Expand All @@ -75,7 +75,7 @@ namespace ent
// Update the member value in an object with data from a tree value.
// In this particular case the member is an object and so must be
// updated from a tree contained within the value.
virtual void from(value &value)
virtual void from(const value &value)
{
if (array)
{
Expand All @@ -88,7 +88,7 @@ namespace ent
if (v.get_type() == value::Type::Object)
{
this->array->push_back(T());
this->array->back().from_tree(v.object());
this->array->back().from(v.object());
}
}
}
Expand All @@ -103,12 +103,12 @@ namespace ent
{
if (i.second.get_type() == value::Type::Object)
{
(*this->map)[i.first].from_tree(i.second.object());
(*this->map)[i.first].from(i.second.object());
}
}
}
}
else if (value.get_type() == value::Type::Object) reference->from_tree(value.object());
else if (value.get_type() == value::Type::Object) reference->from(value.object());
}


Expand Down Expand Up @@ -136,7 +136,7 @@ namespace ent

// Update the member value in the object instance by treating the string value
// as base64.
virtual void from(value &value)
virtual void from(const value &value)
{
*reference = value.get(std::vector<byte> {});
}
Expand Down Expand Up @@ -183,7 +183,7 @@ namespace ent


// Update the member value in an object with data from a tree value.
virtual void from(value &value)
virtual void from(const value &value)
{
if (array)
{
Expand Down Expand Up @@ -257,7 +257,7 @@ namespace ent


// Update the member value in an object with data from a tree value.
virtual void from(value &value)
virtual void from(const value &value)
{
if (array)
{
Expand Down
Loading

0 comments on commit 09dc3c2

Please sign in to comment.