Program Listing for File properties.h
↰ Return to documentation for file (zmesh/core/properties.h)
#pragma once
#include <vector>
#include <string>
#include <memory>
#include <stdexcept>
#include <zmesh/core/handles.h>
namespace zmesh {
namespace core {
class BaseProperty;
template<typename T>
class Property;
template<typename T>
class PropertyHandle;
class PropertyContainer;
using BasePropertyPtr = BaseProperty*;
template<typename T>
using PropertyPtr = Property<T>*;
class BaseProperty {
public:
explicit BaseProperty(std::string name) : name_(name) { }
virtual ~BaseProperty() = default;
virtual void resize(size_t n) = 0;
virtual void reserve(size_t n) = 0;
virtual void push_back() = 0;
virtual void free_memory() = 0;
virtual BasePropertyPtr clone() = 0; // deep copy
const std::string& name() const {
return name_;
}
protected:
std::string name_;
};
template<typename T>
class Property : public BaseProperty {
public:
using ValueType = T;
using VectorType = std::vector<T>;
using reference = typename VectorType::reference;
using const_reference = typename VectorType::const_reference;
public:
Property(std::string name, T default_value = T())
: BaseProperty(std::move(name)), default_value_(std::move(default_value)) { }
// virtual ~Property() {
// }
void resize(size_t n) override {
data_.resize(n);
}
void reserve(size_t n) override {
data_.reserve(n);
}
void push_back() override {
data_.push_back(default_value_);
}
void free_memory() override {
data_.shrink_to_fit();
}
BasePropertyPtr clone() override {
PropertyPtr<T> bp = new Property<T>(name_, default_value_);
bp->data_ = data_;
return bp;
}
VectorType& vector() {
return data_;
}
const VectorType& vector() const {
return data_;
}
ValueType& default_value() {
return default_value_;
}
const ValueType& default_value() const {
return default_value_;
}
reference operator[](size_t idx) {
return data_[idx];
}
const_reference operator[](size_t idx) const {
return data_[idx];
}
private:
VectorType data_;
ValueType default_value_;
};
template<typename T>
class PropertyHandle {
public:
friend class PropertyContainer;
using ValueType = typename Property<T>::ValueType;
using VectorType = typename Property<T>::VectorType;
using reference = typename Property<T>::reference;
using const_reference = typename Property<T>::const_reference;
public:
PropertyHandle(PropertyPtr<T> prop = nullptr) : prop_(prop) { }
// no need to delete the pointer
// virtual ~PropertyHandle() {
// delete prop_;
// }
bool is_valid() const {
return prop_ != nullptr;
}
VectorType& vector() {
return prop_->vector();
}
const VectorType& vector() const {
return prop_->vector();
}
ValueType& default_value() {
return prop_->default_value();
}
const ValueType& default_value() const {
return prop_->default_value();
}
std::string name() {
return prop_->name();
}
reference operator[](size_t idx) {
return (*prop_)[idx];
}
const_reference operator[](size_t idx) const {
return (*prop_)[idx];
}
private:
void reset() {
prop_ = nullptr;
}
private:
PropertyPtr<T> prop_;
};
template<typename T>
class VertexPropertyHandle : public PropertyHandle<T> {
public:
explicit VertexPropertyHandle() = default;
explicit VertexPropertyHandle(PropertyHandle<T> p) : PropertyHandle<T>(p) { }
reference operator[](VertexHandle v) {
return PropertyHandle<T>::operator[](v.idx());
}
const_reference operator[](VertexHandle v) const {
return PropertyHandle<T>::operator[](v.idx());
}
};
template<typename T>
class EdgePropertyHandle : public PropertyHandle<T> {
public:
explicit EdgePropertyHandle() = default;
explicit EdgePropertyHandle(PropertyHandle<T> p) : PropertyHandle<T>(p) { }
reference operator[](EdgeHandle e) {
return PropertyHandle<T>::operator[](e.idx());
}
const_reference operator[](EdgeHandle e) const {
return PropertyHandle<T>::operator[](e.idx());
}
};
template<typename T>
class HalfedgePropertyHandle : public PropertyHandle<T> {
public:
explicit HalfedgePropertyHandle() = default;
explicit HalfedgePropertyHandle(PropertyHandle<T> p) : PropertyHandle<T>(p) { }
reference operator[](HalfedgeHandle h) {
return PropertyHandle<T>::operator[](h.idx());
}
const_reference operator[](HalfedgeHandle h) const {
return PropertyHandle<T>::operator[](h.idx());
}
};
template<typename T>
class FacePropertyHandle : public PropertyHandle<T> {
public:
explicit FacePropertyHandle() = default;
explicit FacePropertyHandle(PropertyHandle<T> p) : PropertyHandle<T>(p) { }
reference operator[](FaceHandle f) {
return PropertyHandle<T>::operator[](f.idx());
}
const_reference operator[](FaceHandle f) const {
return PropertyHandle<T>::operator[](f.idx());
}
};
class PropertyContainer {
public:
PropertyContainer() = default;
~PropertyContainer() {
clear();
}
PropertyContainer(const PropertyContainer& rhs) {
*this = rhs;
}
PropertyContainer& operator=(const PropertyContainer& rhs) {
if (this != &rhs) { // avoid self assignment
size_ = rhs.size_;
clear();
props_.resize(rhs.n_properties());
for (size_t i = 0; i < props_.size(); i++) {
props_[i] = rhs.props_[i]->clone();
}
}
return *this;
}
std::vector<std::string> properties() const {
std::vector<std::string> names;
names.reserve(props_.size());
for (auto& prop : props_) {
names.push_back(prop->name());
}
return names;
}
bool exists(const std::string& name) const {
for (auto& prop : props_) {
if (prop->name() == name) {
return true;
}
}
return false;
}
template<typename T>
PropertyHandle<T> add(const std::string& name, const T default_value = T()) {
// throw an invalid argument exception if a property with [name] is already exists
for (auto& prop : props_) {
if (prop->name() == name) {
throw std::invalid_argument("a property with name " + name + " is already exists.");
}
}
PropertyPtr<T> p = new Property<T>(name, default_value);
p->resize(size_);
props_.push_back(p);
return PropertyHandle<T>(p);
}
template<typename T>
PropertyHandle<T> get(const std::string& name) const {
for (auto& prop : props_) {
if (prop->name() == name) {
return PropertyHandle<T>(dynamic_cast<PropertyPtr<T>>(prop));
}
}
// does not exist a property with this [name], throw an exception
throw std::invalid_argument("does not exists a property with name " + name + ".");
}
template<typename T>
PropertyHandle<T> get_or_add(const std::string& name, const T default_value = T()) {
for (auto& prop : props_) {
if (prop->name() == name) {
return PropertyHandle<T>(dynamic_cast<PropertyPtr<T>>(prop));
}
}
return add<T>(name, default_value);
}
template<typename T>
void remove(PropertyHandle<T>& handle) {
for (auto it = props_.begin(); it != props_.end(); ++it) {
if (*it == handle.prop_) {
props_.erase(it);
it->reset();
handle.reset();
break;
}
}
}
void free_memory() {
for (auto& prop : props_) {
prop->free_memory();
}
}
void clear() {
size_ = 0;
for (auto& prop : props_) {
prop = nullptr;
}
props_.clear();
}
size_t n_properties() const {
return props_.size();
}
size_t size() const {
return size_;
}
void push_back() {
size_++;
for (auto& prop : props_) {
prop->push_back();
}
}
void resize(size_t n) {
size_ = n;
for (auto& prop : props_) {
prop->resize(n);
}
}
void reserve(size_t n) {
for (auto& prop : props_) {
prop->reserve(n);
}
}
private:
std::vector<BasePropertyPtr> props_;
size_t size_{0};
};
}
}