diff --git a/src/ifcopenshell-python/ifcopenshell/geom/stats.py b/src/ifcopenshell-python/ifcopenshell/geom/stats.py index 769313cf70..364083acd7 100644 --- a/src/ifcopenshell-python/ifcopenshell/geom/stats.py +++ b/src/ifcopenshell-python/ifcopenshell/geom/stats.py @@ -138,6 +138,8 @@ class StatsCollector: counters: list + num_semis: int = 0 + def __init__(self): self.streamer = ifcopenshell_wrapper.InstanceStreamer() self.needs_data = True @@ -151,17 +153,19 @@ class StatsCollector: def feed(self, data: str): self.streamer.pushPage(data) self.needs_data = False + self.num_semis = self.streamer.semicolonCount() @staticmethod - def fromFilePath(fn, page_size: int = 4096): + def fromFilePath(fn, page_size: int = 102400): collector = StatsCollector() collector.page_size = page_size collector.feedFromFile(open(str(fn), encoding="ascii")) return collector def next(self): - if self.streamer.hasSemicolon(): + if self.num_semis > 0: if inst := self.streamer.readInstancePy(True): + self.num_semis -= 1 return inst["type"], dict(list(inst.items())[2:]) else: self.finalized = True diff --git a/src/ifcparse/IfcFile.h b/src/ifcparse/IfcFile.h index 4adde443b3..96685a88ee 100644 --- a/src/ifcparse/IfcFile.h +++ b/src/ifcparse/IfcFile.h @@ -139,7 +139,9 @@ private: bool hasSemicolon() const; - void pushPage(const std::string& page); + size_t semicolonCount() const; + + void pushPage(const std::string& page); InstanceStreamer(); diff --git a/src/ifcparse/IfcParse.cpp b/src/ifcparse/IfcParse.cpp index 7da75a5515..2c53d759de 100644 --- a/src/ifcparse/IfcParse.cpp +++ b/src/ifcparse/IfcParse.cpp @@ -1371,6 +1371,30 @@ bool IfcParse::InstanceStreamer::hasSemicolon() const { return false; } +size_t IfcParse::InstanceStreamer::semicolonCount() const { + auto local_stream = stream_->clone(); + auto local_lexer = IfcSpfLexer(&local_stream); + Token t; + size_t count = 0; + try { + t = local_lexer.Next(); + } catch (const std::out_of_range&) { + return false; + } + while (t.type != Token_NONE) { + if (TokenFunc::isOperator(t, ';')) { + count++; + } + try { + t = local_lexer.Next(); + } catch (const std::out_of_range&) { + // This most likely happens when a page boundary is contained within a string + break; + } + } + return count; +} + void IfcParse::InstanceStreamer::pushPage(const std::string& page) { stream_->pushNextPage(page);