Files
IfcOpenShell/src/ifcparse/IfcEntityInstanceData.h
T

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

450 lines
17 KiB
C++
Raw Normal View History

2017-06-05 17:26:58 +02:00
/********************************************************************************
* *
* 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/>. *
* *
********************************************************************************/
#ifndef IFCENTITYINSTANCEDATA_H
#define IFCENTITYINSTANCEDATA_H
2023-09-17 12:30:17 +02:00
#include "ArgumentType.h"
2024-08-23 20:29:07 +02:00
#include "variantarray.h"
#include "aggregate_of_instance.h"
#include "IfcSchema.h"
2017-06-05 17:26:58 +02:00
#pragma push_macro("Handle")
#undef Handle
#include <rocksdb/db.h>
#pragma pop_macro("Handle")
#include <boost/optional.hpp>
2017-06-05 17:26:58 +02:00
#include <boost/shared_ptr.hpp>
2024-08-23 20:29:07 +02:00
#include <boost/logic/tribool.hpp>
#include <boost/dynamic_bitset.hpp>
class EnumerationReference {
private:
const IfcParse::enumeration_type* enumeration_;
size_t index_;
public:
EnumerationReference(const IfcParse::enumeration_type* enumeration = nullptr, size_t index = 0)
2024-08-23 20:29:07 +02:00
: enumeration_(enumeration)
, index_(index)
{}
const char* value() const {
return enumeration_->lookup_enum_value(index_);
}
2017-06-05 17:26:58 +02:00
2024-08-23 20:29:07 +02:00
size_t index() const {
return index_;
}
const IfcParse::enumeration_type* enumeration() const {
return enumeration_;
}
};
class Blank {};
class Derived {};
class empty_aggregate_t {};
class empty_aggregate_of_aggregate_t {};
template<typename... Args>
struct parameter_pack {
static constexpr size_t size = sizeof...(Args);
};
typedef parameter_pack <
2024-08-23 20:29:07 +02:00
// A null argument, it will always serialize to $
Blank,
// @todo Derived is not really necessary anymore, just serialize correctly based on schema
// A derived argument, it will always serialize to *
Derived,
// An integer argument, e.g. 123
// SCALARS:
int,
// A boolean argument, it will serialize to either .T. or .F.
bool,
// A logical argument, it will serialize to either .T. or .F. or .U.
boost::logic::tribool,
// A floating point argument, e.g. 12.3
double,
// A character string argument, e.g. 'IfcOpenShell'
std::string,
// A binary argument, e.g. "092A" -> 100100101010
boost::dynamic_bitset<>,
// An enumeration argument, e.g. .USERDEFINED.
// To initialize the argument a string representation
// has to be explicitly passed of the enumeration value
// which is stored internally as an integer. The argument
// itself does not keep track of what schema enumeration
// type is represented.
EnumerationReference,
// An entity instance argument. It will either serialize to
// e.g. #123 or datatype identifier for simple types, e.g.
// IFCREAL(12.3)
IfcUtil::IfcBaseClass*,
// AGGREGATES:
empty_aggregate_t,
// An aggregate of integers, e.g. (1,2,3)
std::vector<int>,
// An aggregate of floats, e.g. (12.3,4.)
std::vector<double>,
// An aggregate of strings, e.g. ('Ifc','Open','Shell')
std::vector<std::string>,
// An aggregate of binaries, e.g. ("23B", "092A") -> (111011, 100100101010)
std::vector<boost::dynamic_bitset<>>,
// An aggregate of entity instances. It will either serialize to
// e.g. (#1,#2,#3) or datatype identifier for simple types,
// e.g. (IFCREAL(1.2),IFCINTEGER(3.))
aggregate_of_instance::ptr,
// AGGREGATES OF AGGREGATES:
empty_aggregate_of_aggregate_t,
// An aggregate of an aggregate of ints. E.g. ((1, 2), (3))
std::vector<std::vector<int>>,
// An aggregate of an aggregate of floats. E.g. ((1., 2.3), (4.))
std::vector<std::vector<double>>,
// An aggregate of an aggregate of entities. E.g. ((#1, #2), (#3))
aggregate_of_aggregate_of_instance::ptr
> type_variant_parameter_pack;
template<typename Pack>
struct pack_to_variant_array;
template<typename... Args>
struct pack_to_variant_array<parameter_pack<Args...>> {
using type = VariantArray<Args...>;
};
using in_memory_attribute_storage = pack_to_variant_array<type_variant_parameter_pack>::type;
template <typename Pack>
struct TypeEncoder_t;
template <typename... Types>
struct TypeEncoder_t<parameter_pack<Types...>> {
template <typename U>
static char encode_type() {
return 'A' + ::impl::TypeIndex_v<U, Types...>;
}
};
using TypeEncoder = TypeEncoder_t<type_variant_parameter_pack>;
2024-08-23 20:29:07 +02:00
struct MutableAttributeValue {
int name_;
uint8_t index_;
};
namespace IfcParse {
namespace impl {
class rocks_db_file_storage;
}
}
2025-02-25 21:29:54 +01:00
namespace impl {
// Trait to detect contiguous containers (vector / string)
template <typename T>
struct is_contiguous_container : std::false_type {};
template <typename T, typename Alloc>
struct is_contiguous_container<std::vector<T, Alloc>> : std::true_type {};
template <typename CharT, typename Traits, typename Alloc>
struct is_contiguous_container<std::basic_string<CharT, Traits, Alloc>> : std::true_type {};
template <typename T, typename std::enable_if<is_contiguous_container<T>::value && !is_contiguous_container<typename T::value_type>::value, int>::type = 0>
bool serialize(std::string& val, const T& t) {
auto s = sizeof(typename T::value_type) * t.size();
val.resize(s + 1);
val[0] = TypeEncoder::encode_type<T>();
memcpy(val.data() + 1, t.data(), s);
return true;
}
2025-02-27 22:07:31 +01:00
template <typename T, typename std::enable_if<is_contiguous_container<T>::value&& is_contiguous_container<typename T::value_type>::value, int>::type = 0>
bool serialize(std::string& val, const T& t) {
val = std::string(1, TypeEncoder::encode_type<T>());
for (auto& tt : t) {
std::string v2;
serialize(v2, tt);
std::string len(sizeof(size_t), 0);
size_t s = v2.size() - 1;
memcpy(len.data(), &s, sizeof(size_t));
// @todo horribly inefficient
// @todo strip off type label?
val += len + v2.substr(1);
}
return true;
}
2025-02-25 21:29:54 +01:00
template <typename T, typename std::enable_if<std::is_integral_v<T> || std::is_floating_point_v<T>, int>::type = 0>
bool serialize(std::string& val, const T& t) {
val.resize(sizeof(T) + 1);
val[0] = TypeEncoder::encode_type<T>();
memcpy(val.data() + 1, &t, sizeof(T));
return true;
}
bool serialize(std::string& val, const Blank& t);
bool serialize(std::string& val, const Derived& t);
bool serialize(std::string& val, const empty_aggregate_t& t);
bool serialize(std::string& val, const empty_aggregate_of_aggregate_t& t);
bool serialize(std::string& val, const boost::logic::tribool& t);
bool serialize(std::string& val, const boost::dynamic_bitset<>& t);
bool serialize(std::string& val, const IfcUtil::IfcBaseClass* t);
bool serialize(std::string& val, const EnumerationReference& v);
bool serialize(std::string& val, const aggregate_of_instance::ptr& t);
bool serialize(std::string& val, const aggregate_of_aggregate_of_instance::ptr& t);
2025-02-27 22:07:31 +01:00
template <typename T, typename std::enable_if<is_contiguous_container<T>::value && !is_contiguous_container<typename T::value_type>::value, int>::type = 0>
bool deserialize(IfcParse::impl::rocks_db_file_storage*, const std::string& val, T& t, bool prefixed = true) {
if (prefixed && val[0] != TypeEncoder::encode_type<T>()) {
2025-02-25 21:29:54 +01:00
return false;
}
2025-02-27 22:07:31 +01:00
auto s = (val.size() - (prefixed ? 1 : 0)) / sizeof(typename T::value_type);
2025-02-25 21:29:54 +01:00
t.resize(s);
2025-02-27 22:07:31 +01:00
memcpy(t.data(), val.data() + (prefixed ? 1 : 0), s * sizeof(typename T::value_type));
return true;
}
template <typename T, typename std::enable_if<is_contiguous_container<T>::value && is_contiguous_container<typename T::value_type>::value, int>::type = 0>
bool deserialize(IfcParse::impl::rocks_db_file_storage* storage, const std::string& val, T& t) {
// @todo
auto ptr = val.data();
if (*ptr != TypeEncoder::encode_type<T>()) {
return false;
}
ptr++;
t.clear();
while (ptr < val.data() + val.size()) {
size_t s;
memcpy(&s, ptr, sizeof(size_t));
// @todo view
ptr += sizeof(size_t);
std::string part(ptr, s);
t.emplace_back();
deserialize(storage, part, t.back(), false);
ptr += s;
}
2025-02-25 21:29:54 +01:00
return true;
}
template <typename T, typename std::enable_if<std::is_integral_v<T> || std::is_floating_point_v<T>, int>::type = 0>
2025-02-27 22:07:31 +01:00
bool deserialize(IfcParse::impl::rocks_db_file_storage*, const std::string& val, T & t) {
2025-02-25 21:29:54 +01:00
if (val[0] != TypeEncoder::encode_type<T>()) {
return false;
}
auto s = (val.size() - 1) / sizeof(T);
memcpy(&t, val.data() + 1, sizeof(T));
return true;
}
2025-02-27 22:07:31 +01:00
bool deserialize(IfcParse::impl::rocks_db_file_storage*, const std::string& val, boost::logic::tribool& t);
2025-02-25 21:29:54 +01:00
2025-02-27 22:07:31 +01:00
bool deserialize(IfcParse::impl::rocks_db_file_storage*, const std::string& val, boost::dynamic_bitset<>& t);
2025-02-25 21:29:54 +01:00
2025-02-27 22:07:31 +01:00
bool deserialize(IfcParse::impl::rocks_db_file_storage*, const std::string& val, aggregate_of_instance::ptr& t);
2025-02-25 21:29:54 +01:00
2025-02-27 22:07:31 +01:00
bool deserialize(IfcParse::impl::rocks_db_file_storage*, const std::string& val, aggregate_of_aggregate_of_instance::ptr& t);
2025-02-25 21:29:54 +01:00
}
2024-08-23 20:29:07 +02:00
// short lived
struct AttributeValue {
uint8_t index_;
uint8_t storage_model_ = 0;
uint8_t entity_or_type_ = 0;
size_t instance_name_;
union pointer_type {
const in_memory_attribute_storage* storage_ptr;
IfcParse::impl::rocks_db_file_storage* db_ptr;
pointer_type(IfcParse::impl::rocks_db_file_storage* db) : db_ptr(db) {}
pointer_type(const in_memory_attribute_storage* ims) : storage_ptr(ims) {}
};
pointer_type array_;
2024-08-23 20:29:07 +02:00
AttributeValue()
: index_(0)
, array_((const in_memory_attribute_storage*)nullptr)
, storage_model_(0)
2024-08-23 20:29:07 +02:00
{}
AttributeValue(const in_memory_attribute_storage* arr, uint8_t index)
: index_(index)
, array_(arr)
, storage_model_(0)
{}
AttributeValue(IfcParse::impl::rocks_db_file_storage* db, size_t instance_name, uint8_t entity_or_type, uint8_t index)
: index_(index)
, array_(db)
, storage_model_(1)
, instance_name_(instance_name)
, entity_or_type_(entity_or_type)
2024-08-23 20:29:07 +02:00
{}
operator int() const;
operator bool() const;
operator boost::logic::tribool() const;
operator double() const;
operator std::string() const;
operator boost::dynamic_bitset<>() const;
operator IfcUtil::IfcBaseClass* () const;
operator std::vector<int>() const;
operator std::vector<double>() const;
operator std::vector<std::string>() const;
operator std::vector<boost::dynamic_bitset<>>() const;
operator boost::shared_ptr<aggregate_of_instance>() const;
operator std::vector<std::vector<int>>() const;
operator std::vector<std::vector<double>>() const;
operator boost::shared_ptr<aggregate_of_aggregate_of_instance>() const;
operator EnumerationReference() const;
2024-08-23 20:29:07 +02:00
bool isNull() const;
unsigned int size() const;
IfcUtil::ArgumentType type() const;
};
2017-06-05 17:26:58 +02:00
struct rocks_db_attribute_storage {
private:
template<typename Visitor, std::size_t Index>
auto apply_visitor_impl(Visitor&& visitor, std::size_t idx, std::integral_constant<std::size_t, Index>) const {
return apply_visitor_impl(std::forward<Visitor>(visitor), idx, std::integral_constant<std::size_t, Index - 1>{});
}
template<typename Visitor>
void apply_visitor_impl(Visitor&&, std::size_t, std::integral_constant<std::size_t, 0>) const {
throw std::runtime_error("Invalid variant index");
}
public:
2025-02-27 22:07:31 +01:00
size_t size(void*, const IfcParse::declaration*, std::size_t identity) const {
2025-02-25 21:29:54 +01:00
// @todo is this actually needed?
return 8;
}
2025-02-27 22:07:31 +01:00
// @todo void* is obviously very ugly here
template<typename T>
2025-02-27 22:07:31 +01:00
void set(void* storage, const IfcParse::declaration*, std::size_t identity, std::size_t index, const T& value);
template<typename T>
2025-02-27 22:07:31 +01:00
bool has(void* storage, const IfcParse::declaration*, std::size_t identity, std::size_t index) const {
// @todo
return false;
}
template<typename Visitor>
2025-02-27 22:07:31 +01:00
auto apply_visitor(void* storage, const IfcParse::declaration*, std::size_t identity, std::size_t index, Visitor&& visitor) const {
return apply_visitor_impl(std::forward<Visitor>(visitor), index, std::integral_constant<std::size_t, type_variant_parameter_pack::size>{});
}
};
2017-06-05 17:26:58 +02:00
class IFC_PARSE_API IfcEntityInstanceData {
2023-09-17 12:30:17 +02:00
public:
2025-02-27 22:07:31 +01:00
// @todo since rocks_db_attribute_storage has no members anymore, change to in_memory_attribute_storage*?
// 24 -> 8 bytes...
std::variant<in_memory_attribute_storage, rocks_db_attribute_storage> storage_;
2023-09-17 12:30:17 +02:00
IfcEntityInstanceData(in_memory_attribute_storage&& storage)
: storage_(std::move(storage))
{}
IfcEntityInstanceData(rocks_db_attribute_storage&& storage)
2024-08-23 20:29:07 +02:00
: storage_(std::move(storage))
{}
2017-06-05 17:26:58 +02:00
2024-08-23 20:29:07 +02:00
IfcEntityInstanceData(IfcEntityInstanceData&& other) noexcept
: storage_(std::move(other.storage_))
{}
2017-06-05 17:26:58 +02:00
2025-02-27 22:07:31 +01:00
// No copy-constructor anymore because we need the instance for storage model context
IfcEntityInstanceData(const IfcEntityInstanceData&) = delete;
2022-04-28 10:33:54 +02:00
2024-08-23 20:29:07 +02:00
IfcEntityInstanceData& operator=(IfcEntityInstanceData&& other) {
if (this != &other) {
storage_ = std::move(other.storage_);
}
return *this;
}
2025-02-27 22:07:31 +01:00
AttributeValue get_attribute_value(void* storage, const IfcParse::declaration*, std::size_t identity, size_t index) const;
2017-06-05 17:26:58 +02:00
template<typename T>
2025-02-27 22:07:31 +01:00
void set_attribute_value(void* storage, const IfcParse::declaration* decl, std::size_t identity, std::size_t index, T&& value) {
std::visit([&index, &value, storage, decl, identity](auto& x) {
if constexpr (std::is_same_v<std::decay_t<decltype(x)>, in_memory_attribute_storage>) {
return x.set(index, value);
} else {
return x.set(storage, decl, identity, index, value);
}
}, storage_);
}
2017-06-05 17:26:58 +02:00
template<typename T>
2025-02-27 22:07:31 +01:00
bool has_attribute_value(void* storage, const IfcParse::declaration* decl, std::size_t identity, std::size_t index) const {
return std::visit([&index, storage, decl, identity](const auto& x) {
if constexpr (std::is_same_v<std::decay_t<decltype(x)>, in_memory_attribute_storage>) {
return x.has<T>(index);
} else {
return x.has<T>(storage, decl, identity, index);
}
}, storage_);
}
template<typename Visitor>
2025-02-27 22:07:31 +01:00
auto apply_visitor(void* storage, const IfcParse::declaration* decl, std::size_t identity, Visitor&& visitor, std::size_t index) const {
return std::visit([&index, &visitor, storage, decl, identity](const auto& x) {
if constexpr (std::is_same_v<std::decay_t<decltype(x)>, in_memory_attribute_storage>) {
return x.apply_visitor(std::forward<Visitor>(visitor), index);
} else {
return x.apply_visitor(storage, decl, identity, index, std::forward<Visitor>(visitor));
}
}, storage_);
}
2017-06-05 17:26:58 +02:00
2025-02-27 22:07:31 +01:00
size_t size(void* storage, const IfcParse::declaration* decl, std::size_t identity) const {
return std::visit([storage, decl, identity](const auto& x) {
if constexpr (std::is_same_v<std::decay_t<decltype(x)>, in_memory_attribute_storage>) {
return x.size();
} else {
return x.size(storage, decl, identity);
}
}, storage_);
2024-08-23 20:29:07 +02:00
}
2017-06-05 17:26:58 +02:00
2025-02-27 22:07:31 +01:00
void toString(void* storage, const IfcParse::declaration*, std::size_t identity, std::ostream&, bool upper = false) const;
2017-06-05 17:26:58 +02:00
};
#endif