diff --git a/src/jdict.nim b/src/jdict.nim index 0eecb58..f541ac7 100644 --- a/src/jdict.nim +++ b/src/jdict.nim @@ -11,3 +11,12 @@ proc contains*[K, V](d: JDict[K, V], k: K): bool {.importcpp: "#.hasOwnProperty( proc del*[K, V](d: JDict[K, V], k: K) {.importcpp: "delete #[#]".} +type + JSeq*[T] = ref object + +proc `[]`*[T](s: JSeq[T], i: int): T {.importcpp: "#[#]", noSideEffect.} +proc `[]=`*[T](s: JSeq[T], i: int, v: T) {.importcpp: "#[#] = #", noSideEffect.} + +proc newJSeq*[T](): JSeq[T] {.importcpp: "[@]".} +proc len*[T](s: JSeq[T]): int {.importcpp: "#.length", noSideEffect.} +proc add*[T](s: JSeq[T]; x: T) {.importcpp: "#.push(#)", noSideEffect.} diff --git a/src/vstyles.nim b/src/vstyles.nim index a6f1996..2f854e1 100644 --- a/src/vstyles.nim +++ b/src/vstyles.nim @@ -1,5 +1,5 @@ -import kdom, macros +import kdom, macros, jdict type StyleAttr* {.pure.} = enum @@ -208,62 +208,93 @@ macro buildLookupTables(): untyped = buildLookupTables() -type - VStyle* = ref object - attrs: array[StyleAttr, cstring] - mask: set[StyleAttr] +# I optimized the heck out of this representation since profiling showed +# it's relevant. +# even index: key, odd index: value; done this way for memory efficiency: -proc kout[T](x: T) {.importc: "console.log", varargs.} +type + VStyle* = JSeq[cstring] proc eq*(a, b: VStyle): bool = if a.isNil: if b.isNil: return true else: return false elif b.isNil: return false - if a.mask != b.mask: return false - for x in a.mask: - if a.attrs[x] != b.attrs[x]: return false + if a.len != b.len: return false + for i in 0.. a: + s.add nil + s.add nil + # insertion point here: + for j in countdown(s.len-1, i, 2): + s[j] = s[j-2] + s[j-1] = s[j-3] + s[i] = a + s[i+1] = value + return + inc i, 2 + s.add a + s.add value + +proc setAttr*(s: VStyle; attr: StyleAttr, value: cstring) {.noSideEffect.} = assert value != nil, "value must not be nil" - s.attrs[attr] = value - incl(s.mask, attr) + setAttr(s, toStyleAttrName[attr], value) -proc getAttr*(s: VStyle; attr: StyleAttr): cstring = +proc getAttr*(s: VStyle; attr: StyleAttr): cstring {.noSideEffect.} = ## returns 'nil' if the attribute has not been set. - result = s.attrs[attr] + var i = 0 + let a = toStyleAttrName[attr] + while i < s.len: + if s[i] == a: + return s[i+1] + elif s[i] > a: + return nil + inc i, 2 -proc style*(pairs: varargs[(StyleAttr, cstring)]): VStyle = +proc style*(pairs: varargs[(StyleAttr, cstring)]): VStyle {.noSideEffect.} = ## constructs a VStyle object from a list of (attribute, value)-pairs. - result = VStyle(mask: {}) + result = newJSeq[cstring]() for x in pairs: result.setAttr x[0], x[1] -proc style*(a: StyleAttr; val: cstring): VStyle = +proc style*(a: StyleAttr; val: cstring): VStyle {.noSideEffect.} = ## constructs a VStyle object from a single (attribute, value)-pair. - result = VStyle(mask: {}) + result = newJSeq[cstring]() result.setAttr a, val -proc setStyle(d: Style; key, val: cstring) {.importcpp: "#[#] = #".} +proc setStyle(d: Style; key, val: cstring) {.importcpp: "#[#] = #", noSideEffect.} -proc merge*(a, b: VStyle): VStyle = +proc merge*(a, b: VStyle): VStyle {.noSideEffect.} = ## merges two styles. ``b`` takes precedence over ``a``. - result = VStyle(mask: {}) - for i in low(StyleAttr)..high(StyleAttr): - result.attrs[i] = if b.attrs[i].isNil: a.attrs[i] else: b.attrs[i] - if result.attrs[i] != nil: incl(result.mask, i) + result = newJSeq[cstring]() + for i in 0..