Files
IfcOpenShell/src/ifcparse/instance_data.h
T

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

518 lines
19 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 InstanceData_H
#define InstanceData_H
2017-06-05 17:26:58 +02:00
#include "express.h"
2026-03-31 15:32:36 +02:00
#include "argument_type.h"
#include "variant_array.h"
#include "schema.h"
#include "storage.h"
2017-06-05 17:26:58 +02:00
#ifdef IFOPSH_WITH_ROCKSDB
#pragma push_macro("Handle")
#undef Handle
#include <rocksdb/db.h>
#pragma pop_macro("Handle")
#endif
2024-08-23 20:29:07 +02:00
#include <boost/logic/tribool.hpp>
#include <boost/dynamic_bitset.hpp>
2026-03-31 15:32:36 +02:00
class IFC_PARSE_API enumeration_reference {
2024-08-23 20:29:07 +02:00
private:
2026-03-31 15:32:36 +02:00
const ifcopenshell::enumeration_type* enumeration_;
2024-08-23 20:29:07 +02:00
size_t index_;
public:
2026-03-31 15:32:36 +02:00
enumeration_reference(const ifcopenshell::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_;
}
2026-03-31 15:32:36 +02:00
const ifcopenshell::enumeration_type* enumeration() const {
2024-08-23 20:29:07 +02:00
return enumeration_;
}
};
2026-03-31 15:32:36 +02:00
class IFC_PARSE_API blank {};
class IFC_PARSE_API derived {};
2025-09-26 14:24:49 +02:00
class IFC_PARSE_API empty_aggregate_t {};
class IFC_PARSE_API empty_aggregate_of_aggregate_t {};
2024-08-23 20:29:07 +02:00
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 $
2026-03-31 15:32:36 +02:00
blank,
// @todo derived is not really necessary anymore, just serialize correctly based on schema
2024-08-23 20:29:07 +02:00
// A derived argument, it will always serialize to *
2026-03-31 15:32:36 +02:00
derived,
2024-08-23 20:29:07 +02:00
// 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.
2026-03-31 15:32:36 +02:00
enumeration_reference,
2024-08-23 20:29:07 +02:00
// An entity instance argument. It will either serialize to
// e.g. #123 or datatype identifier for simple types, e.g.
// IFCREAL(12.3)
express::Base,
2024-08-23 20:29:07 +02:00
// 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.))
std::vector<express::Base>,
2024-08-23 20:29:07 +02:00
// 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))
std::vector<std::vector<express::Base>>>
type_variant_parameter_pack;
template<typename Pack>
struct pack_to_variant_array;
template<typename... Args>
struct pack_to_variant_array<parameter_pack<Args...>> {
2026-03-31 15:32:36 +02:00
using type = variant_array<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
2026-03-31 15:32:36 +02:00
class IFC_PARSE_API mutable_attribute_value {
public:
2025-10-13 20:47:43 +02:00
uint32_t name_;
2024-08-23 20:29:07 +02:00
uint8_t index_;
};
2026-03-31 15:32:36 +02:00
namespace ifcopenshell {
namespace impl {
2025-09-26 14:24:49 +02:00
class IFC_PARSE_API rocks_db_file_storage;
}
}
2025-10-19 13:20:58 +02:00
#ifdef IFOPSH_WITH_ROCKSDB
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>
2026-03-31 18:23:13 +02:00
bool serialize(std::string& buffer, const T& value) {
auto byte_count = sizeof(typename T::value_type) * value.size();
buffer.resize(byte_count + 1);
buffer[0] = TypeEncoder::encode_type<T>();
memcpy(buffer.data() + 1, value.data(), byte_count);
2025-02-25 21:29:54 +01:00
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>
2026-03-31 18:23:13 +02:00
bool serialize(std::string& buffer, const T& value) {
buffer = std::string(1, TypeEncoder::encode_type<T>());
for (auto& nested_value : value) {
std::string nested_buffer;
serialize(nested_buffer, nested_value);
std::string encoded_length(sizeof(size_t), 0);
size_t payload_size = nested_buffer.size() - 1;
memcpy(encoded_length.data(), &payload_size, sizeof(size_t));
2025-02-27 22:07:31 +01:00
// @todo horribly inefficient
// @todo strip off type label?
2026-03-31 18:23:13 +02:00
buffer += encoded_length + nested_buffer.substr(1);
2025-02-27 22:07:31 +01:00
}
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>
2026-03-31 18:23:13 +02:00
bool serialize(std::string& buffer, const T& value) {
buffer.resize(sizeof(T) + 1);
buffer[0] = TypeEncoder::encode_type<T>();
memcpy(buffer.data() + 1, &value, sizeof(T));
2025-02-25 21:29:54 +01:00
return true;
}
2026-03-31 18:23:13 +02:00
bool serialize(std::string& buffer, const blank& value);
2025-02-25 21:29:54 +01:00
2026-03-31 18:23:13 +02:00
bool serialize(std::string& buffer, const derived& value);
bool serialize(std::string& buffer, const empty_aggregate_t& value);
bool serialize(std::string& buffer, const empty_aggregate_of_aggregate_t& value);
2025-02-25 21:29:54 +01:00
2026-03-31 18:23:13 +02:00
bool serialize(std::string& buffer, const boost::logic::tribool& value);
2025-02-25 21:29:54 +01:00
2026-03-31 18:23:13 +02:00
bool serialize(std::string& buffer, const boost::dynamic_bitset<>& value);
2025-02-25 21:29:54 +01:00
2026-03-31 18:23:13 +02:00
bool serialize(std::string& buffer, const express::Base& value);
2025-02-25 21:29:54 +01:00
2026-03-31 18:23:13 +02:00
bool serialize(std::string& buffer, const enumeration_reference& value);
2025-02-25 21:29:54 +01:00
2026-03-31 18:23:13 +02:00
bool serialize(std::string& buffer, const std::vector<express::Base>& value);
2025-02-25 21:29:54 +01:00
2026-03-31 18:23:13 +02:00
bool serialize(std::string& buffer, const std::vector<std::vector<express::Base>>& value);
2025-02-25 21:29:54 +01:00
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>
2026-03-31 18:23:13 +02:00
bool deserialize(ifcopenshell::impl::rocks_db_file_storage* storage, const std::string& buffer, T& value, bool has_type_prefix = true) {
static_cast<void>(storage);
if (has_type_prefix && buffer[0] != TypeEncoder::encode_type<T>()) {
2025-02-25 21:29:54 +01:00
return false;
}
2026-03-31 18:23:13 +02:00
auto element_count = (buffer.size() - (has_type_prefix ? 1 : 0)) / sizeof(typename T::value_type);
value.resize(element_count);
memcpy(value.data(), buffer.data() + (has_type_prefix ? 1 : 0), element_count * sizeof(typename T::value_type));
2025-02-27 22:07:31 +01:00
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>
2026-03-31 18:23:13 +02:00
bool deserialize(ifcopenshell::impl::rocks_db_file_storage* storage, const std::string& buffer, T& value) {
2025-02-27 22:07:31 +01:00
// @todo
2026-03-31 18:23:13 +02:00
auto ptr = buffer.data();
2025-02-27 22:07:31 +01:00
if (*ptr != TypeEncoder::encode_type<T>()) {
return false;
}
ptr++;
2026-03-31 18:23:13 +02:00
value.clear();
while (ptr < buffer.data() + buffer.size()) {
size_t payload_size;
memcpy(&payload_size, ptr, sizeof(size_t));
2025-02-27 22:07:31 +01:00
// @todo view
ptr += sizeof(size_t);
2026-03-31 18:23:13 +02:00
std::string part(ptr, payload_size);
value.emplace_back();
deserialize(storage, part, value.back(), false);
ptr += payload_size;
2025-02-27 22:07:31 +01:00
}
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>
2026-03-31 18:23:13 +02:00
bool deserialize(ifcopenshell::impl::rocks_db_file_storage* storage, const std::string& buffer, T& value) {
static_cast<void>(storage);
if (buffer[0] != TypeEncoder::encode_type<T>()) {
2025-02-25 21:29:54 +01:00
return false;
}
2026-03-31 18:23:13 +02:00
memcpy(&value, buffer.data() + 1, sizeof(T));
2025-02-25 21:29:54 +01:00
return true;
}
2026-03-31 18:23:13 +02:00
bool deserialize(ifcopenshell::impl::rocks_db_file_storage* storage, const std::string& buffer, boost::logic::tribool& value);
2025-02-25 21:29:54 +01:00
2026-03-31 18:23:13 +02:00
bool deserialize(ifcopenshell::impl::rocks_db_file_storage* storage, const std::string& buffer, boost::dynamic_bitset<>& value);
2025-02-25 21:29:54 +01:00
2026-03-31 18:23:13 +02:00
bool deserialize(ifcopenshell::impl::rocks_db_file_storage* storage, const std::string& buffer, std::vector<express::Base>& value);
2025-02-25 21:29:54 +01:00
2026-03-31 18:23:13 +02:00
bool deserialize(ifcopenshell::impl::rocks_db_file_storage* storage, const std::string& buffer, std::vector<std::vector<express::Base>>& value);
}
2025-02-25 21:29:54 +01:00
#endif
2025-02-25 21:29:54 +01:00
2024-08-23 20:29:07 +02:00
// short lived
2026-03-31 15:32:36 +02:00
class IFC_PARSE_API attribute_value {
2024-08-23 20:29:07 +02:00
uint8_t index_;
uint8_t storage_model_ = 0;
2026-03-31 15:32:36 +02:00
const ifcopenshell::declaration* entity_or_type_ = 0;
size_t instance_name_;
public:
union pointer_type {
const in_memory_attribute_storage* storage_ptr;
2026-03-31 15:32:36 +02:00
ifcopenshell::impl::rocks_db_file_storage* db_ptr;
2026-03-31 18:23:13 +02:00
pointer_type(ifcopenshell::impl::rocks_db_file_storage* storage) : db_ptr(storage) {}
pointer_type(const in_memory_attribute_storage* storage) : storage_ptr(storage) {}
};
private:
pointer_type array_;
public:
2026-03-31 15:32:36 +02:00
attribute_value()
: index_(0)
, storage_model_(0)
2025-08-27 11:03:16 +02:00
, array_((const in_memory_attribute_storage*)nullptr)
2024-08-23 20:29:07 +02:00
{}
2026-03-31 18:23:13 +02:00
attribute_value(const in_memory_attribute_storage* storage, uint8_t index)
: index_(index)
, storage_model_(0)
2026-03-31 18:23:13 +02:00
, array_(storage)
{}
2026-03-31 18:23:13 +02:00
attribute_value(ifcopenshell::impl::rocks_db_file_storage* storage, size_t instance_name, const ifcopenshell::declaration* entity_or_type, uint8_t index)
: index_(index)
, storage_model_(1)
, entity_or_type_(entity_or_type)
2025-08-27 11:03:16 +02:00
, instance_name_(instance_name)
2026-03-31 18:23:13 +02:00
, array_(storage)
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 express::Base() const;
2024-08-23 20:29:07 +02:00
operator std::vector<int>() const;
operator std::vector<double>() const;
operator std::vector<std::string>() const;
operator std::vector<boost::dynamic_bitset<>>() const;
operator std::vector<express::Base>() const;
2024-08-23 20:29:07 +02:00
operator std::vector<std::vector<int>>() const;
operator std::vector<std::vector<double>>() const;
operator std::vector<std::vector<express::Base>>() const;
2024-08-23 20:29:07 +02:00
2026-03-31 15:32:36 +02:00
operator enumeration_reference() const;
2024-08-23 20:29:07 +02:00
bool isNull() const;
unsigned int size() const;
2026-03-31 15:32:36 +02:00
ifcopenshell::argument_type type() const;
2025-03-14 10:20:22 +01:00
template<typename Visitor>
auto apply_visitor(Visitor&& visitor) const {
switch (type()) {
2026-03-31 15:32:36 +02:00
case ifcopenshell::Argument_DERIVED:
return visitor(derived{});
case ifcopenshell::Argument_INT:
2025-03-14 10:20:22 +01:00
return visitor((int)*this);
2026-03-31 15:32:36 +02:00
case ifcopenshell::Argument_BOOL:
2025-03-14 10:20:22 +01:00
return visitor((bool)*this);
2026-03-31 15:32:36 +02:00
case ifcopenshell::Argument_LOGICAL: {
2025-03-14 10:20:22 +01:00
boost::logic::tribool tb = *this;
return visitor(tb);
}
2026-03-31 15:32:36 +02:00
case ifcopenshell::Argument_DOUBLE:
2025-03-14 10:20:22 +01:00
return visitor((double)*this);
2026-03-31 15:32:36 +02:00
case ifcopenshell::Argument_STRING:
2025-03-14 10:20:22 +01:00
return visitor((std::string)*this);
2026-03-31 15:32:36 +02:00
case ifcopenshell::Argument_BINARY:
2025-03-14 10:20:22 +01:00
return visitor((boost::dynamic_bitset<>)*this);
2026-03-31 15:32:36 +02:00
case ifcopenshell::Argument_ENUMERATION:
return visitor((enumeration_reference)*this);
case ifcopenshell::Argument_ENTITY_INSTANCE:
return visitor((express::Base) * this);
2026-03-31 15:32:36 +02:00
case ifcopenshell::Argument_AGGREGATE_OF_INT:
2025-03-14 10:20:22 +01:00
return visitor((std::vector<int>)*this);
2026-03-31 15:32:36 +02:00
case ifcopenshell::Argument_AGGREGATE_OF_DOUBLE:
2025-03-14 10:20:22 +01:00
return visitor((std::vector<double>)*this);
2026-03-31 15:32:36 +02:00
case ifcopenshell::Argument_AGGREGATE_OF_STRING:
2025-03-14 10:20:22 +01:00
return visitor((std::vector<std::string>)*this);
2026-03-31 15:32:36 +02:00
case ifcopenshell::Argument_AGGREGATE_OF_BINARY:
2025-03-14 10:20:22 +01:00
return visitor((std::vector<boost::dynamic_bitset<>>)*this);
2026-03-31 15:32:36 +02:00
case ifcopenshell::Argument_AGGREGATE_OF_ENTITY_INSTANCE:
return visitor((std::vector<express::Base>)*this);
2026-03-31 15:32:36 +02:00
case ifcopenshell::Argument_AGGREGATE_OF_AGGREGATE_OF_INT:
2025-03-14 10:20:22 +01:00
return visitor((std::vector<std::vector<int>>)*this);
2026-03-31 15:32:36 +02:00
case ifcopenshell::Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE:
2025-03-14 10:20:22 +01:00
return visitor((std::vector<std::vector<double>>)*this);
2026-03-31 15:32:36 +02:00
case ifcopenshell::Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE:
return visitor((std::vector<std::vector<express::Base>>)*this);
2026-03-31 15:32:36 +02:00
case ifcopenshell::Argument_EMPTY_AGGREGATE:
2025-03-14 10:20:22 +01:00
return visitor(empty_aggregate_t{});
2026-03-31 15:32:36 +02:00
case ifcopenshell::Argument_AGGREGATE_OF_EMPTY_AGGREGATE:
2025-03-14 10:20:22 +01:00
return visitor(empty_aggregate_of_aggregate_t{});
default:
2026-03-31 15:32:36 +02:00
return visitor(blank{});
2025-03-14 10:20:22 +01:00
}
}
2024-08-23 20:29:07 +02:00
};
2017-06-05 17:26:58 +02:00
2025-09-26 14:24:49 +02:00
struct IFC_PARSE_API rocks_db_attribute_storage {
public:
#ifdef IFOPSH_WITH_ROCKSDB
2025-02-27 22:07:31 +01:00
// @todo void* is obviously very ugly here
template<typename T>
2026-03-31 18:23:13 +02:00
IFC_PARSE_API void set(void* storage, const ifcopenshell::declaration* declaration, std::size_t identity, std::size_t index, const T& value);
template<typename T>
2026-03-31 15:32:36 +02:00
IFC_PARSE_API bool has(void* storage, const ifcopenshell::declaration* decl, std::size_t identity, std::size_t index) const;
#endif
};
2026-03-31 15:32:36 +02:00
class IFC_PARSE_API instance_data {
protected:
static std::atomic_uint32_t counter_;
2026-03-31 15:32:36 +02:00
ifcopenshell::file* file_;
// @todo this could also be a 2-byte index, because we can get the schema from the file. But it wouldn't save space due to alignment
2026-03-31 15:32:36 +02:00
const ifcopenshell::declaration* declaration_;
uint32_t identity_;
uint32_t id_;
template <typename T>
T* get_storage_of_type() const;
void populate_derived_();
2023-09-17 12:30:17 +02:00
public:
2025-03-18 10:41:03 +01:00
// Since rocks_db_attribute_storage has no members this is not a variant<in_memory, rocks> but in_memory*, where nullptr means a rocks_db_attribute_storage is constructed on the fly given the context from instance data.
in_memory_attribute_storage* storage_;
2023-09-17 12:30:17 +02:00
2026-03-31 15:32:36 +02:00
const ifcopenshell::declaration* declaration() const {
return declaration_;
}
2026-03-31 15:32:36 +02:00
ifcopenshell::file* file() const {
return file_;
}
uint32_t identity() const {
return identity_;
}
uint32_t id() const {
return id_;
}
2026-03-31 15:32:36 +02:00
instance_data(ifcopenshell::file* file, const ifcopenshell::declaration* declaration, uint32_t id, in_memory_attribute_storage&& storage)
: file_(file), declaration_(declaration), identity_(counter_++), id_(id), storage_(new in_memory_attribute_storage(std::move(storage)))
{
populate_derived_();
}
2026-03-31 18:23:13 +02:00
instance_data(ifcopenshell::file* file, const ifcopenshell::declaration* declaration, uint32_t id, rocks_db_attribute_storage&& storage)
: file_(file), declaration_(declaration), identity_(counter_++), id_(id), storage_(nullptr)
{
2026-03-31 18:23:13 +02:00
static_cast<void>(storage);
populate_derived_();
}
2017-06-05 17:26:58 +02:00
/*
// now that there are referenced as shared_ptr there is no move constructor anymore
2026-03-31 15:32:36 +02:00
instance_data(instance_data&& other) noexcept
: file_(other.file_), id_(other.id_), declaration_(other.declaration_), storage_(std::exchange(other.storage_, nullptr))
2024-08-23 20:29:07 +02:00
{}
*/
2017-06-05 17:26:58 +02:00
// No copy-constructor/-assignment anymore because we need the instance for storage model context
2026-03-31 18:23:13 +02:00
instance_data(const instance_data& other) = delete;
instance_data& operator=(const instance_data& other) = delete;
instance_data& operator=(instance_data&& other) = delete;
2026-03-31 15:32:36 +02:00
instance_data(instance_data&& other) noexcept = delete;
/*
// same
2026-03-31 15:32:36 +02:00
instance_data& operator=(instance_data&& other) noexcept {
2024-08-23 20:29:07 +02:00
if (this != &other) {
delete storage_;
storage_ = std::exchange(other.storage_, nullptr);
2024-08-23 20:29:07 +02:00
}
return *this;
}
*/
2024-08-23 20:29:07 +02:00
2026-03-31 15:32:36 +02:00
~instance_data() {
delete storage_;
}
2026-03-31 18:23:13 +02:00
attribute_value get_attribute_value(size_t attribute_index) const;
2017-06-05 17:26:58 +02:00
template<typename T>
2026-03-31 18:23:13 +02:00
void set_attribute_value(std::size_t attribute_index, T&& value) {
2025-03-18 10:41:03 +01:00
if (storage_) {
2026-03-31 18:23:13 +02:00
storage_->set(attribute_index, value);
}
#ifdef IFOPSH_WITH_ROCKSDB
else {
2026-04-22 12:04:24 +02:00
rocks_db_attribute_storage{}.set(get_storage_of_type<ifcopenshell::impl::rocks_db_file_storage>(), declaration_, declaration_->as_entity() ? id_ : identity_, attribute_index, value);
2025-03-18 10:41:03 +01:00
}
#endif
}
2017-06-05 17:26:58 +02:00
template<typename T>
2026-03-31 18:23:13 +02:00
bool has_attribute_value(std::size_t attribute_index) const {
2025-03-18 10:41:03 +01:00
if (storage_) {
2026-03-31 18:23:13 +02:00
return storage_->has<T>(attribute_index);
}
#ifdef IFOPSH_WITH_ROCKSDB
else {
2026-04-22 12:04:24 +02:00
return rocks_db_attribute_storage{}.has<T>(get_storage_of_type<ifcopenshell::impl::rocks_db_file_storage>(), declaration_, declaration_->as_entity() ? id_ : identity_, attribute_index);
2025-03-18 10:41:03 +01:00
}
#endif
}
2026-03-31 18:23:13 +02:00
void to_string(std::ostream& stream, bool uppercase = false) const;
2017-06-05 17:26:58 +02:00
};
#endif