ref: move StringPool cache into StringPool
This commit is contained in:
@@ -53,6 +53,7 @@ public struct StringPool {
|
|||||||
let dataString: Index
|
let dataString: Index
|
||||||
let dataStyle: Index
|
let dataStyle: Index
|
||||||
}
|
}
|
||||||
|
private var _lookupTable: [StringPoolRef: String] = [:]
|
||||||
|
|
||||||
init(_ idx: Index, _ bytes: RawBytes) throws {
|
init(_ idx: Index, _ bytes: RawBytes) throws {
|
||||||
self.init(try ChunkHeader(idx, bytes, expect: .StringPool))
|
self.init(try ChunkHeader(idx, bytes, expect: .StringPool))
|
||||||
@@ -81,6 +82,9 @@ public struct StringPool {
|
|||||||
/// Retrieve string for given `StringPoolRef` index
|
/// Retrieve string for given `StringPoolRef` index
|
||||||
public func getString(_ idx: StringPoolRef) -> String {
|
public func getString(_ idx: StringPoolRef) -> String {
|
||||||
precondition(idx < stringCount, "Index out of bounds for string-pool string[\(idx) > \(stringCount)]")
|
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 offset = header._bytes.int32(_offset.indicesString + Index(idx) * 4)
|
||||||
let dataOffset = _offset.dataString + Index(offset)
|
let dataOffset = _offset.dataString + Index(offset)
|
||||||
return flags.contains(.Utf8)
|
return flags.contains(.Utf8)
|
||||||
@@ -95,4 +99,15 @@ public struct StringPool {
|
|||||||
let dataOffset = _offset.dataStyle + Index(offset)
|
let dataOffset = _offset.dataStyle + Index(offset)
|
||||||
return StringPoolSpan(dataOffset, header._bytes)
|
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.
|
/// 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.
|
/// 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 {
|
public func iterElements(_ start: (_ startTag: String, _ attributes: AttributesDict) throws -> Void, _ end: (_ endTag: String) throws -> Void) throws {
|
||||||
// cache StringPool lookups for faster access
|
var pool = stringPool
|
||||||
var _lookupTable: [StringPoolRef: String] = [:]
|
|
||||||
func lookup(_ index: StringPoolRef) -> String {
|
func lookup(_ index: StringPoolRef) -> String {
|
||||||
if let cached = _lookupTable[index] {
|
pool.getStringCached(index)
|
||||||
return cached
|
|
||||||
}
|
|
||||||
let val = stringPool.getString(index)
|
|
||||||
_lookupTable[index] = val
|
|
||||||
return val
|
|
||||||
}
|
}
|
||||||
// cache namespace prefix strings
|
// cache namespace prefix strings
|
||||||
var namespaces: [StringPoolRef: String] = [:]
|
var namespaces: [StringPoolRef: String] = [:]
|
||||||
@@ -120,7 +114,7 @@ public struct Xml_Parser {
|
|||||||
|
|
||||||
case .XmlStartNamespace:
|
case .XmlStartNamespace:
|
||||||
let ns = XmlNamespace(chunk)
|
let ns = XmlNamespace(chunk)
|
||||||
namespaces[ns.uri] = lookup(ns.prefix)
|
namespaces[ns.uri] = pool.getStringCached(ns.prefix)
|
||||||
nsOnNextTag = ns.uri
|
nsOnNextTag = ns.uri
|
||||||
|
|
||||||
case .XmlEndNamespace:
|
case .XmlEndNamespace:
|
||||||
@@ -131,10 +125,10 @@ public struct Xml_Parser {
|
|||||||
let elem = XmlStartElement(chunk)
|
let elem = XmlStartElement(chunk)
|
||||||
let attrs = AttributesDict(elem, stringPool, lookupFn: lookup(_:), namespaces: namespaces, nsNeedsAppend: nsOnNextTag)
|
let attrs = AttributesDict(elem, stringPool, lookupFn: lookup(_:), namespaces: namespaces, nsNeedsAppend: nsOnNextTag)
|
||||||
nsOnNextTag = nil
|
nsOnNextTag = nil
|
||||||
try start(lookup(elem.name), attrs)
|
try start(pool.getStringCached(elem.name), attrs)
|
||||||
|
|
||||||
case .XmlEndElement:
|
case .XmlEndElement:
|
||||||
try end(lookup(XmlEndElement(chunk).name))
|
try end(pool.getStringCached(XmlEndElement(chunk).name))
|
||||||
|
|
||||||
default:
|
default:
|
||||||
throw AXMLError("Dont know how to handle \(chunk.type) (offset: \(chunk.index(.startOfChunk)))")
|
throw AXMLError("Dont know how to handle \(chunk.type) (offset: \(chunk.index(.startOfChunk)))")
|
||||||
|
|||||||
Reference in New Issue
Block a user