Use naked pointer for attribute list and derive size from schema type to reduce mem usage

This commit is contained in:
Thomas Krijnen
2018-01-29 12:11:50 +01:00
parent a3b7a25866
commit af93f2a64d
6 changed files with 167 additions and 126 deletions
+17 -27
View File
@@ -39,41 +39,27 @@ public:
protected:
unsigned id_;
const IfcParse::declaration* type_;
mutable std::vector<Argument*> attributes_;
// To reduce memory footprint, these two could potentially be combined,
// e.g. initialized_ <-> offset_in_file_ == 0, but it would imply that
// instances cannot be located at the beginning of the file. Officially
// there should be a header anyways.
mutable bool initialized_;
mutable Argument** attributes_;
unsigned offset_in_file_;
public:
IfcEntityInstanceData(const IfcParse::declaration* type, IfcParse::IfcFile* file_, unsigned id = 0, unsigned offset_in_file = 0)
: file(file_), id_(id), type_(type), initialized_(false), offset_in_file_(offset_in_file)
: file(file_), id_(id), type_(type), attributes_(0), offset_in_file_(offset_in_file)
{}
IfcEntityInstanceData(IfcParse::IfcFile* file_, size_t size)
: file(file_), id_(0), type_(0), attributes_(new Argument*[size]), offset_in_file_(0)
{}
IfcEntityInstanceData(const IfcParse::declaration* type)
: file(0), id_(0), type_(type), initialized_(true)
: file(0), id_(0), type_(type), attributes_(0)
{}
/*
IfcEntityInstanceData(IfcParse::IfcFile* file = 0, unsigned id = 0, IfcSchema::Type::Enum type = IfcSchema::Type::UNDEFINED, unsigned offset_in_file = 0, size_t n)
: file_(file), id_(0), type_(type), initialized_(false)
{
attributes_.reserve(n);
}
IfcEntityInstanceData(IfcParse::IfcFile* file = 0, unsigned id = 0, IfcSchema::Type::Enum type = IfcSchema::Type::UNDEFINED, const std::vector<Argument*>& attributes)
: file_(file), id_(0), type_(type), attributes_(attributes), initialized_(true)
{}
*/
void load() const;
IfcEntityInstanceData(const IfcEntityInstanceData& e);
~IfcEntityInstanceData();
virtual ~IfcEntityInstanceData();
boost::shared_ptr<IfcEntityList> getInverse(const IfcParse::declaration* type, int attribute_index);
@@ -82,11 +68,15 @@ public:
// NB: This makes a copy of the argument
void setArgument(unsigned int i, Argument* a, IfcUtil::ArgumentType attr_type = IfcUtil::Argument_UNKNOWN);
unsigned int getArgumentCount() const {
if (!initialized_) {
load();
virtual unsigned int getArgumentCount() const {
if (type_ == 0) {
return 0;
}
if (type_->as_entity()) {
return type_->as_entity()->attribute_count();
} else {
return 1;
}
return (unsigned int)attributes_.size();
}
const IfcParse::declaration* type() const {
@@ -99,7 +89,7 @@ public:
unsigned int offset_in_file() const { return offset_in_file_; }
// NB: const ommitted for lazy loading
std::vector<Argument*>& attributes() const { return attributes_; }
Argument**& attributes() const { return attributes_; }
unsigned set_id(boost::optional<unsigned> i = boost::none);
};
+1 -1
View File
@@ -181,7 +181,7 @@ public:
std::string createTimestamp() const;
void load(const IfcEntityInstanceData&);
void load(unsigned entity_instance_name, std::vector<Argument*>& attributes);
size_t load(unsigned entity_instance_name, Argument**& attributes, size_t num_attributes);
void register_inverse(unsigned, Token);
void register_inverse(unsigned, IfcUtil::IfcBaseClass*);
+128 -77
View File
@@ -604,12 +604,54 @@ EntityArgument::EntityArgument(const Token& t) {
entity = file->schema()->instantiate(data);
}
namespace {
template <typename T>
class vector_or_array {
std::vector<T>* vector_;
T* array_;
size_t size_, index_;
public:
vector_or_array(std::vector<T>* vector)
: vector_(vector)
, array_(0)
, size_(0)
, index_(0)
{}
vector_or_array(Argument** arr, size_t size)
: vector_(0)
, array_(arr)
, size_(size)
, index_(0)
{}
void push_back(const T& t) {
if (array_ && index_ < size_) {
array_[index_++] = t;
} else if (vector_) {
vector_->push_back(t);
}
}
};
}
//
// Reads the arguments from a list of token
// Aditionally, registers the ids (i.e. #[\d]+) in the inverse map
//
void IfcParse::IfcFile::load(unsigned entity_instance_name, std::vector<Argument*>& attributes) {
size_t IfcParse::IfcFile::load(unsigned entity_instance_name, Argument**& attributes, size_t num_attributes) {
Token next = tokens->Next();
std::vector<Argument*>* vector = 0;
vector_or_array<Argument*> filler(attributes, num_attributes);
if (attributes == 0) {
vector = new std::vector<Argument*>();
filler = vector_or_array<Argument*>(vector);
}
size_t return_value = num_attributes;
while( next.startPos || next.lexer ) {
if ( TokenFunc::isOperator(next,',') ) {
// do nothing
@@ -617,59 +659,64 @@ void IfcParse::IfcFile::load(unsigned entity_instance_name, std::vector<Argument
break;
} else if ( TokenFunc::isOperator(next,'(') ) {
ArgumentList* alist = new ArgumentList();
load(entity_instance_name, alist->arguments());
attributes.push_back(alist);
alist->size() = load(entity_instance_name, alist->arguments(), 0);
filler.push_back(alist);
} else {
if ( TokenFunc::isIdentifier(next) ) {
if (!parsing_complete_) {
register_inverse(entity_instance_name, next);
}
} if ( TokenFunc::isKeyword(next) ) {
// tokens->Next();
try {
attributes.push_back(new EntityArgument(next));
filler.push_back(new EntityArgument(next));
} catch ( IfcException& e ) {
Logger::Message(Logger::LOG_ERROR, e.what());
}
} else {
attributes.push_back(new TokenArgument(next));
filler.push_back(new TokenArgument(next));
}
}
next = tokens->Next();
}
if (vector) {
attributes = new Argument*[vector->size()];
return_value = vector->size();
for (size_t i = 0; i < vector->size(); ++i) {
attributes[i] = vector->at(i);
}
}
delete vector;
return return_value;
}
IfcUtil::ArgumentType ArgumentList::type() const {
if (list.empty()) {
if (size_ == 0) {
return IfcUtil::Argument_EMPTY_AGGREGATE;
}
const IfcUtil::ArgumentType elem_type = list[0]->type();
const IfcUtil::ArgumentType elem_type = list_[0]->type();
return IfcUtil::make_aggregate(elem_type);
}
void ArgumentList::push(Argument* l) {
list.push_back(l);
}
// templated helper function for reading arguments into a list
template<typename T>
std::vector<T> read_aggregate_as_vector(const std::vector<Argument*>& list) {
std::vector<T> read_aggregate_as_vector(Argument** list, size_t size) {
std::vector<T> return_value;
return_value.reserve(list.size());
std::vector<Argument*>::const_iterator it = list.begin();
for (; it != list.end(); ++it) {
return_value.push_back(**it);
return_value.reserve(size);
for (size_t i = 0; i < size; ++i) {
return_value.push_back(*list[i]);
}
return return_value;
}
template<typename T>
std::vector< std::vector<T> > read_aggregate_of_aggregate_as_vector2(const std::vector<Argument*>& list) {
std::vector< std::vector<T> > read_aggregate_of_aggregate_as_vector2(Argument** list, size_t size) {
std::vector< std::vector<T> > return_value;
return_value.reserve(list.size());
std::vector<Argument*>::const_iterator it = list.begin();
for (; it != list.end(); ++it) {
return_value.push_back(**it);
return_value.reserve(size);
for (size_t i = 0; i < size; ++i) {
return_value.push_back(*list[i]);
}
return return_value;
}
@@ -678,45 +725,43 @@ std::vector< std::vector<T> > read_aggregate_of_aggregate_as_vector2(const std::
// Functions for casting the ArgumentList to other types
//
ArgumentList::operator std::vector<double>() const {
return read_aggregate_as_vector<double>(list);
return read_aggregate_as_vector<double>(list_, size_);
}
ArgumentList::operator std::vector<int>() const {
return read_aggregate_as_vector<int>(list);
return read_aggregate_as_vector<int>(list_, size_);
}
ArgumentList::operator std::vector<std::string>() const {
return read_aggregate_as_vector<std::string>(list);
return read_aggregate_as_vector<std::string>(list_, size_);
}
ArgumentList::operator std::vector<boost::dynamic_bitset<> >() const {
return read_aggregate_as_vector<boost::dynamic_bitset<> >(list);
return read_aggregate_as_vector<boost::dynamic_bitset<> >(list_, size_);
}
ArgumentList::operator IfcEntityList::ptr() const {
IfcEntityList::ptr l ( new IfcEntityList() );
std::vector<Argument*>::const_iterator it;
for ( it = list.begin(); it != list.end(); ++ it ) {
for (size_t i = 0; i < size_; ++i) {
// FIXME: account for $
IfcUtil::IfcBaseClass* entity = **it;
IfcUtil::IfcBaseClass* entity = *list_[i];
l->push(entity);
}
return l;
}
ArgumentList::operator std::vector< std::vector<int> >() const {
return read_aggregate_of_aggregate_as_vector2<int>(list);
return read_aggregate_of_aggregate_as_vector2<int>(list_, size_);
}
ArgumentList::operator std::vector< std::vector<double> >() const {
return read_aggregate_of_aggregate_as_vector2<double>(list);
return read_aggregate_of_aggregate_as_vector2<double>(list_, size_);
}
ArgumentList::operator IfcEntityListList::ptr() const {
IfcEntityListList::ptr l ( new IfcEntityListList() );
std::vector<Argument*>::const_iterator it;
for ( it = list.begin(); it != list.end(); ++ it ) {
const Argument* arg = *it;
for (size_t i = 0; i < size_; ++i) {
const Argument* arg = list_[i];
const ArgumentList* arg_list;
if ((arg_list = dynamic_cast<const ArgumentList*>(arg)) != 0) {
IfcEntityList::ptr e = *arg_list;
@@ -726,15 +771,16 @@ ArgumentList::operator IfcEntityListList::ptr() const {
return l;
}
unsigned int ArgumentList::size() const { return (unsigned int) list.size(); }
unsigned int ArgumentList::size() const { return (unsigned int)size_; }
Argument* ArgumentList::operator [] (unsigned int i) const {
if ( i >= list.size() ) {
if (i >= size_) {
throw IfcAttributeOutOfRangeException("Argument index out of range");
}
return list[i];
return list_[i];
}
/*
void ArgumentList::set(unsigned int i, Argument* argument) {
while (size() < i) {
push(new NullArgument());
@@ -746,13 +792,16 @@ void ArgumentList::set(unsigned int i, Argument* argument) {
list.push_back(argument);
}
}
*/
std::string ArgumentList::toString(bool upper) const {
std::stringstream ss;
ss << "(";
for( std::vector<Argument*>::const_iterator it = list.begin(); it != list.end(); it ++ ) {
if ( it != list.begin() ) ss << ",";
ss << (*it)->toString(upper);
for (size_t i = 0; i < size_; ++i) {
if (i != 0) {
ss << ",";
}
ss << list_[i]->toString(upper);
}
ss << ")";
return ss.str();
@@ -761,10 +810,10 @@ std::string ArgumentList::toString(bool upper) const {
bool ArgumentList::isNull() const { return false; }
ArgumentList::~ArgumentList() {
for( std::vector<Argument*>::iterator it = list.begin(); it != list.end(); it ++ ) {
delete (*it);
for (size_t i = 0; i < size_; ++i) {
delete list_[i];
}
list.clear();
delete[] list_;
}
@@ -850,8 +899,7 @@ void IfcParse::IfcFile::load(const IfcEntityInstanceData& data) {
if (!TokenFunc::isKeyword(datatype)) throw IfcException("Unexpected token while parsing entity instance");
}
tokens->Next();
// TODO: reserve based on number of schema attrs
load(data.id(), data.attributes());
load(data.id(), data.attributes(), data.getArgumentCount());
unsigned int old_offset = tokens->stream->Tell();
Token semilocon = tokens->Next();
if (!TokenFunc::isOperator(semilocon, ';')) {
@@ -884,29 +932,36 @@ void IfcParse::IfcFile::unregister_inverse(unsigned id_from, IfcUtil::IfcBaseCla
// Note that this initializes the entity if it is not initialized
//
std::string IfcEntityInstanceData::toString(bool upper) const {
if (!initialized_) {
if (attributes_ == 0) {
load();
}
std::stringstream ss;
ss.imbue(std::locale::classic());
std::string dt = type()->name();
if (upper) {
boost::to_upper(dt);
}
std::string dt;
if (type_) {
dt = type()->name();
if (upper) {
boost::to_upper(dt);
}
if (type()->as_entity() || id_ != 0) {
ss << "#" << id_ << "=";
if (type()->as_entity() || id_ != 0) {
ss << "#" << id_ << "=";
}
}
ss << dt << "(";
std::vector<Argument*>::const_iterator it = attributes_.begin();
for (; it != attributes_.end(); ++it) {
if (it != attributes_.begin()) {
for (size_t i = 0; i < getArgumentCount(); ++i) {
if (i != 0) {
ss << ",";
}
ss << (*it)->toString(upper);
if (attributes_[i] == 0) {
ss << "$";
} else {
ss << attributes_[i]->toString(upper);
}
}
ss << ")";
@@ -914,10 +969,10 @@ std::string IfcEntityInstanceData::toString(bool upper) const {
}
IfcEntityInstanceData::~IfcEntityInstanceData() {
std::vector<Argument*>::const_iterator it = attributes_.begin();
for (; it != attributes_.end(); ++it) {
delete *it;
for (size_t i = 0; i < getArgumentCount(); ++i) {
delete attributes_[i];
}
delete[] attributes_;
}
unsigned IfcEntityInstanceData::set_id(boost::optional<unsigned> i) {
@@ -936,8 +991,11 @@ IfcEntityList::ptr IfcEntityInstanceData::getInverse(const IfcParse::declaration
}
void IfcEntityInstanceData::load() const {
// type_ is 0 for header entities which have their size predetermined in code
if (type_ != 0) {
attributes_ = new Argument*[getArgumentCount()];
}
file->load(*this);
initialized_ = true;
}
IfcEntityInstanceData::IfcEntityInstanceData(const IfcEntityInstanceData& e) {
@@ -945,21 +1003,23 @@ IfcEntityInstanceData::IfcEntityInstanceData(const IfcEntityInstanceData& e) {
type_ = e.type_;
id_ = 0;
// In order not to have the instance read from file
initialized_ = true;
const unsigned int count = e.getArgumentCount();
// In order not to have the instance read from file
attributes_ = new Argument*[count];
for (unsigned int i = 0; i < count; ++i) {
attributes_[i] = 0;
this->setArgument(i, e.getArgument(i));
}
}
Argument* IfcEntityInstanceData::getArgument(unsigned int i) const {
if (!initialized_) {
if (attributes_ == 0) {
load();
}
if (i < attributes_.size()) {
if (i < getArgumentCount()) {
return attributes_[i];
} else {
throw IfcParse::IfcException("Attribute index out of range");
@@ -1058,14 +1118,10 @@ public:
};
void IfcEntityInstanceData::setArgument(unsigned int i, Argument* a, IfcUtil::ArgumentType attr_type) {
if (!initialized_) {
if (attributes_ == 0) {
load();
}
while (attributes_.size() < i) {
attributes_.push_back(new NullArgument());
}
if (attr_type == IfcUtil::Argument_UNKNOWN) {
attr_type = a->type();
}
@@ -1178,7 +1234,7 @@ void IfcEntityInstanceData::setArgument(unsigned int i, Argument* a, IfcUtil::Ar
return;
}
if (i < attributes_.size()) {
if (attributes_[i] != 0) {
Argument* current_attribute = attributes_[i];
if (this->file) {
unregister_inverse_visitor visitor(*this->file, *this);
@@ -1192,12 +1248,7 @@ void IfcEntityInstanceData::setArgument(unsigned int i, Argument* a, IfcUtil::Ar
apply_individual_instance_visitor(copy).apply(visitor);
}
if (i < attributes_.size()) {
attributes_[i] = copy;
} else {
// We have asserted above that the size is at least i
attributes_.push_back(copy);
}
attributes_[i] = copy;
}
//
+6 -4
View File
@@ -160,9 +160,11 @@ namespace IfcParse {
/// ==========
class IFC_PARSE_API ArgumentList: public Argument {
private:
std::vector<Argument*> list;
void push(Argument* l);
size_t size_;
Argument** list_;
public:
ArgumentList() : size_(0), list_(0) {}
~ArgumentList();
void read(IfcSpfLexer* t, std::vector<unsigned int>& ids);
@@ -183,11 +185,11 @@ namespace IfcParse {
unsigned int size() const;
Argument* operator [] (unsigned int i) const;
void set(unsigned int i, Argument*);
std::string toString(bool upper=false) const;
std::vector<Argument*>& arguments() { return list; }
Argument**& arguments() { return list_; }
size_t& size() { return size_; }
};
+9 -6
View File
@@ -35,14 +35,17 @@ static const char * const DATA = "DATA";
using namespace IfcParse;
HeaderEntity::HeaderEntity(const char * const datatype, IfcFile* file)
: IfcEntityInstanceData(0, file), _datatype(datatype)
HeaderEntity::HeaderEntity(const char * const datatype, size_t size, IfcFile* file)
: IfcEntityInstanceData(file, size), size_(size), _datatype(datatype)
{
if (file) {
offset_in_file_ = file->stream->Tell();
load();
} else {
initialized_ = true;
// attributes_ = new Argument*[size];
for (size_t i = 0; i < size; ++i) {
attributes_[i] = 0;
}
}
}
@@ -168,6 +171,6 @@ FileSchema& IfcSpfHeader::file_schema() {
}
}
FileDescription::FileDescription(IfcFile* file) : HeaderEntity(FILE_DESCRIPTION, file) {}
FileName::FileName(IfcFile* file) : HeaderEntity(FILE_NAME, file) {}
FileSchema::FileSchema(IfcFile* file) : HeaderEntity(FILE_SCHEMA, file) {}
FileDescription::FileDescription(IfcFile* file) : HeaderEntity(FILE_DESCRIPTION, 2, file) {}
FileName::FileName(IfcFile* file) : HeaderEntity(FILE_NAME, 7, file) {}
FileSchema::FileSchema(IfcFile* file) : HeaderEntity(FILE_SCHEMA, 1, file) {}
+6 -11
View File
@@ -30,11 +30,12 @@ namespace IfcParse {
class IFC_PARSE_API HeaderEntity : public IfcEntityInstanceData {
private:
const char * const _datatype;
size_t size_;
HeaderEntity(const HeaderEntity&); //N/A
HeaderEntity& operator =(const HeaderEntity&); //N/A
protected:
HeaderEntity(const char * const datatype, IfcParse::IfcFile* file);
HeaderEntity(const char * const datatype, size_t size, IfcParse::IfcFile* file);
void setValue(unsigned int i, const std::string& s) {
IfcWrite::IfcWriteArgument* argument = new IfcWrite::IfcWriteArgument;
@@ -49,19 +50,13 @@ protected:
}
public:
virtual unsigned int getArgumentCount() const {
return size_;
}
std::string toString(bool upper=false) const {
std::stringstream ss;
// Unfortunately this is duplicated from IfcEntityInstanceData::toString()
ss << _datatype << "(";
std::vector<Argument*>::const_iterator it = attributes_.begin();
for (; it != attributes_.end(); ++it) {
if (it != attributes_.begin()) {
ss << ",";
}
ss << (*it)->toString(upper);
}
ss << ")";
ss << _datatype << IfcEntityInstanceData::toString(upper);
return ss.str();
}
};