about summary refs log tree commit diff stats
path: root/src/utils/twtstr.nim
diff options
context:
space:
mode:
authorbptato <nincsnevem662@gmail.com>2024-08-02 00:29:45 +0200
committerbptato <nincsnevem662@gmail.com>2024-08-02 00:44:19 +0200
commit8f88e5f05b76dd9b16ba91c9e28f07bd1549ae93 (patch)
treeaf65e0743bc92a0dd312b0f0f09b36ec8fa14d70 /src/utils/twtstr.nim
parent22625453ef3275adab3a47990c242dc92397b02b (diff)
downloadchawan-8f88e5f05b76dd9b16ba91c9e28f07bd1549ae93.tar.gz
cssvalues, twtstr, mediaquery: refactor & fixes
* cssvalues, twtstr: unify enum parsing code paths, parse enums by
  bisearch instead of hash tables
* mediaquery: refactor (long overdue), fix range comparison syntax
  parsing, make ident comparisons case-insensitive (as they should be)
Diffstat (limited to 'src/utils/twtstr.nim')
-rw-r--r--src/utils/twtstr.nim53
1 files changed, 25 insertions, 28 deletions
diff --git a/src/utils/twtstr.nim b/src/utils/twtstr.nim
index 7cadd41f..a5770042 100644
--- a/src/utils/twtstr.nim
+++ b/src/utils/twtstr.nim
@@ -537,37 +537,34 @@ proc makeCRLF*(s: string): string =
     else:
       result &= s[i]
 
+type IdentMapItem* = tuple[s: string; n: int]
+
+func getIdentMap*[T: enum](e: typedesc[T]): seq[IdentMapItem] =
+  result = @[]
+  for e in T.low .. T.high:
+    result.add(($e, int(e)))
+  result.sort(proc(x, y: IdentMapItem): int = cmp(x[0], y[0]))
+
 func strictParseEnum*[T: enum](s: string): Option[T] =
-  # cmp when len is small enough, otherwise hashmap
-  when {T.low..T.high}.len <= 4:
-    for e in T.low .. T.high:
-      if $e == s:
-        return some(e)
-  else:
-    const tab = (func(): Table[string, T] =
-      result = initTable[string, T]()
-      for e in T.low .. T.high:
-        result[$e] = e
-    )()
-    if s in tab:
-      return some(tab[s])
+  const IdentMap = getIdentMap(T)
+  let i = IdentMap.binarySearch(s, proc(x: IdentMapItem; y: string): int =
+    return x[0].cmp(y)
+  )
+  if i != -1:
+    return some(cast[T](IdentMap[i].n))
   return none(T)
 
-func parseEnumNoCase*[T: enum](s: string): Option[T] =
-  # cmp when len is small enough, otherwise hashmap
-  when {T.low..T.high}.len <= 4:
-    for e in T.low .. T.high:
-      if ($e).equalsIgnoreCase(s):
-        return some(e)
-  else:
-    const tab = (func(): Table[string, T] =
-      result = initTable[string, T]()
-      for e in T.low .. T.high:
-        result[$e] = e
-    )()
-    if s in tab:
-      return some(tab[s])
-  return none(T)
+func parseEnumNoCase0*(map: openArray[IdentMapItem]; s: string): Opt[int] =
+  let i = map.binarySearch(s, proc(x: IdentMapItem; y: string): int =
+    return x[0].cmpIgnoreCase(y)
+  )
+  if i != -1:
+    return ok(map[i].n)
+  return err()
+
+func parseEnumNoCase*[T: enum](s: string): Opt[T] =
+  const IdentMap = getIdentMap(T)
+  return ok(cast[T](?IdentMap.parseEnumNoCase0(s)))
 
 proc getContentTypeAttr*(contentType, attrname: string): string =
   var i = contentType.find(';')