Fix streamer header ownership

Create file-owned headers after storage is selected but before streaming starts. Let owner-backed streamers use that header directly, and keep owned_header_ exclusively for ownerless streamers.

Generated with the assistance of an AI coding tool.
This commit is contained in:
Thomas Krijnen
2026-07-28 04:19:20 +02:00
parent 02bc09029e
commit ba8dc53718
2 changed files with 31 additions and 30 deletions
+1 -2
View File
@@ -97,7 +97,6 @@ private:
Reader* stream_; Reader* stream_;
std::unique_ptr<spf_lexer<Reader>> lexer_; std::unique_ptr<spf_lexer<Reader>> lexer_;
std::unique_ptr<spf_header> owned_header_; std::unique_ptr<spf_header> owned_header_;
spf_header* header_;
ifcopenshell::file* owner_; ifcopenshell::file* owner_;
boost::circular_buffer<token> token_stream_; boost::circular_buffer<token> token_stream_;
const ifcopenshell::schema_definition* schema_; const ifcopenshell::schema_definition* schema_;
@@ -171,7 +170,7 @@ private:
const ifcopenshell::schema_definition* schema() const { return schema_; } const ifcopenshell::schema_definition* schema() const { return schema_; }
const spf_header* header() const { return header_; } const spf_header* header() const;
~instance_streamer() = default; ~instance_streamer() = default;
+30 -28
View File
@@ -1666,10 +1666,12 @@ bool ifcopenshell::file::initialize(const std::string& fn, bool mmap) {
if (mmap) { if (mmap) {
file_reader<mmap_impl> s(fn); file_reader<mmap_impl> s(fn);
storage_.emplace<1>(this, logger_.get()); storage_.emplace<1>(this, logger_.get());
header_.reset(new spf_header(this, &logger_.get()));
std::get<impl::in_memory_file_storage>(storage_).read_from_stream(&s, schema_, max_id_, types_to_bypass_loading_); std::get<impl::in_memory_file_storage>(storage_).read_from_stream(&s, schema_, max_id_, types_to_bypass_loading_);
} else { } else {
file_reader<full_buffer_impl> s(fn); file_reader<full_buffer_impl> s(fn);
storage_.emplace<1>(this, logger_.get()); storage_.emplace<1>(this, logger_.get());
header_.reset(new spf_header(this, &logger_.get()));
std::get<impl::in_memory_file_storage>(storage_).read_from_stream(&s, schema_, max_id_, types_to_bypass_loading_); std::get<impl::in_memory_file_storage>(storage_).read_from_stream(&s, schema_, max_id_, types_to_bypass_loading_);
} }
@@ -1681,7 +1683,6 @@ bool ifcopenshell::file::initialize(const std::string& fn, bool mmap) {
} }
ifcroot_type_ = schema_ ? schema_->declaration_by_name("IfcRoot") : nullptr; ifcroot_type_ = schema_ ? schema_->declaration_by_name("IfcRoot") : nullptr;
header_.reset(new spf_header(this, &logger_.get()));
return good_ == file_open_status::SUCCESS; return good_ == file_open_status::SUCCESS;
} }
#endif #endif
@@ -1696,6 +1697,7 @@ bool ifcopenshell::file::initialize(const std::string& path, filetype ty, bool r
if (ty == FT_IFCSPF) { if (ty == FT_IFCSPF) {
file_reader<full_buffer_impl> s(path); file_reader<full_buffer_impl> s(path);
storage_.emplace<1>(this, logger_.get()); storage_.emplace<1>(this, logger_.get());
header_.reset(new spf_header(this, &logger_.get()));
std::get<impl::in_memory_file_storage>(storage_).read_from_stream(&s, schema_, max_id_, types_to_bypass_loading_); std::get<impl::in_memory_file_storage>(storage_).read_from_stream(&s, schema_, max_id_, types_to_bypass_loading_);
if ((good_ = std::get<impl::in_memory_file_storage>(storage_).good_)) { if ((good_ = std::get<impl::in_memory_file_storage>(storage_).good_)) {
@@ -1732,7 +1734,9 @@ bool ifcopenshell::file::initialize(const std::string& path, filetype ty, bool r
// throw std::runtime_error("Unsupported file format"); // throw std::runtime_error("Unsupported file format");
} }
ifcroot_type_ = schema_ ? schema_->declaration_by_name("IfcRoot") : nullptr; ifcroot_type_ = schema_ ? schema_->declaration_by_name("IfcRoot") : nullptr;
header_.reset(new spf_header(this, &logger_.get())); if (!header_) {
header_.reset(new spf_header(this, &logger_.get()));
}
return good_ == file_open_status::SUCCESS; return good_ == file_open_status::SUCCESS;
} }
@@ -1763,6 +1767,7 @@ file::file(std::istream& stream, int length, ::logger& log)
s.push_next_page(string_data); s.push_next_page(string_data);
storage_.emplace<1>(this, logger_.get()); storage_.emplace<1>(this, logger_.get());
header_.reset(new spf_header(this, &logger_.get()));
std::get<impl::in_memory_file_storage>(storage_).read_from_stream(&s, schema_, max_id_, types_to_bypass_loading_); std::get<impl::in_memory_file_storage>(storage_).read_from_stream(&s, schema_, max_id_, types_to_bypass_loading_);
good_ = std::get<impl::in_memory_file_storage>(storage_).good_; good_ = std::get<impl::in_memory_file_storage>(storage_).good_;
ifcroot_type_ = schema_ ? schema_->declaration_by_name("IfcRoot") : nullptr; ifcroot_type_ = schema_ ? schema_->declaration_by_name("IfcRoot") : nullptr;
@@ -1771,7 +1776,6 @@ file::file(std::istream& stream, int length, ::logger& log)
byref_excl_ = decltype(byref_excl_)(&std::get<impl::in_memory_file_storage>(storage_).byref_excl_); byref_excl_ = decltype(byref_excl_)(&std::get<impl::in_memory_file_storage>(storage_).byref_excl_);
byguid_ = decltype(byguid_)(&std::get<impl::in_memory_file_storage>(storage_).byguid_); byguid_ = decltype(byguid_)(&std::get<impl::in_memory_file_storage>(storage_).byguid_);
header_.reset(new spf_header(this, &logger_.get()));
} }
file::file(void* data, int length, ::logger& log) file::file(void* data, int length, ::logger& log)
@@ -1783,6 +1787,7 @@ file::file(void* data, int length, ::logger& log)
file_reader<pushed_sequential_impl> s(std::string((char*)data, length), caller_fed_tag{}); file_reader<pushed_sequential_impl> s(std::string((char*)data, length), caller_fed_tag{});
storage_.emplace<1>(this, logger_.get()); storage_.emplace<1>(this, logger_.get());
header_.reset(new spf_header(this, &logger_.get()));
std::get<impl::in_memory_file_storage>(storage_).read_from_stream(&s, schema_, max_id_, types_to_bypass_loading_); std::get<impl::in_memory_file_storage>(storage_).read_from_stream(&s, schema_, max_id_, types_to_bypass_loading_);
good_ = std::get<impl::in_memory_file_storage>(storage_).good_; good_ = std::get<impl::in_memory_file_storage>(storage_).good_;
ifcroot_type_ = schema_ ? schema_->declaration_by_name("IfcRoot") : nullptr; ifcroot_type_ = schema_ ? schema_->declaration_by_name("IfcRoot") : nullptr;
@@ -1791,7 +1796,6 @@ file::file(void* data, int length, ::logger& log)
byref_excl_ = decltype(byref_excl_)(&std::get<impl::in_memory_file_storage>(storage_).byref_excl_); byref_excl_ = decltype(byref_excl_)(&std::get<impl::in_memory_file_storage>(storage_).byref_excl_);
byguid_ = decltype(byguid_)(&std::get<impl::in_memory_file_storage>(storage_).byguid_); byguid_ = decltype(byguid_)(&std::get<impl::in_memory_file_storage>(storage_).byguid_);
header_.reset(new spf_header(this, &logger_.get()));
} }
file::file(const ifcopenshell::schema_definition* schema, filetype ty, const std::string& path, ::logger& log) file::file(const ifcopenshell::schema_definition* schema, filetype ty, const std::string& path, ::logger& log)
@@ -1901,21 +1905,22 @@ bool try_parse_header(
} // namespace } // namespace
template <typename Reader>
const spf_header* ifcopenshell::instance_streamer<Reader>::header() const {
return owner_ ? &owner_->header() : owned_header_.get();
}
template <typename Reader> template <typename Reader>
spf_header& ifcopenshell::instance_streamer<Reader>::ensure_header() { spf_header& ifcopenshell::instance_streamer<Reader>::ensure_header() {
if (header_) {
return *header_;
}
if (owner_ != nullptr) { if (owner_ != nullptr) {
header_ = &owner_->header(); return owner_->header();
header_->owner_file(owner_);
} else {
owned_header_ = std::make_unique<spf_header>(owner_, &logger_.get());
header_ = owned_header_.get();
} }
return *header_; if (!owned_header_) {
owned_header_ = std::make_unique<spf_header>(owner_, &logger_.get());
}
return *owned_header_;
} }
template <typename Reader> template <typename Reader>
@@ -2012,7 +2017,6 @@ void ifcopenshell::instance_streamer<Reader>::push_page(const std::string& page)
template <typename Reader> template <typename Reader>
ifcopenshell::instance_streamer<Reader>::instance_streamer(ifcopenshell::file* f, ::logger& log) ifcopenshell::instance_streamer<Reader>::instance_streamer(ifcopenshell::file* f, ::logger& log)
: stream_(nullptr) : stream_(nullptr)
, header_(nullptr)
, owner_(f) , owner_(f)
, token_stream_(3, token{}) , token_stream_(3, token{})
, schema_(nullptr) , schema_(nullptr)
@@ -2038,7 +2042,6 @@ ifcopenshell::instance_streamer<Reader>::instance_streamer(ifcopenshell::file* f
template <typename Reader> template <typename Reader>
ifcopenshell::instance_streamer<Reader>::instance_streamer(const std::string& fn, bool mmap, ifcopenshell::file* f, ::logger& log) ifcopenshell::instance_streamer<Reader>::instance_streamer(const std::string& fn, bool mmap, ifcopenshell::file* f, ::logger& log)
: stream_(nullptr) : stream_(nullptr)
, header_(nullptr)
, owner_(f) , owner_(f)
, token_stream_(3, token{}) , token_stream_(3, token{})
, schema_(nullptr) , schema_(nullptr)
@@ -2067,7 +2070,6 @@ ifcopenshell::instance_streamer<Reader>::instance_streamer(const std::string& fn
template <typename Reader> template <typename Reader>
ifcopenshell::instance_streamer<Reader>::instance_streamer(void* data, int length, ifcopenshell::file* f, ::logger& log) ifcopenshell::instance_streamer<Reader>::instance_streamer(void* data, int length, ifcopenshell::file* f, ::logger& log)
: stream_(nullptr) : stream_(nullptr)
, header_(nullptr)
, owner_(f) , owner_(f)
, token_stream_(3, token{}) , token_stream_(3, token{})
, schema_(nullptr) , schema_(nullptr)
@@ -2092,7 +2094,6 @@ ifcopenshell::instance_streamer<Reader>::instance_streamer(void* data, int lengt
template <typename Reader> template <typename Reader>
ifcopenshell::instance_streamer<Reader>::instance_streamer(Reader* stream, ifcopenshell::file* f, ::logger& log) ifcopenshell::instance_streamer<Reader>::instance_streamer(Reader* stream, ifcopenshell::file* f, ::logger& log)
: stream_(stream) : stream_(stream)
, header_(nullptr)
, owner_(f) , owner_(f)
, token_stream_(3, token{}) , token_stream_(3, token{})
, schema_(nullptr) , schema_(nullptr)
@@ -2120,33 +2121,34 @@ template <typename Reader>
std::optional<std::tuple<size_t, const ifcopenshell::declaration*, shared_pointer_type>> ifcopenshell::instance_streamer<Reader>::read_instance() { std::optional<std::tuple<size_t, const ifcopenshell::declaration*, shared_pointer_type>> ifcopenshell::instance_streamer<Reader>::read_instance() {
std::optional<std::tuple<size_t, const ifcopenshell::declaration*, shared_pointer_type>> return_value; std::optional<std::tuple<size_t, const ifcopenshell::declaration*, shared_pointer_type>> return_value;
if (yield_header_instances_ && header_ && yielded_header_instances_ < 3) { const auto* header = this->header();
if (yield_header_instances_ && header && yielded_header_instances_ < 3) {
if (yielded_header_instances_ == 0) { if (yielded_header_instances_ == 0) {
return_value.emplace( return_value.emplace(
0, 0,
&header_->file_description().declaration(), &header->file_description().declaration(),
#ifdef IFOPSH_SAFE_INSTANCE #ifdef IFOPSH_SAFE_INSTANCE
header_->file_description().data_weak().lock()); header->file_description().data_weak().lock());
#else #else
header_->file_description().data_weak()); header->file_description().data_weak());
#endif #endif
} else if (yielded_header_instances_ == 1) { } else if (yielded_header_instances_ == 1) {
return_value.emplace( return_value.emplace(
0, 0,
&header_->file_name().declaration(), &header->file_name().declaration(),
#ifdef IFOPSH_SAFE_INSTANCE #ifdef IFOPSH_SAFE_INSTANCE
header_->file_name().data_weak().lock()); header->file_name().data_weak().lock());
#else #else
header_->file_name().data_weak()); header->file_name().data_weak());
#endif #endif
} else if (yielded_header_instances_ == 2) { } else if (yielded_header_instances_ == 2) {
return_value.emplace( return_value.emplace(
0, 0,
&header_->file_schema().declaration(), &header->file_schema().declaration(),
#ifdef IFOPSH_SAFE_INSTANCE #ifdef IFOPSH_SAFE_INSTANCE
header_->file_schema().data_weak().lock()); header->file_schema().data_weak().lock());
#else #else
header_->file_schema().data_weak()); header->file_schema().data_weak());
#endif #endif
} }
yielded_header_instances_ += 1; yielded_header_instances_ += 1;