summary refs log tree commit diff stats
path: root/lib
diff options
context:
space:
mode:
authorAmjad Ben Hedhili <amjadhedhili@outlook.com>2022-09-25 20:23:23 +0100
committerGitHub <noreply@github.com>2022-09-25 15:23:23 -0400
commitf7f375f59d99ab0006d3aab839449e61cc8153c0 (patch)
tree4071e7ab4f2815f9ffaa9c62a8d96d879cd20e1b /lib
parent30bd75e459eb52eb043071d91e333fcb3abacf15 (diff)
downloadNim-f7f375f59d99ab0006d3aab839449e61cc8153c0.tar.gz
Optimize `base64.encodeMime` (#20409)
* Optimize `base64.encodeMime`

* 5x faster for common scenarios, 13x faster if `lineLen` <= encoded
string's length or `newLine` is empty.
* Changed `lineLen`'s type to `Positive` to disallow `0`.

* Fix
Diffstat (limited to 'lib')
-rw-r--r--lib/pure/base64.nim26
1 files changed, 20 insertions, 6 deletions
diff --git a/lib/pure/base64.nim b/lib/pure/base64.nim
index 9b7af88ef..bc01a9164 100644
--- a/lib/pure/base64.nim
+++ b/lib/pure/base64.nim
@@ -180,7 +180,7 @@ proc encode*(s: string, safe = false): string =
     assert encode("Hello World") == "SGVsbG8gV29ybGQ="
   encodeImpl()
 
-proc encodeMime*(s: string, lineLen = 75, newLine = "\r\n"): string =
+proc encodeMime*(s: string, lineLen = 75.Positive, newLine = "\r\n"): string =
   ## Encodes `s` into base64 representation as lines.
   ## Used in email MIME format, use `lineLen` and `newline`.
   ##
@@ -191,11 +191,25 @@ proc encodeMime*(s: string, lineLen = 75, newLine = "\r\n"): string =
   ## * `decode proc<#decode,string>`_ for decoding a string
   runnableExamples:
     assert encodeMime("Hello World", 4, "\n") == "SGVs\nbG8g\nV29y\nbGQ="
-  result = newStringOfCap(encodeSize(s.len))
-  for i, c in encode(s):
-    if i != 0 and (i mod lineLen == 0):
-      result.add(newLine)
-    result.add(c)
+  template cpy(l, src, idx) =
+    b = l
+    while i < b:
+      result[i] = src[idx]
+      inc i
+      inc idx
+
+  if s.len == 0: return
+  let e = encode(s)
+  if e.len <= lineLen or newLine.len == 0:
+    return e
+  result = newString(e.len + newLine.len * ((e.len div lineLen) - int(e.len mod lineLen == 0)))
+  var i, j, k, b: int
+  let nd = e.len - lineLen
+  while j < nd:
+    cpy(i + lineLen, e, j)
+    cpy(i + newLine.len, newLine, k)
+    k = 0
+  cpy(result.len, e, j)
 
 proc initDecodeTable*(): array[256, char] =
   # computes a decode table at compile time