ref: move StringPool cache into StringPool
This commit is contained in:
@@ -53,6 +53,7 @@ public struct StringPool {
|
||||
let dataString: Index
|
||||
let dataStyle: Index
|
||||
}
|
||||
private var _lookupTable: [StringPoolRef: String] = [:]
|
||||
|
||||
init(_ idx: Index, _ bytes: RawBytes) throws {
|
||||
self.init(try ChunkHeader(idx, bytes, expect: .StringPool))
|
||||
@@ -81,6 +82,9 @@ public struct StringPool {
|
||||
/// Retrieve string for given `StringPoolRef` index
|
||||
public func getString(_ idx: StringPoolRef) -> String {
|
||||
precondition(idx < stringCount, "Index out of bounds for string-pool string[\(idx) > \(stringCount)]")
|
||||
if let cached = _lookupTable[idx] {
|
||||
return cached
|
||||
}
|
||||
let offset = header._bytes.int32(_offset.indicesString + Index(idx) * 4)
|
||||
let dataOffset = _offset.dataString + Index(offset)
|
||||
return flags.contains(.Utf8)
|
||||
@@ -95,4 +99,15 @@ public struct StringPool {
|
||||
let dataOffset = _offset.dataStyle + Index(offset)
|
||||
return StringPoolSpan(dataOffset, header._bytes)
|
||||
}
|
||||
|
||||
/// Performs `getString()` and caches the results in a lookup-table.
|
||||
/// For memory-efficiency you should use this only on keys which are expected to repeat.
|
||||
public mutating func getStringCached(_ index: StringPoolRef) -> String {
|
||||
if let cached = _lookupTable[index] {
|
||||
return cached
|
||||
}
|
||||
let val = self.getString(index)
|
||||
_lookupTable[index] = val
|
||||
return val
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,15 +95,9 @@ public struct Xml_Parser {
|
||||
/// Iterate over whole tree and call `start` and `end` blocks for each element.
|
||||
/// Each `start` block contains the `tag` name and its attribute `(name, value)` pairs.
|
||||
public func iterElements(_ start: (_ startTag: String, _ attributes: AttributesDict) throws -> Void, _ end: (_ endTag: String) throws -> Void) throws {
|
||||
// cache StringPool lookups for faster access
|
||||
var _lookupTable: [StringPoolRef: String] = [:]
|
||||
var pool = stringPool
|
||||
func lookup(_ index: StringPoolRef) -> String {
|
||||
if let cached = _lookupTable[index] {
|
||||
return cached
|
||||
}
|
||||
let val = stringPool.getString(index)
|
||||
_lookupTable[index] = val
|
||||
return val
|
||||
pool.getStringCached(index)
|
||||
}
|
||||
// cache namespace prefix strings
|
||||
var namespaces: [StringPoolRef: String] = [:]
|
||||
@@ -120,7 +114,7 @@ public struct Xml_Parser {
|
||||
|
||||
case .XmlStartNamespace:
|
||||
let ns = XmlNamespace(chunk)
|
||||
namespaces[ns.uri] = lookup(ns.prefix)
|
||||
namespaces[ns.uri] = pool.getStringCached(ns.prefix)
|
||||
nsOnNextTag = ns.uri
|
||||
|
||||
case .XmlEndNamespace:
|
||||
@@ -131,10 +125,10 @@ public struct Xml_Parser {
|
||||
let elem = XmlStartElement(chunk)
|
||||
let attrs = AttributesDict(elem, stringPool, lookupFn: lookup(_:), namespaces: namespaces, nsNeedsAppend: nsOnNextTag)
|
||||
nsOnNextTag = nil
|
||||
try start(lookup(elem.name), attrs)
|
||||
try start(pool.getStringCached(elem.name), attrs)
|
||||
|
||||
case .XmlEndElement:
|
||||
try end(lookup(XmlEndElement(chunk).name))
|
||||
try end(pool.getStringCached(XmlEndElement(chunk).name))
|
||||
|
||||
default:
|
||||
throw AXMLError("Dont know how to handle \(chunk.type) (offset: \(chunk.index(.startOfChunk)))")
|
||||
|
||||
Reference in New Issue
Block a user