mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-08-11 02:02:22 +00:00
Merge remote-tracking branch 'origin/v0.8.0' into ifcviewer-wgpu
This commit is contained in:
@@ -45,10 +45,10 @@ IFC_SCHEMA_API Ifc4x3_add2::IfcAlignment addAlignment(hierarchy_helper<Ifc4x3_ad
|
||||
// Maps horizontal alignment business logic to geometry.
|
||||
// Bloss curves have two geometry elements for one horizontal alignment segment. That is the reason for returning a pair.
|
||||
// Typically the first element of the pair will have the geometry and the second element will be nullptr
|
||||
IFC_SCHEMA_API std::pair<Ifc4x3_add2::IfcCurveSegment, Ifc4x3_add2::IfcCurveSegment> mapAlignmentSegment(hierarchy_helper<Ifc4x3_add2>& model, const Ifc4x3_add2::IfcAlignmentSegment& segment);
|
||||
IFC_SCHEMA_API std::pair<Ifc4x3_add2::IfcCurveSegment, Ifc4x3_add2::IfcCurveSegment> mapAlignmentHorizontalSegment(hierarchy_helper<Ifc4x3_add2>& model, const Ifc4x3_add2::IfcAlignmentHorizontalSegment& segment);
|
||||
IFC_SCHEMA_API std::pair<Ifc4x3_add2::IfcCurveSegment, Ifc4x3_add2::IfcCurveSegment> mapAlignmentVerticalSegment(hierarchy_helper<Ifc4x3_add2>& model, const Ifc4x3_add2::IfcAlignmentVerticalSegment& segment);
|
||||
IFC_SCHEMA_API std::pair<Ifc4x3_add2::IfcCurveSegment, Ifc4x3_add2::IfcCurveSegment> mapAlignmentCantSegment(hierarchy_helper<Ifc4x3_add2>& model, const Ifc4x3_add2::IfcAlignmentCantSegment& segment);
|
||||
IFC_SCHEMA_API std::pair<Ifc4x3_add2::IfcCurveSegment, Ifc4x3_add2::IfcCurveSegment> mapAlignmentSegment(hierarchy_helper<Ifc4x3_add2>& model, const Ifc4x3_add2::IfcAlignmentSegment& segment, Logger& logger = Logger::Root());
|
||||
IFC_SCHEMA_API std::pair<Ifc4x3_add2::IfcCurveSegment, Ifc4x3_add2::IfcCurveSegment> mapAlignmentHorizontalSegment(hierarchy_helper<Ifc4x3_add2>& model, const Ifc4x3_add2::IfcAlignmentHorizontalSegment& segment, Logger& logger = Logger::Root());
|
||||
IFC_SCHEMA_API std::pair<Ifc4x3_add2::IfcCurveSegment, Ifc4x3_add2::IfcCurveSegment> mapAlignmentVerticalSegment(hierarchy_helper<Ifc4x3_add2>& model, const Ifc4x3_add2::IfcAlignmentVerticalSegment& segment, Logger& logger = Logger::Root());
|
||||
IFC_SCHEMA_API std::pair<Ifc4x3_add2::IfcCurveSegment, Ifc4x3_add2::IfcCurveSegment> mapAlignmentCantSegment(hierarchy_helper<Ifc4x3_add2>& model, const Ifc4x3_add2::IfcAlignmentCantSegment& segment, Logger& logger = Logger::Root());
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -31,6 +31,10 @@
|
||||
|
||||
#if defined(IFCOPENSHELL_BRANCH) && defined(IFCOPENSHELL_COMMIT)
|
||||
IFC_PARSE_API const char *IFCOPENSHELL_VERSION = STRINGIFY(IFCOPENSHELL_BRANCH) "-" STRINGIFY(IFCOPENSHELL_COMMIT);
|
||||
#elif defined(IFCOPENSHELL_VERSION_STRING)
|
||||
// Set from CMake's RELEASE_VERSION (the repository VERSION file) so a release
|
||||
// build without commit-sha info still reports the correct version. See #8164.
|
||||
IFC_PARSE_API const char *IFCOPENSHELL_VERSION = STRINGIFY(IFCOPENSHELL_VERSION_STRING);
|
||||
#else
|
||||
IFC_PARSE_API const char *IFCOPENSHELL_VERSION = "0.8.0";
|
||||
#endif
|
||||
|
||||
@@ -224,7 +224,7 @@ namespace {
|
||||
parse_state += PAGE;
|
||||
} else if (IS_HEXADECIMAL(current_char) && EXPECTS_HEX(parse_state)) {
|
||||
if (IS_LOWERCASE_HEX(current_char)) {
|
||||
logger::warning("Lowercase hexadecimal character '" + std::string(1, current_char) +
|
||||
logger.Warning("SYN", 2, "Lowercase hexadecimal character '" + std::string(1, current_char) +
|
||||
"' found at offset " + std::to_string(stream_.tell()) +
|
||||
". It is recommended to use uppercase for hexadecimal.");
|
||||
}
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#define IFCCHARACTERDECODER_H
|
||||
|
||||
#include "file_reader.h"
|
||||
#include "logger.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
@@ -43,6 +44,7 @@ template <typename Reader>
|
||||
class IFC_PARSE_API character_decoder {
|
||||
private:
|
||||
Reader* stream_;
|
||||
Logger& logger_;
|
||||
int codepage_;
|
||||
std::u32string builder_;
|
||||
|
||||
@@ -55,7 +57,7 @@ class IFC_PARSE_API character_decoder {
|
||||
inline static ConversionMode mode = UTF8;
|
||||
inline static char substitution_character = '_';
|
||||
|
||||
character_decoder(Reader* stream);
|
||||
character_decoder(Reader* stream, Logger& logger = Logger::Root());
|
||||
~character_decoder();
|
||||
// Gets a decoded string representation at the token stream
|
||||
// read pointer and advances the underlying token stream.
|
||||
|
||||
@@ -34,7 +34,22 @@ namespace {
|
||||
inline T dispatch_get_(attribute_value::pointer_type array_, uint8_t storage_model_, size_t instance_name_, const ifcopenshell::declaration* entity_or_type, uint8_t index_)
|
||||
{
|
||||
if (storage_model_ == 0) {
|
||||
return array_.storage_ptr->get<T>(index_);
|
||||
try {
|
||||
return array_.storage_ptr->get<T>(index_);
|
||||
} catch (const impl::storage_type_mismatch& e) {
|
||||
throw IfcParse::IfcException(
|
||||
// entity_or_type not passed, but in v0.9 this is beginning to make sense
|
||||
(entity_or_type
|
||||
? std::string("On instance #" + std::to_string(instance_name_) + " of " + entity_or_type->name() + ": ")
|
||||
: std::string("")) +
|
||||
"Requested type <" + e.requested() + "> does not match actual type <" + e.actual() + "> at index " + std::to_string(index_));
|
||||
} catch (const std::out_of_range& e) {
|
||||
throw IfcParse::IfcException(
|
||||
(entity_or_type
|
||||
? std::string("On instance #" + std::to_string(instance_name_) + " of " + entity_or_type->name() + ": ")
|
||||
: std::string("")) +
|
||||
e.what());
|
||||
}
|
||||
}
|
||||
#ifdef IFOPSH_WITH_ROCKSDB
|
||||
else {
|
||||
|
||||
+14
-10
@@ -27,6 +27,7 @@
|
||||
#include "storage.h"
|
||||
#include "file_open_status.h"
|
||||
|
||||
#include <functional>
|
||||
#include <boost/multi_index/ordered_index.hpp>
|
||||
#include <boost/multi_index/random_access_index.hpp>
|
||||
#include <boost/multi_index/sequenced_index.hpp>
|
||||
@@ -102,6 +103,7 @@ private:
|
||||
const ifcopenshell::schema_definition* schema_;
|
||||
ifcopenshell::impl::in_memory_file_storage storage_;
|
||||
ifcopenshell::file_open_status good_ = ifcopenshell::file_open_status::SUCCESS;
|
||||
std::reference_wrapper<Logger> logger_;
|
||||
int progress_;
|
||||
ifcopenshell::unresolved_references references_to_resolve_;
|
||||
int yielded_header_instances_ = 0;
|
||||
@@ -155,13 +157,13 @@ private:
|
||||
|
||||
void push_page(const std::string& page_data);
|
||||
|
||||
instance_streamer(ifcopenshell::file* owner_file = nullptr);
|
||||
instance_streamer(ifcopenshell::file* owner_file = nullptr, Logger& logger = Logger::Root());
|
||||
|
||||
instance_streamer(const std::string& path, bool use_mmap = false, ifcopenshell::file* owner_file = nullptr);
|
||||
instance_streamer(const std::string& path, bool use_mmap = false, ifcopenshell::file* owner_file = nullptr, Logger& logger = Logger::Root());
|
||||
|
||||
instance_streamer(void* data, int data_size, ifcopenshell::file* owner_file = nullptr);
|
||||
instance_streamer(void* data, int data_size, ifcopenshell::file* owner_file = nullptr, Logger& logger = Logger::Root());
|
||||
|
||||
instance_streamer(Reader* stream, ifcopenshell::file* owner_file = nullptr);
|
||||
instance_streamer(Reader* stream, ifcopenshell::file* owner_file = nullptr, Logger& logger = Logger::Root());
|
||||
|
||||
void bypass_types(const std::set<std::string>& type_names);
|
||||
|
||||
@@ -209,6 +211,7 @@ public:
|
||||
|
||||
private:
|
||||
file_open_status good_ = file_open_status::SUCCESS;
|
||||
std::reference_wrapper<Logger> logger_;
|
||||
|
||||
const ifcopenshell::schema_definition* schema_;
|
||||
const ifcopenshell::declaration* ifcroot_type_;
|
||||
@@ -239,7 +242,7 @@ public:
|
||||
/// </summary>
|
||||
/// <param name="path">UTF-8 file path to an IFC-SPF file</param>
|
||||
/// <param name="mmap">Whether to use memory-mapped I/O</param>
|
||||
file(const std::string& path, bool use_mmap);
|
||||
file(const std::string& path, bool use_mmap, Logger& logger = Logger::Root());
|
||||
#endif
|
||||
/// <summary>
|
||||
/// Constructs an file object from a file path, supports IFC-SPF and the IfcOpenShell-specific RocksDB format.
|
||||
@@ -247,17 +250,17 @@ public:
|
||||
/// <param name="path">UTF-8 file path to an IFC-SPF file or RocksDB database directory</param>
|
||||
/// <param name="ty">File type of the path</param>
|
||||
/// <param name="readonly">Whether to open in read-only mode, only supported on RocksDB databases</param>
|
||||
file(const std::string& path, filetype type = FT_AUTODETECT, bool read_only = false);
|
||||
file(const std::string& path, filetype type = FT_AUTODETECT, bool read_only = false, Logger& logger = Logger::Root());
|
||||
|
||||
/// <summary>
|
||||
/// Constructs an file object from a stream containing IFC-SPF data.
|
||||
/// </summary>
|
||||
file(std::istream& stream, int data_size);
|
||||
file(std::istream& stream, int data_size, Logger& logger = Logger::Root());
|
||||
|
||||
/// <summary>
|
||||
/// Constructs an file object from a memory buffer containing IFC-SPF data.
|
||||
/// </summary>
|
||||
file(void* data, int data_size);
|
||||
file(void* data, int data_size, Logger& logger = Logger::Root());
|
||||
|
||||
/// <summary>
|
||||
/// Constructs an file object with the specified schema, file type, and file path.
|
||||
@@ -266,12 +269,12 @@ public:
|
||||
/// <param name="schema">Pointer to the schema definition to use. Defaults to the IFC4 schema if not specified.</param>
|
||||
/// <param name="ty">The file type to use for the file. Defaults to FT_AUTODETECT.</param>
|
||||
/// <param name="path">The file system path to the IFC file. Defaults to an empty string.</param>
|
||||
file(const ifcopenshell::schema_definition* schema = ifcopenshell::schema_by_name("IFC4"), filetype type = FT_AUTODETECT, const std::string& path = "");
|
||||
file(const ifcopenshell::schema_definition* schema = ifcopenshell::schema_by_name("IFC4"), filetype type = FT_AUTODETECT, const std::string& path = "", Logger& logger = Logger::Root());
|
||||
|
||||
/// <summary>
|
||||
/// Constructs an unitialized file object. Call initialize() later on. Allows to specify which types to bypass during load.
|
||||
/// </summary>
|
||||
file(const uninitialized_tag& tag);
|
||||
file(const uninitialized_tag& tag, Logger& logger = Logger::Root());
|
||||
|
||||
bool initialize(const std::string& path, filetype type = FT_AUTODETECT, bool read_only = false);
|
||||
#ifdef USE_MMAP
|
||||
@@ -285,6 +288,7 @@ public:
|
||||
~file();
|
||||
|
||||
ifcopenshell::file_open_status good() const { return good_; }
|
||||
Logger& logger() const { return logger_.get(); }
|
||||
|
||||
/// Returns the first entity in the range of instances contained in the model,
|
||||
/// in arbitrary order
|
||||
|
||||
@@ -94,7 +94,7 @@ void expand(const std::string& s, std::vector<unsigned char>& v) {
|
||||
static boost::uuids::basic_random_generator<boost::mt19937> gen;
|
||||
#endif
|
||||
|
||||
ifcopenshell::global_id::global_id() {
|
||||
ifcopenshell::global_id::global_id(Logger& logger) {
|
||||
uuid_data_ = gen();
|
||||
std::vector<unsigned char> v(uuid_data_.size());
|
||||
std::copy(uuid_data_.begin(), uuid_data_.end(), v.begin());
|
||||
@@ -111,12 +111,12 @@ ifcopenshell::global_id::global_id() {
|
||||
boost::uuids::uuid test_uuid;
|
||||
std::copy(test_vector.begin(), test_vector.end(), test_uuid.begin());
|
||||
if (uuid_data_ != test_uuid) {
|
||||
logger::message(logger::LOG_ERROR, "Internal error generating GlobalId");
|
||||
logger.Message(Logger::LOG_ERROR, "SYS", 34, "Internal error generating GlobalId");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ifcopenshell::global_id::global_id(const std::string& string)
|
||||
ifcopenshell::global_id::global_id(const std::string& string, Logger& logger)
|
||||
: string_data_(string) {
|
||||
std::vector<unsigned char> result;
|
||||
expand(string_data_, result);
|
||||
@@ -130,7 +130,7 @@ ifcopenshell::global_id::global_id(const std::string& string)
|
||||
#ifndef NDEBUG
|
||||
const std::string test_string = compress(&uuid_data_.data[0]);
|
||||
if (string_data_ != test_string) {
|
||||
logger::message(logger::LOG_ERROR, "Internal error generating GlobalId");
|
||||
logger.Message(Logger::LOG_ERROR, "SYS", 35, "Internal error generating GlobalId");
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#define IFCGLOBALID_H
|
||||
|
||||
#include "ifc_parse_api.h"
|
||||
#include "IfcLogger.h"
|
||||
|
||||
#include <boost/uuid/uuid.hpp>
|
||||
#include <string>
|
||||
@@ -36,8 +37,8 @@ class IFC_PARSE_API global_id {
|
||||
|
||||
public:
|
||||
static const unsigned int length = 22;
|
||||
global_id();
|
||||
global_id(const std::string& value);
|
||||
global_id(Logger& logger = Logger::Root());
|
||||
global_id(const std::string& value, Logger& logger = Logger::Root());
|
||||
operator const std::string&() const;
|
||||
operator const boost::uuids::uuid&() const;
|
||||
const std::string& formatted() const;
|
||||
|
||||
@@ -73,6 +73,83 @@ class IFC_PARSE_API derived {};
|
||||
class IFC_PARSE_API empty_aggregate_t {};
|
||||
class IFC_PARSE_API empty_aggregate_of_aggregate_t {};
|
||||
|
||||
namespace impl {
|
||||
template <>
|
||||
struct VariantTypeName<Blank> {
|
||||
static std::string get() { return "null"; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct VariantTypeName<Derived> {
|
||||
static std::string get() { return "derived"; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct VariantTypeName<int> {
|
||||
static std::string get() { return "int"; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct VariantTypeName<bool> {
|
||||
static std::string get() { return "bool"; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct VariantTypeName<boost::logic::tribool> {
|
||||
static std::string get() { return "logical"; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct VariantTypeName<double> {
|
||||
static std::string get() { return "real"; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct VariantTypeName<std::string> {
|
||||
static std::string get() { return "string"; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct VariantTypeName<boost::dynamic_bitset<>> {
|
||||
static std::string get() { return "binary"; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct VariantTypeName<EnumerationReference> {
|
||||
static std::string get() { return "enumeration"; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct VariantTypeName<IfcUtil::IfcBaseClass*> {
|
||||
static std::string get() { return "instance"; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct VariantTypeName<empty_aggregate_t> {
|
||||
static std::string get() { return "aggregate"; }
|
||||
};
|
||||
|
||||
template <typename T, typename Allocator>
|
||||
struct VariantTypeName<std::vector<T, Allocator>> {
|
||||
static std::string get() { return "aggregate of " + VariantTypeName<T>::get(); }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct VariantTypeName<aggregate_of_instance::ptr> {
|
||||
static std::string get() { return "aggregate of instance"; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct VariantTypeName<empty_aggregate_of_aggregate_t> {
|
||||
static std::string get() { return "aggregate of aggregate"; }
|
||||
};
|
||||
|
||||
template <>
|
||||
struct VariantTypeName<aggregate_of_aggregate_of_instance::ptr> {
|
||||
static std::string get() { return "aggregate of aggregate of instance"; }
|
||||
};
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
struct parameter_pack {
|
||||
static constexpr size_t size = sizeof...(Args);
|
||||
|
||||
+117
-33
@@ -29,6 +29,7 @@
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/version.hpp>
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
#include <ctime>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
@@ -63,10 +64,17 @@ const std::array<std::basic_string<char>, 5> severity_strings<char>::value = {"P
|
||||
template <>
|
||||
const std::array<std::basic_string<wchar_t>, 5> severity_strings<wchar_t>::value = {L"Performance", L"Debug", L"notice", L"warning", L"error"};
|
||||
|
||||
std::string format_code(const char (&code_prefix)[4], uint16_t code_number) {
|
||||
std::ostringstream oss;
|
||||
oss << code_prefix[0] << code_prefix[1] << code_prefix[2] << std::setfill('0') << std::setw(3) << code_number;
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void plain_text_message(T& out, const express::Base& current_product, logger::Severity type, const std::string& message, const express::Base& instance) {
|
||||
void plain_text_message(T& out, const express::Base& current_product, Logger::Severity type, const std::string& code, const std::string& message, const express::Base& instance) {
|
||||
out << "[" << severity_strings<typename T::char_type>::value[type] << "] ";
|
||||
out << "[" << get_time(type <= logger::LOG_PERF).c_str() << "] ";
|
||||
out << "[" << code.c_str() << "] ";
|
||||
out << "[" << get_time(type <= Logger::LOG_PERF).c_str() << "] ";
|
||||
if (current_product) {
|
||||
std::string global_id = current_product.as<express::Entity>().get("GlobalId");
|
||||
out << "{" << global_id.c_str() << "} ";
|
||||
@@ -91,17 +99,19 @@ std::basic_string<T> string_as(const std::string& string) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void json_message(T& out, const express::Base& current_product, logger::Severity type, const std::string& message, const express::Base& instance) {
|
||||
void json_message(T& out, const express::Base* current_product, Logger::Severity type, const std::string& code, const std::string& message, const express::Base& instance) {
|
||||
boost::property_tree::basic_ptree<std::basic_string<typename T::char_type>, std::basic_string<typename T::char_type>> property_tree;
|
||||
|
||||
// @todo this is crazy
|
||||
static const typename T::char_type time_string[] = {'t', 'i', 'm', 'e', 0};
|
||||
static const typename T::char_type level_string[] = {'l', 'e', 'v', 'e', 'l', 0};
|
||||
static const typename T::char_type code_string[] = {'c', 'o', 'd', 'e', 0};
|
||||
static const typename T::char_type product_string[] = {'p', 'r', 'o', 'd', 'u', 'c', 't', 0};
|
||||
static const typename T::char_type message_string[] = {'m', 'e', 's', 's', 'a', 'g', 'e', 0};
|
||||
static const typename T::char_type instance_string[] = {'i', 'n', 's', 't', 'a', 'n', 'c', 'e', 0};
|
||||
|
||||
property_tree.put(level_string, severity_strings<typename T::char_type>::value[type]);
|
||||
property_tree.put(code_string, string_as<typename T::char_type>(code));
|
||||
if (current_product) {
|
||||
std::ostringstream oss;
|
||||
current_product.to_string(oss);
|
||||
@@ -126,10 +136,51 @@ void json_message(T& out, const express::Base& current_product, logger::Severity
|
||||
}
|
||||
} // namespace
|
||||
|
||||
log_message::log_message(
|
||||
int severity,
|
||||
const char (&code_prefix)[4],
|
||||
uint16_t code_number,
|
||||
const std::string& timestamp,
|
||||
const std::string& message,
|
||||
const IfcUtil::IfcBaseInterface* inst,
|
||||
const IfcUtil::IfcBaseClass* current_product)
|
||||
: severity(severity)
|
||||
, timestamp(timestamp)
|
||||
, message(message)
|
||||
{
|
||||
snprintf(code, 7, "%s%03u", code_prefix, code_number);
|
||||
if (inst) {
|
||||
std::ostringstream oss;
|
||||
inst->as<IfcUtil::IfcBaseClass>()->toString(oss);
|
||||
instance = oss.str();
|
||||
}
|
||||
if (current_product) {
|
||||
std::ostringstream oss;
|
||||
current_product->toString(oss);
|
||||
product = oss.str();
|
||||
}
|
||||
}
|
||||
|
||||
Logger& Logger::Root() {
|
||||
static Logger logger;
|
||||
return logger;
|
||||
}
|
||||
|
||||
const express::Base& Logger::current_product() const {
|
||||
return current_product_;
|
||||
}
|
||||
|
||||
void logger::set_product(std::optional<const express::Base> product) {
|
||||
if (verbosity_ <= LOG_DEBUG && product) {
|
||||
message(LOG_DEBUG, "Begin processing", *product);
|
||||
}
|
||||
current_product_ = product;
|
||||
}
|
||||
|
||||
void Logger::SetProduct(boost::optional<const IfcUtil::IfcBaseClass*> product) {
|
||||
if (verbosity_ <= LOG_DEBUG && product) {
|
||||
Message(LOG_DEBUG, "SYS", 3, "Begin processing", *product);
|
||||
}
|
||||
if (!product && print_perf_stats_on_element_) {
|
||||
print_performance_stats();
|
||||
performance_statistics_.clear();
|
||||
@@ -155,13 +206,13 @@ void logger::set_output(std::wostream* stream1, std::wostream* stream2) {
|
||||
}
|
||||
}
|
||||
|
||||
void logger::message(logger::Severity type, const std::string& text, const express::Base& instance) {
|
||||
void Logger::Message(Logger::Severity type, const char (&code_prefix)[4], uint16_t code_number, const std::string& message, const express::Base& instance) {
|
||||
if (type < verbosity_) {
|
||||
return;
|
||||
}
|
||||
|
||||
static std::mutex mtx;
|
||||
std::lock_guard<std::mutex> lock(mtx);
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
const std::string code = format_code(code_prefix, code_number);
|
||||
|
||||
if (type == LOG_PERF) {
|
||||
if (!first_timepoint_) {
|
||||
@@ -179,25 +230,28 @@ void logger::message(logger::Severity type, const std::string& text, const expre
|
||||
if (type > max_severity_) {
|
||||
max_severity_ = type;
|
||||
}
|
||||
if (((log2_ != nullptr) || (wlog2_ != nullptr))) {
|
||||
|
||||
if (format_ == FMT_INMEMORY) {
|
||||
log_messages_.emplace_back(type, code_prefix, code_number, get_time(), message, instance, current_product());
|
||||
} else if (((log2_ != nullptr) || (wlog2_ != nullptr))) {
|
||||
if (format_ == FMT_PLAIN) {
|
||||
if (log2_ != nullptr) {
|
||||
plain_text_message(*log2_, current_product_, type, text, instance);
|
||||
plain_text_message(*log2_, current_product(), type, code, message, instance);
|
||||
} else if (wlog2_ != nullptr) {
|
||||
plain_text_message(*wlog2_, current_product_, type, text, instance);
|
||||
plain_text_message(*wlog2_, current_product(), type, code, message, instance);
|
||||
}
|
||||
} else if (format_ == FMT_JSON) {
|
||||
if (log2_ != nullptr) {
|
||||
json_message(*log2_, current_product_, type, text, instance);
|
||||
json_message(*log2_, current_product(), type, code, message, instance);
|
||||
} else if (wlog2_ != nullptr) {
|
||||
json_message(*wlog2_, current_product_, type, text, instance);
|
||||
json_message(*wlog2_, current_product(), type, code, message, instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void logger::message(logger::Severity type, const std::exception& exception, const express::Base& instance) {
|
||||
message(type, std::string(exception.what()), instance);
|
||||
void Logger::Message(Logger::Severity type, const char (&code_prefix)[4], uint16_t code_number, const std::exception& exception, const express::Base&) {
|
||||
Message(type, code_prefix, code_number, std::string(exception.what()), instance);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -226,6 +280,49 @@ std::string logger::get_log() {
|
||||
return log_stream_.str();
|
||||
}
|
||||
|
||||
std::string Logger::GetLog() {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
return log_stream_.str();
|
||||
}
|
||||
|
||||
void Logger::ClearLog() {
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
log_stream_.str(std::string());
|
||||
log_stream_.clear();
|
||||
log_messages_.clear();
|
||||
}
|
||||
|
||||
void Logger::Append(Logger& logger) {
|
||||
if (&logger == this) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::scoped_lock lock(mutex_, logger.mutex_);
|
||||
|
||||
if (logger.max_severity_ > max_severity_) {
|
||||
max_severity_ = logger.max_severity_;
|
||||
}
|
||||
|
||||
if (format_ == FMT_INMEMORY) {
|
||||
log_messages_.insert(log_messages_.end(), logger.log_messages_.begin(), logger.log_messages_.end());
|
||||
} else {
|
||||
const std::string log = logger.log_stream_.str();
|
||||
if (!log.empty()) {
|
||||
if (log2_ != nullptr) {
|
||||
*log2_ << log;
|
||||
} else if (wlog2_ != nullptr) {
|
||||
*wlog2_ << string_as<wchar_t>(log);
|
||||
} else {
|
||||
log_stream_ << log;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
logger.log_stream_.str(std::string());
|
||||
logger.log_stream_.clear();
|
||||
logger.log_messages_.clear();
|
||||
}
|
||||
|
||||
void logger::print_performance_stats() {
|
||||
std::vector<std::pair<double, std::string>> items;
|
||||
for (auto& stat : performance_statistics_) {
|
||||
@@ -243,28 +340,15 @@ void logger::print_performance_stats() {
|
||||
}
|
||||
|
||||
for (auto& item : items) {
|
||||
auto text = item.second + std::string(max_size - item.second.size(), ' ') + ": " + std::to_string(item.first);
|
||||
logger::message(LOG_PERF, text);
|
||||
auto message = item.second + std::string(max_size - item.second.size(), ' ') + ": " + std::to_string(item.first);
|
||||
Message(LOG_PERF, "SYS", 4, message);
|
||||
}
|
||||
}
|
||||
|
||||
void logger::verbosity(logger::Severity severity) { verbosity_ = severity; }
|
||||
logger::Severity logger::verbosity() { return verbosity_; }
|
||||
void Logger::Verbosity(Logger::Severity severity) { verbosity_ = severity; }
|
||||
Logger::Severity Logger::Verbosity() const { return verbosity_; }
|
||||
|
||||
logger::Severity logger::max_severity() { return max_severity_; }
|
||||
Logger::Severity Logger::MaxSeverity() const { return max_severity_; }
|
||||
|
||||
void logger::output_format(Format format) { format_ = format; }
|
||||
logger::Format logger::output_format() { return format_; }
|
||||
|
||||
std::ostream* logger::log1_ = 0;
|
||||
std::ostream* logger::log2_ = 0;
|
||||
std::wostream* logger::wlog1_ = 0;
|
||||
std::wostream* logger::wlog2_ = 0;
|
||||
std::stringstream logger::log_stream_;
|
||||
logger::Severity logger::verbosity_ = logger::LOG_NOTICE;
|
||||
logger::Severity logger::max_severity_ = logger::LOG_NOTICE;
|
||||
logger::Format logger::format_ = logger::FMT_PLAIN;
|
||||
std::optional<long long> logger::first_timepoint_;
|
||||
std::map<std::string, double> logger::performance_statistics_;
|
||||
std::map<std::string, double> logger::performance_signal_start_;
|
||||
bool logger::print_perf_stats_on_element_ = false;
|
||||
void Logger::OutputFormat(Format format) { format_ = format; }
|
||||
Logger::Format Logger::OutputFormat() const { return format_; }
|
||||
|
||||
+76
-37
@@ -25,10 +25,29 @@
|
||||
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/scope_exit.hpp>
|
||||
#include <cstdint>
|
||||
#include <exception>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
class IFC_PARSE_API log_message {
|
||||
public:
|
||||
char code[7];
|
||||
int severity;
|
||||
std::string timestamp, message, instance, product;
|
||||
|
||||
log_message(
|
||||
int severity,
|
||||
const char (&code_prefix)[4],
|
||||
uint16_t code_number,
|
||||
const std::string& timestamp,
|
||||
const std::string& message,
|
||||
const IfcUtil::IfcBaseInterface* inst = 0,
|
||||
const IfcUtil::IfcBaseClass* current_product = 0);
|
||||
};
|
||||
|
||||
class IFC_PARSE_API logger {
|
||||
public:
|
||||
@@ -39,76 +58,96 @@ class IFC_PARSE_API logger {
|
||||
LOG_WARNING,
|
||||
LOG_ERROR
|
||||
} Severity;
|
||||
|
||||
typedef enum {
|
||||
FMT_PLAIN,
|
||||
FMT_JSON
|
||||
FMT_JSON,
|
||||
FMT_INMEMORY
|
||||
} Format;
|
||||
|
||||
private:
|
||||
std::vector<log_message> log_messages_;
|
||||
|
||||
// To both stream variants need to exist at runtime or should this be a
|
||||
// template argument of logger or controlled using preprocessor directives?
|
||||
static std::ostream* log1_;
|
||||
static std::ostream* log2_;
|
||||
// template argument of Logger or controlled using preprocessor directives?
|
||||
std::ostream* log1_ = nullptr;
|
||||
std::ostream* log2_ = nullptr;
|
||||
|
||||
static std::wostream* wlog1_;
|
||||
static std::wostream* wlog2_;
|
||||
std::wostream* wlog1_ = nullptr;
|
||||
std::wostream* wlog2_ = nullptr;
|
||||
|
||||
static std::stringstream log_stream_;
|
||||
std::stringstream log_stream_;
|
||||
const IfcUtil::IfcBaseClass* current_product_ = nullptr;
|
||||
|
||||
static Severity verbosity_;
|
||||
static Format format_;
|
||||
static Severity max_severity_;
|
||||
Severity verbosity_ = LOG_NOTICE;
|
||||
Format format_ = FMT_PLAIN;
|
||||
Severity max_severity_ = LOG_NOTICE;
|
||||
|
||||
static std::optional<long long> first_timepoint_;
|
||||
static std::map<std::string, double> performance_statistics_;
|
||||
static std::map<std::string, double> performance_signal_start_;
|
||||
std::optional<long long> first_timepoint_;
|
||||
std::map<std::string, double> performance_statistics_;
|
||||
std::map<std::string, double> performance_signal_start_;
|
||||
|
||||
static bool print_perf_stats_on_element_;
|
||||
bool print_perf_stats_on_element_ = false;
|
||||
std::mutex mutex_;
|
||||
|
||||
const IfcUtil::IfcBaseClass* current_product() const;
|
||||
void current_product(const IfcUtil::IfcBaseClass* product);
|
||||
|
||||
public:
|
||||
static void set_product(std::optional<const express::Base> product);
|
||||
logger() = default;
|
||||
logger(const logger&) = delete;
|
||||
logger& operator=(const logger&) = delete;
|
||||
|
||||
static logger& Root();
|
||||
|
||||
void set_product(std::optional<const IfcUtil::IfcBaseClass*> product);
|
||||
|
||||
/// Determines to what stream respectively progress and errors are logged
|
||||
static void set_output(std::wostream* progress_stream, std::wostream* error_stream);
|
||||
void set_output(std::wostream* stream1, std::wostream* stream2);
|
||||
|
||||
/// Determines to what stream respectively progress and errors are logged
|
||||
static void set_output(std::ostream* progress_stream, std::ostream* error_stream);
|
||||
void set_output(std::ostream* stream1, std::ostream* stream2);
|
||||
|
||||
/// Determines the types of log messages to get logged
|
||||
static void verbosity(Severity severity);
|
||||
static Severity verbosity();
|
||||
static Severity max_severity();
|
||||
void verbosity(Severity severity);
|
||||
Severity verbosity() const;
|
||||
Severity max_severity() const;
|
||||
|
||||
/// Determines output format: plain text or sequence of JSON objects
|
||||
static void output_format(Format format);
|
||||
static Format output_format();
|
||||
void output_format(Format format);
|
||||
Format output_format() const;
|
||||
|
||||
/// Log a message to the output stream
|
||||
static void message(Severity severity, const std::string& text, const express::Base& instance = express::Base());
|
||||
static void message(Severity severity, const std::exception& exception, const express::Base& instance = express::Base());
|
||||
void message(Severity type, const char (&code_prefix)[4], uint16_t code_number, const std::string& message, const IfcUtil::IfcBaseInterface* instance = 0);
|
||||
void message(Severity type, const char (&code_prefix)[4], uint16_t code_number, const std::exception& exception, const IfcUtil::IfcBaseInterface* instance = 0);
|
||||
|
||||
static void notice(const std::string& text, const express::Base& instance = express::Base()) { logger::message(LOG_NOTICE, text, instance); }
|
||||
static void warning(const std::string& text, const express::Base& instance = express::Base()) { logger::message(LOG_WARNING, text, instance); }
|
||||
static void error(const std::string& text, const express::Base& instance = express::Base()) { logger::message(LOG_ERROR, text, instance); }
|
||||
void notice(const char (&code_prefix)[4], uint16_t code_number, const std::string& message, const IfcUtil::IfcBaseInterface* instance = 0) { Message(LOG_NOTICE, code_prefix, code_number, message, instance); }
|
||||
void warning(const char (&code_prefix)[4], uint16_t code_number, const std::string& message, const IfcUtil::IfcBaseInterface* instance = 0) { Message(LOG_WARNING, code_prefix, code_number, message, instance); }
|
||||
void error(const char (&code_prefix)[4], uint16_t code_number, const std::string& message, const IfcUtil::IfcBaseInterface* instance = 0) { Message(LOG_ERROR, code_prefix, code_number, message, instance); }
|
||||
|
||||
static void notice(const std::exception& exception, const express::Base& instance = express::Base()) { message(LOG_NOTICE, exception, instance); }
|
||||
static void warning(const std::exception& exception, const express::Base& instance = express::Base()) { message(LOG_WARNING, exception, instance); }
|
||||
static void error(const std::exception& exception, const express::Base& instance = express::Base()) { message(LOG_ERROR, exception, instance); }
|
||||
void notice(const char (&code_prefix)[4], uint16_t code_number, const std::exception& exception, const IfcUtil::IfcBaseInterface* instance = 0) { Message(LOG_NOTICE, code_prefix, code_number, exception, instance); }
|
||||
void warning(const char (&code_prefix)[4], uint16_t code_number, const std::exception& exception, const IfcUtil::IfcBaseInterface* instance = 0) { Message(LOG_WARNING, code_prefix, code_number, exception, instance); }
|
||||
void error(const char (&code_prefix)[4], uint16_t code_number, const std::exception& exception, const IfcUtil::IfcBaseInterface* instance = 0) { Message(LOG_ERROR, code_prefix, code_number, exception, instance); }
|
||||
|
||||
static void status(const std::string& message, bool append_newline = true);
|
||||
void status(const std::string& message, bool new_line = true);
|
||||
|
||||
static void progress_bar(int progress_percent);
|
||||
static std::string get_log();
|
||||
static void print_performance_stats();
|
||||
static void print_performance_stats_on_element(bool enabled) { print_perf_stats_on_element_ = enabled; }
|
||||
void progress_bar(int progress);
|
||||
std::string get_log();
|
||||
void clear();
|
||||
void append(Logger& logger);
|
||||
void print_performance_stats();
|
||||
void print_performance_stats(bool b) { print_perf_stats_on_element_ = b; }
|
||||
bool print_performance_stats() const { return print_perf_stats_on_element_; }
|
||||
|
||||
const std::vector<log_message>& log_messages() const { return log_messages_; }
|
||||
};
|
||||
|
||||
#define PERF(x) \
|
||||
\
|
||||
logger::message(logger::LOG_PERF, x); \
|
||||
Logger::Root().Message(Logger::LOG_PERF, "SYS", 1, x); \
|
||||
\
|
||||
BOOST_SCOPE_EXIT(void) { \
|
||||
logger::message(logger::LOG_PERF, "done " + std::string(x)); \
|
||||
Logger::Root().Message(Logger::LOG_PERF, "SYS", 2, "done " + std::string(x)); \
|
||||
} \
|
||||
BOOST_SCOPE_EXIT_END
|
||||
|
||||
|
||||
@@ -27,6 +27,9 @@
|
||||
#define STRINGIFY_(x) #x
|
||||
#define STRINGIFY(x) STRINGIFY_(x)
|
||||
|
||||
#define INCLUDE_SCHEMA(prefix, x) STRINGIFY(prefix/x.h)
|
||||
#define INCLUDE_SCHEMA_DEFINITIONS(prefix, x) STRINGIFY(prefix/x-definitions.h)
|
||||
|
||||
#define MAKE_INIT_FN__(a, b) init_##a##_##b
|
||||
#define MAKE_INIT_FN_(a, b) MAKE_INIT_FN__(a, b)
|
||||
#define MAKE_INIT_FN(t) MAKE_INIT_FN_(t, IfcSchema)
|
||||
|
||||
+13
-10
@@ -601,20 +601,21 @@ void warn_attribute_count(
|
||||
const ifcopenshell::declaration* declaration,
|
||||
std::optional<size_t> instance_name,
|
||||
size_t expected_size,
|
||||
size_t actual_size
|
||||
size_t actual_size,
|
||||
::Logger& logger
|
||||
) {
|
||||
if (!declaration || expected_size == actual_size) {
|
||||
return;
|
||||
}
|
||||
if (declaration->schema() == &Header_section_schema::get_schema()) {
|
||||
logger::warning("Expected " + std::to_string(expected_size) + " attribute values, found " + std::to_string(actual_size) + " for header entity " + declaration->name());
|
||||
logger.Warning("VAL", 15, "Expected " + std::to_string(expected_size) + " attribute values, found " + std::to_string(actual_size) + " for header entity " + declaration->name());
|
||||
} else {
|
||||
logger::warning("Expected " + std::to_string(expected_size) + " attribute values, found " + std::to_string(actual_size) + (instance_name ? std::string(" for instance #" + std::to_string(*instance_name)) : std::string("")));
|
||||
logger.Warning("VAL", 16, "Expected " + std::to_string(expected_size) + " attribute values, found " + std::to_string(actual_size) + (instance_name ? std::string(" for instance #" + std::to_string(*instance_name)) : std::string("")));
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Fn>
|
||||
void dispatch_token_direct(ifcopenshell::token token, ifcopenshell::declaration* declaration, int attribute_index, Fn&& fn) {
|
||||
void dispatch_token_direct(ifcopenshell::token token, ifcopenshell::declaration* declaration, int attribute_index, Logger& logger, Fn&& fn) {
|
||||
if (token.is_binary()) {
|
||||
fn(token.as_binary());
|
||||
} else if (token.is_bool()) {
|
||||
@@ -627,10 +628,10 @@ void dispatch_token_direct(ifcopenshell::token token, ifcopenshell::declaration*
|
||||
try {
|
||||
fn(enumeration_reference(declaration->as_enumeration_type(), declaration->as_enumeration_type()->lookup_enum_offset(value)));
|
||||
} catch (ifcopenshell::exception&) {
|
||||
logger::error("An enumeration literal '" + value + "' is not valid for type '" + declaration->name() + "' at offset " + std::to_string(token.start_pos));
|
||||
logger.Error("VAL", 12, "An enumeration literal '" + value + "' is not valid for type '" + declaration->name() + "' at offset " + std::to_string(token.start_pos));
|
||||
}
|
||||
} else {
|
||||
logger::error("An enumeration literal '" + value + "' is not expected at attribute index '" + std::to_string(attribute_index) + "' at offset " + std::to_string(token.start_pos));
|
||||
logger.Error("VAL", 13, "An enumeration literal '" + value + "' is not expected at attribute index '" + std::to_string(attribute_index) + "' at offset " + std::to_string(token.start_pos));
|
||||
}
|
||||
} else if (token.is_int()) {
|
||||
fn(token.as_int());
|
||||
@@ -663,6 +664,7 @@ struct direct_aggregate {
|
||||
direct_aggregate_storage storage;
|
||||
size_t pending_empty_aggregates = 0;
|
||||
size_t values = 0;
|
||||
Logger& logger;
|
||||
|
||||
template <typename T>
|
||||
void append(const T& value) {
|
||||
@@ -679,7 +681,7 @@ struct direct_aggregate {
|
||||
}
|
||||
}
|
||||
if (pending_empty_aggregates) {
|
||||
logger::error("Inconsistent aggregate valuation while attempting to append " + std::string(typeid(T).name()) + " after an empty nested aggregate");
|
||||
logger.Error("VAL", 14, "Inconsistent aggregate valuation while attempting to append " + std::string(typeid(T).name()) + " after an empty nested aggregate");
|
||||
pending_empty_aggregates = 0;
|
||||
}
|
||||
if (storage.index() == 0) {
|
||||
@@ -690,7 +692,7 @@ struct direct_aggregate {
|
||||
append_promoted(value);
|
||||
}
|
||||
} else {
|
||||
logger::error(std::string("Aggregates of ") + typeid(T).name() + " are not supported in the IfcOpenShell parser");
|
||||
logger.Error("UNS", 31, std::string("Aggregates of ") + typeid(T).name() + " are not supported in the IfcOpenShell parser");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -872,7 +874,8 @@ direct_aggregate read_direct_aggregate(
|
||||
std::optional<size_t> entity_instance_name,
|
||||
const ifcopenshell::entity* entity,
|
||||
int attribute_index,
|
||||
const ifcopenshell::aggregation_type* aggregate_type
|
||||
const ifcopenshell::aggregation_type* aggregate_type,
|
||||
::Logger& logger
|
||||
) {
|
||||
direct_aggregate aggregate;
|
||||
token next = tokens->next();
|
||||
@@ -900,7 +903,7 @@ direct_aggregate read_direct_aggregate(
|
||||
storage.read_simple_type_instances.push_back(data);
|
||||
aggregate.append(ifcopenshell::reference_or_simple_type{express::Base(data)});
|
||||
} catch (exception& e) {
|
||||
logger::message(logger::LOG_ERROR, std::string(e.what()) + " at offset " + std::to_string(next.start_pos));
|
||||
logger.error("SYN", 123, std::string(e.what()) + " at offset " + std::to_string(next.start_pos));
|
||||
}
|
||||
} else {
|
||||
if (next.is_identifier() && entity && entity_instance_name) {
|
||||
|
||||
@@ -52,6 +52,8 @@ template <typename Reader>
|
||||
class IFC_PARSE_API spf_lexer {
|
||||
private:
|
||||
character_decoder<Reader>* decoder_;
|
||||
Logger& logger_;
|
||||
|
||||
size_t skip_whitespace() const;
|
||||
size_t skip_comment() const;
|
||||
|
||||
@@ -59,6 +61,7 @@ class IFC_PARSE_API spf_lexer {
|
||||
mutable size_t pool_index = 0;
|
||||
|
||||
public:
|
||||
|
||||
spf_lexer(const spf_lexer&) = delete;
|
||||
spf_lexer& operator=(const spf_lexer&) = delete;
|
||||
|
||||
@@ -74,7 +77,7 @@ class IFC_PARSE_API spf_lexer {
|
||||
|
||||
Reader* stream;
|
||||
// file* file;
|
||||
spf_lexer(Reader* stream);
|
||||
spf_lexer(Reader* stream, Logger& logger = Logger::Root());
|
||||
token next();
|
||||
~spf_lexer();
|
||||
// void TokenString(size_t offset, std::string& result);
|
||||
|
||||
@@ -11,7 +11,7 @@ using namespace ifcopenshell;
|
||||
|
||||
namespace {
|
||||
|
||||
shared_pointer_type make_header_entity(ifcopenshell::file* file, const ifcopenshell::entity& decl) {
|
||||
shared_pointer_type make_header_entity(ifcopenshell::file* file, const ifcopenshell::entity& decl, Logger& logger) {
|
||||
const bool in_memory = file == nullptr || std::visit([](auto& storage) {
|
||||
return std::is_same_v<std::decay_t<decltype(storage)>, ifcopenshell::impl::in_memory_file_storage>;
|
||||
}, file->storage_);
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "ifc_parse_api.h"
|
||||
#include "instance_data.h"
|
||||
#include "schemas/Header_section_schema.h"
|
||||
#include <functional>
|
||||
|
||||
namespace ifcopenshell {
|
||||
|
||||
@@ -31,29 +32,36 @@ class file;
|
||||
class IFC_PARSE_API spf_header {
|
||||
private:
|
||||
ifcopenshell::file* file_;
|
||||
std::reference_wrapper<Logger> logger_;
|
||||
IfcParse::impl::in_memory_file_storage* storage_ = nullptr;
|
||||
|
||||
std::array<shared_pointer_type, 3> header_entities_;
|
||||
|
||||
public:
|
||||
explicit spf_header(ifcopenshell::file* owner_file);
|
||||
~spf_header();
|
||||
explicit spf_header(ifcopenshell::file* file = nullptr, Logger& logger = Logger::Root());
|
||||
explicit spf_header(spf_lexer* lexer, Logger& logger = Logger::Root());
|
||||
|
||||
void write(std::ostream& stream) const;
|
||||
|
||||
ifcopenshell::file* owner_file() { return file_; }
|
||||
void owner_file(ifcopenshell::file* file);
|
||||
Logger& logger() const { return logger_.get(); }
|
||||
|
||||
void set_file_description(const shared_pointer_type& description_data);
|
||||
void set_file_name(const shared_pointer_type& name_data);
|
||||
void set_file_schema(const shared_pointer_type& schema_data);
|
||||
|
||||
const Header_section_schema::file_description file_description() const;
|
||||
const Header_section_schema::file_name file_name() const;
|
||||
const Header_section_schema::file_schema file_schema() const;
|
||||
void assign(const IfcSpfHeader& other);
|
||||
|
||||
void write(std::ostream& out) const;
|
||||
|
||||
Header_section_schema::file_description file_description();
|
||||
Header_section_schema::file_name file_name();
|
||||
Header_section_schema::file_schema file_schema();
|
||||
|
||||
const Header_section_schema::file_description file_description() const;
|
||||
const Header_section_schema::file_name file_name() const;
|
||||
const Header_section_schema::file_schema file_schema() const;
|
||||
};
|
||||
|
||||
} // namespace ifcopenshell
|
||||
|
||||
@@ -24,9 +24,9 @@ namespace rocksdb {
|
||||
#include "map_transformer.h"
|
||||
#include "set_to_map_transformer.h"
|
||||
#include "file_open_status.h"
|
||||
#include "IfcLogger.h"
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <variant>
|
||||
#include <algorithm>
|
||||
#include <cstdint>
|
||||
@@ -38,7 +38,6 @@ namespace rocksdb {
|
||||
#include <iostream>
|
||||
#include <deque>
|
||||
#include <vector>
|
||||
#include <deque>
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
@@ -413,6 +412,10 @@ namespace ifcopenshell {
|
||||
return std::move(read_simple_type_instances);
|
||||
}
|
||||
|
||||
ifcopenshell::spf_lexer* tokens;
|
||||
std::reference_wrapper<Logger> logger_;
|
||||
// IfcParse::FileReader* stream;
|
||||
|
||||
// Either one of these needs to be set
|
||||
ifcopenshell::file* file;
|
||||
const ifcopenshell::schema_definition* schema;
|
||||
@@ -427,7 +430,7 @@ namespace ifcopenshell {
|
||||
typedef inverse_index entities_by_ref_t;
|
||||
typedef entity_instance_by_name_t::iterator iterator;
|
||||
|
||||
in_memory_file_storage(ifcopenshell::file* owner_file = nullptr) : file(owner_file), schema(nullptr), byid_read_(&byid_, [this](const shared_pointer_type& data) { return express::Base(data); }) {};
|
||||
in_memory_file_storage(ifcopenshell::file* owner_file = nullptr, Logger& logger = Logger::Root()) : logger_(logger), file(owner_file), schema(nullptr), byid_read_(&byid_, [this](const shared_pointer_type& data) { return express::Base(data); }) {};
|
||||
in_memory_file_storage(const in_memory_file_storage& other) = delete;
|
||||
in_memory_file_storage(const in_memory_file_storage&& other) = delete;
|
||||
|
||||
|
||||
@@ -266,6 +266,17 @@ IFC_PARSE_API bool ifcopenshell::path::rename_file(const std::string& old_filena
|
||||
return success;
|
||||
}
|
||||
|
||||
IFC_PARSE_API bool IfcUtil::path::atomic_rename_file(const std::string& old_filename, const std::string& new_filename) {
|
||||
std::wstring old_filename_w = from_utf8(old_filename);
|
||||
std::wstring new_filename_w = from_utf8(new_filename);
|
||||
// MOVEFILE_REPLACE_EXISTING makes the replace atomic on NTFS (no unlink
|
||||
// of the destination first). MOVEFILE_WRITE_THROUGH waits until the move
|
||||
// is flushed to disk before returning.
|
||||
const bool success = !!MoveFileExW(old_filename_w.c_str(), new_filename_w.c_str(),
|
||||
MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH);
|
||||
return success;
|
||||
}
|
||||
|
||||
IFC_PARSE_API bool ifcopenshell::path::delete_file(const std::string& filename) {
|
||||
std::wstring filename_w = from_utf8(filename);
|
||||
const bool success = !!DeleteFileW(filename_w.c_str());
|
||||
@@ -281,6 +292,12 @@ IFC_PARSE_API bool ifcopenshell::path::rename_file(const std::string& old_filena
|
||||
return std::rename(old_filename.c_str(), new_filename.c_str()) == 0;
|
||||
}
|
||||
|
||||
IFC_PARSE_API bool IfcUtil::path::atomic_rename_file(const std::string& old_filename, const std::string& new_filename) {
|
||||
// POSIX rename() atomically replaces an existing destination on the same
|
||||
// filesystem, so there is no window in which new_filename is missing.
|
||||
return std::rename(old_filename.c_str(), new_filename.c_str()) == 0;
|
||||
}
|
||||
|
||||
IFC_PARSE_API bool ifcopenshell::path::delete_file(const std::string& filename) {
|
||||
return std::remove(filename.c_str()) != 0;
|
||||
}
|
||||
|
||||
@@ -37,6 +37,13 @@ namespace path {
|
||||
IFC_PARSE_API bool delete_file(const std::string& filename);
|
||||
IFC_PARSE_API bool rename_file(const std::string& old_filename, const std::string& new_filename);
|
||||
|
||||
/// Atomically renames old_filename onto new_filename, replacing an existing
|
||||
/// destination in a single filesystem operation. Unlike rename_file(), the
|
||||
/// destination is never unlinked before the rename, so an interruption can
|
||||
/// never leave the destination missing. This requires both paths to live on
|
||||
/// the same filesystem. Returns true on success.
|
||||
IFC_PARSE_API bool atomic_rename_file(const std::string& old_filename, const std::string& new_filename);
|
||||
|
||||
#if defined(_MSC_VER) && defined(_UNICODE)
|
||||
|
||||
/// Uses windows.h string conversion functions
|
||||
|
||||
@@ -37,10 +37,28 @@ variant - which is the maximum size of its constituents - is reduced.
|
||||
#include <cstring>
|
||||
#include <cstddef>
|
||||
#include <limits>
|
||||
|
||||
#include "exception.h"
|
||||
#include <exception>
|
||||
|
||||
namespace impl {
|
||||
class storage_type_mismatch : public std::exception {
|
||||
private:
|
||||
std::string requested_, actual__, message_;
|
||||
|
||||
public:
|
||||
storage_type_mismatch(const std::string& requested, const std::string& actual)
|
||||
: requested_(requested), actual__(actual), message_("Requested type " + requested_ + " does not match actual type " + actual__) {}
|
||||
|
||||
const char* what() const noexcept override {
|
||||
return message_.c_str();
|
||||
}
|
||||
|
||||
const std::string& requested() const { return requested_; }
|
||||
const std::string& actual() const { return actual__; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct VariantTypeName;
|
||||
|
||||
// Trait to detect unique_ptr
|
||||
template <typename...> struct is_unique_ptr : std::false_type {};
|
||||
template<class T, typename... Args>
|
||||
@@ -166,14 +184,13 @@ public:
|
||||
using U = std::decay_t<T>;
|
||||
static_assert(::impl::TypeIndex_v<U, Types...> < sizeof...(Types), "Type not supported by variant");
|
||||
if (index >= size()) {
|
||||
throw std::out_of_range("Index out of range");
|
||||
throw std::out_of_range("Index " + std::to_string(index) + " is out of range for storage of size " + std::to_string(size()));
|
||||
}
|
||||
|
||||
destroy_at_index(index);
|
||||
|
||||
size_and_indices_[index + 1] = ::impl::TypeIndex_v<U, Types...>;
|
||||
using V = typename std::tuple_element<::impl::TypeIndex_v<U, Types...>, ::impl::MapTypes_t<Types... >>::type;
|
||||
// std::wcout << "setting " << index << " to " << typeid(V).name() << " (" << ::impl::TypeIndex_v<U, Types...> << ")" << std::endl;
|
||||
if constexpr (::impl::is_unique_ptr<V>::value) {
|
||||
new(&storage_[index]) V(new U(value));
|
||||
} else {
|
||||
@@ -187,8 +204,8 @@ public:
|
||||
|
||||
std::size_t index(std::size_t index) const {
|
||||
if (index >= size()) {
|
||||
throw ifcopenshell::exception(
|
||||
"Index " + std::to_string(index) + " is out of range for variant of size " + std::to_string(size())
|
||||
throw std::out_of_range(
|
||||
"Index " + std::to_string(index) + " is out of range for storage of size " + std::to_string(size())
|
||||
);
|
||||
}
|
||||
return size_and_indices_[index + 1];
|
||||
@@ -197,8 +214,8 @@ public:
|
||||
template<typename T>
|
||||
T& get(std::size_t index) {
|
||||
if (index >= size()) {
|
||||
throw ifcopenshell::exception(
|
||||
"Index " + std::to_string(index) + " is out of range for variant of size " + std::to_string(size())
|
||||
throw std::out_of_range(
|
||||
"Index " + std::to_string(index) + " is out of range for storage of size " + std::to_string(size())
|
||||
);
|
||||
}
|
||||
if (!has<T>(index)) {
|
||||
@@ -220,17 +237,16 @@ public:
|
||||
template<typename T>
|
||||
const T& get(std::size_t index) const {
|
||||
if (index >= size()) {
|
||||
throw ifcopenshell::exception(
|
||||
"Index " + std::to_string(index) + " is out of range for variant of size " + std::to_string(size())
|
||||
throw std::out_of_range(
|
||||
"Index " + std::to_string(index) + " is out of range for storage of size " + std::to_string(size())
|
||||
);
|
||||
}
|
||||
if (size_and_indices_[index + 1] != ::impl::TypeIndex<T, Types...>::value) {
|
||||
// @todo this exception is silly. Figure out what
|
||||
// to do, but at the moment it is specifically caught
|
||||
// in various places.
|
||||
throw ifcopenshell::exception(
|
||||
"Type held at index " + std::to_string(index) + " is " +
|
||||
get_type_name(size_and_indices_[index + 1]) + " and not " + typeid(T).name()
|
||||
throw impl::storage_type_mismatch(
|
||||
::impl::VariantTypeName<T>::get(), get_type_name(size_and_indices_[index + 1])
|
||||
);
|
||||
}
|
||||
using V = typename std::tuple_element<::impl::TypeIndex_v<T, Types...>, ::impl::MapTypes_t<Types... >>::type;
|
||||
@@ -244,8 +260,8 @@ public:
|
||||
template<typename Visitor>
|
||||
auto apply_visitor(Visitor&& visitor, std::size_t index) const {
|
||||
if (index >= size()) {
|
||||
throw ifcopenshell::exception(
|
||||
"Index " + std::to_string(index) + " is out of range for variant of size " + std::to_string(size())
|
||||
throw std::out_of_range(
|
||||
"Index " + std::to_string(index) + " is out of range for storage of size " + std::to_string(size())
|
||||
);
|
||||
}
|
||||
return apply_visitor_impl(std::forward<Visitor>(visitor), index, std::integral_constant<std::size_t, sizeof...(Types)>{});
|
||||
@@ -316,19 +332,19 @@ private:
|
||||
}
|
||||
|
||||
template <size_t I>
|
||||
const char* get_type_name_impl(size_t type_index) const {
|
||||
std::string get_type_name_impl(size_t type_index) const {
|
||||
if constexpr (I == 0) {
|
||||
return "";
|
||||
} else {
|
||||
if (type_index == I - 1) {
|
||||
return typeid(std::tuple_element_t<I - 1, std::tuple<Types...>>).name();
|
||||
return ::impl::VariantTypeName<std::tuple_element_t<I - 1, std::tuple<Types...>>>::get();
|
||||
} else {
|
||||
return get_type_name_impl<I - 1>(type_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const char* get_type_name(size_t type_index) const {
|
||||
std::string get_type_name(size_t type_index) const {
|
||||
return get_type_name_impl<sizeof...(Types)>(type_index);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user