/**
* @file unique_storage.h
* Unique storage of values
*
* @remark Copyright 2002 OProfile authors
* @remark Read the file COPYING
*
* @author Philippe Elie
* @author John Levon
*/
#ifndef UNIQUE_STORAGE_H
#define UNIQUE_STORAGE_H
#include <vector>
#include <map>
#include <stdexcept>
/**
* Store values such that only one copy of the value
* is ever stored.
*
* I is an arbitrary typename that's never
* used.
*
* It is a required parameter in order to enforce
* type-safety for a collection.
*
* The value type "V" must be default-constructible,
* and this is the value returned by a stored id_value
* where .set() is false
*/
template <typename I, typename V> class unique_storage {
public:
unique_storage() {
// id 0
values.push_back(V());
}
virtual ~unique_storage() {}
typedef std::vector<V> stored_values;
/// the actual ID type
struct id_value {
/// id == 0 means "empty" / "undefined"
id_value() : id(0) {}
/// does this ID map to a non-default value ?
bool set() const {
return id;
}
bool operator<(id_value const & rhs) const {
return id < rhs.id;
}
bool operator==(id_value const & rhs) const {
return id == rhs.id;
}
bool operator!=(id_value const & rhs) const {
return !(id == rhs.id);
}
private:
friend class unique_storage<I, V>;
typedef typename stored_values::size_type size_type;
explicit id_value(size_type s) : id(s) {}
/// actual ID value
size_type id;
};
/// ensure this value is available
id_value const create(V const & value) {
typename id_map::value_type val(value, id_value(values.size()));
std::pair<typename id_map::iterator, bool>
inserted = ids.insert(val);
if (inserted.second)
values.push_back(value);
return inserted.first->second;
}
/// return the stored value for the given ID
V const & get(id_value const & id) const {
// some stl lack at(), so we emulate it
if (id.id < values.size())
return values[id.id];
throw std::out_of_range("unique_storage::get(): out of bounds");
}
private:
typedef std::map<V, id_value> id_map;
/// the contained values
stored_values values;
/// map from ID to value
id_map ids;
};
#endif /* !UNIQUE_STORAGE_H */