mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-22 05:00:53 +00:00
Non-streaming rocksdb serializer nearing completion
This commit is contained in:
@@ -97,12 +97,7 @@ protected:
|
|||||||
IfcEntityInstanceData data_;
|
IfcEntityInstanceData data_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IfcBaseClass(IfcEntityInstanceData&& data)
|
IfcBaseClass(IfcEntityInstanceData&& data);
|
||||||
: identity_(counter_++)
|
|
||||||
, id_(0)
|
|
||||||
, file_(nullptr)
|
|
||||||
, data_(std::move(data))
|
|
||||||
{}
|
|
||||||
|
|
||||||
const IfcEntityInstanceData& data() const { return data_; }
|
const IfcEntityInstanceData& data() const { return data_; }
|
||||||
IfcEntityInstanceData& data() { return data_; }
|
IfcEntityInstanceData& data() { return data_; }
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ public:
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline T dispatch_get_(AttributeValue::pointer_type array_, uint8_t storage_model_, size_t instance_name_, uint8_t index_)
|
inline T dispatch_get_(AttributeValue::pointer_type array_, uint8_t storage_model_, size_t instance_name_, bool is_entity, uint8_t index_)
|
||||||
{
|
{
|
||||||
if (storage_model_ == 0) {
|
if (storage_model_ == 0) {
|
||||||
return array_.storage_ptr->get<T>(index_);
|
return array_.storage_ptr->get<T>(index_);
|
||||||
@@ -43,7 +43,7 @@ namespace {
|
|||||||
!std::is_same_v<std::remove_cv_t<std::remove_pointer_t<T>>, IfcUtil::IfcBaseClass>)
|
!std::is_same_v<std::remove_cv_t<std::remove_pointer_t<T>>, IfcUtil::IfcBaseClass>)
|
||||||
{
|
{
|
||||||
std::string str;
|
std::string str;
|
||||||
array_.db_ptr->db->Get(rocksdb::ReadOptions{}, "i|" + std::to_string(instance_name_) + "|" + std::to_string(index_), &str);
|
array_.db_ptr->db->Get(rocksdb::ReadOptions{}, (is_entity ? "i|" : "t|") + std::to_string(instance_name_) + "|" + std::to_string(index_), &str);
|
||||||
impl::deserialize(array_.db_ptr, str, val);
|
impl::deserialize(array_.db_ptr, str, val);
|
||||||
}
|
}
|
||||||
return val;
|
return val;
|
||||||
@@ -51,24 +51,29 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline bool dispatch_has_(AttributeValue::pointer_type array_, uint8_t storage_model_, size_t instance_name_, uint8_t index_)
|
inline bool dispatch_has_(AttributeValue::pointer_type array_, uint8_t storage_model_, size_t instance_name_, bool is_entity, uint8_t index_)
|
||||||
{
|
{
|
||||||
if (storage_model_ == 0) {
|
if (storage_model_ == 0) {
|
||||||
return array_.storage_ptr->has<T>(index_);
|
return array_.storage_ptr->has<T>(index_);
|
||||||
} else {
|
} else {
|
||||||
std::string str;
|
std::string str;
|
||||||
array_.db_ptr->db->Get(rocksdb::ReadOptions{}, "i|" + std::to_string(instance_name_) + "|" + std::to_string(index_), &str);
|
array_.db_ptr->db->Get(rocksdb::ReadOptions{}, (is_entity ? "i|" : "t|") + std::to_string(instance_name_) + "|" + std::to_string(index_), &str);
|
||||||
|
if constexpr (std::is_same_v<T, Blank>) {
|
||||||
|
if (str.size() == 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
return str[0] == TypeEncoder::encode_type<T>();
|
return str[0] == TypeEncoder::encode_type<T>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline size_t dispatch_index_(AttributeValue::pointer_type array_, uint8_t storage_model_, size_t instance_name_, uint8_t index_)
|
inline size_t dispatch_index_(AttributeValue::pointer_type array_, uint8_t storage_model_, size_t instance_name_, bool is_entity, uint8_t index_)
|
||||||
{
|
{
|
||||||
if (storage_model_ == 0) {
|
if (storage_model_ == 0) {
|
||||||
return array_.storage_ptr->index(index_);
|
return array_.storage_ptr->index(index_);
|
||||||
} else {
|
} else {
|
||||||
std::string str;
|
std::string str;
|
||||||
array_.db_ptr->db->Get(rocksdb::ReadOptions{}, "i|" + std::to_string(instance_name_) + "|" + std::to_string(index_), &str);
|
array_.db_ptr->db->Get(rocksdb::ReadOptions{}, (is_entity ? "i|" : "t|") + std::to_string(instance_name_) + "|" + std::to_string(index_), &str);
|
||||||
return (size_t) str[0] - 'A';
|
return (size_t) str[0] - 'A';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -77,57 +82,57 @@ namespace {
|
|||||||
|
|
||||||
AttributeValue::operator int() const
|
AttributeValue::operator int() const
|
||||||
{
|
{
|
||||||
return dispatch_get_<int>(array_, storage_model_, instance_name_, index_);
|
return dispatch_get_<int>(array_, storage_model_, instance_name_, entity_or_type_ == 1 ? true : false, index_);
|
||||||
}
|
}
|
||||||
|
|
||||||
AttributeValue::operator bool() const
|
AttributeValue::operator bool() const
|
||||||
{
|
{
|
||||||
return dispatch_get_<bool>(array_, storage_model_, instance_name_, index_);
|
return dispatch_get_<bool>(array_, storage_model_, instance_name_, entity_or_type_ == 1 ? true : false, index_);
|
||||||
}
|
}
|
||||||
|
|
||||||
AttributeValue::operator double() const
|
AttributeValue::operator double() const
|
||||||
{
|
{
|
||||||
return dispatch_get_<double>(array_, storage_model_, instance_name_, index_);
|
return dispatch_get_<double>(array_, storage_model_, instance_name_, entity_or_type_ == 1 ? true : false, index_);
|
||||||
}
|
}
|
||||||
|
|
||||||
AttributeValue::operator boost::logic::tribool() const
|
AttributeValue::operator boost::logic::tribool() const
|
||||||
{
|
{
|
||||||
if (dispatch_has_<bool>(array_, storage_model_, instance_name_, index_)) {
|
if (dispatch_has_<bool>(array_, storage_model_, instance_name_, entity_or_type_ == 1 ? true : false, index_)) {
|
||||||
return dispatch_get_<bool>(array_, storage_model_, instance_name_, index_);
|
return dispatch_get_<bool>(array_, storage_model_, instance_name_, entity_or_type_ == 1 ? true : false, index_);
|
||||||
}
|
}
|
||||||
return dispatch_get_<boost::logic::tribool>(array_, storage_model_, instance_name_, index_);
|
return dispatch_get_<boost::logic::tribool>(array_, storage_model_, instance_name_, entity_or_type_ == 1 ? true : false, index_);
|
||||||
}
|
}
|
||||||
|
|
||||||
AttributeValue::operator std::string() const
|
AttributeValue::operator std::string() const
|
||||||
{
|
{
|
||||||
if (dispatch_has_<EnumerationReference>(array_, storage_model_, instance_name_, index_)) {
|
if (dispatch_has_<EnumerationReference>(array_, storage_model_, instance_name_, entity_or_type_ == 1 ? true : false, index_)) {
|
||||||
// @todo this is silly, but the way things currently work,
|
// @todo this is silly, but the way things currently work,
|
||||||
// @todo also we don't really need to store a reference to the enumeration type, when this same type is already stored on the definition of the entity and no other value can be provided.
|
// @todo also we don't really need to store a reference to the enumeration type, when this same type is already stored on the definition of the entity and no other value can be provided.
|
||||||
if (storage_model_ == 0) {
|
if (storage_model_ == 0) {
|
||||||
return dispatch_get_<EnumerationReference>(array_, storage_model_, instance_name_, index_).value();
|
return dispatch_get_<EnumerationReference>(array_, storage_model_, instance_name_, entity_or_type_ == 1 ? true : false, index_).value();
|
||||||
} else {
|
} else {
|
||||||
std::string str;
|
std::string str;
|
||||||
array_.db_ptr->db->Get(rocksdb::ReadOptions{}, "i|" + std::to_string(instance_name_) + "|" + std::to_string(index_), &str);
|
array_.db_ptr->db->Get(rocksdb::ReadOptions{}, (entity_or_type_ == 1 ? "i|" : "t|") + std::to_string(instance_name_) + "|" + std::to_string(index_), &str);
|
||||||
size_t v;
|
size_t v;
|
||||||
memcpy(&v, str.data() + 1, sizeof(size_t));
|
memcpy(&v, str.data() + 1, sizeof(size_t));
|
||||||
auto decl = schema_->declarations()[v]->as_enumeration_type();
|
auto decl = array_.db_ptr->file->schema()->declarations()[v]->as_enumeration_type();
|
||||||
memcpy(&v, str.data() + 1 + sizeof(size_t), sizeof(size_t));
|
memcpy(&v, str.data() + 1 + sizeof(size_t), sizeof(size_t));
|
||||||
return decl->lookup_enum_value(v);
|
return decl->lookup_enum_value(v);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return dispatch_get_<std::string>(array_, storage_model_, instance_name_, index_);
|
return dispatch_get_<std::string>(array_, storage_model_, instance_name_, entity_or_type_ == 1 ? true : false, index_);
|
||||||
}
|
}
|
||||||
|
|
||||||
AttributeValue::operator EnumerationReference() const
|
AttributeValue::operator EnumerationReference() const
|
||||||
{
|
{
|
||||||
if (storage_model_ == 0) {
|
if (storage_model_ == 0) {
|
||||||
return dispatch_get_<EnumerationReference>(array_, storage_model_, instance_name_, index_);
|
return dispatch_get_<EnumerationReference>(array_, storage_model_, instance_name_, entity_or_type_ == 1 ? true : false, index_);
|
||||||
} else {
|
} else {
|
||||||
std::string str;
|
std::string str;
|
||||||
array_.db_ptr->db->Get(rocksdb::ReadOptions{}, "i|" + std::to_string(instance_name_) + "|" + std::to_string(index_), &str);
|
array_.db_ptr->db->Get(rocksdb::ReadOptions{}, (entity_or_type_ == 1 ? "i|" : "t|") + std::to_string(instance_name_) + "|" + std::to_string(index_), &str);
|
||||||
size_t v;
|
size_t v;
|
||||||
memcpy(&v, str.data() + 1, sizeof(size_t));
|
memcpy(&v, str.data() + 1, sizeof(size_t));
|
||||||
auto decl = schema_->declarations()[v]->as_enumeration_type();
|
auto decl = array_.db_ptr->file->schema()->declarations()[v]->as_enumeration_type();
|
||||||
memcpy(&v, str.data() + 5, sizeof(size_t));
|
memcpy(&v, str.data() + 5, sizeof(size_t));
|
||||||
return EnumerationReference(decl, v);
|
return EnumerationReference(decl, v);
|
||||||
}
|
}
|
||||||
@@ -135,24 +140,24 @@ AttributeValue::operator EnumerationReference() const
|
|||||||
|
|
||||||
AttributeValue::operator boost::dynamic_bitset<>() const
|
AttributeValue::operator boost::dynamic_bitset<>() const
|
||||||
{
|
{
|
||||||
return dispatch_get_<boost::dynamic_bitset<>>(array_, storage_model_, instance_name_, index_);
|
return dispatch_get_<boost::dynamic_bitset<>>(array_, storage_model_, instance_name_, entity_or_type_ == 1 ? true : false, index_);
|
||||||
}
|
}
|
||||||
|
|
||||||
AttributeValue::operator IfcUtil::IfcBaseClass* () const
|
AttributeValue::operator IfcUtil::IfcBaseClass* () const
|
||||||
{
|
{
|
||||||
if (storage_model_ == 0) {
|
if (storage_model_ == 0) {
|
||||||
return dispatch_get_<IfcUtil::IfcBaseClass*>(array_, storage_model_, instance_name_, index_);
|
return dispatch_get_<IfcUtil::IfcBaseClass*>(array_, storage_model_, instance_name_, entity_or_type_ == 1 ? true : false, index_);
|
||||||
} else {
|
} else {
|
||||||
std::string str;
|
std::string str;
|
||||||
array_.db_ptr->db->Get(rocksdb::ReadOptions{}, "i|" + std::to_string(instance_name_) + "|" + std::to_string(index_), &str);
|
array_.db_ptr->db->Get(rocksdb::ReadOptions{}, (entity_or_type_ == 1 ? "i|" : "t|") + std::to_string(instance_name_) + "|" + std::to_string(index_), &str);
|
||||||
size_t v;
|
size_t v;
|
||||||
memcpy(&v, str.data() + 2, sizeof(size_t));
|
memcpy(&v, str.data() + 2, sizeof(size_t));
|
||||||
if (str[1] == 'e') {
|
if (str[1] == 'i') {
|
||||||
// entity reference, by #Name
|
// entity reference, by #Name
|
||||||
return array_.db_ptr->assert_existance(v, IfcParse::impl::rocks_db_file_storage::by_name);
|
return array_.db_ptr->assert_existance(v, IfcParse::impl::rocks_db_file_storage::entityinstance_ref);
|
||||||
} else if (str[1] == 't') {
|
} else if (str[1] == 't') {
|
||||||
// type reference by Identity
|
// type reference by Identity
|
||||||
return array_.db_ptr->assert_existance(v, IfcParse::impl::rocks_db_file_storage::by_identity);
|
return array_.db_ptr->assert_existance(v, IfcParse::impl::rocks_db_file_storage::typedecl_ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -160,47 +165,47 @@ AttributeValue::operator IfcUtil::IfcBaseClass* () const
|
|||||||
|
|
||||||
AttributeValue::operator std::vector<int>() const
|
AttributeValue::operator std::vector<int>() const
|
||||||
{
|
{
|
||||||
return dispatch_get_<std::vector<int>>(array_, storage_model_, instance_name_, index_);
|
return dispatch_get_<std::vector<int>>(array_, storage_model_, instance_name_, entity_or_type_ == 1 ? true : false, index_);
|
||||||
}
|
}
|
||||||
|
|
||||||
AttributeValue::operator std::vector<double>() const
|
AttributeValue::operator std::vector<double>() const
|
||||||
{
|
{
|
||||||
return dispatch_get_<std::vector<double>>(array_, storage_model_, instance_name_, index_);
|
return dispatch_get_<std::vector<double>>(array_, storage_model_, instance_name_, entity_or_type_ == 1 ? true : false, index_);
|
||||||
}
|
}
|
||||||
|
|
||||||
AttributeValue::operator std::vector<std::string>() const
|
AttributeValue::operator std::vector<std::string>() const
|
||||||
{
|
{
|
||||||
return dispatch_get_<std::vector<std::string>>(array_, storage_model_, instance_name_, index_);
|
return dispatch_get_<std::vector<std::string>>(array_, storage_model_, instance_name_, entity_or_type_ == 1 ? true : false, index_);
|
||||||
}
|
}
|
||||||
|
|
||||||
AttributeValue::operator std::vector<boost::dynamic_bitset<>>() const
|
AttributeValue::operator std::vector<boost::dynamic_bitset<>>() const
|
||||||
{
|
{
|
||||||
return dispatch_get_<std::vector<boost::dynamic_bitset<>>>(array_, storage_model_, instance_name_, index_);
|
return dispatch_get_<std::vector<boost::dynamic_bitset<>>>(array_, storage_model_, instance_name_, entity_or_type_ == 1 ? true : false, index_);
|
||||||
}
|
}
|
||||||
|
|
||||||
AttributeValue::operator boost::shared_ptr<aggregate_of_instance>() const
|
AttributeValue::operator boost::shared_ptr<aggregate_of_instance>() const
|
||||||
{
|
{
|
||||||
return dispatch_get_<boost::shared_ptr<aggregate_of_instance>>(array_, storage_model_, instance_name_, index_);
|
return dispatch_get_<boost::shared_ptr<aggregate_of_instance>>(array_, storage_model_, instance_name_, entity_or_type_ == 1 ? true : false, index_);
|
||||||
}
|
}
|
||||||
|
|
||||||
AttributeValue::operator std::vector<std::vector<int>>() const
|
AttributeValue::operator std::vector<std::vector<int>>() const
|
||||||
{
|
{
|
||||||
return dispatch_get_<std::vector<std::vector<int>>>(array_, storage_model_, instance_name_, index_);
|
return dispatch_get_<std::vector<std::vector<int>>>(array_, storage_model_, instance_name_, entity_or_type_ == 1 ? true : false, index_);
|
||||||
}
|
}
|
||||||
|
|
||||||
AttributeValue::operator std::vector<std::vector<double>>() const
|
AttributeValue::operator std::vector<std::vector<double>>() const
|
||||||
{
|
{
|
||||||
return dispatch_get_<std::vector<std::vector<double>>>(array_, storage_model_, instance_name_, index_);
|
return dispatch_get_<std::vector<std::vector<double>>>(array_, storage_model_, instance_name_, entity_or_type_ == 1 ? true : false, index_);
|
||||||
}
|
}
|
||||||
|
|
||||||
AttributeValue::operator boost::shared_ptr<aggregate_of_aggregate_of_instance>() const
|
AttributeValue::operator boost::shared_ptr<aggregate_of_aggregate_of_instance>() const
|
||||||
{
|
{
|
||||||
return dispatch_get_<boost::shared_ptr<aggregate_of_aggregate_of_instance>>(array_, storage_model_, instance_name_, index_);
|
return dispatch_get_<boost::shared_ptr<aggregate_of_aggregate_of_instance>>(array_, storage_model_, instance_name_, entity_or_type_ == 1 ? true : false, index_);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AttributeValue::isNull() const
|
bool AttributeValue::isNull() const
|
||||||
{
|
{
|
||||||
return dispatch_has_<Blank>(array_, storage_model_, instance_name_, index_);
|
return dispatch_has_<Blank>(array_, storage_model_, instance_name_, entity_or_type_ == 1 ? true : false, index_);
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned int AttributeValue::size() const
|
unsigned int AttributeValue::size() const
|
||||||
@@ -211,7 +216,7 @@ unsigned int AttributeValue::size() const
|
|||||||
|
|
||||||
IfcUtil::ArgumentType AttributeValue::type() const
|
IfcUtil::ArgumentType AttributeValue::type() const
|
||||||
{
|
{
|
||||||
return static_cast<IfcUtil::ArgumentType>(dispatch_index_(array_, storage_model_, instance_name_, index_));
|
return static_cast<IfcUtil::ArgumentType>(dispatch_index_(array_, storage_model_, instance_name_, entity_or_type_ == 1 ? true : false, index_));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool impl::serialize(std::string& val, const IfcUtil::IfcBaseClass* t)
|
bool impl::serialize(std::string& val, const IfcUtil::IfcBaseClass* t)
|
||||||
@@ -221,8 +226,8 @@ bool impl::serialize(std::string& val, const IfcUtil::IfcBaseClass* t)
|
|||||||
val[0] = TypeEncoder::encode_type<IfcUtil::IfcBaseClass*>();
|
val[0] = TypeEncoder::encode_type<IfcUtil::IfcBaseClass*>();
|
||||||
// 1 = entity - stored by id (entity name)
|
// 1 = entity - stored by id (entity name)
|
||||||
// 2 = type - stored by identity (internal counter in class)
|
// 2 = type - stored by identity (internal counter in class)
|
||||||
val[1] = t->declaration().as_entity() ? 'e' : 't';
|
val[1] = t->declaration().as_entity() ? 'i' : 't';
|
||||||
size_t iden = t->declaration().as_entity() ? t->id() : t->identity();
|
size_t iden = t->id() ? t->id() : t->identity();
|
||||||
memcpy(val.data() + 2, &iden, s);
|
memcpy(val.data() + 2, &iden, s);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -243,12 +248,12 @@ bool impl::serialize(std::string& val, const aggregate_of_instance::ptr& t)
|
|||||||
{
|
{
|
||||||
// no attempt at alignment
|
// no attempt at alignment
|
||||||
val.resize(t->size() * (sizeof(size_t) + 1) + 1);
|
val.resize(t->size() * (sizeof(size_t) + 1) + 1);
|
||||||
val[0] = TypeEncoder::encode_type<EnumerationReference>();
|
val[0] = TypeEncoder::encode_type<aggregate_of_instance::ptr>();
|
||||||
char* ptr = val.data() + 1;
|
char* ptr = val.data() + 1;
|
||||||
for (auto it = t->begin(); it != t->end(); ++it) {
|
for (auto it = t->begin(); it != t->end(); ++it) {
|
||||||
*ptr = (*it)->declaration().as_entity() ? 'e' : 't';
|
*ptr = (*it)->declaration().as_entity() ? 'i' : 't';
|
||||||
ptr++;
|
ptr++;
|
||||||
size_t iden = (*it)->declaration().as_entity() ? (*it)->id() : (*it)->identity();
|
size_t iden = (*it)->id() ? (*it)->id() : (*it)->identity();
|
||||||
memcpy(ptr, &iden, sizeof(size_t));
|
memcpy(ptr, &iden, sizeof(size_t));
|
||||||
ptr += sizeof(size_t);
|
ptr += sizeof(size_t);
|
||||||
}
|
}
|
||||||
@@ -328,10 +333,10 @@ bool impl::deserialize(IfcParse::impl::rocks_db_file_storage* storage, const std
|
|||||||
ptr++;
|
ptr++;
|
||||||
size_t v;
|
size_t v;
|
||||||
memcpy(&v, ptr, sizeof(size_t));
|
memcpy(&v, ptr, sizeof(size_t));
|
||||||
if (tt == 'e') {
|
if (tt == 'i') {
|
||||||
t->push(storage->assert_existance(v, IfcParse::impl::rocks_db_file_storage::by_name));
|
t->push(storage->assert_existance(v, IfcParse::impl::rocks_db_file_storage::entityinstance_ref));
|
||||||
} else if (tt == 't') {
|
} else if (tt == 't') {
|
||||||
t->push(storage->assert_existance(v, IfcParse::impl::rocks_db_file_storage::by_identity));
|
t->push(storage->assert_existance(v, IfcParse::impl::rocks_db_file_storage::typedecl_ref));
|
||||||
} else {
|
} else {
|
||||||
throw std::runtime_error("");
|
throw std::runtime_error("");
|
||||||
}
|
}
|
||||||
@@ -352,7 +357,7 @@ void rocks_db_attribute_storage::set(void* storage, const IfcParse::declaration*
|
|||||||
impl::serialize(v, value);
|
impl::serialize(v, value);
|
||||||
rdb_storage->db->Put(
|
rdb_storage->db->Put(
|
||||||
rocksdb::WriteOptions{},
|
rocksdb::WriteOptions{},
|
||||||
(is_header ? "h|" : "i|") +
|
(is_header ? "h|" : (decl->as_entity() ? "i|" : "t|")) +
|
||||||
(is_header ? decl->name() : std::to_string(identity)) + "|" +
|
(is_header ? decl->name() : std::to_string(identity)) + "|" +
|
||||||
std::to_string(index), v);
|
std::to_string(index), v);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -280,9 +280,8 @@ namespace impl {
|
|||||||
struct AttributeValue {
|
struct AttributeValue {
|
||||||
uint8_t index_;
|
uint8_t index_;
|
||||||
uint8_t storage_model_ = 0;
|
uint8_t storage_model_ = 0;
|
||||||
|
uint8_t entity_or_type_ = 0;
|
||||||
size_t instance_name_;
|
size_t instance_name_;
|
||||||
// @todo couple with db_ptr;
|
|
||||||
const IfcParse::schema_definition* schema_;
|
|
||||||
union pointer_type {
|
union pointer_type {
|
||||||
const in_memory_attribute_storage* storage_ptr;
|
const in_memory_attribute_storage* storage_ptr;
|
||||||
IfcParse::impl::rocks_db_file_storage* db_ptr;
|
IfcParse::impl::rocks_db_file_storage* db_ptr;
|
||||||
@@ -303,12 +302,12 @@ struct AttributeValue {
|
|||||||
, storage_model_(0)
|
, storage_model_(0)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
AttributeValue(const IfcParse::schema_definition* schema, IfcParse::impl::rocks_db_file_storage* db, size_t instance_name, uint8_t index)
|
AttributeValue(IfcParse::impl::rocks_db_file_storage* db, size_t instance_name, uint8_t entity_or_type, uint8_t index)
|
||||||
: index_(index)
|
: index_(index)
|
||||||
, array_(db)
|
, array_(db)
|
||||||
, storage_model_(1)
|
, storage_model_(1)
|
||||||
, instance_name_(instance_name)
|
, instance_name_(instance_name)
|
||||||
, schema_(schema)
|
, entity_or_type_(entity_or_type)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
operator int() const;
|
operator int() const;
|
||||||
|
|||||||
+27
-29
@@ -329,6 +329,7 @@ IfcEntityInstanceData IfcParse::parse_context::construct(int name, unresolved_re
|
|||||||
return IfcEntityInstanceData(std::move(storage));
|
return IfcEntityInstanceData(std::move(storage));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
IfcUtil::IfcBaseClass* IfcParse::impl::rocks_db_file_storage::rocksdb_instance_iterator::operator*() const {
|
IfcUtil::IfcBaseClass* IfcParse::impl::rocks_db_file_storage::rocksdb_instance_iterator::operator*() const {
|
||||||
auto it = storage_->byid_.find(*read_id_());
|
auto it = storage_->byid_.find(*read_id_());
|
||||||
if (it != storage_->byid_.end()) {
|
if (it != storage_->byid_.end()) {
|
||||||
@@ -341,32 +342,22 @@ IfcUtil::IfcBaseClass* IfcParse::impl::rocks_db_file_storage::rocksdb_instance_i
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
const IfcParse::declaration* IfcParse::impl::rocks_db_file_storage::rocksdb_types_iterator::operator*() const {
|
const IfcParse::declaration* IfcParse::impl::rocks_db_file_storage::rocksdb_types_iterator::operator*() const {
|
||||||
return storage_->file->schema()->declarations()[*read_id_()];
|
return storage_->file->schema()->declarations()[*read_id_()];
|
||||||
}
|
}
|
||||||
|
|
||||||
IfcUtil::IfcBaseClass* IfcParse::impl::rocks_db_file_storage::assert_existance(size_t number, instance_ref r) {
|
IfcUtil::IfcBaseClass* IfcParse::impl::rocks_db_file_storage::assert_existance(size_t number, instance_ref r) {
|
||||||
size_t name, identity;
|
decltype(instance_cache_)::const_iterator it = instance_cache_.find({ r, number });
|
||||||
std::string v;
|
|
||||||
if (r == by_identity) {
|
|
||||||
name = 0;
|
|
||||||
identity = number;
|
|
||||||
} else {
|
|
||||||
name = number;
|
|
||||||
auto it = byid_.find(name);
|
|
||||||
if (it == byid_.end()) {
|
|
||||||
throw std::runtime_error("Unable to lookup identity of name: #" + std::to_string(number));
|
|
||||||
}
|
|
||||||
identity = it->second;
|
|
||||||
}
|
|
||||||
|
|
||||||
decltype(instance_cache_)::const_iterator it = instance_cache_.find(identity);
|
|
||||||
if (it != instance_cache_.end()) {
|
if (it != instance_cache_.end()) {
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
rocksdb::Status s = db->Get(rocksdb::ReadOptions{}, "i|" + std::to_string(identity) + "|t", &v);
|
std::string v;
|
||||||
|
|
||||||
|
// @todo should always be name, as we can/should not assign to identity
|
||||||
|
rocksdb::Status s = db->Get(rocksdb::ReadOptions{}, (r == entityinstance_ref ? "i|" : "t|") + std::to_string(number) + "|_", &v);
|
||||||
if (s.ok()) {
|
if (s.ok()) {
|
||||||
size_t s;
|
size_t s;
|
||||||
memcpy(&s, v.data(), sizeof(size_t));
|
memcpy(&s, v.data(), sizeof(size_t));
|
||||||
@@ -375,17 +366,14 @@ IfcUtil::IfcBaseClass* IfcParse::impl::rocks_db_file_storage::assert_existance(s
|
|||||||
}
|
}
|
||||||
auto decl = file->schema()->declarations()[s];
|
auto decl = file->schema()->declarations()[s];
|
||||||
bool is_entity = decl->as_entity() != nullptr;
|
bool is_entity = decl->as_entity() != nullptr;
|
||||||
if (is_entity != (r == by_name)) {
|
if (is_entity != (r == entityinstance_ref)) {
|
||||||
throw std::runtime_error("Incorrect reference");
|
throw std::runtime_error("Incorrect reference");
|
||||||
}
|
}
|
||||||
IfcEntityInstanceData data(rocks_db_attribute_storage{});
|
IfcEntityInstanceData data(rocks_db_attribute_storage{});
|
||||||
auto inst = file->schema()->instantiate(decl, std::move(data));
|
auto inst = file->schema()->instantiate(decl, std::move(data));
|
||||||
inst->id_ = name;
|
inst->id_ = number;
|
||||||
inst->file_ = file;
|
inst->file_ = file;
|
||||||
instance_cache_.insert({ inst->identity(), inst });
|
instance_cache_.insert({ {r, number}, inst });
|
||||||
if (is_entity) {
|
|
||||||
byid_.insert({ inst->id(), inst->identity() });
|
|
||||||
}
|
|
||||||
return inst;
|
return inst;
|
||||||
}
|
}
|
||||||
throw std::runtime_error("");
|
throw std::runtime_error("");
|
||||||
@@ -410,11 +398,13 @@ IfcParse::impl::rocks_db_file_storage::rocks_db_file_storage(const std::string&
|
|||||||
: file(ffile)
|
: file(ffile)
|
||||||
, db(init_db(filepath))
|
, db(init_db(filepath))
|
||||||
, byguid_internal_(db, "g|")
|
, byguid_internal_(db, "g|")
|
||||||
, byguid_(&byguid_internal_, [this](size_t v) { return assert_existance(v, by_name); }, [](IfcUtil::IfcBaseClass* v) { return v->identity(); })
|
, byguid_(&byguid_internal_, [this](size_t v) { return assert_existance(v, entityinstance_ref); }, [](IfcUtil::IfcBaseClass* v) { return v->identity(); })
|
||||||
, byid_(db, "d|")
|
, instance_ids_(db, "i|")
|
||||||
|
, instance_by_name_(&instance_ids_, [this](size_t v) { return assert_existance(v, entityinstance_ref); })
|
||||||
, bytype_(db, "t|")
|
, bytype_(db, "t|")
|
||||||
|
, byref_excl_(db, "v|")
|
||||||
// @todo by_identity is probably not correct here, this mapping is Name -> Identity, so Fn should have access to full pair?
|
// @todo by_identity is probably not correct here, this mapping is Name -> Identity, so Fn should have access to full pair?
|
||||||
, byidentity_(&byid_, [this](size_t v) { return assert_existance(v, by_identity); }, [](IfcUtil::IfcBaseClass* v) { return v->identity(); })
|
// , byidentity_(&byid_, [this](size_t v) { return assert_existance(v, by_identity); }, [](IfcUtil::IfcBaseClass* v) { return v->identity(); })
|
||||||
{}
|
{}
|
||||||
|
|
||||||
IfcParse::impl::rocks_db_file_storage::~rocks_db_file_storage()
|
IfcParse::impl::rocks_db_file_storage::~rocks_db_file_storage()
|
||||||
@@ -433,7 +423,8 @@ IfcParse::impl::rocks_db_file_storage::~rocks_db_file_storage()
|
|||||||
IfcUtil::IfcBaseClass* IfcParse::impl::rocks_db_file_storage::instance_by_id(int id)
|
IfcUtil::IfcBaseClass* IfcParse::impl::rocks_db_file_storage::instance_by_id(int id)
|
||||||
{
|
{
|
||||||
// @todo rename assert_existance() -> instance_by_id();
|
// @todo rename assert_existance() -> instance_by_id();
|
||||||
return assert_existance(id, by_name);
|
// - no cannot be done, because it needs to differentiate between entity instances and typedecls
|
||||||
|
return assert_existance(id, entityinstance_ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IfcParse::impl::rocks_db_file_storage::process_deletion_inverse(IfcUtil::IfcBaseClass* inst)
|
void IfcParse::impl::rocks_db_file_storage::process_deletion_inverse(IfcUtil::IfcBaseClass* inst)
|
||||||
@@ -441,8 +432,8 @@ void IfcParse::impl::rocks_db_file_storage::process_deletion_inverse(IfcUtil::If
|
|||||||
auto id = inst->id();
|
auto id = inst->id();
|
||||||
|
|
||||||
{
|
{
|
||||||
// compute next prefix that does not start with v|{id}
|
// compute next prefix that does not start with v|{id}|
|
||||||
auto prefix = "v|" + id;
|
auto prefix = "v|" + std::to_string(id) + "|";
|
||||||
auto it = db->NewIterator(rocksdb::ReadOptions());
|
auto it = db->NewIterator(rocksdb::ReadOptions());
|
||||||
it->Seek(prefix);
|
it->Seek(prefix);
|
||||||
while (it->Valid()) {
|
while (it->Valid()) {
|
||||||
@@ -472,7 +463,7 @@ void IfcParse::impl::rocks_db_file_storage::process_deletion_inverse(IfcUtil::If
|
|||||||
// and update inverses from entity into other
|
// and update inverses from entity into other
|
||||||
|
|
||||||
{
|
{
|
||||||
auto prefix = "v|" + name;
|
auto prefix = "v|" + std::to_string(name) + "|";
|
||||||
auto it = db->NewIterator(rocksdb::ReadOptions());
|
auto it = db->NewIterator(rocksdb::ReadOptions());
|
||||||
it->Seek(prefix);
|
it->Seek(prefix);
|
||||||
while (it->Valid() && it->key().starts_with(prefix)) {
|
while (it->Valid() && it->key().starts_with(prefix)) {
|
||||||
@@ -499,3 +490,10 @@ IfcUtil::IfcBaseClass* IfcParse::impl::in_memory_file_storage::instance_by_id(in
|
|||||||
}
|
}
|
||||||
return it->second;
|
return it->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IfcParse::IfcFile::~IfcFile() {
|
||||||
|
// @todo this does not make sense for rocksdb, because it would assert existance for the entire lazy model only to free the instances again
|
||||||
|
for (const auto& p : byid_) {
|
||||||
|
delete p.second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+61
-72
@@ -25,8 +25,10 @@
|
|||||||
#include "IfcSchema.h"
|
#include "IfcSchema.h"
|
||||||
#include "IfcSpfHeader.h"
|
#include "IfcSpfHeader.h"
|
||||||
#include "rocksdb_map_adapter.h"
|
#include "rocksdb_map_adapter.h"
|
||||||
|
#include "rocksdb_set_view.h"
|
||||||
#include "map_variant.h"
|
#include "map_variant.h"
|
||||||
#include "map_transformer.h"
|
#include "map_transformer.h"
|
||||||
|
#include "set_to_map_transformer.h"
|
||||||
|
|
||||||
#include <boost/multi_index/ordered_index.hpp>
|
#include <boost/multi_index/ordered_index.hpp>
|
||||||
#include <boost/multi_index/random_access_index.hpp>
|
#include <boost/multi_index/random_access_index.hpp>
|
||||||
@@ -213,35 +215,24 @@ namespace impl {
|
|||||||
struct in_memory_file_storage {
|
struct in_memory_file_storage {
|
||||||
IfcParse::IfcSpfLexer* tokens;
|
IfcParse::IfcSpfLexer* tokens;
|
||||||
IfcParse::IfcSpfStream* stream;
|
IfcParse::IfcSpfStream* stream;
|
||||||
|
|
||||||
IfcParse::IfcFile* file;
|
IfcParse::IfcFile* file;
|
||||||
|
|
||||||
unresolved_references references_to_resolve;
|
unresolved_references references_to_resolve;
|
||||||
|
|
||||||
typedef std::map<const IfcParse::declaration*, aggregate_of_instance::ptr> entities_by_type_t;
|
typedef std::map<const IfcParse::declaration*, aggregate_of_instance::ptr> entities_by_type_t;
|
||||||
typedef boost::unordered_map<size_t, size_t> identity_by_id_t;
|
typedef boost::unordered_map<uint32_t, IfcUtil::IfcBaseClass*> entity_instance_by_name_t;
|
||||||
typedef boost::unordered_map<uint32_t, IfcUtil::IfcBaseClass*> entity_by_iden_t;
|
typedef boost::unordered_map<uint32_t, IfcUtil::IfcBaseClass*> type_instance_by_name_t;
|
||||||
typedef std::map<std::string, IfcUtil::IfcBaseClass*> entity_by_guid_t;
|
typedef std::map<std::string, IfcUtil::IfcBaseClass*> entity_instance_by_guid_t;
|
||||||
typedef std::tuple<int, short, short> inverse_attr_record;
|
typedef std::tuple<int, short, short> inverse_attr_record;
|
||||||
enum INVERSE_ATTR {
|
enum INVERSE_ATTR {
|
||||||
INSTANCE_ID,
|
INSTANCE_ID,
|
||||||
INSTANCE_TYPE,
|
INSTANCE_TYPE,
|
||||||
ATTRIBUTE_INDEX
|
ATTRIBUTE_INDEX
|
||||||
};
|
};
|
||||||
typedef std::map<inverse_attr_record, std::vector<int>> entities_by_ref_t;
|
typedef std::map<inverse_attr_record, std::vector<uint32_t>> entities_by_ref_t;
|
||||||
typedef std::map<int, std::vector<int>> entities_by_ref_excl_t;
|
typedef entity_instance_by_name_t::iterator iterator;
|
||||||
typedef std::map<unsigned int, aggregate_of_instance::ptr> ref_map_t;
|
|
||||||
typedef map_transformer<identity_by_id_t, std::function<IfcUtil::IfcBaseClass* (size_t)>, std::function<size_t(IfcUtil::IfcBaseClass*)>> entity_by_id_t;
|
|
||||||
typedef entity_by_id_t::iterator iterator;
|
|
||||||
|
|
||||||
in_memory_file_storage()
|
|
||||||
: byid_(
|
|
||||||
&idenbyid_,
|
|
||||||
[this](size_t v) { return byidentity_[v]; },
|
|
||||||
[](IfcUtil::IfcBaseClass* inst) { return inst->identity(); }
|
|
||||||
)
|
|
||||||
{}
|
|
||||||
|
|
||||||
|
in_memory_file_storage() : tokens(nullptr), stream(nullptr), file(nullptr) {}
|
||||||
in_memory_file_storage(const in_memory_file_storage&) = delete;
|
in_memory_file_storage(const in_memory_file_storage&) = delete;
|
||||||
in_memory_file_storage(const in_memory_file_storage&&) = delete;
|
in_memory_file_storage(const in_memory_file_storage&&) = delete;
|
||||||
|
|
||||||
@@ -289,15 +280,11 @@ namespace impl {
|
|||||||
static bool guid_map() { return guid_map_; }
|
static bool guid_map() { return guid_map_; }
|
||||||
static void guid_map(bool b) { guid_map_ = b; }
|
static void guid_map(bool b) { guid_map_ = b; }
|
||||||
|
|
||||||
// this is for simple types
|
entity_instance_by_name_t byid_;
|
||||||
entity_by_iden_t byidentity_;
|
type_instance_by_name_t tbyid_;
|
||||||
// entities_by_type_t bytype_;
|
|
||||||
entities_by_type_t bytype_excl_;
|
entities_by_type_t bytype_excl_;
|
||||||
// entities_by_ref_t byref_;
|
|
||||||
entities_by_ref_t byref_excl_;
|
entities_by_ref_t byref_excl_;
|
||||||
entity_by_guid_t byguid_;
|
entity_instance_by_guid_t byguid_;
|
||||||
identity_by_id_t idenbyid_;
|
|
||||||
entity_by_id_t byid_;
|
|
||||||
|
|
||||||
void load(unsigned entity_instance_name, const IfcParse::entity* entity, parse_context&, int attribute_index = -1);
|
void load(unsigned entity_instance_name, const IfcParse::entity* entity, parse_context&, int attribute_index = -1);
|
||||||
void try_read_semicolon() const;
|
void try_read_semicolon() const;
|
||||||
@@ -315,33 +302,26 @@ namespace impl {
|
|||||||
|
|
||||||
void add_type_ref(IfcUtil::IfcBaseClass* new_entity) {
|
void add_type_ref(IfcUtil::IfcBaseClass* new_entity) {
|
||||||
auto ty = new_entity->declaration().as_entity();
|
auto ty = new_entity->declaration().as_entity();
|
||||||
if (bytype_excl_.find(ty) == bytype_excl_.end()) {
|
if (ty) {
|
||||||
bytype_excl_[ty].reset(new aggregate_of_instance());
|
if (bytype_excl_.find(ty) == bytype_excl_.end()) {
|
||||||
|
bytype_excl_[ty].reset(new aggregate_of_instance());
|
||||||
|
}
|
||||||
|
bytype_excl_[ty]->push(new_entity);
|
||||||
}
|
}
|
||||||
bytype_excl_[ty]->push(new_entity);
|
|
||||||
}
|
}
|
||||||
void remove_type_ref(IfcUtil::IfcBaseClass* new_entity) {
|
void remove_type_ref(IfcUtil::IfcBaseClass* new_entity) {
|
||||||
auto ty = new_entity->declaration().as_entity();
|
auto ty = new_entity->declaration().as_entity();
|
||||||
auto it = bytype_excl_.find(ty);
|
if (ty) {
|
||||||
if (it != bytype_excl_.end()) {
|
auto it = bytype_excl_.find(ty);
|
||||||
it->second->remove(new_entity);
|
if (it != bytype_excl_.end()) {
|
||||||
if (it->second->size() == 0) {
|
it->second->remove(new_entity);
|
||||||
bytype_excl_.erase(ty);
|
if (it->second->size() == 0) {
|
||||||
|
bytype_excl_.erase(ty);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void add_inverse_ref(IfcUtil::IfcBaseClass* new_entity) {
|
|
||||||
auto ty = new_entity->declaration().as_entity();
|
|
||||||
if (bytype_excl_.find(ty) == bytype_excl_.end()) {
|
|
||||||
bytype_excl_[ty].reset(new aggregate_of_instance());
|
|
||||||
}
|
|
||||||
bytype_excl_[ty]->push(new_entity);
|
|
||||||
}
|
|
||||||
void remove_inverse_ref(IfcUtil::IfcBaseClass* new_entity) {
|
|
||||||
// @todo
|
|
||||||
}
|
|
||||||
|
|
||||||
void process_deletion_inverse(IfcUtil::IfcBaseClass* inst);
|
void process_deletion_inverse(IfcUtil::IfcBaseClass* inst);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
@@ -355,19 +335,30 @@ namespace impl {
|
|||||||
rocksdb::DB* db;
|
rocksdb::DB* db;
|
||||||
IfcParse::IfcFile* file;
|
IfcParse::IfcFile* file;
|
||||||
|
|
||||||
|
enum instance_ref {
|
||||||
|
typedecl_ref,
|
||||||
|
entityinstance_ref
|
||||||
|
};
|
||||||
|
|
||||||
// to make sure that instance pointer are constant during file lifetime
|
// to make sure that instance pointer are constant during file lifetime
|
||||||
// cache instances because we want stable pointers
|
// cache instances because we want stable pointers
|
||||||
// @todo this is silly, but we cannot have the same type, this should be just a pointer then on the IfcFile side?
|
// @todo this is silly, but we cannot have the same type, this should be just a pointer then on the IfcFile side?
|
||||||
typedef std::map<uint32_t, IfcUtil::IfcBaseClass*> entity_by_iden_cache_t;
|
typedef std::map<std::pair<instance_ref, uint32_t>, IfcUtil::IfcBaseClass*> entity_by_iden_cache_t;
|
||||||
entity_by_iden_cache_t instance_cache_;
|
entity_by_iden_cache_t instance_cache_;
|
||||||
|
|
||||||
// lookup id->identity
|
// @todo all these size_ts should probably be uint32_t for consistency with in-mem storage
|
||||||
typedef rocksdb_map_adapter<size_t, size_t> identity_by_id_t;
|
|
||||||
identity_by_id_t byid_;
|
|
||||||
|
|
||||||
typedef map_transformer<rocksdb_map_adapter<size_t, size_t>, std::function<IfcUtil::IfcBaseClass*(size_t)>, std::function<size_t(IfcUtil::IfcBaseClass*)>> entity_by_id_t;
|
// lookup id->identity
|
||||||
|
// typedef rocksdb_map_adapter<size_t, size_t> identity_by_id_t;
|
||||||
|
// identity_by_id_t byid_;
|
||||||
|
typedef rocksdb_set_view<size_t> instance_name_view_t;
|
||||||
|
instance_name_view_t instance_ids_;
|
||||||
|
typedef set_to_map_transformer<instance_name_view_t, std::function<IfcUtil::IfcBaseClass* (size_t)>> entity_instance_by_name_t;
|
||||||
|
entity_instance_by_name_t instance_by_name_;
|
||||||
|
|
||||||
|
// typedef map_transformer<rocksdb_map_adapter<size_t, size_t>, std::function<IfcUtil::IfcBaseClass*(size_t)>, std::function<size_t(IfcUtil::IfcBaseClass*)>> entity_by_id_t;
|
||||||
// storage is now Instance name -> Identity -> Pointer (cached)
|
// storage is now Instance name -> Identity -> Pointer (cached)
|
||||||
entity_by_id_t byidentity_;
|
// entity_by_id_t byidentity_;
|
||||||
|
|
||||||
// index in schema to binary serialized ids
|
// index in schema to binary serialized ids
|
||||||
typedef rocksdb_map_adapter<size_t, std::string> instance_id_str_by_type_t;
|
typedef rocksdb_map_adapter<size_t, std::string> instance_id_str_by_type_t;
|
||||||
@@ -378,8 +369,17 @@ namespace impl {
|
|||||||
instance_id_by_guid_str_t byguid_internal_;
|
instance_id_by_guid_str_t byguid_internal_;
|
||||||
|
|
||||||
// guid -> id -> instance
|
// guid -> id -> instance
|
||||||
typedef map_transformer<rocksdb_map_adapter<std::string, size_t>, std::function<IfcUtil::IfcBaseClass* (size_t)>, std::function< size_t(IfcUtil::IfcBaseClass*)>> entity_by_guid_t;
|
typedef map_transformer<rocksdb_map_adapter<std::string, size_t>, std::function<IfcUtil::IfcBaseClass* (size_t)>, std::function< size_t(IfcUtil::IfcBaseClass*)>> entity_instance_by_guid_t;
|
||||||
entity_by_guid_t byguid_;
|
entity_instance_by_guid_t byguid_;
|
||||||
|
|
||||||
|
typedef std::tuple<int, int, int> inverse_attr_record;
|
||||||
|
enum INVERSE_ATTR {
|
||||||
|
INSTANCE_ID,
|
||||||
|
INSTANCE_TYPE,
|
||||||
|
ATTRIBUTE_INDEX
|
||||||
|
};
|
||||||
|
typedef rocksdb_map_adapter<inverse_attr_record, std::vector<uint32_t>> entities_by_ref_t;
|
||||||
|
entities_by_ref_t byref_excl_;
|
||||||
|
|
||||||
// @todo naming
|
// @todo naming
|
||||||
rocks_db_file_storage(const std::string& filepath, IfcParse::IfcFile* file);
|
rocks_db_file_storage(const std::string& filepath, IfcParse::IfcFile* file);
|
||||||
@@ -387,14 +387,10 @@ namespace impl {
|
|||||||
|
|
||||||
bool read_schema(const IfcParse::schema_definition*& schema);
|
bool read_schema(const IfcParse::schema_definition*& schema);
|
||||||
|
|
||||||
enum instance_ref {
|
|
||||||
by_name,
|
|
||||||
by_identity
|
|
||||||
};
|
|
||||||
|
|
||||||
IfcUtil::IfcBaseClass* assert_existance(size_t instanceId, instance_ref r);
|
IfcUtil::IfcBaseClass* assert_existance(size_t instanceId, instance_ref r);
|
||||||
|
|
||||||
// @todo this could be another map_adapter?
|
// @todo this could be another map_adapter?
|
||||||
|
/*
|
||||||
class rocksdb_instance_iterator {
|
class rocksdb_instance_iterator {
|
||||||
private:
|
private:
|
||||||
rocksdb::Iterator* state_;
|
rocksdb::Iterator* state_;
|
||||||
@@ -467,6 +463,7 @@ namespace impl {
|
|||||||
|
|
||||||
IfcUtil::IfcBaseClass* operator*() const;
|
IfcUtil::IfcBaseClass* operator*() const;
|
||||||
};
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
// @todo merge iterators (template?)
|
// @todo merge iterators (template?)
|
||||||
class rocksdb_types_iterator {
|
class rocksdb_types_iterator {
|
||||||
@@ -554,7 +551,7 @@ namespace impl {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// @todo rocksdb_instance_iterator?
|
// @todo rocksdb_instance_iterator?
|
||||||
using const_iterator = rocksdb_types_iterator;
|
using const_iterator = entity_instance_by_name_t::iterator;
|
||||||
|
|
||||||
void register_inverse(unsigned, const IfcParse::entity* from_entity, int inst_id, int attribute_index);
|
void register_inverse(unsigned, const IfcParse::entity* from_entity, int inst_id, int attribute_index);
|
||||||
void unregister_inverse(unsigned, const IfcParse::entity* from_entity, IfcUtil::IfcBaseClass*, int attribute_index);
|
void unregister_inverse(unsigned, const IfcParse::entity* from_entity, IfcUtil::IfcBaseClass*, int attribute_index);
|
||||||
@@ -634,11 +631,7 @@ private:
|
|||||||
// @nb path is only used in rocksdb mode, for spf file is in-memory only until write() is called
|
// @nb path is only used in rocksdb mode, for spf file is in-memory only until write() is called
|
||||||
IfcFile(const IfcParse::schema_definition* schema = IfcParse::schema_by_name("IFC4"), filetype ty = ifcspf, const std::string& path = "");
|
IfcFile(const IfcParse::schema_definition* schema = IfcParse::schema_by_name("IFC4"), filetype ty = ifcspf, const std::string& path = "");
|
||||||
|
|
||||||
~IfcFile() {
|
~IfcFile();
|
||||||
for (const auto& p : byidentity_) {
|
|
||||||
delete p.second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
file_open_status good() const { return good_; }
|
file_open_status good() const { return good_; }
|
||||||
|
|
||||||
@@ -761,18 +754,14 @@ private:
|
|||||||
void register_inverse(unsigned, const IfcParse::entity* from_entity, int inst_id, int attribute_index);
|
void register_inverse(unsigned, const IfcParse::entity* from_entity, int inst_id, int attribute_index);
|
||||||
void unregister_inverse(unsigned, const IfcParse::entity* from_entity, IfcUtil::IfcBaseClass*, int attribute_index);
|
void unregister_inverse(unsigned, const IfcParse::entity* from_entity, IfcUtil::IfcBaseClass*, int attribute_index);
|
||||||
|
|
||||||
typedef VariantMap<impl::in_memory_file_storage::entity_by_guid_t, impl::rocks_db_file_storage::entity_by_guid_t> entity_by_guid_t;
|
typedef VariantMap<impl::in_memory_file_storage::entity_instance_by_guid_t, impl::rocks_db_file_storage::entity_instance_by_guid_t> entity_instance_by_guid_t;
|
||||||
entity_by_guid_t byguid_;
|
entity_instance_by_guid_t byguid_;
|
||||||
typedef VariantMap<impl::in_memory_file_storage::entity_by_id_t, impl::rocks_db_file_storage::entity_by_id_t> entity_by_id_t;
|
typedef VariantMap<impl::in_memory_file_storage::entity_instance_by_name_t, impl::rocks_db_file_storage::entity_instance_by_name_t> entity_by_id_t;
|
||||||
entity_by_id_t byid_;
|
entity_by_id_t byid_;
|
||||||
typedef VariantMap<impl::in_memory_file_storage::entity_by_iden_t, impl::rocks_db_file_storage::entity_by_iden_cache_t> entity_by_iden_t;
|
typedef VariantMap<impl::in_memory_file_storage::entities_by_ref_t, impl::rocks_db_file_storage::entities_by_ref_t> entities_by_ref_t;
|
||||||
entity_by_iden_t byidentity_;
|
entities_by_ref_t byref_excl_;
|
||||||
typedef VariantMap<impl::in_memory_file_storage::identity_by_id_t, impl::rocks_db_file_storage::identity_by_id_t> identity_by_id_t;
|
|
||||||
identity_by_id_t idenbyid_;
|
|
||||||
|
|
||||||
|
entity_instance_by_guid_t internal_guid_map() { return byguid_; };
|
||||||
// @todo
|
|
||||||
entity_by_guid_t internal_guid_map() { return byguid_; };
|
|
||||||
|
|
||||||
void add_type_ref(IfcUtil::IfcBaseClass* new_entity);
|
void add_type_ref(IfcUtil::IfcBaseClass* new_entity);
|
||||||
void remove_type_ref(IfcUtil::IfcBaseClass* new_entity);
|
void remove_type_ref(IfcUtil::IfcBaseClass* new_entity);
|
||||||
|
|||||||
+131
-77
@@ -767,8 +767,8 @@ void IfcParse::impl::in_memory_file_storage::register_inverse(unsigned id_from,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void IfcParse::impl::in_memory_file_storage::unregister_inverse(unsigned id_from, const IfcParse::entity* from_entity, IfcUtil::IfcBaseClass* inst, int attribute_index) {
|
void IfcParse::impl::in_memory_file_storage::unregister_inverse(unsigned id_from, const IfcParse::entity* from_entity, IfcUtil::IfcBaseClass* inst, int attribute_index) {
|
||||||
std::vector<int>& ids = byref_excl_[{inst->id(), from_entity->index_in_schema(), attribute_index}];
|
auto& ids = byref_excl_[{inst->id(), from_entity->index_in_schema(), attribute_index}];
|
||||||
std::vector<int>::iterator iter = std::find(ids.begin(), ids.end(), id_from);
|
auto iter = std::find(ids.begin(), ids.end(), id_from);
|
||||||
if (iter == ids.end()) {
|
if (iter == ids.end()) {
|
||||||
// @todo inverses also need to be populated when multiple instances are added to a new file.
|
// @todo inverses also need to be populated when multiple instances are added to a new file.
|
||||||
// throw IfcParse::IfcException("Instance not found among inverses");
|
// throw IfcParse::IfcException("Instance not found among inverses");
|
||||||
@@ -780,8 +780,9 @@ void IfcParse::impl::in_memory_file_storage::unregister_inverse(unsigned id_from
|
|||||||
namespace {
|
namespace {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
std::string to_string_fixed_width(const T& t, size_t w) {
|
std::string to_string_fixed_width(const T& t, size_t w) {
|
||||||
|
// @todo currently inactive
|
||||||
std::ostringstream oss;
|
std::ostringstream oss;
|
||||||
oss << std::setfill('0') << std::setw(w) << t;
|
oss << /*std::setfill('0') << std::setw(w) <<*/ t;
|
||||||
return oss.str();
|
return oss.str();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -824,44 +825,47 @@ void IfcParse::impl::rocks_db_file_storage::unregister_inverse(unsigned id_from,
|
|||||||
|
|
||||||
void IfcParse::impl::rocks_db_file_storage::add_type_ref(IfcUtil::IfcBaseClass* new_entity)
|
void IfcParse::impl::rocks_db_file_storage::add_type_ref(IfcUtil::IfcBaseClass* new_entity)
|
||||||
{
|
{
|
||||||
if (!new_entity->declaration().as_entity()) {
|
size_t v;
|
||||||
throw std::runtime_error("Type refs are only supposed to be used for entities");
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t v = new_entity->id();
|
|
||||||
std::string s(sizeof(size_t), ' ');
|
std::string s(sizeof(size_t), ' ');
|
||||||
memcpy(s.data(), &v, sizeof(size_t));
|
|
||||||
|
|
||||||
// no merges yet, because the python client doesn't support them
|
if (new_entity->declaration().as_entity()) {
|
||||||
// db->Merge(rocksdb::WriteOptions{}, "t|" + std::to_string(new_entity->declaration().index_in_schema()), s);
|
v = new_entity->id();
|
||||||
{
|
memcpy(s.data(), &v, sizeof(size_t));
|
||||||
std::string current;
|
|
||||||
auto key = "t|" + std::to_string(new_entity->declaration().index_in_schema());
|
// no merges yet, because the python client doesn't support them
|
||||||
db->Get(rocksdb::ReadOptions{}, key, ¤t);
|
// db->Merge(rocksdb::WriteOptions{}, "t|" + std::to_string(new_entity->declaration().index_in_schema()), s);
|
||||||
auto new_val = current + s;
|
{
|
||||||
db->Put(rocksdb::WriteOptions{}, key, new_val);
|
std::string current;
|
||||||
|
// @todo this uses the same key-namespace as typedecl instances, not a direct conflict, but also not very clear
|
||||||
|
auto key = "t|" + std::to_string(new_entity->declaration().index_in_schema());
|
||||||
|
db->Get(rocksdb::ReadOptions{}, key, ¤t);
|
||||||
|
auto new_val = current + s;
|
||||||
|
db->Put(rocksdb::WriteOptions{}, key, new_val);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// not only mapping also register type
|
// not only mapping also register type
|
||||||
v = new_entity->declaration().index_in_schema();
|
v = new_entity->declaration().index_in_schema();
|
||||||
memcpy(s.data(), &v, sizeof(size_t));
|
memcpy(s.data(), &v, sizeof(size_t));
|
||||||
db->Put(rocksdb::WriteOptions{}, "i|" + std::to_string(new_entity->identity()) + "|t", s);
|
db->Put(rocksdb::WriteOptions{}, (new_entity->declaration().as_entity() ? "i|" : "t|") + std::to_string(new_entity->id() ? new_entity->id() : new_entity->identity()) + "|_", s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IfcParse::impl::rocks_db_file_storage::remove_type_ref(IfcUtil::IfcBaseClass* new_entity)
|
void IfcParse::impl::rocks_db_file_storage::remove_type_ref(IfcUtil::IfcBaseClass* new_entity)
|
||||||
{
|
{
|
||||||
std::string s;
|
if (new_entity->declaration().as_entity()) {
|
||||||
auto key = "t|" + std::to_string(new_entity->declaration().index_in_schema());
|
std::string s;
|
||||||
if (db->Get(rocksdb::ReadOptions{}, key, &s).ok()) {
|
auto key = "t|" + std::to_string(new_entity->declaration().index_in_schema());
|
||||||
std::vector<size_t> vals(s.size() / sizeof(size_t));
|
if (db->Get(rocksdb::ReadOptions{}, key, &s).ok()) {
|
||||||
memcpy(vals.data(), s.data(), s.size());
|
std::vector<size_t> vals(s.size() / sizeof(size_t));
|
||||||
vals.erase(std::find(vals.begin(), vals.end(), (size_t)new_entity->id()));
|
memcpy(vals.data(), s.data(), s.size());
|
||||||
s.resize(vals.size() * sizeof(size_t));
|
vals.erase(std::find(vals.begin(), vals.end(), (size_t)new_entity->id()));
|
||||||
memcpy(s.data(), vals.data(), s.size());
|
s.resize(vals.size() * sizeof(size_t));
|
||||||
db->Put(rocksdb::WriteOptions{}, key, s);
|
memcpy(s.data(), vals.data(), s.size());
|
||||||
|
db->Put(rocksdb::WriteOptions{}, key, s);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
db->Delete(rocksdb::WriteOptions{}, "i|" + std::to_string(new_entity->identity()) + "|t");
|
db->Delete(rocksdb::WriteOptions{}, (new_entity->declaration().as_entity() ? "i|" : "t|") + std::to_string(new_entity->id() ? new_entity->id() : new_entity->identity()) + "|_");
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -1242,12 +1246,12 @@ void IfcUtil::IfcBaseClass::set_attribute_value(size_t i, const T& t) {
|
|||||||
void* const storage = file_ ? std::visit([](const auto& m) { return (void*)&m; }, file_->storage_) : nullptr;
|
void* const storage = file_ ? std::visit([](const auto& m) { return (void*)&m; }, file_->storage_) : nullptr;
|
||||||
if constexpr (std::is_pointer_v<T>) {
|
if constexpr (std::is_pointer_v<T>) {
|
||||||
if (t) {
|
if (t) {
|
||||||
data_.set_attribute_value(storage, &declaration(), identity(), i, t);
|
data_.set_attribute_value(storage, &declaration(), id() ? id() : identity(), i, t);
|
||||||
} else {
|
} else {
|
||||||
data_.set_attribute_value(storage, &declaration(), identity(), i, Blank{});
|
data_.set_attribute_value(storage, &declaration(), id() ? id() : identity(), i, Blank{});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
data_.set_attribute_value(storage, &declaration(), identity(),i, t);
|
data_.set_attribute_value(storage, &declaration(), id() ? id() : identity(),i, t);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
auto new_attribute = get_attribute_value(i);
|
auto new_attribute = get_attribute_value(i);
|
||||||
@@ -1301,16 +1305,16 @@ IfcFile::IfcFile(const std::string& path, filetype ty) {
|
|||||||
|
|
||||||
// @todo unify these names, it's already confusing enough as it stands
|
// @todo unify these names, it's already confusing enough as it stands
|
||||||
byid_ = decltype(byid_)(&std::get<impl::in_memory_file_storage>(storage_).byid_);
|
byid_ = decltype(byid_)(&std::get<impl::in_memory_file_storage>(storage_).byid_);
|
||||||
idenbyid_ = decltype(idenbyid_)(&std::get<impl::in_memory_file_storage>(storage_).idenbyid_);
|
byref_excl_ = decltype(byref_excl_)(&std::get<impl::in_memory_file_storage>(storage_).byref_excl_);
|
||||||
byidentity_ = decltype(byidentity_)(&std::get<impl::in_memory_file_storage>(storage_).byidentity_);
|
// byidentity_ = decltype(byidentity_)(&std::get<impl::in_memory_file_storage>(storage_).byidentity_);
|
||||||
} else {
|
} else {
|
||||||
// @todo this can only be used for databases that already exist, because otherwise there is no way to specify the schema
|
// @todo this can only be used for databases that already exist, because otherwise there is no way to specify the schema
|
||||||
storage_.emplace<2>(path, this);
|
storage_.emplace<2>(path, this);
|
||||||
std::get<impl::rocks_db_file_storage>(storage_).read_schema(schema_);
|
std::get<impl::rocks_db_file_storage>(storage_).read_schema(schema_);
|
||||||
|
|
||||||
byid_ = decltype(byid_)(&std::get<impl::rocks_db_file_storage>(storage_).byidentity_);
|
byid_ = decltype(byid_)(&std::get<impl::rocks_db_file_storage>(storage_).instance_by_name_);
|
||||||
idenbyid_ = decltype(idenbyid_)(&std::get<impl::rocks_db_file_storage>(storage_).byid_);
|
byref_excl_ = decltype(byref_excl_)(&std::get<impl::rocks_db_file_storage>(storage_).byref_excl_);
|
||||||
byidentity_ = decltype(byidentity_)(&std::get<impl::rocks_db_file_storage>(storage_).instance_cache_);
|
// byidentity_ = decltype(byidentity_)(&std::get<impl::rocks_db_file_storage>(storage_).instance_cache_);
|
||||||
}
|
}
|
||||||
ifcroot_type_ = schema_->declaration_by_name("IfcRoot");
|
ifcroot_type_ = schema_->declaration_by_name("IfcRoot");
|
||||||
}
|
}
|
||||||
@@ -1347,14 +1351,14 @@ IfcFile::IfcFile(const IfcParse::schema_definition* schema, filetype ty, const s
|
|||||||
std::get<impl::in_memory_file_storage>(storage_).file = this;
|
std::get<impl::in_memory_file_storage>(storage_).file = this;
|
||||||
|
|
||||||
byid_ = decltype(byid_)(&std::get<impl::in_memory_file_storage>(storage_).byid_);
|
byid_ = decltype(byid_)(&std::get<impl::in_memory_file_storage>(storage_).byid_);
|
||||||
idenbyid_ = decltype(idenbyid_)(&std::get<impl::in_memory_file_storage>(storage_).idenbyid_);
|
byref_excl_ = decltype(byref_excl_)(&std::get<impl::in_memory_file_storage>(storage_).byref_excl_);
|
||||||
byidentity_ = decltype(byidentity_)(&std::get<impl::in_memory_file_storage>(storage_).byidentity_);
|
// byidentity_ = decltype(byidentity_)(&std::get<impl::in_memory_file_storage>(storage_).byidentity_);
|
||||||
} else {
|
} else {
|
||||||
storage_.emplace<2>(path, this);
|
storage_.emplace<2>(path, this);
|
||||||
|
|
||||||
byid_ = decltype(byid_)(&std::get<impl::rocks_db_file_storage>(storage_).byidentity_);
|
byid_ = decltype(byid_)(&std::get<impl::rocks_db_file_storage>(storage_).instance_by_name_);
|
||||||
idenbyid_ = decltype(idenbyid_)(&std::get<impl::rocks_db_file_storage>(storage_).byid_);
|
byref_excl_ = decltype(byref_excl_)(&std::get<impl::rocks_db_file_storage>(storage_).byref_excl_);
|
||||||
byidentity_ = decltype(byidentity_)(&std::get<impl::rocks_db_file_storage>(storage_).instance_cache_);
|
// byidentity_ = decltype(byidentity_)(&std::get<impl::rocks_db_file_storage>(storage_).instance_cache_);
|
||||||
}
|
}
|
||||||
setDefaultHeaderValues();
|
setDefaultHeaderValues();
|
||||||
}
|
}
|
||||||
@@ -1492,8 +1496,8 @@ void IfcParse::impl::in_memory_file_storage::read_from_stream(IfcParse::IfcSpfSt
|
|||||||
Logger::Message(Logger::LOG_WARNING, ss.str());
|
Logger::Message(Logger::LOG_WARNING, ss.str());
|
||||||
}
|
}
|
||||||
|
|
||||||
idenbyid_[current_id] = instance->identity();
|
// byidentity_[instance->identity()] = instance;
|
||||||
byidentity_[instance->identity()] = instance;
|
byid_.insert({ current_id, instance });
|
||||||
|
|
||||||
// @nb cannot assign to byid_;
|
// @nb cannot assign to byid_;
|
||||||
// byid_[current_id] = instance;
|
// byid_[current_id] = instance;
|
||||||
@@ -1548,10 +1552,10 @@ void IfcParse::impl::in_memory_file_storage::read_from_stream(IfcParse::IfcSpfSt
|
|||||||
if (it == byid_.end()) {
|
if (it == byid_.end()) {
|
||||||
Logger::Error("Instance reference #" + std::to_string(*name) + " used by instance #" + std::to_string(ref) + " at attribute index " + std::to_string(refattr) + " not found");
|
Logger::Error("Instance reference #" + std::to_string(*name) + " used by instance #" + std::to_string(ref) + " at attribute index " + std::to_string(refattr) + " not found");
|
||||||
} else {
|
} else {
|
||||||
byidentity_[idenbyid_[p.first.name_]]->data().set_attribute_value(nullptr, nullptr, 0, p.first.index_, it->second);
|
byid_[p.first.name_]->data().set_attribute_value(nullptr, nullptr, 0, p.first.index_, it->second);
|
||||||
}
|
}
|
||||||
} else if (auto* inst = boost::get<IfcUtil::IfcBaseClass*>(v)) {
|
} else if (auto* inst = boost::get<IfcUtil::IfcBaseClass*>(v)) {
|
||||||
byidentity_[idenbyid_[p.first.name_]]->data().set_attribute_value(nullptr, nullptr, 0, p.first.index_, *inst);
|
byid_[p.first.name_]->data().set_attribute_value(nullptr, nullptr, 0, p.first.index_, *inst);
|
||||||
}
|
}
|
||||||
} else if (auto* v = boost::get<std::vector<reference_or_simple_type>>(&p.second)) {
|
} else if (auto* v = boost::get<std::vector<reference_or_simple_type>>(&p.second)) {
|
||||||
aggregate_of_instance::ptr instances(new aggregate_of_instance);
|
aggregate_of_instance::ptr instances(new aggregate_of_instance);
|
||||||
@@ -1568,7 +1572,7 @@ void IfcParse::impl::in_memory_file_storage::read_from_stream(IfcParse::IfcSpfSt
|
|||||||
instances->push(*inst);
|
instances->push(*inst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
byidentity_[idenbyid_[p.first.name_]]->data().set_attribute_value(nullptr, nullptr, 0, p.first.index_, instances);
|
byid_[p.first.name_]->data().set_attribute_value(nullptr, nullptr, 0, p.first.index_, instances);
|
||||||
} else if (auto* v = boost::get<std::vector<std::vector<reference_or_simple_type>>>(&p.second)) {
|
} else if (auto* v = boost::get<std::vector<std::vector<reference_or_simple_type>>>(&p.second)) {
|
||||||
aggregate_of_aggregate_of_instance::ptr instances(new aggregate_of_aggregate_of_instance);
|
aggregate_of_aggregate_of_instance::ptr instances(new aggregate_of_aggregate_of_instance);
|
||||||
for (const auto& vi : *v) {
|
for (const auto& vi : *v) {
|
||||||
@@ -1587,7 +1591,7 @@ void IfcParse::impl::in_memory_file_storage::read_from_stream(IfcParse::IfcSpfSt
|
|||||||
}
|
}
|
||||||
instances->push(inner);
|
instances->push(inner);
|
||||||
}
|
}
|
||||||
byidentity_[idenbyid_[p.first.name_]]->data().set_attribute_value(nullptr, nullptr, 0, p.first.index_, instances);
|
byid_[p.first.name_]->data().set_attribute_value(nullptr, nullptr, 0, p.first.index_, instances);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1760,7 +1764,12 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity, int id)
|
|||||||
if (entity->declaration().as_entity() == nullptr) {
|
if (entity->declaration().as_entity() == nullptr) {
|
||||||
// While not a mapping that can be queried, we do need to free the instance later on
|
// While not a mapping that can be queried, we do need to free the instance later on
|
||||||
// @todo. why (over?)write this when adding from the same file?
|
// @todo. why (over?)write this when adding from the same file?
|
||||||
byidentity_.insert({ new_entity->identity(), new_entity });
|
std::visit([new_entity](auto& m) {
|
||||||
|
if constexpr (std::is_same_v<std::decay_t<decltype(m)>, impl::in_memory_file_storage>) {
|
||||||
|
// @todo not freed yet
|
||||||
|
m.tbyid_.insert({ new_entity->identity(), new_entity });
|
||||||
|
}
|
||||||
|
}, storage_);
|
||||||
}
|
}
|
||||||
|
|
||||||
// If it is part of this file
|
// If it is part of this file
|
||||||
@@ -1786,10 +1795,23 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity, int id)
|
|||||||
}
|
}
|
||||||
new_entity->file_ = this;
|
new_entity->file_ = this;
|
||||||
|
|
||||||
|
// A new entity instance name is generated and
|
||||||
|
// the instance is pointed to this file.
|
||||||
|
if (new_entity->declaration().as_entity() != nullptr) {
|
||||||
|
if (id == -1) {
|
||||||
|
new_entity->as<IfcUtil::IfcBaseEntity>()->set_id(FreshId());
|
||||||
|
} else {
|
||||||
|
new_entity->as<IfcUtil::IfcBaseEntity>()->set_id((unsigned int)id);
|
||||||
|
if ((unsigned)id > max_id_) {
|
||||||
|
max_id_ = (unsigned)id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void* own_storage = std::visit([](const auto& m) { return (void*)&m; }, storage_);
|
void* own_storage = std::visit([](const auto& m) { return (void*)&m; }, storage_);
|
||||||
void* other_storage = std::visit([](const auto& m) { return (void*)&m; }, other_file->storage_);
|
void* other_storage = std::visit([](const auto& m) { return (void*)&m; }, other_file->storage_);
|
||||||
for (size_t i = 0; i < (entity->declaration().as_entity() ? entity->declaration().as_entity()->attribute_count() : 1); ++i) {
|
for (size_t i = 0; i < (entity->declaration().as_entity() ? entity->declaration().as_entity()->attribute_count() : 1); ++i) {
|
||||||
entity->data().apply_visitor(other_storage, decl, entity->identity(), [this, i, decl, new_entity, own_storage](const auto& v) {
|
entity->data().apply_visitor(other_storage, decl, entity->id() ? entity->id() : entity->identity(), [this, i, decl, new_entity, own_storage](const auto& v) {
|
||||||
using U = std::decay_t<decltype(v)>;
|
using U = std::decay_t<decltype(v)>;
|
||||||
// only need to copy non-instance attribute values, others are assigned below after mapping
|
// only need to copy non-instance attribute values, others are assigned below after mapping
|
||||||
if constexpr (std::is_same_v<U, IfcUtil::IfcBaseClass*>) {
|
if constexpr (std::is_same_v<U, IfcUtil::IfcBaseClass*>) {
|
||||||
@@ -1895,19 +1917,6 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity, int id)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// A new entity instance name is generated and
|
|
||||||
// the instance is pointed to this file.
|
|
||||||
if (new_entity->declaration().as_entity() != nullptr) {
|
|
||||||
if (id == -1) {
|
|
||||||
new_entity->as<IfcUtil::IfcBaseEntity>()->set_id(FreshId());
|
|
||||||
} else {
|
|
||||||
new_entity->as<IfcUtil::IfcBaseEntity>()->set_id((unsigned int)id);
|
|
||||||
if ((unsigned)id > max_id_) {
|
|
||||||
max_id_ = (unsigned)id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
entity_file_map_.insert(entity_entity_map_t::value_type(entity->identity(), new_entity));
|
entity_file_map_.insert(entity_entity_map_t::value_type(entity->identity(), new_entity));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1929,9 +1938,10 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity, int id)
|
|||||||
// The mapping by entity type is updated.
|
// The mapping by entity type is updated.
|
||||||
const IfcParse::declaration* ty = &new_entity->declaration();
|
const IfcParse::declaration* ty = &new_entity->declaration();
|
||||||
|
|
||||||
if (ty->as_entity() != nullptr) {
|
// @nb happens always because this also registers the type of the instance in rocksdb
|
||||||
|
// if (ty->as_entity() != nullptr) {
|
||||||
add_type_ref(new_entity);
|
add_type_ref(new_entity);
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (ty->as_entity() != nullptr) {
|
if (ty->as_entity() != nullptr) {
|
||||||
int new_id = -1;
|
int new_id = -1;
|
||||||
@@ -1956,17 +1966,27 @@ IfcUtil::IfcBaseClass* IfcFile::addEntity(IfcUtil::IfcBaseClass* entity, int id)
|
|||||||
ss << "Overwriting entity with id " << new_id;
|
ss << "Overwriting entity with id " << new_id;
|
||||||
Logger::Message(Logger::LOG_WARNING, ss.str());
|
Logger::Message(Logger::LOG_WARNING, ss.str());
|
||||||
}
|
}
|
||||||
// The mapping by entity instance name is updated.
|
|
||||||
idenbyid_.insert({ new_id, new_entity->identity() });
|
// rocksdb instances are assumed to be create with file.create();
|
||||||
byidentity_.insert({ new_entity->identity(), new_entity });
|
std::visit([new_entity](auto& m) {
|
||||||
|
if constexpr (std::is_same_v<std::decay_t<decltype(m)>, impl::in_memory_file_storage>) {
|
||||||
|
// @todo not freed yet
|
||||||
|
m.byid_.insert({ new_entity->identity(), new_entity });
|
||||||
|
}
|
||||||
|
}, storage_);
|
||||||
} else if (new_entity->file_ == nullptr) {
|
} else if (new_entity->file_ == nullptr) {
|
||||||
// For non-entity instances, no mappings are updated, but the file
|
// For non-entity instances, no mappings are updated, but the file
|
||||||
// pointer has to be set, so that actual copies are created in subsequent
|
// pointer has to be set, so that actual copies are created in subsequent
|
||||||
// times.
|
// times.
|
||||||
new_entity->file_ = this;
|
new_entity->file_ = this;
|
||||||
|
|
||||||
// While not a mapping that can be queried, we do need to free the instance
|
// rocksdb instances are assumed to be create with file.create();
|
||||||
byidentity_.insert({ new_entity->identity(), new_entity });
|
std::visit([new_entity](auto& m) {
|
||||||
|
if constexpr (std::is_same_v<std::decay_t<decltype(m)>, impl::in_memory_file_storage>) {
|
||||||
|
// @todo not freed yet
|
||||||
|
m.tbyid_.insert({ new_entity->identity(), new_entity });
|
||||||
|
}
|
||||||
|
}, storage_);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2077,7 +2097,8 @@ void IfcFile::removeEntity(IfcUtil::IfcBaseClass* entity) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
byid_.erase(byid_.find(id));
|
//byid_.erase(byid_.find(id));
|
||||||
|
byid_.erase(id);
|
||||||
|
|
||||||
const IfcParse::declaration* ty = &entity->declaration();
|
const IfcParse::declaration* ty = &entity->declaration();
|
||||||
|
|
||||||
@@ -2183,7 +2204,7 @@ aggregate_of_instance::ptr IfcFile::instances_by_type_excl_subtypes(const IfcPar
|
|||||||
std::vector<size_t> vals(s.size() / sizeof(size_t));
|
std::vector<size_t> vals(s.size() / sizeof(size_t));
|
||||||
memcpy(vals.data(), s.data(), s.size());
|
memcpy(vals.data(), s.data(), s.size());
|
||||||
for (auto& v : vals) {
|
for (auto& v : vals) {
|
||||||
ret->push(x.assert_existance(v, IfcParse::impl::rocks_db_file_storage::by_name));
|
ret->push(x.assert_existance(v, IfcParse::impl::rocks_db_file_storage::entityinstance_ref));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
@@ -2413,7 +2434,26 @@ aggregate_of_instance::ptr IfcFile::getInverse(int instance_id, const IfcParse::
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if constexpr (std::is_same_v<std::decay_t<decltype(x)>, impl::rocks_db_file_storage>) {
|
} else if constexpr (std::is_same_v<std::decay_t<decltype(x)>, impl::rocks_db_file_storage>) {
|
||||||
// @todo
|
if (attribute_index == -1) {
|
||||||
|
// @todo no lower/upper_bounds() implemented yet
|
||||||
|
auto prefix = "v|" + std::to_string(instance_id) + "|";
|
||||||
|
auto it = x.db->NewIterator(rocksdb::ReadOptions());
|
||||||
|
it->Seek(prefix);
|
||||||
|
while (it->Valid() && it->key().starts_with(prefix)) {
|
||||||
|
std::vector<size_t> vals(it->value().size() / sizeof(size_t));
|
||||||
|
memcpy(vals.data(), it->value().data(), it->value().size());
|
||||||
|
for (auto& v : vals) {
|
||||||
|
return_value->push(instance_by_id(v));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto it = x.byref_excl_.find({ instance_id, ent->index_in_schema(), attribute_index });
|
||||||
|
if (it != x.byref_excl_.end()) {
|
||||||
|
for (auto& i : it->second) {
|
||||||
|
return_value->push(instance_by_id(i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, storage_);
|
}, storage_);
|
||||||
});
|
});
|
||||||
@@ -2586,12 +2626,12 @@ std::atomic_uint32_t IfcUtil::IfcBaseClass::counter_(0);
|
|||||||
|
|
||||||
void IfcUtil::IfcBaseClass::unset_attribute_value(size_t index) {
|
void IfcUtil::IfcBaseClass::unset_attribute_value(size_t index) {
|
||||||
void* storage = file_ ? std::visit([](const auto& m) { return (void*)&m; }, file_->storage_) : nullptr;
|
void* storage = file_ ? std::visit([](const auto& m) { return (void*)&m; }, file_->storage_) : nullptr;
|
||||||
data_.set_attribute_value(storage, &declaration(), identity(), index, Blank{});
|
data_.set_attribute_value(storage, &declaration(), id() ? id() : identity(), index, Blank{});
|
||||||
}
|
}
|
||||||
|
|
||||||
AttributeValue IfcUtil::IfcBaseClass::get_attribute_value(size_t index) const {
|
AttributeValue IfcUtil::IfcBaseClass::get_attribute_value(size_t index) const {
|
||||||
void* storage = file_ ? std::visit([](const auto& m) { return (void*)&m; }, file_->storage_) : nullptr;
|
void* storage = file_ ? std::visit([](const auto& m) { return (void*)&m; }, file_->storage_) : nullptr;
|
||||||
return data_.get_attribute_value(storage, &declaration(), identity(), index);
|
return data_.get_attribute_value(storage, &declaration(), id() ? id() : identity(), index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IfcUtil::IfcBaseClass::toString(std::ostream& out, bool upper) const
|
void IfcUtil::IfcBaseClass::toString(std::ostream& out, bool upper) const
|
||||||
@@ -2606,7 +2646,7 @@ void IfcUtil::IfcBaseClass::toString(std::ostream& out, bool upper) const
|
|||||||
out << declaration().name();
|
out << declaration().name();
|
||||||
}
|
}
|
||||||
void* storage = file_ ? std::visit([](const auto& m) { return (void*)&m; }, file_->storage_) : nullptr;
|
void* storage = file_ ? std::visit([](const auto& m) { return (void*)&m; }, file_->storage_) : nullptr;
|
||||||
data().toString(storage, &declaration(), identity(), out, upper);
|
data().toString(storage, &declaration(), id() ? id() : identity(), out, upper);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -2623,8 +2663,7 @@ AttributeValue IfcEntityInstanceData::get_attribute_value(void* storage, const I
|
|||||||
if constexpr (std::is_same_v<std::decay_t<decltype(x)>, in_memory_attribute_storage>) {
|
if constexpr (std::is_same_v<std::decay_t<decltype(x)>, in_memory_attribute_storage>) {
|
||||||
return AttributeValue(&x, (uint8_t)index);
|
return AttributeValue(&x, (uint8_t)index);
|
||||||
} else if constexpr (std::is_same_v<std::decay_t<decltype(x)>, rocks_db_attribute_storage>) {
|
} else if constexpr (std::is_same_v<std::decay_t<decltype(x)>, rocks_db_attribute_storage>) {
|
||||||
// @todo
|
return AttributeValue((IfcParse::impl::rocks_db_file_storage*) storage, identity, decl->as_entity() ? 1 : 0, index);
|
||||||
return AttributeValue(decl->schema(), (IfcParse::impl::rocks_db_file_storage*) storage, identity, index);
|
|
||||||
} else {
|
} else {
|
||||||
return AttributeValue{};
|
return AttributeValue{};
|
||||||
}
|
}
|
||||||
@@ -2643,6 +2682,21 @@ bool IfcParse::impl::rocks_db_file_storage::read_schema(const IfcParse::schema_d
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
IfcUtil::IfcBaseClass::IfcBaseClass(IfcEntityInstanceData&& data)
|
||||||
|
: identity_(counter_++)
|
||||||
|
, id_(0)
|
||||||
|
, file_(nullptr)
|
||||||
|
, data_(std::move(data))
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* @todo this is not allowed cannot call virtual func in constructor
|
||||||
|
if (!declaration().as_entity()) {
|
||||||
|
// @nb from v0.9 type decl instances have their own id, which may collide with instance names in the file
|
||||||
|
// but is otherwise unique
|
||||||
|
id_ = identity_;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template void IFC_PARSE_API IfcUtil::IfcBaseClass::set_attribute_value<Blank>(size_t index, const Blank& value);
|
template void IFC_PARSE_API IfcUtil::IfcBaseClass::set_attribute_value<Blank>(size_t index, const Blank& value);
|
||||||
|
|||||||
@@ -120,8 +120,7 @@ double IfcParse::get_SI_equivalent(typename Schema::IfcNamedUnit* named_unit) {
|
|||||||
if (component->declaration().is(Schema::IfcSIUnit::Class())) {
|
if (component->declaration().is(Schema::IfcSIUnit::Class())) {
|
||||||
si_unit = component->template as<typename Schema::IfcSIUnit>();
|
si_unit = component->template as<typename Schema::IfcSIUnit>();
|
||||||
typename Schema::IfcValue* value = factor->ValueComponent();
|
typename Schema::IfcValue* value = factor->ValueComponent();
|
||||||
// @todo provide sufficient context
|
scale = value->as<IfcUtil::IfcBaseClass>()->get_attribute_value(0);
|
||||||
scale = value->data().get_attribute_value(nullptr, nullptr, 0, 0);
|
|
||||||
}
|
}
|
||||||
} else if (named_unit->declaration().is(Schema::IfcSIUnit::Class())) {
|
} else if (named_unit->declaration().is(Schema::IfcSIUnit::Class())) {
|
||||||
si_unit = named_unit->template as<typename Schema::IfcSIUnit>();
|
si_unit = named_unit->template as<typename Schema::IfcSIUnit>();
|
||||||
|
|||||||
@@ -25,10 +25,18 @@
|
|||||||
#include <iterator>
|
#include <iterator>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct is_std_tuple : std::false_type {};
|
||||||
|
|
||||||
|
template <typename... Ts>
|
||||||
|
struct is_std_tuple<std::tuple<Ts...>> : std::true_type {};
|
||||||
|
|
||||||
// Serialization and deserialization primitives
|
// Serialization and deserialization primitives
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct DefaultCodec;
|
struct DefaultCodec;
|
||||||
|
|
||||||
|
// @todo specialize for integral types in one go
|
||||||
|
|
||||||
// Specialization for size_t.
|
// Specialization for size_t.
|
||||||
template <>
|
template <>
|
||||||
struct DefaultCodec<size_t> {
|
struct DefaultCodec<size_t> {
|
||||||
@@ -46,6 +54,38 @@ struct DefaultCodec<size_t> {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Specialization for uint32_t.
|
||||||
|
template <>
|
||||||
|
struct DefaultCodec<uint32_t> {
|
||||||
|
std::string encode(const uint32_t& v) const {
|
||||||
|
std::string s(sizeof(v), 0);
|
||||||
|
memcpy(s.data(), &v, sizeof(v));
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
uint32_t decode(const std::string& s) const {
|
||||||
|
uint32_t v = 0;
|
||||||
|
// @todo take min of sizeof(v), len(s)
|
||||||
|
// @todo unify all serialization primitives
|
||||||
|
memcpy(&v, s.data(), sizeof(v));
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Specialization for std::vector<int>.
|
||||||
|
template <>
|
||||||
|
struct DefaultCodec<std::vector<uint32_t>> {
|
||||||
|
std::string encode(const std::vector<uint32_t>& vs) const {
|
||||||
|
std::string s(sizeof(uint32_t) * vs.size(), 0);
|
||||||
|
memcpy(s.data(), vs.data(), s.size());
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
std::vector<uint32_t> decode(const std::string& s) const {
|
||||||
|
std::vector<uint32_t> vs(s.size() / sizeof(uint32_t), 0);
|
||||||
|
memcpy(vs.data(), s.data(), s.size());
|
||||||
|
return vs;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Specialization for std::string (identity)
|
// Specialization for std::string (identity)
|
||||||
template <>
|
template <>
|
||||||
struct DefaultCodec<std::string> {
|
struct DefaultCodec<std::string> {
|
||||||
@@ -67,7 +107,7 @@ std::string key_to_string(const KeyT& key) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Convert from a string to a key. For non-string types, we assume numeric keys.
|
// Convert from a string to a key. For non-string types, we assume numeric keys.
|
||||||
template <typename KeyT>
|
template <typename KeyT, typename std::enable_if<!is_std_tuple<KeyT>::value, int>::type = 0>
|
||||||
KeyT key_from_string(const std::string& s) {
|
KeyT key_from_string(const std::string& s) {
|
||||||
// @todo tuples
|
// @todo tuples
|
||||||
if constexpr (std::is_same_v<KeyT, std::string>) {
|
if constexpr (std::is_same_v<KeyT, std::string>) {
|
||||||
@@ -79,6 +119,51 @@ KeyT key_from_string(const std::string& s) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Tuple, std::size_t... Is>
|
||||||
|
std::string tuple_to_string_impl(const Tuple& t, std::index_sequence<Is...>) {
|
||||||
|
std::ostringstream oss;
|
||||||
|
// Unpack the tuple; add a pipe before each element except the first.
|
||||||
|
((oss << (Is == 0 ? "" : "|") << std::to_string(std::get<Is>(t))), ...);
|
||||||
|
return oss.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename... Ts>
|
||||||
|
std::string key_to_string(const std::tuple<Ts...>& key) {
|
||||||
|
return tuple_to_string_impl(key, std::index_sequence_for<Ts...>{});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper: Convert a string token to the desired numeric type.
|
||||||
|
template<typename T>
|
||||||
|
T convert_string(const std::string& token) {
|
||||||
|
if constexpr (std::is_integral_v<T>) {
|
||||||
|
return static_cast<T>(std::stoll(token));
|
||||||
|
} else if constexpr (std::is_floating_point_v<T>) {
|
||||||
|
return static_cast<T>(std::stod(token));
|
||||||
|
} else {
|
||||||
|
static_assert(sizeof(T) == 0, "convert_string not implemented for this type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Helper: Build a tuple from a vector of string tokens.
|
||||||
|
template <typename TupleT, std::size_t... Is>
|
||||||
|
TupleT tuple_from_string_impl(const std::vector<std::string>& tokens, std::index_sequence<Is...>) {
|
||||||
|
return std::make_tuple(convert_string<std::tuple_element_t<Is, TupleT>>(tokens[Is])...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename TupleT, typename std::enable_if<is_std_tuple<TupleT>::value, int>::type = 0>
|
||||||
|
TupleT key_from_string(const std::string& s) {
|
||||||
|
std::vector<std::string> tokens;
|
||||||
|
std::istringstream iss(s);
|
||||||
|
std::string token;
|
||||||
|
while (std::getline(iss, token, '|')) {
|
||||||
|
tokens.push_back(token);
|
||||||
|
}
|
||||||
|
if (tokens.size() != std::tuple_size<TupleT>::value) {
|
||||||
|
throw std::runtime_error("Invalid tuple format");
|
||||||
|
}
|
||||||
|
return tuple_from_string_impl<TupleT>(tokens, std::make_index_sequence<std::tuple_size<TupleT>::value>{});
|
||||||
|
}
|
||||||
|
|
||||||
// rocksdb_map_adapter: a std::map-like interface on a RocksDB keyspace with a given prefix.
|
// rocksdb_map_adapter: a std::map-like interface on a RocksDB keyspace with a given prefix.
|
||||||
// The mapped_type is templated and encoded/decoded via Codec.
|
// The mapped_type is templated and encoded/decoded via Codec.
|
||||||
template <typename KeyT, typename MappedT, typename Codec = DefaultCodec<MappedT>>
|
template <typename KeyT, typename MappedT, typename Codec = DefaultCodec<MappedT>>
|
||||||
|
|||||||
@@ -0,0 +1,195 @@
|
|||||||
|
/********************************************************************************
|
||||||
|
* *
|
||||||
|
* This file is part of IfcOpenShell. *
|
||||||
|
* *
|
||||||
|
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the Lesser GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* Lesser GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the Lesser GNU General Public License *
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||||
|
* *
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
#include <rocksdb/db.h>
|
||||||
|
#include <rocksdb/options.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include <iterator>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <cstring>
|
||||||
|
#include <stdexcept>
|
||||||
|
|
||||||
|
|
||||||
|
template <typename KeyT>
|
||||||
|
class rocksdb_set_view {
|
||||||
|
public:
|
||||||
|
using key_type = KeyT;
|
||||||
|
using value_type = key_type;
|
||||||
|
|
||||||
|
private:
|
||||||
|
rocksdb::DB* db_;
|
||||||
|
std::string prefix_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
// Constructor: provide a pointer to an open RocksDB instance and the key-space prefix,
|
||||||
|
// e.g. "i|"
|
||||||
|
rocksdb_set_view(rocksdb::DB* db, const std::string& prefix)
|
||||||
|
: db_(db), prefix_(prefix) {}
|
||||||
|
|
||||||
|
// --- Iterator ---
|
||||||
|
class iterator {
|
||||||
|
public:
|
||||||
|
using value_type = key_type;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using iterator_category = std::forward_iterator_tag;
|
||||||
|
using pointer = const value_type*;
|
||||||
|
using reference = const value_type&;
|
||||||
|
|
||||||
|
private:
|
||||||
|
rocksdb::DB* db_;
|
||||||
|
std::string prefix_;
|
||||||
|
std::unique_ptr<rocksdb::Iterator> it_;
|
||||||
|
mutable value_type cached_value_;
|
||||||
|
|
||||||
|
// Helper: extract the key (i.e. the value) from the current RocksDB key.
|
||||||
|
value_type extract_current_value() const {
|
||||||
|
std::string full_key = it_->key().ToString();
|
||||||
|
std::string remainder = full_key.substr(prefix_.size());
|
||||||
|
size_t pos = remainder.find('|');
|
||||||
|
std::string key_str = (pos != std::string::npos) ? remainder.substr(0, pos) : remainder;
|
||||||
|
return key_from_string<key_type>(key_str);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validates the current iterator state.
|
||||||
|
void check_valid() {
|
||||||
|
if (!it_ || !it_->Valid() || !it_->key().starts_with(prefix_))
|
||||||
|
it_.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
iterator() : db_(nullptr), prefix_(), it_(nullptr) {}
|
||||||
|
|
||||||
|
iterator(rocksdb::DB* db, const std::string& prefix,
|
||||||
|
std::unique_ptr<rocksdb::Iterator> iter)
|
||||||
|
: db_(db), prefix_(prefix), it_(std::move(iter))
|
||||||
|
{
|
||||||
|
check_valid();
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator(const iterator& other)
|
||||||
|
: db_(other.db_), prefix_(other.prefix_)
|
||||||
|
{
|
||||||
|
if (other.it_) {
|
||||||
|
std::string curr = other.it_->key().ToString();
|
||||||
|
it_.reset(db_->NewIterator(rocksdb::ReadOptions{}));
|
||||||
|
it_->Seek(curr);
|
||||||
|
if (!it_->Valid() || it_->key().ToString() != curr)
|
||||||
|
it_.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator& operator=(const iterator& other) {
|
||||||
|
if (this != &other) {
|
||||||
|
db_ = other.db_;
|
||||||
|
prefix_ = other.prefix_;
|
||||||
|
if (other.it_) {
|
||||||
|
std::string curr = other.it_->key().ToString();
|
||||||
|
it_.reset(db_->NewIterator(rocksdb::ReadOptions{}));
|
||||||
|
it_->Seek(curr);
|
||||||
|
if (!it_->Valid() || it_->key().ToString() != curr)
|
||||||
|
it_.reset();
|
||||||
|
} else {
|
||||||
|
it_.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dereference: extract the key part from the RocksDB key.
|
||||||
|
value_type operator*() const {
|
||||||
|
return extract_current_value();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pointer access (via a cached value)
|
||||||
|
const value_type* operator->() const {
|
||||||
|
cached_value_ = **this;
|
||||||
|
return &cached_value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pre-increment: advance the iterator and skip over any duplicate keys.
|
||||||
|
iterator& operator++() {
|
||||||
|
if (it_) {
|
||||||
|
// Record the current key value.
|
||||||
|
value_type curr = extract_current_value();
|
||||||
|
do {
|
||||||
|
it_->Next();
|
||||||
|
} while (it_ && it_->Valid() && it_->key().starts_with(prefix_) &&
|
||||||
|
(extract_current_value() == curr));
|
||||||
|
if (!it_ || !it_->Valid() || !it_->key().starts_with(prefix_))
|
||||||
|
it_.reset();
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator operator++(int) {
|
||||||
|
iterator tmp(*this);
|
||||||
|
++(*this);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const iterator& other) const {
|
||||||
|
if (!it_ && !other.it_)
|
||||||
|
return true;
|
||||||
|
if (it_ && other.it_)
|
||||||
|
return it_->key().ToString() == other.it_->key().ToString();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const iterator& other) const {
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Returns an iterator to the first element in the key-space (or end() if none exist).
|
||||||
|
iterator begin() const {
|
||||||
|
auto iter = std::unique_ptr<rocksdb::Iterator>(db_->NewIterator(rocksdb::ReadOptions{}));
|
||||||
|
iter->Seek(prefix_);
|
||||||
|
if (iter->Valid() && iter->key().starts_with(prefix_))
|
||||||
|
return iterator(db_, prefix_, std::move(iter));
|
||||||
|
return end();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns an iterator representing the end of the key-space.
|
||||||
|
iterator end() const {
|
||||||
|
return iterator();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read-only find: returns an iterator to the element with the given key if it exists.
|
||||||
|
iterator find(const key_type& key) const {
|
||||||
|
std::string key_str = key_to_string(key);
|
||||||
|
// Construct the search key: prefix + key_str + separator.
|
||||||
|
std::string start_key = prefix_ + key_str + "|";
|
||||||
|
auto iter = std::unique_ptr<rocksdb::Iterator>(db_->NewIterator(rocksdb::ReadOptions{}));
|
||||||
|
iter->Seek(start_key);
|
||||||
|
if (iter->Valid() && iter->key().starts_with(prefix_)) {
|
||||||
|
std::string full_key = iter->key().ToString();
|
||||||
|
std::string remainder = full_key.substr(prefix_.size());
|
||||||
|
size_t pos = remainder.find('|');
|
||||||
|
std::string found_key_str = (pos != std::string::npos) ? remainder.substr(0, pos) : remainder;
|
||||||
|
if (key_from_string<key_type>(found_key_str) == key)
|
||||||
|
return iterator(db_, prefix_, std::move(iter));
|
||||||
|
}
|
||||||
|
return end();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t erase(const key_type& key) {
|
||||||
|
// @todo
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
/********************************************************************************
|
||||||
|
* *
|
||||||
|
* This file is part of IfcOpenShell. *
|
||||||
|
* *
|
||||||
|
* IfcOpenShell is free software: you can redistribute it and/or modify *
|
||||||
|
* it under the terms of the Lesser GNU General Public License as published by *
|
||||||
|
* the Free Software Foundation, either version 3.0 of the License, or *
|
||||||
|
* (at your option) any later version. *
|
||||||
|
* *
|
||||||
|
* IfcOpenShell is distributed in the hope that it will be useful, *
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
||||||
|
* Lesser GNU General Public License for more details. *
|
||||||
|
* *
|
||||||
|
* You should have received a copy of the Lesser GNU General Public License *
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
|
||||||
|
* *
|
||||||
|
********************************************************************************/
|
||||||
|
|
||||||
|
#include <iterator>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
|
// map_transformer: wraps a set-like construct so that its iterator returns
|
||||||
|
// a value_type where of the underlying set element as the key, with the value
|
||||||
|
// that same key transformed via a function.
|
||||||
|
template <typename BaseSet, typename Transform>
|
||||||
|
class set_to_map_transformer {
|
||||||
|
public:
|
||||||
|
using key_type = typename BaseSet::value_type;
|
||||||
|
using transformed_mapped_type = std::invoke_result_t<Transform, key_type>;
|
||||||
|
using value_type = std::pair<key_type, transformed_mapped_type>;
|
||||||
|
using mapped_type = transformed_mapped_type;
|
||||||
|
|
||||||
|
private:
|
||||||
|
BaseSet* base_map_;
|
||||||
|
Transform transform_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
set_to_map_transformer(BaseSet* map, Transform transform)
|
||||||
|
: base_map_(map), transform_(transform) {}
|
||||||
|
|
||||||
|
class iterator {
|
||||||
|
public:
|
||||||
|
using base_iterator = typename BaseSet::iterator;
|
||||||
|
using iterator_category = std::forward_iterator_tag;
|
||||||
|
using difference_type = typename std::iterator_traits<base_iterator>::difference_type;
|
||||||
|
using key_type = typename BaseSet::key_type;
|
||||||
|
using transformed_mapped_type = std::invoke_result_t<Transform, key_type>;
|
||||||
|
using value_type = std::pair<key_type, transformed_mapped_type>;
|
||||||
|
|
||||||
|
private:
|
||||||
|
base_iterator base_it_;
|
||||||
|
Transform* transform_ptr_;
|
||||||
|
|
||||||
|
mutable value_type cached_value_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
iterator() : base_it_(), transform_ptr_(nullptr) {}
|
||||||
|
iterator(base_iterator base_it, Transform* transform_ptr)
|
||||||
|
: base_it_(base_it), transform_ptr_(transform_ptr) {}
|
||||||
|
|
||||||
|
// On dereference, return a pair where the key is the set value and the mapped value
|
||||||
|
// is the result of applying the transform to the underlying value.
|
||||||
|
value_type operator*() const {
|
||||||
|
auto base_val = *base_it_;
|
||||||
|
return { base_val, (*transform_ptr_)(base_val) };
|
||||||
|
}
|
||||||
|
|
||||||
|
// operator-> uses a mutable cache to return a pointer to the current value.
|
||||||
|
value_type* operator->() const {
|
||||||
|
cached_value_ = **this;
|
||||||
|
return &cached_value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator& operator++() {
|
||||||
|
++base_it_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator operator++(int) {
|
||||||
|
iterator tmp(*this);
|
||||||
|
++(*this);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator==(const iterator& other) const {
|
||||||
|
return base_it_ == other.base_it_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(const iterator& other) const {
|
||||||
|
return !(*this == other);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
iterator begin() {
|
||||||
|
return iterator(base_map_->begin(), &transform_);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator end() {
|
||||||
|
return iterator(base_map_->end(), &transform_);
|
||||||
|
}
|
||||||
|
|
||||||
|
iterator find(const key_type& k) {
|
||||||
|
return iterator(base_map_->find(k), &transform_);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t erase(const key_type& k) {
|
||||||
|
// @todo
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -195,6 +195,8 @@ IF "%IFCOS_INSTALL_PYTHON%"=="TRUE" (
|
|||||||
echo PYTHONHOME=%PYTHONHOME%>>"%~dp0\%BUILD_DEPS_CACHE_PATH%"
|
echo PYTHONHOME=%PYTHONHOME%>>"%~dp0\%BUILD_DEPS_CACHE_PATH%"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
goto :rocksdb
|
||||||
|
|
||||||
:proj
|
:proj
|
||||||
|
|
||||||
IF EXIST "%INSTALL_DIR%\proj-9.2.1" (
|
IF EXIST "%INSTALL_DIR%\proj-9.2.1" (
|
||||||
|
|||||||
Reference in New Issue
Block a user