diff --git a/src/ifcparse/IfcEntityInstanceData.cpp b/src/ifcparse/IfcEntityInstanceData.cpp index e87c429545..88aa766086 100644 --- a/src/ifcparse/IfcEntityInstanceData.cpp +++ b/src/ifcparse/IfcEntityInstanceData.cpp @@ -34,7 +34,22 @@ namespace { inline T dispatch_get_(AttributeValue::pointer_type array_, uint8_t storage_model_, size_t instance_name_, const IfcParse::declaration* entity_or_type, uint8_t index_) { if (storage_model_ == 0) { - return array_.storage_ptr->get(index_); + try { + return array_.storage_ptr->get(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 { diff --git a/src/ifcparse/IfcEntityInstanceData.h b/src/ifcparse/IfcEntityInstanceData.h index f51345a25e..237ddb0d35 100644 --- a/src/ifcparse/IfcEntityInstanceData.h +++ b/src/ifcparse/IfcEntityInstanceData.h @@ -72,6 +72,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 { + static std::string get() { return "null"; } + }; + + template <> + struct VariantTypeName { + static std::string get() { return "derived"; } + }; + + template <> + struct VariantTypeName { + static std::string get() { return "int"; } + }; + + template <> + struct VariantTypeName { + static std::string get() { return "bool"; } + }; + + template <> + struct VariantTypeName { + static std::string get() { return "logical"; } + }; + + template <> + struct VariantTypeName { + static std::string get() { return "real"; } + }; + + template <> + struct VariantTypeName { + static std::string get() { return "string"; } + }; + + template <> + struct VariantTypeName> { + static std::string get() { return "binary"; } + }; + + template <> + struct VariantTypeName { + static std::string get() { return "enumeration"; } + }; + + template <> + struct VariantTypeName { + static std::string get() { return "instance"; } + }; + + template <> + struct VariantTypeName { + static std::string get() { return "aggregate"; } + }; + + template + struct VariantTypeName> { + static std::string get() { return "aggregate of " + VariantTypeName::get(); } + }; + + template <> + struct VariantTypeName { + static std::string get() { return "aggregate of instance"; } + }; + + template <> + struct VariantTypeName { + static std::string get() { return "aggregate of aggregate"; } + }; + + template <> + struct VariantTypeName { + static std::string get() { return "aggregate of aggregate of instance"; } + }; +} + template struct parameter_pack { static constexpr size_t size = sizeof...(Args); diff --git a/src/ifcparse/variantarray.h b/src/ifcparse/variantarray.h index 1b00774bf7..b3fcb481b2 100644 --- a/src/ifcparse/variantarray.h +++ b/src/ifcparse/variantarray.h @@ -37,10 +37,28 @@ variant - which is the maximum size of its constituents - is reduced. #include #include #include - -#include "IfcException.h" +#include 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 + struct VariantTypeName; + // Trait to detect unique_ptr template struct is_unique_ptr : std::false_type {}; template @@ -166,14 +184,13 @@ public: using U = std::decay_t; static_assert(::impl::TypeIndex_v < 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; using V = typename std::tuple_element<::impl::TypeIndex_v, ::impl::MapTypes_t>::type; - // std::wcout << "setting " << index << " to " << typeid(V).name() << " (" << ::impl::TypeIndex_v << ")" << std::endl; if constexpr (::impl::is_unique_ptr::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 IfcParse::IfcException( - "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 T& get(std::size_t index) { if (index >= size()) { - throw IfcParse::IfcException( - "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(index)) { @@ -220,17 +237,16 @@ public: template const T& get(std::size_t index) const { if (index >= size()) { - throw IfcParse::IfcException( - "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::value) { // @todo this IfcException is silly. Figure out what // to do, but at the moment it is specifically caught // in various places. - throw IfcParse::IfcException( - "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::get(), get_type_name(size_and_indices_[index + 1]) ); } using V = typename std::tuple_element<::impl::TypeIndex_v, ::impl::MapTypes_t>::type; @@ -244,8 +260,8 @@ public: template auto apply_visitor(Visitor&& visitor, std::size_t index) const { if (index >= size()) { - throw IfcParse::IfcException( - "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), index, std::integral_constant{}); @@ -312,19 +328,19 @@ private: } template - const char* get_type_name_impl(size_t i) const { + std::string get_type_name_impl(size_t i) const { if constexpr (I == 0) { return ""; } else { if (i == I - 1) { - return typeid(std::tuple_element_t>).name(); + return ::impl::VariantTypeName>>::get(); } else { return get_type_name_impl(i); } } } - const char* get_type_name(size_t i) const { + std::string get_type_name(size_t i) const { return get_type_name_impl(i); } };