/*
(c) 2012 +++ Filip Stoklas, aka FipS, http://www.4FipS.com +++
THIS CODE IS FREE - LICENSED UNDER THE MIT LICENSE
ARTICLE URL: http://forums.4fips.com/viewtopic.php?f=3&t=727
*/
#include <vector>
#include <string>
#include <cstdio>
#include <cassert>
/// Represents a read-only entity state (a kind of public data interface).
struct Entity
{
const char *name;
int x, y;
Entity(const char *name, int x, int y) : name(name), x(x), y(y) {}
};
/// Entity table with just a single getter and multiple setters.
class Entity_table
{
public:
/// Adds a new entity, returns its index.
size_t add(const char *name, int x, int y)
{
assert(name);
_records.emplace_back(Entity_record(Entity_data(name, x, y)));
return _records.size() - 1;
}
/// Returns the size of the table.
size_t size() const { return _records.size(); }
/// Returns an existing entity (its whole read-only state).
const Entity & get(size_t index) const
{
assert(index < _records.size());
return _records[index].entity;
}
/// Sets entity name.
void set_name(size_t index, const char *name)
{
assert(index < _records.size());
assert(name);
const Entity_data &orig_data = _records[index].data;
_records[index] = Entity_record(Entity_data(name, orig_data.x, orig_data.y));
}
/// Sets entity position.
void set_position(size_t index, int x, int y)
{
assert(index < _records.size());
const Entity_data &orig_data = _records[index].data;
_records[index] = Entity_record(Entity_data(orig_data.name, x, y));
}
private:
/// Represents a private entity state (data holder).
struct Entity_data
{
std::string name;
int x, y;
// here might come more implementation details that are not exposed in Entity
Entity_data(const std::string &name, int x, int y) : name(name), x(x), y(y) {}
};
/// Contains entity and its data, it's responsible for keeping them linked and in sync.
struct Entity_record
{
Entity_data data;
Entity entity;
/// Initializes data, links entity to the data.
Entity_record(const Entity_data &data):
data(data),
entity(data.name.c_str(), data.x, data.y)
{}
/// Copies data, links entity to the new data.
Entity_record(const Entity_record &rhs):
data(rhs.data),
entity(data.name.c_str(), data.x, data.y)
{}
/// Copies data, links entity to the new data.
Entity_record & operator = (const Entity_record &rhs)
{
data = rhs.data;
entity = Entity(data.name.c_str(), data.x, data.y);
return *this;
}
};
std::vector<Entity_record> _records;
};
int main()
{
Entity_table entities;
entities.add("foo", 10, 20);
entities.add("bar", 30, 40);
for(size_t i = 0, n = entities.size(); i < n; ++i)
{
const Entity &e = entities.get(i); // atomic getter
printf("entity[%u] : name='%s', pos=[%d, %d]\n", unsigned(i), e.name, int(e.x), int(e.y));
}
// fine grained setters
entities.set_name(0, "FOO");
entities.set_position(0, 50, 60);
entities.set_name(1, "BAR");
entities.set_position(1, 70, 80);
for(size_t i = 0, n = entities.size(); i < n; ++i)
{
const Entity &e = entities.get(i); // atomic getter
printf("entity[%u] : name='%s', pos=[%d, %d]\n", unsigned(i), e.name, int(e.x), int(e.y));
}
return 0;
}
// output:
// entity[0] : name='foo', pos=[10, 20]
// entity[1] : name='bar', pos=[30, 40]
// entity[0] : name='FOO', pos=[50, 60]
// entity[1] : name='BAR', pos=[70, 80]