import std/hashes import html/enums import chame/tags #TODO use a better hash map const CAtomFactoryStrMapLength = 1024 # must be a power of 2 static: doAssert (CAtomFactoryStrMapLength and (CAtomFactoryStrMapLength - 1)) == 0 # Null atom + mapped tag types + mapped attr types const AttrMapNum = 1 + ({TagType.low..TagType.high} - {TAG_UNKNOWN}).card + ({AttrType.low..AttrType.high} - {atUnknown}).card type CAtom* = distinct int CAtomFactoryInit = object obj: CAtomFactoryObj attrToAtom: array[AttrType, CAtom] atomToAttr: array[AttrMapNum, AttrType] CAtomFactoryObj = object strMap: array[CAtomFactoryStrMapLength, seq[CAtom]] atomMap: seq[string] #TODO could be a ptr probably CAtomFactory* = ref CAtomFactoryObj const CAtomNull* = CAtom(0) # Mandatory Atom functions func `==`*(a, b: CAtom): bool {.borrow.} func hash*(atom: CAtom): Hash {.borrow.} func `$`*(a: CAtom): string {.borrow.} func toAtom(factory: var CAtomFactoryObj, s: string): CAtom = let h = s.hash() let i = h and (factory.strMap.len - 1) for atom in factory.strMap[i]: if factory.atomMap[int(atom)] == s: # Found return atom # Not found let atom = CAtom(factory.atomMap.len) factory.atomMap.add(s) factory.strMap[i].add(atom) return atom const factoryInit = (func(): CAtomFactoryInit = var init = CAtomFactoryInit() # Null atom init.obj.atomMap.add("") # TagType: 1..TagType.high for tagType in TagType(1) .. TagType.high: discard init.obj.toAtom($tagType) # Attr: may overlap with TagType; exclude atUnknown for attrType in AttrType(1) .. AttrType.high: let atom = init.obj.toAtom($attrType) init.attrToAtom[attrType] = atom init.atomToAttr[int(atom)] = attrType return init )() proc newCAtomFactory*(): CAtomFactory = let factory = new(CAtomFactory) factory[] = factoryInit.obj return factory func toAtom*(factory: CAtomFactory, s: string): CAtom = return factory[].toAtom(s) func toAtom*(factory: CAtomFactory, tagType: TagType): CAtom = assert tagType != TAG_UNKNOWN return CAtom(tagType) func toAtom*(factory: CAtomFactory, attrType: AttrType): CAtom = assert attrType != atUnknown return factoryInit.attrToAtom[attrType] func toStr*(factory: CAtomFactory, atom: CAtom): string = return factory.atomMap[int(atom)] func toTagType*(factory: CAtomFactory, atom: CAtom): TagType = let i = int(atom) if i in 1 .. int(TagType.high): return TagType(atom) return TAG_UNKNOWN func toAttrType*(factory: CAtomFactory, atom: CAtom): AttrType = let i = int(atom) if i < factoryInit.atomToAttr.len: return factoryInit.atomToAttr[i] return atUnknown