ifcparse: map argument_type to its stored type, size() as size_t

Review: argument_type enumerates the members of type_variant_parameter_pack
in order, so express that once as argument_storage_type_t<A> (pinned by
static_asserts) and let attribute_value::size() on RocksDB go through a
single aggregate_size_<A>() helper instead of spelling each vector type
out in the switch. size() now returns size_t; its only caller already
took size_t.

Also build the RocksDB DeleteRange upper bounds as prefix + ('|' + 1)
rather than a literal '}', which read as the {id} placeholder notation.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HNrXDmR88wKPCYwGE21SyH
This commit is contained in:
Dion Moult
2026-09-16 21:13:51 +10:00
parent 4b642c5e00
commit 2a2cb63b89
4 changed files with 45 additions and 22 deletions
+17 -11
View File
@@ -135,6 +135,12 @@ namespace {
#endif #endif
throw std::logic_error("RocksDB storage is unavailable"); throw std::logic_error("RocksDB storage is unavailable");
} }
template<argument_type A>
inline size_t aggregate_size_(attribute_value::pointer_type array_, uint8_t storage_model_, size_t instance_name_, const ifcopenshell::declaration* entity_or_type, uint8_t index_)
{
return dispatch_get_<argument_storage_type_t<A>>(array_, storage_model_, instance_name_, entity_or_type, index_).size();
}
} }
attribute_value::operator int64_t() const attribute_value::operator int64_t() const
@@ -289,10 +295,10 @@ bool attribute_value::isNull() const
return dispatch_has_<blank>(array_, storage_model_, instance_name_, entity_or_type_, index_); return dispatch_has_<blank>(array_, storage_model_, instance_name_, entity_or_type_, index_);
} }
unsigned int attribute_value::size() const size_t attribute_value::size() const
{ {
if (storage_model_ == 0) { if (storage_model_ == 0) {
return array_.storage_ptr->apply_visitor(size_visitor{}, index_); return (size_t)array_.storage_ptr->apply_visitor(size_visitor{}, index_);
} }
#ifdef IFOPSH_WITH_ROCKSDB #ifdef IFOPSH_WITH_ROCKSDB
else { else {
@@ -302,23 +308,23 @@ unsigned int attribute_value::size() const
case Argument_AGGREGATE_OF_EMPTY_AGGREGATE: case Argument_AGGREGATE_OF_EMPTY_AGGREGATE:
return 0; return 0;
case Argument_AGGREGATE_OF_INT: case Argument_AGGREGATE_OF_INT:
return (unsigned int)dispatch_get_<std::vector<int64_t>>(array_, storage_model_, instance_name_, entity_or_type_, index_).size(); return aggregate_size_<Argument_AGGREGATE_OF_INT>(array_, storage_model_, instance_name_, entity_or_type_, index_);
case Argument_AGGREGATE_OF_DOUBLE: case Argument_AGGREGATE_OF_DOUBLE:
return (unsigned int)dispatch_get_<std::vector<double>>(array_, storage_model_, instance_name_, entity_or_type_, index_).size(); return aggregate_size_<Argument_AGGREGATE_OF_DOUBLE>(array_, storage_model_, instance_name_, entity_or_type_, index_);
case Argument_AGGREGATE_OF_STRING: case Argument_AGGREGATE_OF_STRING:
return (unsigned int)dispatch_get_<std::vector<std::string>>(array_, storage_model_, instance_name_, entity_or_type_, index_).size(); return aggregate_size_<Argument_AGGREGATE_OF_STRING>(array_, storage_model_, instance_name_, entity_or_type_, index_);
case Argument_AGGREGATE_OF_BINARY: case Argument_AGGREGATE_OF_BINARY:
return (unsigned int)dispatch_get_<std::vector<boost::dynamic_bitset<>>>(array_, storage_model_, instance_name_, entity_or_type_, index_).size(); return aggregate_size_<Argument_AGGREGATE_OF_BINARY>(array_, storage_model_, instance_name_, entity_or_type_, index_);
case Argument_AGGREGATE_OF_ENTITY_INSTANCE: case Argument_AGGREGATE_OF_ENTITY_INSTANCE:
return (unsigned int)((std::vector<express::base>)*this).size(); return aggregate_size_<Argument_AGGREGATE_OF_ENTITY_INSTANCE>(array_, storage_model_, instance_name_, entity_or_type_, index_);
case Argument_AGGREGATE_OF_AGGREGATE_OF_INT: case Argument_AGGREGATE_OF_AGGREGATE_OF_INT:
return (unsigned int)dispatch_get_<std::vector<std::vector<int64_t>>>(array_, storage_model_, instance_name_, entity_or_type_, index_).size(); return aggregate_size_<Argument_AGGREGATE_OF_AGGREGATE_OF_INT>(array_, storage_model_, instance_name_, entity_or_type_, index_);
case Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE: case Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE:
return (unsigned int)dispatch_get_<std::vector<std::vector<double>>>(array_, storage_model_, instance_name_, entity_or_type_, index_).size(); return aggregate_size_<Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE>(array_, storage_model_, instance_name_, entity_or_type_, index_);
case Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE: case Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE:
return (unsigned int)((std::vector<std::vector<express::base>>)*this).size(); return aggregate_size_<Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE>(array_, storage_model_, instance_name_, entity_or_type_, index_);
default: default:
return (unsigned int)-1; return (size_t)-1;
} }
} }
#endif #endif
+4 -5
View File
@@ -215,12 +215,11 @@ void ifcopenshell::impl::rocks_db_file_storage::process_deletion_inverse(const e
auto id = inst.id(); auto id = inst.id();
{ {
// Delete every record referencing inst: all keys under v|{id}|. The // Delete every record referencing inst: all keys under v|<id>|. The
// prefix with its last byte incremented is the exclusive upper bound // exclusive upper bound is the same prefix with its separator
// ('}' follows '|'), so no iterator is needed to find the range end. // incremented, so no iterator is needed to find the range end.
auto prefix = "v|" + std::to_string(id) + "|"; auto prefix = "v|" + std::to_string(id) + "|";
auto upper_bound = prefix; auto upper_bound = "v|" + std::to_string(id) + std::string(1, '|' + 1);
upper_bound.back() = '}';
rocksdb::WriteBatch batch; rocksdb::WriteBatch batch;
batch.DeleteRange(prefix, upper_bound); batch.DeleteRange(prefix, upper_bound);
+20 -1
View File
@@ -32,6 +32,7 @@
#undef Handle #undef Handle
#include <rocksdb/db.h> #include <rocksdb/db.h>
#include <tuple>
#pragma pop_macro("Handle") #pragma pop_macro("Handle")
@@ -226,6 +227,24 @@ struct pack_to_variant_array<parameter_pack<Args...>> {
using in_memory_attribute_storage = pack_to_variant_array<type_variant_parameter_pack>::type; using in_memory_attribute_storage = pack_to_variant_array<type_variant_parameter_pack>::type;
// argument_type enumerates the members of type_variant_parameter_pack in
// order, so a member maps back to the type stored for it.
template <typename Pack>
struct pack_element;
template <typename... Args>
struct pack_element<parameter_pack<Args...>> {
template <size_t I>
using type = std::tuple_element_t<I, std::tuple<Args...>>;
};
template <argument_type A>
using argument_storage_type_t = typename pack_element<type_variant_parameter_pack>::template type<A>;
static_assert(std::is_same_v<argument_storage_type_t<Argument_INT>, int64_t>, "argument_type must enumerate type_variant_parameter_pack in order");
static_assert(std::is_same_v<argument_storage_type_t<Argument_AGGREGATE_OF_INT>, std::vector<int64_t>>, "argument_type must enumerate type_variant_parameter_pack in order");
static_assert(std::is_same_v<argument_storage_type_t<Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE>, std::vector<std::vector<express::base>>>, "argument_type must enumerate type_variant_parameter_pack in order");
template <typename Pack> template <typename Pack>
struct type_encoder_impl; struct type_encoder_impl;
@@ -427,7 +446,7 @@ public:
operator enumeration_reference() const; operator enumeration_reference() const;
bool isNull() const; bool isNull() const;
unsigned int size() const; size_t size() const;
ifcopenshell::argument_type type() const; ifcopenshell::argument_type type() const;
+4 -5
View File
@@ -197,17 +197,16 @@ public:
return iterator(); return iterator();
} }
// Removes the element: every key under prefix + key + "|". The prefix // Removes the element: every key under prefix + key + "|". The exclusive
// with its last byte incremented is the exclusive upper bound ('}' // upper bound is the same prefix with its separator incremented. Returns
// follows '|'). Returns 1 if the element existed, 0 otherwise. // 1 if the element existed, 0 otherwise.
size_t erase(const key_type& key) { size_t erase(const key_type& key) {
#ifdef IFOPSH_WITH_ROCKSDB #ifdef IFOPSH_WITH_ROCKSDB
if (find(key) == end()) { if (find(key) == end()) {
return 0; return 0;
} }
const std::string lower_bound = prefix_ + key_to_string(key) + "|"; const std::string lower_bound = prefix_ + key_to_string(key) + "|";
std::string upper_bound = lower_bound; const std::string upper_bound = prefix_ + key_to_string(key) + std::string(1, '|' + 1);
upper_bound.back() = '}';
rocksdb::WriteBatch batch; rocksdb::WriteBatch batch;
batch.DeleteRange(lower_bound, upper_bound); batch.DeleteRange(lower_bound, upper_bound);
db_->Write(rocksdb::WriteOptions{}, &batch); db_->Write(rocksdb::WriteOptions{}, &batch);