diff --git a/src/ifcparse/IfcHdf5File.cpp b/src/ifcparse/IfcHdf5File.cpp index 4f363db71b..63fb4be517 100644 --- a/src/ifcparse/IfcHdf5File.cpp +++ b/src/ifcparse/IfcHdf5File.cpp @@ -8,58 +8,704 @@ #pragma message("warning: HDF5 compression support is recommended") #endif -class UnmetDependencyException : public std::exception {}; +class type_mapper { +public: + type_mapper(IfcParse::IfcFile& ifc_file, H5::H5File* hdf5_file); -void visit(void* buffer, H5::DataType* dt) { - if (dt->getClass() == H5T_COMPOUND) { - H5::CompType* ct = (H5::CompType*) dt; - for (int i = 0; i < ct->getNmembers(); ++i) { - std::cerr << ct->getMemberName(i) << " "; - size_t offs = ct->getMemberOffset(i); - H5::DataType dt2 = ct->getMemberDataType(i); - visit((uint8_t*)buffer+offs, &dt2); - dt2.close(); + H5::DataType* commit(H5::DataType* dt, const std::string& name); + + H5::DataType* operator()(const IfcParse::parameter_type* pt); + H5::DataType* operator()(const IfcParse::select_type* pt); + H5::CompType* operator()(const IfcParse::entity* e); + H5::EnumType* operator()(const IfcParse::enumeration_type* en); + + void operator()(); + + std::pair make_select_leaf(const IfcParse::declaration* decl); + +private: + bool padded_; + bool referenced_; + IfcParse::Hdf5Settings settings_; + + IfcParse::IfcFile& ifc_file_; + H5::H5File* hdf5_file_; + H5::Group schema_group_; + H5::CompType* instance_reference_; + std::vector default_types_; + std::vector default_type_names_; + std::vector default_cpp_type_names_; + std::vector declared_types_; + + std::string flatten_aggregate_name(const IfcParse::parameter_type* at) const; +}; + +class enumeration_reference { +private: + size_t index_; +public: + explicit enumeration_reference(size_t index) + : index_(index) + {} + + operator size_t() const { + return index_; + } +}; + +class select_item { +private: + IfcUtil::IfcBaseClass* data_; +public: + explicit select_item(IfcUtil::IfcBaseClass* data) + : data_(data) + {} + + operator IfcUtil::IfcBaseClass*() const { + return data_; + } +}; + +template struct is_hdf5_integral { static const bool value = false; }; +template <> struct is_hdf5_integral { static const bool value = true; }; +template <> struct is_hdf5_integral { static const bool value = true; }; +template <> struct is_hdf5_integral { static const bool value = true; }; +template <> struct is_hdf5_integral { static const bool value = true; }; +template <> struct is_hdf5_integral { static const bool value = true; }; + +template struct hdf5_datatype_for{}; +template <> struct hdf5_datatype_for { static const H5T_class_t value = H5T_INTEGER; }; +// Booleans are enumerations in HDF5 as well! +template <> struct hdf5_datatype_for { static const H5T_class_t value = H5T_ENUM; }; +template <> struct hdf5_datatype_for { static const H5T_class_t value = H5T_FLOAT; }; +template <> struct hdf5_datatype_for { static const H5T_class_t value = H5T_FLOAT; }; +template <> struct hdf5_datatype_for { static const H5T_class_t value = H5T_ENUM; }; + +template struct uint_of_size {}; +template <> struct uint_of_size <1> { typedef uint8_t type; }; +template <> struct uint_of_size <2> { typedef uint16_t type; }; +template <> struct uint_of_size <4> { typedef uint32_t type; }; +template <> struct uint_of_size <8> { typedef uint64_t type; }; + +template struct int_of_size {}; +template <> struct int_of_size <1> { typedef int8_t type; }; +template <> struct int_of_size <2> { typedef int16_t type; }; +template <> struct int_of_size <4> { typedef int32_t type; }; +template <> struct int_of_size <8> { typedef int64_t type; }; + +template struct float_of_size {}; +template <> struct float_of_size <4> { typedef float type; }; +template <> struct float_of_size <8> { typedef double type; }; + +template struct number_of_size {}; +template struct number_of_size { typedef typename int_of_size::type type; }; +template struct number_of_size { typedef typename float_of_size::type type; }; +template struct number_of_size { typedef typename float_of_size::type type; }; + +std::pair compound_member_types_as_pair(H5::DataType& datatype) { + if (datatype.getClass() != H5T_COMPOUND) { + throw std::runtime_error("Expected a compound"); + } + + H5::CompType* compound = (H5::CompType*) &datatype; + + if (compound->getNmembers() != 2) { + throw std::runtime_error("Expected a compound with two members"); + } + + return std::make_pair( + compound->getMemberDataType(0).getClass(), + compound->getMemberDataType(1).getClass()); +} + +bool is_select(H5::DataType& datatype) { + if (datatype.getClass() != H5T_COMPOUND) { + return false; + } + + H5::CompType* compound = (H5::CompType*) &datatype; + + if (compound->getNmembers() < 1) { + return false; + } + + return compound->getMemberName(0) == "type_code"; +} + +void advance(void*& ptr, size_t n) { + ptr = (uint8_t*)ptr + n; +} + +template +void write(void*& ptr, const T& t) { + *((T*)ptr) = t; + advance(ptr, sizeof(T)); +} + +template <> +void write(void*& ptr, const std::string& s) { + // TFK: So we assume this is freed by h5 vlen reclaim? + char* c = new char[s.size() + 1]; + strcpy(c, s.c_str()); + write(ptr, c); +} + +template +void write_number_of_size(void*& ptr, size_t n, T i) { + void* old_ptr = ptr; + if (std::is_floating_point::value) { + if (n == 4) { + write(ptr, static_cast< float_of_size<4>::type > (i)); + } else if (n == 8) { + write(ptr, static_cast< float_of_size<8>::type > (i)); } - } else if (dt->getClass() == H5T_VLEN) { - hvl_t* ht = (hvl_t*) buffer; - H5::VarLenType* vt = (H5::VarLenType*) dt; - H5::DataType dt2 = vt->getSuper(); - for (int i = 0; i < ht->len; ++i) { - std::cerr << i << " "; - visit((uint8_t*)ht->p + i * vt->getSize(), &dt2); + } else if (std::numeric_limits::is_signed) { + if (n == 1) { + write(ptr, static_cast< int_of_size<1>::type > (i)); + } else if (n == 2) { + write(ptr, static_cast< int_of_size<2>::type > (i)); + } else if (n == 4) { + write(ptr, static_cast< int_of_size<4>::type > (i)); + } else if (n == 8) { + write(ptr, static_cast< int_of_size<8>::type > (i)); } - dt2.close(); - } else if (dt->getClass() == H5T_STRING) { - char* c = *(char**)buffer; - std::cerr << "'" << c << "'" << " "; + } else { + // NB: enumeration_reference also ends up here + if (n == 1) { + write(ptr, static_cast< uint_of_size<1>::type > (i)); + } else if (n == 2) { + write(ptr, static_cast< uint_of_size<2>::type > (i)); + } else if (n == 4) { + write(ptr, static_cast< uint_of_size<4>::type > (i)); + } else if (n == 8) { + write(ptr, static_cast< uint_of_size<8>::type > (i)); + } + } + if (old_ptr == ptr) { + throw std::runtime_error("No value written"); } } -H5::DataType* IfcParse::IfcHdf5File::map_type(const IfcParse::parameter_type* pt) { - H5::DataType* h5_dt; - if (pt->as_aggregation_type()) { - h5_dt = new H5::VarLenType(map_type(pt->as_aggregation_type()->type_of_element())); - } else if (pt->as_named_type()) { - if (pt->as_named_type()->declared_type()->as_entity()) { - h5_dt = new H5::DataType(); - h5_dt->copy(*instance_reference); - } else { - IfcSchema::Type::Enum ty = pt->as_named_type()->declared_type()->type(); - if (declared_types.find(ty) == declared_types.end()) { - throw UnmetDependencyException(); - } else { - h5_dt = new H5::DataType(); - h5_dt->copy(*declared_types[ty]); - } +void write_string_of_size(void*& ptr, size_t n, const std::string& s) { + memset(ptr, 0, n); + memcpy(ptr, s.c_str(), s.size()); + advance(ptr, n); +} + +void write_vlen_t(void*& ptr, size_t n_elements, void* vlen_data) { + advance(ptr, HOFFSET(hvl_t, len)); + void* temp_ptr; + write_number_of_size(temp_ptr = ptr, sizeof(size_t), n_elements); + advance(ptr, HOFFSET(hvl_t, p)); + write(ptr, vlen_data); +} + +#define CAST_AND_CALL(attr, type, fn) {IfcUtil::attr_type_to_cpp_type::cpp_type v = *attr; fn(v);} +#define CHECK_CAST_AND_CALL(ty) else if (attr_->type() == ty) CAST_AND_CALL(attr_, ty, t) + +class apply_attribute_visitor { +private: + Argument* attr_; + const IfcParse::entity::attribute* schema_attr_; +public: + apply_attribute_visitor(Argument* attr, const IfcParse::entity::attribute* schema_attr) + : attr_(attr) + , schema_attr_(schema_attr) + {} + + template + typename T::return_type apply(T& t) const { + if (attr_->type() == IfcUtil::Argument_NULL) { + t(boost::none); + } else if (attr_->type() == IfcUtil::Argument_DERIVED) { + throw std::runtime_error("Derived attributes should not be written to the file"); + // IfcWrite::IfcWriteArgument::Derived d; + // t(d); + } + CHECK_CAST_AND_CALL(IfcUtil::Argument_INT) + CHECK_CAST_AND_CALL(IfcUtil::Argument_BOOL) + CHECK_CAST_AND_CALL(IfcUtil::Argument_DOUBLE) + CHECK_CAST_AND_CALL(IfcUtil::Argument_STRING) + else if (attr_->type() == IfcUtil::Argument_BINARY) { + throw std::runtime_error("Binary not supported at the moment"); + } + else if (attr_->type() == IfcUtil::Argument_ENUMERATION) { + std::string v = *attr_; + const std::vector& enum_values = schema_attr_->type_of_attribute()->as_named_type()->declared_type()->as_enumeration_type()->enumeration_items(); + size_t d = std::distance(enum_values.begin(), std::find(enum_values.begin(), enum_values.end(), v)); + enumeration_reference enum_ref(d); + t(enum_ref); + } + CHECK_CAST_AND_CALL(IfcUtil::Argument_ENTITY_INSTANCE) + + CHECK_CAST_AND_CALL(IfcUtil::Argument_AGGREGATE_OF_INT) + CHECK_CAST_AND_CALL(IfcUtil::Argument_AGGREGATE_OF_BOOL) + CHECK_CAST_AND_CALL(IfcUtil::Argument_AGGREGATE_OF_DOUBLE) + CHECK_CAST_AND_CALL(IfcUtil::Argument_AGGREGATE_OF_STRING) + else if (attr_->type() == IfcUtil::Argument_AGGREGATE_OF_BINARY) { + throw std::runtime_error("Not supported currently"); + } + else if (attr_->type() == IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE) { + IfcUtil::attr_type_to_cpp_type::cpp_type v = *attr_; + std::vector vec(v->begin(), v->end()); + t(vec); + } + + CHECK_CAST_AND_CALL(IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_INT) + CHECK_CAST_AND_CALL(IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_BOOL) + CHECK_CAST_AND_CALL(IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE) + else if (attr_->type() == IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_ENTITY_INSTANCE) { + IfcUtil::attr_type_to_cpp_type::cpp_type v = *attr_; + std::vector< std::vector > vec(v->begin(), v->end()); + t(vec); + } + + else if (attr_->type() == IfcUtil::Argument_UNKNOWN) { + auto aggregation = schema_attr_->type_of_attribute()->as_aggregation_type(); + if (aggregation == nullptr) { + throw std::exception("Attribute of unknown type encountered, expected empty aggregate"); + } + auto elem_type = aggregation->type_of_element(); + if (elem_type->as_named_type()) { + auto entity = elem_type->as_named_type()->declared_type()->as_entity(); + if (entity == nullptr) { + throw std::exception("Not implemented"); + } + std::vector empty; + t(empty); + } else if (elem_type->as_simple_type()) { + auto dt = elem_type->as_simple_type()->declared_type(); + if (dt == IfcParse::simple_type::integer_type) { + std::vector empty; + t(empty); + } else { + throw std::exception("Not implemented"); + } + } else { + throw std::exception("Not implemented"); + } + } + } +}; + +class sorted_instance_locator { +private: + IfcParse::IfcFile& file_; + std::vector< IfcSchema::Type::Enum > dataset_names_; + std::vector< std::vector* > cache_; + +public: + sorted_instance_locator(IfcParse::IfcFile& file) + : file_(file) + { + std::set dataset_names_temp; + for (auto it = file_.begin(); it != file_.end(); ++it) { + dataset_names_temp.insert(it->second->declaration().type()); + } + dataset_names_.assign(dataset_names_temp.begin(), dataset_names_temp.end()); + std::sort(dataset_names_.begin(), dataset_names_.end()); + + cache_.resize(IfcSchema::Type::UNDEFINED); + } + + std::pair operator()(IfcUtil::IfcBaseClass* v) { + if (IfcSchema::Type::IsSimple(v->declaration().type())) { + throw std::exception("Simple type not expected here"); + } + + IfcSchema::Type::Enum t = v->declaration().type(); + auto tt = std::lower_bound(dataset_names_.begin(), dataset_names_.end(), t); + int a = std::distance(dataset_names_.begin(), tt); + int b; + + if (cache_[t] == nullptr) { + auto li = file_.entitiesByType(t); + std::vector* vs = cache_[t] = new std::vector(); + vs->reserve(li->size()); + + for (auto jt = li->begin(); jt != li->end(); ++jt) { + if ((*jt)->declaration().type() == t) { + vs->push_back(static_cast(*jt)); + } + } + + std::sort(vs->begin(), vs->end(), [](IfcUtil::IfcBaseEntity* i1, IfcUtil::IfcBaseEntity* i2) { + return i1->data().id() < i2->data().id(); + }); + } + + auto it = std::lower_bound(cache_[t]->begin(), cache_[t]->end(), v); + b = std::distance(cache_[t]->begin(), it); + + return std::make_pair(a, b); + } +}; + +class pointer_increment_assert { + void*& ptr_reference_; + uint8_t* ptr_initial_; + size_t datatype_size_; +public: + pointer_increment_assert(void*& ptr_reference, size_t datatype_size) + : ptr_reference_(ptr_reference) + , ptr_initial_(static_cast(ptr_reference)) + , datatype_size_(datatype_size) + {} + + ~pointer_increment_assert() noexcept(false) { + if (ptr_initial_ + datatype_size_ != ptr_reference_) { + throw std::runtime_error("Incorrect amount of bytes written"); + } + } +}; + +// template +class write_visit { +private: + bool padded_; + bool referenced_; + type_mapper& type_mapper_; + +public: + typedef sorted_instance_locator locator_type; + + locator_type& instance_locator_; + + write_visit(bool padded, bool referenced, locator_type& instance_locator, type_mapper& type_mapper) + : padded_(padded) + , referenced_(referenced) + , instance_locator_(instance_locator) + , type_mapper_(type_mapper) + {} + + template ::value, T>::type* = nullptr> + void visit(void*& ptr, H5::DataType& datatype, T& v) { + if (datatype.getClass() != hdf5_datatype_for::value) { + throw std::runtime_error("Datatype and value do not match"); + } + write_number_of_size(ptr, datatype.getSize(), v); + } + + void visit(void*& ptr, H5::DataType& datatype, const boost::none_t&) { + // TODO: Do we need to do sth based on datatype here, eg. allocate vlen/char* if necessary? + memset(ptr, 0, datatype.getSize()); + advance(ptr, datatype.getSize()); + } + + // template <> + void visit(void*& ptr, H5::DataType& datatype, std::string& v) { + pointer_increment_assert _(ptr, datatype.getSize()); + if (padded_) { + if (compound_member_types_as_pair(datatype) != std::make_pair(H5T_INTEGER, H5T_STRING)) { + throw std::runtime_error("Datatype and value do not match"); + } + + H5::CompType* compound = (H5::CompType*) &datatype; + H5::IntType int_type = compound->getMemberIntType(0); + H5::StrType string_type = compound->getMemberStrType(1); + + if (string_type.getSize() < v.size()) { + throw std::runtime_error("Not enough space reserved for string"); + } + + write_number_of_size(ptr, int_type.getSize(), v.size()); + write_string_of_size(ptr, string_type.getSize(), v); + } else { + if (datatype.getClass() != H5T_STRING) { + throw std::runtime_error("Datatype and value do not match"); + } + + H5::StrType* string_type = (H5::StrType*) &datatype; + + // TFK: Check whether this does not leak resources + if (*string_type == H5::StrType(H5::PredType::C_S1, H5T_VARIABLE)) { + write(ptr, v); + } else { + if (string_type->getSize() < v.size()) { + throw std::runtime_error("Not enough space reserved for string"); + } + write_string_of_size(ptr, string_type->getSize(), v); + } + } + } + + void visit(void*& ptr, H5::DataType& datatype, select_item& v); + + void visit(void*& ptr, H5::DataType& datatype, IfcUtil::IfcBaseClass*& v) { + + // This does not seem to help + // if (datatype.committed()) { + // std::cout << datatype.getObjName(); + // } + + if (is_select(datatype)) { + select_item si(v); + return visit(ptr, datatype, si); + } + + pointer_increment_assert _(ptr, datatype.getSize()); + + if (referenced_) { + if (datatype.getClass() != H5T_REFERENCE) { + throw std::runtime_error("Datatype and value do not match"); + } + } else { + if (datatype.getClass() != H5T_COMPOUND) { + throw std::runtime_error("Datatype and value do not match"); + } + + if (compound_member_types_as_pair(datatype) != std::make_pair(H5T_INTEGER, H5T_INTEGER)) { + throw std::runtime_error("Datatype and value do not match"); + } + + H5::CompType* compound = (H5::CompType*) &datatype; + H5::IntType ds_idx = compound->getMemberIntType(0); + H5::IntType ds_row = compound->getMemberIntType(1); + + std::pair ref = instance_locator_(v); + + write_number_of_size(ptr, ds_idx.getSize(), ref.first); + write_number_of_size(ptr, ds_row.getSize(), ref.second); + } + } + + template + void visit(void*& ptr, H5::DataType& datatype, std::vector& v) { + pointer_increment_assert _(ptr, datatype.getSize()); + if (padded_) { + if (datatype.getClass() != H5T_COMPOUND) { + throw std::runtime_error("Datatype and value do not match"); + } + + if (compound_member_types_as_pair(datatype) != std::make_pair(H5T_INTEGER, H5T_ARRAY)) { + throw std::runtime_error("Datatype and value do not match"); + } + + H5::CompType* compound = (H5::CompType*) &datatype; + H5::IntType size_dt = compound->getMemberIntType(0); + H5::ArrayType array_dt = compound->getMemberArrayType(1); + + write_number_of_size(ptr, size_dt.getSize(), v.size()); + + // TFK: Enable multi-dimensional arrays for LISTS of LISTS as well. + if (array_dt.getArrayNDims() != 1) { + throw std::runtime_error("Unexpected array dimensions"); + } + + hsize_t n; + array_dt.getArrayDims(&n); + H5::DataType elem_dt = array_dt.getSuper(); + + for (size_t i = 0; i < n; ++i) { + if (i < v.size()) { + // I only get this to work if I make a copy. + // cannot convert from 'std::_Vb_reference>>' to 'const boost::none_t' :( + T t = v[i]; + visit(ptr, elem_dt, t); + } else { + // TODO: Figure this out. + // visit(ptr, elem_dt, T()); + } + } + } else { + if (datatype.getClass() != H5T_VLEN) { + throw std::runtime_error("Datatype and value do not match"); + } + + H5::VarLenType* vlen = (H5::VarLenType*) &datatype; + H5::DataType elem_dt = vlen->getSuper(); + + void* vlen_data = new uint8_t[elem_dt.getSize() * v.size()]; + void* temp = vlen_data; + for (size_t i = 0; i < v.size(); ++i) { + T t = v[i]; + visit(temp, elem_dt, t); + } + + write_vlen_t(ptr, v.size(), vlen_data); + } + } + +}; + +// template +class write_visit_instance_attribute { +private: + void*& ptr_; + write_visit& fn_; + H5::DataType& dt_; + +public: + typedef void return_type; + + write_visit_instance_attribute(void*& ptr, write_visit& fn, H5::DataType& dt) + : ptr_(ptr) + , fn_(fn) + , dt_(dt) + {} + + template + void operator()(T& t) { + fn_.visit(ptr_, dt_, t); + } +}; + +static const std::string Entity_Instance_Identifier = "Entity-Instance-Identifier"; +static const std::string set_unset_bitmap = "set_unset_bitmap"; + +template +void IfcParse::IfcHdf5File::write_instance(void*& ptr, T& visitor, H5::DataType& datatype, IfcUtil::IfcBaseEntity* v) { + pointer_increment_assert _(ptr, datatype.getSize()); + + if (datatype.getClass() != H5T_COMPOUND) { + throw std::runtime_error("Datatype and value do not match"); + } + + H5::CompType* compound = (H5::CompType*) &datatype; + + auto attributes = v->declaration().all_attributes(); + // TFK: Creating copies + // TFK: Do this once for every entity + std::vector attribute_names; + attribute_names.reserve(attributes.size()); + + std::transform(attributes.begin(), attributes.end(), + std::back_inserter(attribute_names), + [](const IfcParse::entity::attribute* attr) { + return attr->name(); + }); + + void* set_unset_bitmap_location = 0; + uint32_t set_unset_bitmap_value = 0; + size_t set_unset_bitmap_size = 0; + + for (int i = 0; i < compound->getNmembers(); ++i) { + const std::string name = compound->getMemberName(i); + H5::DataType attr_type = compound->getMemberDataType(i); + + if (name == Entity_Instance_Identifier) { + write_number_of_size(ptr, attr_type.getSize(), v->data().id()); + continue; + } else if (name == set_unset_bitmap) { + set_unset_bitmap_location = ptr; + set_unset_bitmap_size = attr_type.getSize(); + advance(ptr, set_unset_bitmap_size); + continue; + } + + auto it = std::find(attribute_names.begin(), attribute_names.end(), name); + if (it == attribute_names.end()) { + throw std::runtime_error("Unexpected compound member"); + } + int idx = std::distance(attribute_names.begin(), it); + + Argument* attr = v->data().getArgument(idx); + if (!attr->isNull()) { + // TODO: This is now index in IFC-attributes list, specify + set_unset_bitmap_value |= (1 << idx); + } + write_visit_instance_attribute/**/ attribute_visitor(ptr, visitor, attr_type); + apply_attribute_visitor(attr, attributes[idx]).apply(attribute_visitor); + } + + if (set_unset_bitmap_size && set_unset_bitmap_location) { + write_number_of_size(set_unset_bitmap_location, set_unset_bitmap_size, set_unset_bitmap_value); + } +} + +class default_value_visitor { +private: + H5::DataType& datatype_; + +public: + default_value_visitor(H5::DataType& datatype) + : datatype_(datatype) + {} + + void operator()(void*& ptr) { + switch (datatype_.getClass()) { + case H5T_INTEGER: + write_number_of_size(ptr, datatype_.getSize(), 0); + break; + case H5T_FLOAT: + write_number_of_size(ptr, datatype_.getSize(), 0.); + break; + case H5T_STRING: + if (datatype_ == H5::StrType(H5::PredType::C_S1, H5T_VARIABLE)) { + write(ptr, new char(0)); + } else { + write_string_of_size(ptr, datatype_.getSize(), ""); + } + break; + case H5T_COMPOUND: + { + H5::CompType* compound = (H5::CompType*) &datatype_; + for (int i = 0; i < compound->getNmembers(); ++i) { + H5::DataType attr_type = compound->getMemberDataType(i); + default_value_visitor visitor(attr_type); + visitor(ptr); + } + break; + } + case H5T_REFERENCE: + throw std::runtime_error("Not implemented"); + break; + case H5T_ENUM: + write_number_of_size(ptr, datatype_.getSize(), 0); + break; + case H5T_VLEN: + { + // H5::VarLenType* vlen = (H5::VarLenType*) &datatype_; + // Does this work? + write_vlen_t(ptr, 0, nullptr); + break; + } + case H5T_ARRAY: + { + H5::ArrayType* arr = (H5::ArrayType*) &datatype_; + size_t ndims = arr->getArrayNDims(); + hsize_t* array_dims = new hsize_t[ndims]; + arr->getArrayDims(array_dims); + if (ndims != 1) { + throw std::runtime_error("Not implemented"); + } + H5::DataType super = arr->getSuper(); + default_value_visitor visitor(super); + for (hsize_t i = 0; i < array_dims[0]; ++i) { + visitor(ptr); + } + break; + } + default: + throw std::runtime_error("Unexpected type encountered"); + } + } +}; + +void write_visit::visit(void*& ptr, H5::DataType& datatype, select_item& v) { + pointer_increment_assert _(ptr, datatype.getSize()); + + IfcUtil::IfcBaseClass* data = v; + + H5::CompType* compound = (H5::CompType*) &datatype; + const bool data_is_entity = !!data->declaration().as_entity(); + + for (int i = 0; i < compound->getNmembers(); ++i) { + const std::string name = compound->getMemberName(i); + H5::DataType attr_type = compound->getMemberDataType(i); + + if (name == "type_code") { + write_number_of_size(ptr, attr_type.getSize(), data->declaration().type()); + } else if (data_is_entity && name == "instance-value") { + visit(ptr, attr_type, data); + } else if (type_mapper_.make_select_leaf(&data->declaration()).first == name) { + write_visit_instance_attribute/**/ attribute_visitor(ptr, *this, attr_type); + apply_attribute_visitor(data->data().getArgument(0), 0).apply(attribute_visitor); + } else { + default_value_visitor visitor(attr_type); + visitor(ptr); } - } else if (pt->as_simple_type()) { - const H5::DataType* orig = default_types[pt->as_simple_type()->declared_type()]; - h5_dt = new H5::DataType(); - h5_dt->copy(*orig); - } else { - throw UnmetDependencyException(); } - return h5_dt; } H5::CompType* create_compound(const std::vector< IfcParse::IfcHdf5File::compound_member >& members) { @@ -82,7 +728,7 @@ H5::EnumType* create_enumeration(const std::vector& items, int offs size_t size = items.size(); while (size != 0) { size >>= 8; - numbytes ++; + numbytes++; } int i = offset; @@ -94,119 +740,7 @@ H5::EnumType* create_enumeration(const std::vector& items, int offs return h5_enum; } -H5::EnumType* map_enumeration(const IfcParse::enumeration_type* en) { - return create_enumeration(en->enumeration_items()); -} - -H5::DataType* IfcParse::IfcHdf5File::commit(H5::DataType* dt, const std::string& name) { - dt->commit(schema_group, name); - return dt; -} - -H5::CompType* IfcParse::IfcHdf5File::map_entity(const IfcParse::entity* e) { - std::vector attributes = e->all_attributes(); - std::vector inverse_attributes; - if (settings_.instantiate_inverse()) { - inverse_attributes = e->all_inverse_attributes(); - } - - std::vector< IfcParse::IfcHdf5File::compound_member > h5_attributes; - h5_attributes.reserve(attributes.size() + inverse_attributes.size() + 2); - - h5_attributes.push_back(std::make_pair(std::string("set_unset_bitmap"), &H5::PredType::NATIVE_INT16)); - h5_attributes.push_back(std::make_pair(std::string("Entity-Instance-Identifier"), &H5::PredType::NATIVE_INT32)); - - const std::vector& attributes_derived_in_subtype = e->derived(); - auto jt = attributes_derived_in_subtype.begin(); - - for (auto it = attributes.begin(); it != attributes.end(); ++it, ++jt) { - if (*jt) { - continue; - } - const std::string& name = (*it)->name(); - const bool is_optional = (*it)->optional(); - const H5::DataType* type; - const std::string qualified_attr_name = e->name() + "." + name; - if (std::binary_search(settings_.ref_attributes().begin(), settings_.ref_attributes().end(), qualified_attr_name)) { - type = new H5::PredType(H5::PredType::STD_REF_OBJ); - } else if (overridden_types.find(qualified_attr_name) != overridden_types.end()) { - type = overridden_types.find(qualified_attr_name)->second; - } else if (overridden_types.find("*." + name) != overridden_types.end()) { - type = overridden_types.find("*." + name)->second; - } else { - type = map_type((*it)->type_of_attribute()); - } - h5_attributes.push_back(std::make_pair(name, type)); - } - - if (settings_.instantiate_inverse()) { - for (auto it = inverse_attributes.begin(); it != inverse_attributes.end(); ++it) { - const std::string& name = (*it)->name(); - H5::DataType* ir_copy = new H5::DataType(); - ir_copy->copy(*instance_reference); - const H5::DataType* type = new H5::VarLenType(ir_copy); - h5_attributes.push_back(std::make_pair(name, type)); - } - } - - return create_compound(h5_attributes); -} - -void IfcParse::IfcHdf5File::init_default_types() { - { - std::vector< compound_member > members; - members.push_back( std::make_pair(std::string("_HDF5_dataset_index_"), new H5::PredType(H5::PredType::NATIVE_INT16)) ); - members.push_back( std::make_pair(std::string("_HDF5_instance_index_"), new H5::PredType(H5::PredType::NATIVE_INT32)) ); - instance_reference = static_cast(commit(create_compound(members), "_HDF_INSTANCE_REFERENCE_HANDLE_")); - } - - object_reference_type = &H5::PredType::STD_REF_OBJ; - - { - std::vector names; - names.push_back("BOOLEAN-FALSE"); - names.push_back("BOOLEAN-TRUE"); - default_types[simple_type::boolean_type] = create_enumeration(names); - } - - { - std::vector names; - names.push_back("LOGICAL-UNKNOWN"); - names.push_back("LOGICAL-FALSE"); - names.push_back("LOGICAL-TRUE"); - default_types[simple_type::logical_type] = create_enumeration(names, -1); - } - - default_types[simple_type::binary_type] = &H5::PredType::NATIVE_OPAQUE; // vlen? - default_types[simple_type::real_type] = &H5::PredType::NATIVE_DOUBLE; - default_types[simple_type::number_type] = &H5::PredType::NATIVE_DOUBLE; - default_types[simple_type::string_type] = new H5::StrType(H5::PredType::C_S1, H5T_VARIABLE); - default_types[simple_type::integer_type] = &H5::PredType::NATIVE_INT; - - default_type_names[simple_type::logical_type] = "logical"; - default_type_names[simple_type::boolean_type] = "boolean"; - default_type_names[simple_type::binary_type] = "binary"; - default_type_names[simple_type::real_type] = "real"; - default_type_names[simple_type::number_type] = "number"; - default_type_names[simple_type::string_type] = "string"; - default_type_names[simple_type::integer_type] = "integer"; - - default_cpp_type_names[IfcUtil::Argument_BOOL] = "boolean"; - default_cpp_type_names[IfcUtil::Argument_DOUBLE] = "real"; - default_cpp_type_names[IfcUtil::Argument_STRING] = "string"; - default_cpp_type_names[IfcUtil::Argument_INT] = "integer"; - - if (settings_.fix_global_id()) { - overridden_types["*.GlobalId"] = new H5::StrType(H5::PredType::C_S1, 22); - } - if (settings_.fix_cartesian_point()) { - hsize_t dims = 3; - overridden_types["IfcCartesianPoint.Coordinates"] = new H5::ArrayType(*default_types[simple_type::real_type], 1, &dims); - overridden_types["IfcDirection.DirectionRatios"] = new H5::ArrayType(*default_types[simple_type::real_type], 1, &dims); - } -} - -void IfcParse::IfcHdf5File::visit_select(const IfcParse::select_type* pt, std::set& leafs) { +void visit_select(const IfcParse::select_type* pt, std::set& leafs) { for (auto it = pt->select_list().begin(); it != pt->select_list().end(); ++it) { if ((*it)->as_select_type()) { visit_select((*it)->as_select_type(), leafs); @@ -216,11 +750,13 @@ void IfcParse::IfcHdf5File::visit_select(const IfcParse::select_type* pt, std::s } } -std::string IfcParse::IfcHdf5File::flatten_aggregate_name(const IfcParse::parameter_type* at) const { +class UnmetDependencyException : public std::exception {}; + +std::string type_mapper::flatten_aggregate_name(const IfcParse::parameter_type* at) const { if (at->as_aggregation_type()) { return std::string("aggregate-of-") + flatten_aggregate_name(at->as_aggregation_type()->type_of_element()); } else if (at->as_simple_type()) { - return default_type_names.find(at->as_simple_type()->declared_type())->second; + return default_type_names_[at->as_simple_type()->declared_type()]; } else if (at->as_named_type()) { // TODO: Unwind type name return at->as_named_type()->declared_type()->name(); @@ -229,9 +765,147 @@ std::string IfcParse::IfcHdf5File::flatten_aggregate_name(const IfcParse::parame } } -H5::DataType* IfcParse::IfcHdf5File::map_select(const IfcParse::select_type* pt) { - if (settings_.instantiate_select()) return 0; +type_mapper::type_mapper(IfcParse::IfcFile& ifc_file, H5::H5File* hdf5_file) + : ifc_file_(ifc_file) + , hdf5_file_(hdf5_file) + // TODO: Configure + , padded_(false) + , referenced_(false) +{ + schema_group_ = hdf5_file_->openGroup(ifc_file_.schema()->name() + "_encoding"); + default_types_.resize(IfcParse::simple_type::datatype_COUNT); + default_type_names_.resize(IfcParse::simple_type::datatype_COUNT); + default_cpp_type_names_.resize(IfcUtil::Argument_UNKNOWN); + declared_types_.resize(IfcSchema::Type::UNDEFINED); + + { + std::vector< IfcParse::IfcHdf5File::compound_member > members; + members.push_back(std::make_pair(std::string("_HDF5_dataset_index_"), new H5::PredType(H5::PredType::NATIVE_INT16))); + members.push_back(std::make_pair(std::string("_HDF5_instance_index_"), new H5::PredType(H5::PredType::NATIVE_INT32))); + instance_reference_ = static_cast(commit(create_compound(members), "_HDF_INSTANCE_REFERENCE_HANDLE_")); + } + + { + std::vector names; + names.push_back("BOOLEAN-FALSE"); + names.push_back("BOOLEAN-TRUE"); + default_types_[IfcParse::simple_type::boolean_type] = create_enumeration(names); + } + + { + std::vector names; + names.push_back("LOGICAL-UNKNOWN"); + names.push_back("LOGICAL-FALSE"); + names.push_back("LOGICAL-TRUE"); + default_types_[IfcParse::simple_type::logical_type] = create_enumeration(names, -1); + } + + default_types_[IfcParse::simple_type::binary_type] = &H5::PredType::NATIVE_OPAQUE; // vlen? + default_types_[IfcParse::simple_type::real_type] = &H5::PredType::NATIVE_DOUBLE; + default_types_[IfcParse::simple_type::number_type] = &H5::PredType::NATIVE_DOUBLE; + default_types_[IfcParse::simple_type::string_type] = new H5::StrType(H5::PredType::C_S1, H5T_VARIABLE); + default_types_[IfcParse::simple_type::integer_type] = &H5::PredType::NATIVE_INT; + + default_type_names_[IfcParse::simple_type::logical_type] = "logical"; + default_type_names_[IfcParse::simple_type::boolean_type] = "boolean"; + default_type_names_[IfcParse::simple_type::binary_type] = "binary"; + default_type_names_[IfcParse::simple_type::real_type] = "real"; + default_type_names_[IfcParse::simple_type::number_type] = "number"; + default_type_names_[IfcParse::simple_type::string_type] = "string"; + default_type_names_[IfcParse::simple_type::integer_type] = "integer"; + + default_cpp_type_names_[IfcUtil::Argument_BOOL] = "boolean"; + default_cpp_type_names_[IfcUtil::Argument_DOUBLE] = "real"; + default_cpp_type_names_[IfcUtil::Argument_STRING] = "string"; + default_cpp_type_names_[IfcUtil::Argument_INT] = "integer"; +} + +H5::DataType* type_mapper::commit(H5::DataType* dt, const std::string& name) { + dt->commit(schema_group_, name); + return dt; +} + +H5::DataType* type_mapper::operator()(const IfcParse::parameter_type* pt) { + H5::DataType* h5_dt; + if (pt->as_aggregation_type()) { + if (padded_) { + // TODO: Determine dimensions + // TODO: Check whether these pointers can safely be dereferenced + hsize_t dims = 1; + h5_dt = new H5::ArrayType(*(*this)(pt->as_aggregation_type()->type_of_element()), 1, &dims); + } else { + h5_dt = new H5::VarLenType((*this)(pt->as_aggregation_type()->type_of_element())); + } + } else if (pt->as_named_type()) { + if (pt->as_named_type()->declared_type()->as_entity()) { + return instance_reference_; + // TFK: Do not copy, we want to retain path to simplify datatype identify checks later on + // h5_dt = new H5::DataType(); + // h5_dt->copy(*instance_reference_); + } else { + IfcSchema::Type::Enum ty = pt->as_named_type()->declared_type()->type(); + if (!declared_types_[ty]) { + throw UnmetDependencyException(); + } else { + // TFK: Copy, as well be committed under different name? + h5_dt = new H5::DataType(); + h5_dt->copy(*declared_types_[ty]); + } + } + } else if (pt->as_simple_type()) { + const H5::DataType* orig = default_types_[pt->as_simple_type()->declared_type()]; + h5_dt = new H5::DataType(); + h5_dt->copy(*orig); + } else { + throw UnmetDependencyException(); + } + + return h5_dt; +} + +std::pair type_mapper::make_select_leaf(const IfcParse::declaration* decl) { + std::string name; + const H5::DataType* dt = 0; + + if (decl) { + while (decl->as_type_declaration()) { + const IfcParse::parameter_type* leaf_pt = decl->as_type_declaration()->declared_type(); + const IfcParse::named_type* nt = leaf_pt->as_named_type(); + const IfcParse::simple_type* st = leaf_pt->as_simple_type(); + const IfcParse::aggregation_type* at = leaf_pt->as_aggregation_type(); + if (nt) { + decl = nt->declared_type(); + } else if (st) { + name = default_type_names_[st->declared_type()]; + dt = default_types_[st->declared_type()]; + break; + } else if (at) { + name = flatten_aggregate_name(at); + dt = (*this)(at); + break; + } + } + } + + if (!dt) { + if (decl->as_entity()) { + name = "instance"; + dt = instance_reference_; + } else if (decl->as_enumeration_type()) { + name = decl->name(); + dt = declared_types_[decl->type()]; + } else { + throw; + } + } + + name += "-value"; + + return std::make_pair(name, dt); +} + +H5::DataType* type_mapper::operator()(const IfcParse::select_type* pt) { std::set leafs; visit_select(pt, leafs); @@ -247,72 +921,390 @@ H5::DataType* IfcParse::IfcHdf5File::map_select(const IfcParse::select_type* pt) return 0; } else { std::set member_names; - std::vector h5_attributes; - - h5_attributes.push_back(std::make_pair(std::string("select_bitmap"), &H5::PredType::NATIVE_INT8)); - h5_attributes.push_back(std::make_pair(std::string("type_path"), default_types[simple_type::string_type])); + std::vector h5_attributes; + + h5_attributes.push_back(std::make_pair(std::string("type_code"), &H5::PredType::NATIVE_INT16)); for (auto it = leafs.begin(); it != leafs.end(); ++it) { - std::string name; - const H5::DataType* dt = 0; - const IfcParse::declaration* decl = (*it); + auto leaf_type = make_select_leaf(decl); - if ((*it)->as_type_declaration()) { - while (decl->as_type_declaration()) { - const IfcParse::parameter_type* pt = decl->as_type_declaration()->declared_type(); - const IfcParse::named_type* nt = pt->as_named_type(); - const IfcParse::simple_type* st = pt->as_simple_type(); - const IfcParse::aggregation_type* at = pt->as_aggregation_type(); - if (nt) { - decl = nt->declared_type(); - } else if (st) { - name = default_type_names[st->declared_type()]; - dt = default_types[st->declared_type()]; - break; - } else if (at) { - name = flatten_aggregate_name(at); - dt = map_type(at); - break; - } - } - } - - if (!dt) { - if ((*it)->as_entity()) { - name = "instance"; - dt = instance_reference; - } else if ((*it)->as_enumeration_type()) { - name = (*it)->name(); - dt = declared_types[(*it)->type()]; - } else { - throw; - } - } - - if (member_names.find(name) != member_names.end()) { + if (member_names.find(leaf_type.first) != member_names.end()) { continue; } - member_names.insert(name); + member_names.insert(leaf_type.first); - name += "-value"; - h5_attributes.push_back(std::make_pair(name, dt)); + h5_attributes.push_back(leaf_type); } return create_compound(h5_attributes); } } -void IfcParse::IfcHdf5File::advance(void*& ptr, size_t n) const { - ptr = ( uint8_t*) ptr + n; +H5::CompType* type_mapper::operator()(const IfcParse::entity* e) { + + // List of entity instances of this type, no subtypes + IfcEntityList::ptr incl_subtypes = ifc_file_.entitiesByType(e->name()); + IfcEntityList::ptr instances(new IfcEntityList); + if (incl_subtypes) { + for (auto it = incl_subtypes->begin(); it != incl_subtypes->end(); ++it) { + if ((**it).declaration().type() == e->type()) { + instances->push(*it); + } + } + } + + if (instances->size() == 0) { + return 0; + } + + std::vector attributes = e->all_attributes(); + std::vector inverse_attributes; + if (settings_.instantiate_inverse()) { + inverse_attributes = e->all_inverse_attributes(); + } + + const std::vector& attributes_derived_in_subtype = e->derived(); + + bool has_optional_attributes = false; + const size_t num_extra = has_optional_attributes ? 2 : 1; + // size_t num_all_null = 0; + std::vector attributes_all_null(attributes.size(), false); + + auto jt = attributes_derived_in_subtype.begin(); + for (auto it = attributes.begin(); it != attributes.end(); ++it, ++jt) { + if (*jt) { + continue; + } + if ((**it).optional()) { + const int idx = std::distance(attributes.begin(), it); + + has_optional_attributes = true; + + /* + apply_attribute_visitor_instance_list dispatch(instances, idx); + all_null_visitor visitor; + dispatch.apply(visitor); + if (visitor.all_null()) { + num_all_null += 1; + attributes_all_null[idx] = true; + attributes_omitted.insert(std::make_pair(e->name(), idx)); + } + */ + } + } + + /* + if (has_optional_attributes) { + entities_with_optional_attrs.insert(e->name()); + } + */ + + std::vector< IfcParse::IfcHdf5File::compound_member > h5_attributes; + h5_attributes.reserve(attributes.size() + inverse_attributes.size() + num_extra); + + if (has_optional_attributes) { + h5_attributes.push_back(std::make_pair(std::string("set_unset_bitmap"), &H5::PredType::NATIVE_INT16)); + } + h5_attributes.push_back(std::make_pair(std::string("Entity-Instance-Identifier"), &H5::PredType::NATIVE_INT32)); + + jt = attributes_derived_in_subtype.begin(); + for (auto it = attributes.begin(); it != attributes.end(); ++it, ++jt) { + if (*jt) { + continue; + } + + const int idx = std::distance(attributes.begin(), it); + + if (attributes_all_null[idx]) { + continue; + } + + const std::string& name = (*it)->name(); + if (name == "InnerCurves") { + std::cerr << 1; + } + const bool is_optional = (*it)->optional(); + const H5::DataType* type; + const std::string qualified_attr_name = e->name() + "." + name; + if (std::binary_search(settings_.ref_attributes().begin(), settings_.ref_attributes().end(), qualified_attr_name)) { + type = new H5::PredType(H5::PredType::STD_REF_OBJ); + // } else if (overridden_types.find(qualified_attr_name) != overridden_types.end()) { + // type = overridden_types.find(qualified_attr_name)->second; + // } else if (overridden_types.find("*." + name) != overridden_types.end()) { + // type = overridden_types.find("*." + name)->second; + } else { + type = (*this)((*it)->type_of_attribute()); + } + + /* + apply_attribute_visitor_instance_list dispatch(instances, idx); + max_length_visitor visitor; + dispatch.apply(visitor); + if (visitor) { + type = specify_length(type, visitor.max_length()); + } + */ + + // TODO: Re-evaluate + // if (false && visitor && visitor.max_length()[0] == 0) { + // attributes_omitted.insert(std::make_pair(e->name(), idx)); + // } else { + h5_attributes.push_back(std::make_pair(name, type)); + // } + } + + if (settings_.instantiate_inverse()) { + for (auto it = inverse_attributes.begin(); it != inverse_attributes.end(); ++it) { + const std::string& name = (*it)->name(); + // H5::DataType* ir_copy = new H5::DataType(); + // ir_copy->copy(*instance_reference_); + const H5::DataType* type = new H5::VarLenType(instance_reference_); + h5_attributes.push_back(std::make_pair(name, type)); + } + } + + return create_compound(h5_attributes); } -template -void IfcParse::IfcHdf5File::write(void*& ptr, const T& t) const { - *((T*)ptr) = t; - advance(ptr, sizeof(T)); +H5::EnumType* type_mapper::operator()(const IfcParse::enumeration_type* en) { + return create_enumeration(en->enumeration_items()); } +void type_mapper::operator()() { + const IfcParse::schema_definition& schema = *ifc_file_.schema(); + + for (auto it = schema.enumeration_types().begin(); it != schema.enumeration_types().end(); ++it) { + declared_types_[(*it)->type()] = commit((*this)(*it), (*it)->name()); + } + + const std::vector& ts = schema.type_declarations(); + std::set processed; + while (processed.size() < ts.size()) { + for (auto it = ts.begin(); it != ts.end(); ++it) { + auto pt = (*it)->declared_type(); + const std::string& name = (*it)->name(); + if (processed.find(*it) != processed.end()) continue; + try { + declared_types_[(*it)->type()] = commit((*this)(pt), name); + processed.insert(*it); + } catch (const UnmetDependencyException&) {} + } + } + + for (auto it = schema.select_types().begin(); it != schema.select_types().end(); ++it) { + H5::DataType* dt = (*this)(*it); + if (dt) { + declared_types_[(*it)->type()] = commit(dt, (*it)->name()); + } else { + declared_types_[(*it)->type()] = instance_reference_; + } + } + + for (auto it = schema.entities().begin(); it != schema.entities().end(); ++it) { + auto dt = (*this)(*it); + if (dt) { + declared_types_[(*it)->type()] = commit(dt, (*it)->name()); + } + } + + H5::StrType schema_name_t; + schema_name_t.copy(H5::PredType::C_S1); + schema_name_t.setSize(schema.name().size()); + + hsize_t schema_name_length = 1; + H5::DataSpace schema_name_s(1, &schema_name_length); + + H5::Attribute attr = schema_group_.createAttribute("iso_10303_26_data", schema_name_t, schema_name_s); + attr.write(schema_name_t, schema.name()); + attr.close(); +} + +void visit(void* buffer, H5::DataType* dt) { + if (dt->getClass() == H5T_COMPOUND) { + H5::CompType* ct = (H5::CompType*) dt; + for (int i = 0; i < ct->getNmembers(); ++i) { + std::cerr << ct->getMemberName(i) << " "; + size_t offs = ct->getMemberOffset(i); + H5::DataType dt2 = ct->getMemberDataType(i); + visit((uint8_t*)buffer + offs, &dt2); + dt2.close(); + } + } else if (dt->getClass() == H5T_VLEN) { + hvl_t* ht = (hvl_t*)buffer; + H5::VarLenType* vt = (H5::VarLenType*) dt; + H5::DataType dt2 = vt->getSuper(); + for (size_t i = 0; i < ht->len; ++i) { + std::cerr << i << " "; + visit((uint8_t*)ht->p + i * vt->getSize(), &dt2); + } + dt2.close(); + } else if (dt->getClass() == H5T_STRING) { + char* c = *(char**)buffer; + std::cerr << "'" << c << "'" << " "; + } +} + +/* +const H5::DataType* IfcParse::IfcHdf5File::specify_length(const H5::DataType* dt, const size_t * n) { + const hsize_t N = *n; + + H5::DataType* dt3 = 0; + if (dt->getClass() == H5T_VLEN) { + H5::VarLenType* vt = (H5::VarLenType*) dt; + H5::DataType dt2 = vt->getSuper(); + if (dt2.getClass() == H5T_VLEN) { + throw IfcParse::IfcException("Not supported"); + } + + if (dt2.getClass() == H5T_STRING) { + dt2.close(); + dt2 = H5::StrType(H5::PredType::C_S1, n[1] + 1); + } + + dt3 = new H5::ArrayType(dt2, 1, &N); + + if (dt2.getClass() != H5T_STRING) { + dt2.close(); + } + } else if (dt->getClass() == H5T_STRING) { + // + 1? 0-sized strings not allowed. + dt3 = new H5::StrType(H5::PredType::C_S1, *n + 1); + } + + if (dt3) { + if (dt->committed()) { + std::string nm = dt->getObjName() + "_" + boost::lexical_cast(*n); + dt3->commit(schema_group, nm); + } + return dt3; + } else { + return dt; + } +} +*/ + +size_t get_alignment() { + return 0; +} + +H5::EnumType* map_enumeration(const IfcParse::enumeration_type* en) { + return create_enumeration(en->enumeration_items()); +} + +H5::DataType* IfcParse::IfcHdf5File::commit(H5::DataType* dt, const std::string& name) { + dt->commit(schema_group, name); + return dt; +} + +class all_null_visitor { +private: + bool all_null_; +public: + typedef void return_type; + + all_null_visitor() + : all_null_(true) + {} + + void operator()(const boost::none_t&) { + // Empty on purpose + } + + template + void operator()(const T& other) { + all_null_ = false; + } + + bool all_null() const { + return all_null_; + } +}; + +class max_length_visitor { +private: + std::vector max_length_; + void contain(size_t dim, size_t count) { + if (dim == max_length_.size()) { + max_length_.push_back(count); + } else if (count > max_length_[dim]) { + max_length_[dim] = count; + } + } + +public: + typedef void return_type; + + void operator()(const IfcEntityList::ptr& aggregate) { + contain(0, aggregate->size()); + } + + void operator()(const IfcEntityListList::ptr& aggregate) { + contain(0, aggregate->size()); + for (auto it = aggregate->begin(); it != aggregate->end(); ++it) { + contain(1, it->size()); + } + } + + void operator()(const std::string& str) { + contain(0, str.size()); + } + + void operator()(const std::vector& aggregate) { + contain(0, aggregate.size()); + for (auto it = aggregate.begin(); it != aggregate.end(); ++it) { + contain(1, it->size()); + } + } + + template + void operator()(const std::vector< std::vector >& aggregate) { + contain(0, aggregate.size()); + for (auto it = aggregate.begin(); it != aggregate.end(); ++it) { + contain(1, it->size()); + } + } + + template + void operator()(const std::vector& aggregate) { + contain(0, aggregate.size()); + } + + template + void operator()(const T& other) { + } + + operator bool() const { + return !max_length_.empty(); + } + + const size_t* max_length() const { + return max_length_.data(); + } +}; + +class apply_attribute_visitor_instance_list { +private: + const IfcEntityList::ptr& instances_; + int attribute_idx_; +public: + apply_attribute_visitor_instance_list(const IfcEntityList::ptr& instances, int attribute_idx) + : instances_(instances) + , attribute_idx_(attribute_idx) + {} + + template + typename T::return_type apply(T& t) const { + for (auto it = instances_->begin(); it != instances_->end(); ++it) { + apply_attribute_visitor((**it).data().getArgument(attribute_idx_)).apply(t); + } + } +}; + +std::set< std::pair > attributes_omitted; +std::set< std::string > entities_with_optional_attrs; + +/* template <> void IfcParse::IfcHdf5File::write(void*& ptr, const std::string& s) const { char* c = new(allocator.allocate(s.size()+1)) char [s.size()+1]; @@ -320,51 +1312,10 @@ void IfcParse::IfcHdf5File::write(void*& ptr, const std::string& s) const { write(ptr, c); } -template struct uint_of_size {}; -template <> struct uint_of_size <1> { typedef uint8_t type; }; -template <> struct uint_of_size <2> { typedef uint16_t type; }; -template <> struct uint_of_size <4> { typedef uint32_t type; }; -template <> struct uint_of_size <8> { typedef uint64_t type; }; - -template struct int_of_size {}; -template <> struct int_of_size <1> { typedef int8_t type; }; -template <> struct int_of_size <2> { typedef int16_t type; }; -template <> struct int_of_size <4> { typedef int32_t type; }; -template <> struct int_of_size <8> { typedef int64_t type; }; - -template struct float_of_size {}; -template <> struct float_of_size <4> { typedef float type; }; -template <> struct float_of_size <8> { typedef double type; }; - -template -void IfcParse::IfcHdf5File::write_number_of_size(void*& ptr, size_t n, T i) const { - if (!std::numeric_limits::is_integer) { - if (n == 4) { - write(ptr, static_cast< float_of_size<4>::type > (i)); - } else if (n == 8) { - write(ptr, static_cast< float_of_size<8>::type > (i)); - } - } else if (std::numeric_limits::is_signed) { - if (n == 1) { - write(ptr, static_cast< int_of_size<1>::type > (i)); - } else if (n == 2) { - write(ptr, static_cast< int_of_size<2>::type > (i)); - } else if (n == 4) { - write(ptr, static_cast< int_of_size<4>::type > (i)); - } else if (n == 8) { - write(ptr, static_cast< int_of_size<8>::type > (i)); - } - } else { - if (n == 1) { - write(ptr, static_cast< uint_of_size<1>::type > (i)); - } else if (n == 2) { - write(ptr, static_cast< uint_of_size<2>::type > (i)); - } else if (n == 4) { - write(ptr, static_cast< uint_of_size<4>::type > (i)); - } else if (n == 8) { - write(ptr, static_cast< uint_of_size<8>::type > (i)); - } - } +void IfcParse::IfcHdf5File::write_string_of_size(void*& ptr, const std::string& s, size_t n) const { + memset(ptr, 0, n); + memcpy(ptr, s.c_str(), s.size()); + advance(ptr, n); } void IfcParse::IfcHdf5File::write_vlen_t(void*& ptr, size_t n_elements, void* vlen_data) const { @@ -388,6 +1339,43 @@ void IfcParse::IfcHdf5File::write_aggregate(void*& ptr, const T& ts) const { write_vlen_t(ptr, n_elements, aggr_data); } +template +void IfcParse::IfcHdf5File::write_consecutive(void*& ptr, const std::vector& ts, hsize_t* num, size_t* elem_size) const { + size_t sz = get_datatype()->getSize(); + hsize_t n = 0; + for (typename std::vector::const_iterator it = ts.begin(); it != ts.end(); ++it, ++n) { + write_number_of_size(ptr, sz, *it); + } + while (n++ < num[0]) { + write_number_of_size(ptr, sz, T()); + } +} + +template <> +void IfcParse::IfcHdf5File::write_consecutive(void*& ptr, const std::vector& ts, hsize_t* num, size_t*) const { + hsize_t n = 0; + for (std::vector::const_iterator it = ts.begin(); it != ts.end(); ++it, ++n) { + auto ref = make_instance_reference(*it); + write_number_of_size(ptr, 2, ref.first); + write_number_of_size(ptr, 4, ref.second); + } + while (n++ < num[0]) { + write_number_of_size(ptr, 2, 0); + write_number_of_size(ptr, 4, 0); + } +} + +template <> +void IfcParse::IfcHdf5File::write_consecutive(void*& ptr, const std::vector& ts, hsize_t* num, size_t* elem_size) const { + hsize_t n = 0; + for (std::vector::const_iterator it = ts.begin(); it != ts.end(); ++it, ++n) { + write_string_of_size(ptr, *it, elem_size[0]); + } + while (n++ < num[0]) { + write_string_of_size(ptr, "", elem_size[0]); + } +} + template <> void IfcParse::IfcHdf5File::write_aggregate(void*& ptr, const std::vector& ts) const { size_t elem_size = sizeof(char*); @@ -656,8 +1644,9 @@ void IfcParse::IfcHdf5File::write_reference_attribute2(void*& ptr, const std::st } } } +*/ -void IfcParse::IfcHdf5File::write_schema(const IfcParse::schema_definition& schema) { +void IfcParse::IfcHdf5File::write_schema(const IfcParse::schema_definition& schema, IfcParse::IfcFile& ifc_file) { // From h5ex_g_compact.c // Compact groups? @@ -672,49 +1661,10 @@ void IfcParse::IfcHdf5File::write_schema(const IfcParse::schema_definition& sche schema_group = file->createGroup(schema.name() + "_encoding"); population_group = file->createGroup("population"); - init_default_types(); - - for (auto it = schema.enumeration_types().begin(); it != schema.enumeration_types().end(); ++it) { - declared_types[(*it)->type()] = commit(map_enumeration((*it)), (*it)->name()); - } - - const std::vector& ts = schema.type_declarations(); - std::set processed; - while (processed.size() < ts.size()) { - for (auto it = ts.begin(); it != ts.end(); ++it) { - const std::string& name = (*it)->name(); - if (processed.find(*it) != processed.end()) continue; - try { - declared_types[(*it)->type()] = commit(map_type((*it)->declared_type()), (*it)->name()); - processed.insert(*it); - } catch(const UnmetDependencyException&) {} - auto pt = (*it)->declared_type(); - } - } + // init_default_types(); - for (auto it = schema.select_types().begin(); it != schema.select_types().end(); ++it) { - H5::DataType* dt = map_select(*it); - if (dt) { - declared_types[(*it)->type()] = commit(dt, (*it)->name()); - } else { - declared_types[(*it)->type()] = instance_reference; - } - } - - for (auto it = schema.entities().begin(); it != schema.entities().end(); ++it) { - declared_types[(*it)->type()] = commit(map_entity(*it), (*it)->name()); - } - - H5::StrType schema_name_t; - schema_name_t.copy(H5::PredType::C_S1); - schema_name_t.setSize(schema.name().size()); - - hsize_t schema_name_length = 1; - H5::DataSpace schema_name_s(1, &schema_name_length); - - H5::Attribute attr = schema_group.createAttribute("iso_10303_26_data", schema_name_t, schema_name_s); - attr.write(schema_name_t, schema.name()); - attr.close(); + mapper_ = new type_mapper(ifc_file, file); + (*(type_mapper*)mapper_)(); }; std::pair IfcParse::IfcHdf5File::make_instance_reference(const IfcUtil::IfcBaseClass* instance) const { @@ -737,6 +1687,7 @@ std::pair IfcParse::IfcHdf5File::make_instance_reference(const I return std::make_pair(dataset_offset, instance_offset); } +/* void IfcParse::IfcHdf5File::write_select(void*& ptr, IfcUtil::IfcBaseClass* instance, const H5::CompType* datatype) const { int member_index = -1; @@ -764,8 +1715,8 @@ void IfcParse::IfcHdf5File::write_select(void*& ptr, IfcUtil::IfcBaseClass* inst void* ptr_member = (uint8_t*) ptr + offset; switch(wrapped_data.type()) { case IfcUtil::Argument_BOOL: { - bool instance = wrapped_data; - write_number_of_size(ptr_member, member_size, static_cast(instance ? 1 : 0)); + bool v = wrapped_data; + write_number_of_size(ptr_member, member_size, static_cast(v ? 1 : 0)); break; } case IfcUtil::Argument_DOUBLE: { double d = wrapped_data; @@ -801,7 +1752,143 @@ void IfcParse::IfcHdf5File::write_select(void*& ptr, IfcUtil::IfcBaseClass* inst advance(ptr, datatype->getSize()); } +*/ +H5::DataSet IfcParse::IfcHdf5File::create_dataset(const std::string& path, H5::DataType datatype, int rank, hsize_t* dimensions) { + if (rank != 1) { + throw std::runtime_error("Expected rank 1"); + } + + const size_t datatype_size = datatype.getSize(); + + hsize_t chunk; + if (settings_.chunk_size() > 0 && settings_.chunk_size() < dimensions[0]) { + chunk = static_cast(settings_.chunk_size()); + } else { + chunk = dimensions[0]; + } + + const H5::DSetCreatPropList* plist; + // H5O_MESG_MAX_SIZE = 65536 + const bool compact = dimensions[0] * datatype_size < (1 << 15); + if (settings_.compress() && !compact) { + H5::DSetCreatPropList* plist_ = new H5::DSetCreatPropList; + plist_->setChunk(1, &chunk); + // D'oh. Order is significant, according to h5ex_d_shuffle.c + plist_->setShuffle(); + plist_->setDeflate(9); + plist = plist_; + } else if (compact) { + H5::DSetCreatPropList* plist_ = new H5::DSetCreatPropList; + // Set compact according to h5ex_d_compact.c + plist_->setLayout(H5D_COMPACT); + plist = plist_; + } else if (chunk != dimensions[0]) { + H5::DSetCreatPropList* plist_ = new H5::DSetCreatPropList; + plist_->setChunk(1, &chunk); + plist = plist_; + } else { + plist = &H5::DSetCreatPropList::DEFAULT; + } + + H5::DataSpace space(1, dimensions); + H5::DataSet ds = population_group.createDataSet(path, datatype, space, *plist); + + if (plist != &H5::DSetCreatPropList::DEFAULT) { + // ->close() doesn't work due to const, hack hack hack + H5Pclose(plist->getId()); + } + + return ds; +} + +void IfcParse::IfcHdf5File::write_population(IfcFile& f) { + std::set tys; + + // Wth was this? + // this->file->close(); + + std::set types_with_instiated_selected; + + for (auto it = f.begin(); it != f.end(); ++it) { + IfcSchema::Type::Enum ty = it->second->declaration().type(); + tys.insert(ty); + // This already is sorted on entity instance name +#ifdef SORT_ON_NAME + sorted_entities[ty].push_back(static_cast(it->first)); +#else + sorted_entities[ty].push_back(it->second); +#endif + } + + dataset_names.assign(tys.begin(), tys.end()); + std::sort(dataset_names.begin(), dataset_names.end()); + + { + hsize_t dataset_names_length = dataset_names.size(); + H5::DataSpace dataset_names_s(1, &dataset_names_length); + + H5::Attribute attr = schema_group.createAttribute("iso_10303_26_data_set_names", H5::PredType::C_S1, dataset_names_s); + char** attr_data = (char**)allocator.allocate(static_cast(sizeof(char*) * dataset_names_length)); + size_t i = 0; + for (auto it = dataset_names.begin(); it != dataset_names.end(); ++it, ++i) { + std::string nm = IfcSchema::Type::ToString(*it); + attr_data[i] = (char*)allocator.allocate(nm.size() + 1); + strcpy(attr_data[i], nm.c_str()); + } + attr.write(H5::PredType::C_S1, attr_data); + attr.close(); + } + +#ifdef SORT_ON_NAME + for (auto it = sorted_entities.begin(); it != sorted_entities.end(); ++it) { + std::sort(it->second.begin(), it->second.end()); + } +#endif + + sorted_instance_locator locator(this->ifcfile_); + write_visit/**/ visitor(false, false, locator, *((type_mapper*)mapper_)); + + for (auto dsn_it = dataset_names.begin(); dsn_it != dataset_names.end(); ++dsn_it) { + + const std::string current_entity_name = IfcSchema::Type::ToString(*dsn_it); + std::cerr << current_entity_name << std::endl; + +#ifdef SORT_ON_NAME + std::vector instances; + const auto& idxs = sorted_entities.find(*dsn_it)->second; + std::transform(idxs.begin(), idxs.end(), std::back_inserter(instances), [&f](uint32_t idx) { + return f.entityById(idx); + }); +#else + const std::vector& instances = sorted_entities.find(*it)->second; +#endif + hsize_t num_instances = instances.size(); + H5::DataType entity_datatype = schema_group.openDataType(current_entity_name); + H5::DataSet dataset = create_dataset(current_entity_name + "_instances", entity_datatype, 1, &num_instances); + + size_t dataset_size = entity_datatype.getSize() * static_cast(num_instances); + void* data = allocator.allocate(dataset_size); + void* ptr = data; + std::cerr << dataset_size << std::endl; + + for (auto inst_it = instances.begin(); inst_it != instances.end(); ++inst_it) { + write_instance(ptr, visitor, entity_datatype, (IfcUtil::IfcBaseEntity*)*inst_it); + } + + dataset.write(data, entity_datatype); + H5::DataSpace space(1, &num_instances); + H5Dvlen_reclaim(entity_datatype.getId(), space.getId(), H5P_DEFAULT, data); + + dataset.close(); + space.close(); + + // allocator.free(); + delete[] data; + } +} + +/* void IfcParse::IfcHdf5File::write_population(IfcFile& f) { std::set tys; @@ -856,13 +1943,15 @@ void IfcParse::IfcHdf5File::write_population(IfcFile& f) { dataset_names.assign(tys.begin(), tys.end()); std::sort(dataset_names.begin(), dataset_names.end()); + + // dataset_names.push_back(IfcSchema::Type::IfcPostalAddress); { hsize_t dataset_names_length = dataset_names.size(); H5::DataSpace dataset_names_s(1, &dataset_names_length); H5::Attribute attr = schema_group.createAttribute("iso_10303_26_data_set_names", *default_types[simple_type::string_type], dataset_names_s); - char** attr_data = (char**) allocator.allocate(sizeof(char*) * dataset_names_length); + char** attr_data = (char**) allocator.allocate(static_cast(sizeof(char*) * dataset_names_length)); size_t i = 0; for (auto it = dataset_names.begin(); it != dataset_names.end(); ++it, ++i) { std::string nm = IfcSchema::Type::ToString(*it); @@ -956,23 +2045,23 @@ void IfcParse::IfcHdf5File::write_population(IfcFile& f) { if (!decl.as_entity()) { if (!settings_.instantiate_select()) throw; // This is a type - auto q = dt->getClass(); - auto s = dt->getSize(); + // auto q = dt->getClass(); + auto size = dt->getSize(); const Argument& attr_value = *dat.getArgument(0); if (*dt == *default_types[simple_type::real_type]) { double d = attr_value; - write_number_of_size(ptr, s, d); + write_number_of_size(ptr, size, d); } else if (*dt == *default_types[simple_type::string_type]) { std::string s = attr_value; write(ptr, s); } else if (*dt == *default_types[simple_type::integer_type]) { int i = attr_value; - write_number_of_size(ptr, s, i); + write_number_of_size(ptr, size, i); } else if (*dt == *default_types[simple_type::boolean_type] || *dt == *default_types[simple_type::logical_type]) { bool b = attr_value; - write_number_of_size(ptr, s, static_cast(b ? 1 : 0)); + write_number_of_size(ptr, size, static_cast(b ? 1 : 0)); } else { throw; } @@ -987,13 +2076,26 @@ void IfcParse::IfcHdf5File::write_population(IfcFile& f) { const std::vector& attributes_derived_in_subtype = decl.as_entity()->derived(); std::vector::const_iterator is_derived = attributes_derived_in_subtype.begin(); - member_type = dt->getMemberDataType(member_idx++); - uint32_t set_unset_mask = 0; - void* set_unset_ptr = ptr; - size_t set_unset_size = member_type.getSize(); - // skip for now write later - advance(ptr, set_unset_size); - member_type.close(); + //for (auto qt = attributes_derived_in_subtype.begin(); qt != attributes_derived_in_subtype.end(); ++qt) { + // std::cout << int(*qt); + //} + //std::cout << std::endl; + + const bool has_optional = entities_with_optional_attrs.find(current_entity_name) != entities_with_optional_attrs.end(); + + uint32_t set_unset_mask; + size_t set_unset_size; + void* set_unset_ptr; + + if (has_optional) { + member_type = dt->getMemberDataType(member_idx++); + set_unset_mask = 0; + set_unset_ptr = ptr; + set_unset_size = member_type.getSize(); + // skip for now write later + advance(ptr, set_unset_size); + member_type.close(); + } member_type = dt->getMemberDataType(member_idx++); const unsigned int inst_name = static_cast(dat.id()); @@ -1003,16 +2105,26 @@ void IfcParse::IfcHdf5File::write_population(IfcFile& f) { // ----v----- In some IFC files there are extra superfluous attributes in the instantiation. For example FJK haus. const size_t attr_count = (std::min)(attributes.size(), (size_t) dat.getArgumentCount()); for (unsigned i = 0; i < attr_count; ++i, ++is_derived) { + + //std::cout << i << std::endl; + if (*is_derived) { continue; } + if (attributes_omitted.find(std::make_pair(current_entity_name, i)) != attributes_omitted.end()) { + continue; + } + const IfcParse::entity::attribute* schema_attr = attributes[i]; const std::string& attribute_name = schema_attr->name(); + //std::cout << "ifc " << attribute_name << std::endl; Argument& attr_value = *dat.getArgument(i); member_type = dt->getMemberDataType(member_idx++); + //std::cout << "hdf5 " << dt->getMemberName(member_idx - 1) << ": " << member_type.getClass() << std::endl; + if (attr_value.isNull()) { if (member_type == *default_types[simple_type::string_type]) { // HDF5 otherwise crashes on derefencing a zero pointer for the string type @@ -1059,11 +2171,11 @@ void IfcParse::IfcHdf5File::write_population(IfcFile& f) { memcpy(static_cast(ptr), s.c_str(), s.size()); advance(ptr, s.length()); } else if (settings_.fix_cartesian_point() && ((attribute_name == "Coordinates" && current_entity_name == "IfcCartesianPoint") || (attribute_name == "DirectionRatios" && current_entity_name == "IfcDirection"))) { - std::vector ds = attr_value; - for (auto it = ds.begin(); it != ds.end(); ++it) { - write_number_of_size(ptr, default_types[simple_type::real_type]->getSize(), *it); + std::vector vs = attr_value; + for (auto vs_it = vs.begin(); vs_it != vs.end(); ++vs_it) { + write_number_of_size(ptr, default_types[simple_type::real_type]->getSize(), *vs_it); } - if (ds.size() == 2) { + if (vs.size() == 2) { write_number_of_size(ptr, default_types[simple_type::real_type]->getSize(), std::numeric_limits::quiet_NaN()); } } else if (member_type == *instance_reference) { @@ -1076,12 +2188,16 @@ void IfcParse::IfcHdf5File::write_population(IfcFile& f) { } else if (member_type == *default_types[simple_type::real_type]) { double d = attr_value; write_number_of_size(ptr, member_type.getSize(), d); - } else if (member_type == *default_types[simple_type::string_type]) { + } else if (member_type == *default_types[simple_type::string_type] || member_type.getClass() == H5T_STRING) { std::string s = attr_value; - write(ptr, s); + if (member_type == *default_types[simple_type::string_type]) { + write(ptr, s); + } else { + write_string_of_size(ptr, s, member_type.getSize()); + } } else if (member_type == *default_types[simple_type::integer_type]) { - int i = attr_value; - write_number_of_size(ptr, member_type.getSize(), i); + int v = attr_value; + write_number_of_size(ptr, member_type.getSize(), v); } else if (member_type == *default_types[simple_type::boolean_type] || member_type == *default_types[simple_type::logical_type]) { @@ -1094,7 +2210,7 @@ void IfcParse::IfcHdf5File::write_population(IfcFile& f) { const std::vector& enum_values = schema_attr->type_of_attribute()->as_named_type()->declared_type()->as_enumeration_type()->enumeration_items(); size_t d = std::distance(enum_values.begin(), std::find(enum_values.begin(), enum_values.end(), s)); write_number_of_size(ptr, member_type.getSize(), d); - } else if (member_type.getClass() == H5T_VLEN) { + } else if (member_type.getClass() == H5T_VLEN || member_type.getClass() == H5T_ARRAY) { const parameter_type* pt = schema_attr->type_of_attribute(); while (pt->as_named_type()) { pt = pt->as_named_type()->declared_type()->as_type_declaration()->declared_type(); @@ -1102,65 +2218,168 @@ void IfcParse::IfcHdf5File::write_population(IfcFile& f) { const named_type* nt = pt->as_aggregation_type()->type_of_element()->as_named_type(); if (nt && nt->declared_type()->as_select_type()) { const H5::DataType* datatype = declared_types[nt->declared_type()->type()]; - IfcEntityList::ptr es = attr_value; + IfcEntityList::ptr vs = attr_value; if (datatype == instance_reference) { // For a SELECTs with only ENTITY leaves, a blind instance reference type is used - write_aggregate(ptr, es); - } else { - size_t size_in_bytes = datatype->getSize(); - size_t num_elements = es->size(); - void* buffer_ptr; - // void* buffer = buffer_ptr = new uint8_t[size_in_bytes * num_elements]; - void* buffer = buffer_ptr = allocator.allocate(size_in_bytes * num_elements); - memset(buffer, 0, size_in_bytes * num_elements); - for (auto it = es->begin(); it != es->end(); ++it) { - write_select(buffer_ptr, *it, static_cast(datatype)); - } - write_vlen_t(ptr, num_elements, buffer); - } + // TK: Is this actually correct? + if (member_type.getClass() == H5T_VLEN) { + write_aggregate(ptr, vs); + } else { + H5::ArrayType* adt = (H5::ArrayType*) &member_type; + size_t ndims = adt->getArrayNDims(); + size_t element_size = adt->getSuper().getSize(); + hsize_t* array_dims = new hsize_t[ndims]; + adt->getArrayDims(array_dims); - } else { - if (sizeof(hvl_t) != member_type.getSize()) throw; - switch(attr_value.type()) { - case IfcUtil::Argument_AGGREGATE_OF_INT: { - std::vector ds = attr_value; - write_aggregate(ptr, ds); - break; } - case IfcUtil::Argument_AGGREGATE_OF_BOOL: { - std::vector ds = attr_value; - write_aggregate(ptr, ds); - break; } - case IfcUtil::Argument_AGGREGATE_OF_DOUBLE: { - std::vector ds = attr_value; - write_aggregate(ptr, ds); - break; } - case IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE: { - IfcEntityList::ptr es = attr_value; - write_aggregate(ptr, es); - break; } - case IfcUtil::Argument_AGGREGATE_OF_STRING: { - std::vector ss = attr_value; - write_aggregate(ptr, ss); - break; } - case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_INT: { - std::vector< std::vector > ds = attr_value; - write_aggregate2(ptr, ds); - break; } - case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_BOOL: { - std::vector< std::vector > ds = attr_value; - write_aggregate2(ptr, ds); - break; } - case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE: { - std::vector< std::vector > ds = attr_value; - write_aggregate2(ptr, ds); - break; } - default: - // Can be an empty list in which case parser does not know type - if (attr_value.size() > 0) { - Logger::Message(Logger::LOG_ERROR, "Unsupported aggregate encountered", *jt); + std::vector es2(vs->begin(), vs->end()); + write_consecutive(ptr, es2, array_dims, &element_size); } - memset(ptr, 0, member_type.getSize()); - ptr = (uint8_t*) ptr + member_type.getSize(); + } else { + if (member_type.getClass() == H5T_VLEN) { + size_t size_in_bytes = datatype->getSize(); + size_t num_elements = vs->size(); + void* buffer_ptr; + // void* buffer = buffer_ptr = new uint8_t[size_in_bytes * num_elements]; + void* buffer = buffer_ptr = allocator.allocate(size_in_bytes * num_elements); + memset(buffer, 0, size_in_bytes * num_elements); + for (auto vs_it = vs->begin(); vs_it != vs->end(); ++vs_it) { + write_select(buffer_ptr, *vs_it, static_cast(datatype)); + } + write_vlen_t(ptr, num_elements, buffer); + } else { + // Set to zero in case of different size + memset(ptr, 0, member_type.getSize()); + void* ptr_ = ptr; + for (auto vs_it = vs->begin(); vs_it != vs->end(); ++vs_it) { + write_select(ptr_, *vs_it, static_cast(datatype)); + } + // This is cheating, let's hope the sizes align. + advance(ptr, member_type.getSize()); + } + } + } else { + if (member_type.getClass() == H5T_VLEN) { + switch (attr_value.type()) { + case IfcUtil::Argument_AGGREGATE_OF_INT: { + std::vector vs = attr_value; + write_aggregate(ptr, vs); + break; } + case IfcUtil::Argument_AGGREGATE_OF_BOOL: { + std::vector vs = attr_value; + write_aggregate(ptr, vs); + break; } + case IfcUtil::Argument_AGGREGATE_OF_DOUBLE: { + std::vector vs = attr_value; + write_aggregate(ptr, vs); + break; } + case IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE: { + IfcEntityList::ptr vs = attr_value; + write_aggregate(ptr, vs); + break; } + case IfcUtil::Argument_AGGREGATE_OF_STRING: { + std::vector ss = attr_value; + write_aggregate(ptr, ss); + break; } + case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_INT: { + std::vector< std::vector > vs = attr_value; + write_aggregate2(ptr, vs); + break; } + case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_BOOL: { + std::vector< std::vector > vs = attr_value; + write_aggregate2(ptr, vs); + break; } + case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE: { + std::vector< std::vector > vs = attr_value; + write_aggregate2(ptr, vs); + break; } + default: + // Can be an empty list in which case parser does not know type + if (attr_value.size() > 0) { + Logger::Message(Logger::LOG_ERROR, "Unsupported aggregate encountered", *jt); + } + memset(ptr, 0, member_type.getSize()); + ptr = (uint8_t*)ptr + member_type.getSize(); + } + } else { + if (member_type.getClass() != H5T_ARRAY) throw; + H5::ArrayType* adt = (H5::ArrayType*) &member_type; + size_t ndims = adt->getArrayNDims(); + size_t element_size = adt->getSuper().getSize(); + hsize_t* array_dims = new hsize_t[ndims]; + adt->getArrayDims(array_dims); + + size_t ifcdims = 0; + + switch (attr_value.type()) { + case IfcUtil::Argument_AGGREGATE_OF_INT: + case IfcUtil::Argument_AGGREGATE_OF_BOOL: + case IfcUtil::Argument_AGGREGATE_OF_DOUBLE: + case IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE: + case IfcUtil::Argument_AGGREGATE_OF_STRING: + ifcdims = 1; + break; + case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_INT: + case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_BOOL: + case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE: + ifcdims = 2; + break; + } + + // Caught in default block below and memset() to zero. + // if (false && ifcdims != ndims) { + // std::cerr << "Expected dim " << ndims << " got " << ifcdims << std::endl; + // std::cin.get(); + // abort(); + // } + + switch (attr_value.type()) { + case IfcUtil::Argument_AGGREGATE_OF_INT: { + std::vector vs = attr_value; + write_consecutive(ptr, vs, array_dims, &element_size); + break; } + case IfcUtil::Argument_AGGREGATE_OF_BOOL: { + std::vector vs = attr_value; + write_consecutive(ptr, vs, array_dims, &element_size); + break; } + case IfcUtil::Argument_AGGREGATE_OF_DOUBLE: { + std::vector vs = attr_value; + write_consecutive(ptr, vs, array_dims, &element_size); + break; } + case IfcUtil::Argument_AGGREGATE_OF_ENTITY_INSTANCE: { + IfcEntityList::ptr vs = attr_value; + std::vector vs2(vs->begin(), vs->end()); + write_consecutive(ptr, vs2, array_dims, &element_size); + break; } + case IfcUtil::Argument_AGGREGATE_OF_STRING: { + std::vector vs = attr_value; + write_consecutive(ptr, vs, array_dims, &element_size); + break; } + case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_INT: { + // std::vector< std::vector > ds = attr_value; + // write_consecutive2(ptr, ds); + break; } + case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_BOOL: { + // std::vector< std::vector > ds = attr_value; + // write_consecutive2(ptr, ds); + break; } + case IfcUtil::Argument_AGGREGATE_OF_AGGREGATE_OF_DOUBLE: { + // std::vector< std::vector > ds = attr_value; + // write_consecutive2(ptr, ds); + break; } + default: + // Can be an empty list in which case parser does not know type + if (attr_value.size() > 0) { + Logger::Message(Logger::LOG_ERROR, "Unsupported aggregate encountered", *jt); + } + memset(ptr, 0, member_type.getSize()); + advance(ptr, member_type.getSize()); + } + + + + + + delete[] array_dims; } } } else if (member_type.getClass() == H5T_COMPOUND) { @@ -1168,8 +2387,7 @@ void IfcParse::IfcHdf5File::write_population(IfcFile& f) { IfcUtil::ArgumentType ty = attr_value.type(); if (ty != IfcUtil::Argument_ENTITY_INSTANCE) throw; - IfcUtil::IfcBaseClass* b = attr_value; - + // v impl. cast write_select(ptr, attr_value, static_cast(&member_type)); } } @@ -1177,16 +2395,15 @@ void IfcParse::IfcHdf5File::write_population(IfcFile& f) { member_type.close(); } - for (auto it = inverse_attributes.begin(); it != inverse_attributes.end(); ++it) { + for (auto inv_it = inverse_attributes.begin(); inv_it != inverse_attributes.end(); ++inv_it) { member_type = dt->getMemberDataType(member_idx++); - auto q = member_type.getClass(); if (member_type.getClass() != H5T_VLEN) { std::cerr << dt->getMemberName(member_idx - 1) << " "; std::cerr << "Inverse attribute must be vlen" << std::endl; } - const IfcParse::entity* entity_ref = (*it)->entity_reference(); - const IfcParse::entity::attribute* attribute_ref = (*it)->attribute_reference(); + const IfcParse::entity* entity_ref = (*inv_it)->entity_reference(); + const IfcParse::entity::attribute* attribute_ref = (*inv_it)->attribute_reference(); IfcEntityList::ptr instances = f.getInverse(dat.id(), entity_ref->type(), entity_ref->attribute_index(attribute_ref)); if (instances->size() == 0) { memset(ptr, 0, member_type.getSize()); @@ -1198,17 +2415,21 @@ void IfcParse::IfcHdf5File::write_population(IfcFile& f) { member_type.close(); } - write_number_of_size(set_unset_ptr, set_unset_size, set_unset_mask); + if (has_optional) { + write_number_of_size(set_unset_ptr, set_unset_size, set_unset_mask); + } const size_t written_length = (uint8_t*) ptr - (uint8_t*) start; if (written_length != datatype_size) { std::cerr << "Written " << written_length << " bytes, but expected " << datatype_size << std::endl; + std::cin.get(); + abort(); } } - /* for (size_t i = 0; i < dataset_size; ++i) { - std::cout << std::hex << (int)((uint8_t*)data)[i] << " "; - } */ + // for (size_t i = 0; i < dataset_size; ++i) { + // std::cout << std::hex << (int)((uint8_t*)data)[i] << " "; + // } // visit(data, declared_types[*it]); ds.write(data, *declared_types[*it]); @@ -1225,12 +2446,13 @@ void IfcParse::IfcHdf5File::write_population(IfcFile& f) { // allocator.free(); delete[] data; - for (auto it = es.begin(); it != es.end(); ++it) { - if (types_with_instiated_selected.find((**it).declaration().type()) == types_with_instiated_selected.end()) { + for (auto es_it = es.begin(); es_it != es.end(); ++es_it) { + if (types_with_instiated_selected.find((**es_it).declaration().type()) == types_with_instiated_selected.end()) { // Instances possibly refering to embedded simple type instantiations are not freed - static_cast(&(**it).data())->Unload(); + static_cast(&(**es_it).data())->Unload(); } } } -} \ No newline at end of file +} +*/ \ No newline at end of file diff --git a/src/ifcparse/IfcHdf5File.h b/src/ifcparse/IfcHdf5File.h index 259a1e79d9..ae52d6a71e 100644 --- a/src/ifcparse/IfcHdf5File.h +++ b/src/ifcparse/IfcHdf5File.h @@ -31,7 +31,17 @@ namespace IfcParse { class IfcHdf5File { + public: + enum Profile { + standard, + padded, + standard_referenced, + padded_referenced + }; + private: + Profile profile_; + class allocator_t { private: // TODO: Change this? @@ -57,6 +67,7 @@ namespace IfcParse { std::string name_; schema_definition schema_; + IfcFile& ifcfile_; H5::H5File* file; H5::Group schema_group; @@ -68,10 +79,12 @@ namespace IfcParse { std::map declared_types; // TODO: why? get_datatype() + /* std::map default_types; std::map overridden_types; std::map default_type_names; std::map default_cpp_type_names; + */ #ifdef SORT_ON_NAME std::map > sorted_entities; @@ -89,9 +102,9 @@ namespace IfcParse { void visit_select(const IfcParse::select_type* pt, std::set& leafs); std::string flatten_aggregate_name(const IfcParse::parameter_type* at) const; std::pair make_instance_reference(const IfcUtil::IfcBaseClass* instance) const; - void write_select(void*& ptr, IfcUtil::IfcBaseClass* instance, const H5::CompType* datatype) const; + // void write_select(void*& ptr, IfcUtil::IfcBaseClass* instance, const H5::CompType* datatype) const; - void write_schema(const schema_definition& schema); + void write_schema(const schema_definition& schema, IfcFile& f); void write_population(IfcFile& f); template @@ -99,6 +112,7 @@ namespace IfcParse { return default_types.find(IfcUtil::cpp_to_schema_type::schema_type)->second; } + /* void advance(void*& ptr, size_t n) const; template @@ -112,28 +126,49 @@ namespace IfcParse { template void write_number_of_size(void*& ptr, size_t n, T i) const; + void write_string_of_size(void*& ptr, const std::string& s, size_t n) const; + template void write_aggregate(void*& ptr, const T& ts) const; + template + void write_consecutive(void*& ptr, const std::vector& ts, hsize_t* num = 0, size_t* elem_size=0) const; + template void write_aggregate2(void*& ptr, const std::vector< std::vector >& ts) const; + template + void write_consecutive2(void*& ptr, const std::vector< std::vector >& ts, hsize_t* num = 0, size_t* elem_size = 0) const; + template void write_reference_attribute(void*& ptr, const std::string& dsn, const std::vector& vs); template void write_reference_attribute2(void*& ptr, const std::string& dsn, const std::vector< std::vector >& vs); + const H5::DataType* specify_length(const H5::DataType* dt, const size_t* n); + */ + + H5::DataSet create_dataset(const std::string& path, H5::DataType datatype, int rank, hsize_t* dimensions); + + template + void write_instance(void*& ptr, T& visitor, H5::DataType& datatype, IfcUtil::IfcBaseEntity* v); + + // TODO: Obviously change this; + void* mapper_; public: typedef std::pair compound_member; - - IfcHdf5File(IfcFile* f, const std::string& name, const Hdf5Settings& settings) - : name_(name) + + + IfcHdf5File(IfcFile* f, const std::string& name, const Hdf5Settings& settings, Profile profile) + : profile_(profile) + , name_(name) , schema_(*f->schema()) + , ifcfile_(*f) , settings_(settings) { - write_schema(*f->schema()); - write_population(*f); + write_schema(schema_, ifcfile_); + write_population(ifcfile_); }; }; diff --git a/src/ifcparse/IfcParse.cpp b/src/ifcparse/IfcParse.cpp index 5fede461fb..d6edeaaf67 100644 --- a/src/ifcparse/IfcParse.cpp +++ b/src/ifcparse/IfcParse.cpp @@ -1552,5 +1552,5 @@ std::pair IfcFile::getUnit(IfcSchema::IfcUnitE } void IfcFile::write_hdf5(const std::string& name, const Hdf5Settings& settings) { - IfcHdf5File(this, name, settings); + IfcHdf5File(this, name, settings, IfcHdf5File::standard); } \ No newline at end of file diff --git a/src/ifcparse/IfcSchema.h b/src/ifcparse/IfcSchema.h index adfea4f73a..fc0f99acfd 100644 --- a/src/ifcparse/IfcSchema.h +++ b/src/ifcparse/IfcSchema.h @@ -75,7 +75,7 @@ namespace IfcParse { class simple_type : public parameter_type { public: - typedef enum { binary_type, boolean_type, integer_type, logical_type, number_type, real_type, string_type } data_type; + typedef enum { binary_type, boolean_type, integer_type, logical_type, number_type, real_type, string_type, datatype_COUNT } data_type; protected: data_type declared_type_; public: diff --git a/src/ifcparse/IfcUtil.h b/src/ifcparse/IfcUtil.h index 0c387a6546..e5534869d4 100644 --- a/src/ifcparse/IfcUtil.h +++ b/src/ifcparse/IfcUtil.h @@ -232,7 +232,7 @@ public: } outer_it begin() const { return ls.begin(); } outer_it end() const { return ls.end(); } - int size() const { return (int)ls.size(); } + unsigned int size() const { return (unsigned int)ls.size(); } int totalSize() const { int accum = 0; for (outer_it it = begin(); it != end(); ++it) { @@ -379,4 +379,27 @@ public: static std::string GetLog(); }; +namespace IfcUtil { + template + struct attr_type_to_cpp_type; + template <> struct attr_type_to_cpp_type { typedef int cpp_type; }; + template <> struct attr_type_to_cpp_type { typedef bool cpp_type; }; + template <> struct attr_type_to_cpp_type { typedef double cpp_type; }; + template <> struct attr_type_to_cpp_type { typedef std::string cpp_type; }; + template <> struct attr_type_to_cpp_type { typedef boost::dynamic_bitset<> cpp_type; }; + template <> struct attr_type_to_cpp_type { typedef IfcUtil::IfcBaseClass* cpp_type; }; + + template <> struct attr_type_to_cpp_type { typedef std::vector cpp_type; }; + template <> struct attr_type_to_cpp_type { typedef std::vector cpp_type; }; + template <> struct attr_type_to_cpp_type { typedef std::vector cpp_type; }; + template <> struct attr_type_to_cpp_type { typedef std::vector cpp_type; }; + template <> struct attr_type_to_cpp_type { typedef std::vector< boost::dynamic_bitset<> > cpp_type; }; + template <> struct attr_type_to_cpp_type { typedef IfcEntityList::ptr cpp_type; }; + + template <> struct attr_type_to_cpp_type { typedef std::vector< std::vector > cpp_type; }; + template <> struct attr_type_to_cpp_type { typedef std::vector< std::vector > cpp_type; }; + template <> struct attr_type_to_cpp_type { typedef std::vector< std::vector > cpp_type; }; + template <> struct attr_type_to_cpp_type { typedef IfcEntityListList::ptr cpp_type; }; +} + #endif diff --git a/win/utils/cecho.cmd b/win/utils/cecho.cmd index 2923fcb986..97de7a57e3 100644 --- a/win/utils/cecho.cmd +++ b/win/utils/cecho.cmd @@ -1,4 +1,5 @@ :: Usage: call cecho.cmd background foreground "message here" :: NOTES/TODOS 1) This is super slow 2) leading spaces are omitted 3) printing string with quotes doesn't work (quotes must be escaped awkwardly) -@powershell -command write-host -background %~1 -foreground "%~2" "%3" +:: @powershell -command write-host -background %~1 -foreground "%~2" "%3" +echo %3 @exit /b