about summary refs log tree commit diff stats
path: root/src/utils/strwidth.nim
Commit message (Expand)AuthorAgeFilesLines
* strwidth, renderdocument: small refactoringbptato2024-03-031-37/+20
* Re-design word handling, add e, E, W, B, etc.bptato2024-01-191-11/+19
* charwidth: use pre-generated map filebptato2024-01-041-136/+2
* strwidth & url fixesbptato2023-12-161-1/+1
* charcategory: move out isDigitAsciibptato2023-12-141-0/+3
* break up twtstr somewhatbptato2023-12-131-0/+246
id='n68' href='#n68'>68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
discard """
  output: '''foo bar to appendmore here
foo bar to appendmore here
foo bar to appendmore here
foo bar to appendmore here
foo bar to appendmore here
after 20 20'''
  cmd: '''nim c --newruntime $file'''
"""

type
  mystring = object
    len, cap: int
    data: ptr UncheckedArray[char]

var
  allocCount, deallocCount: int

proc `=destroy`*(s: var mystring) =
  if s.data != nil:
    dealloc(s.data)
    inc deallocCount
    s.data = nil
    s.len = 0
    s.cap = 0

proc `=sink`*(a: var mystring, b: mystring) =
  # we hope this is optimized away for not yet alive objects:
  if a.data != nil and a.data != b.data:
    dealloc(a.data)
    inc deallocCount
  a.len = b.len
  a.cap = b.cap
  a.data = b.data

proc `=`*(a: var mystring; b: mystring) =
  if a.data != nil and a.data != b.data:
    dealloc(a.data)
    inc deallocCount
    a.data = nil
  a.len = b.len
  a.cap = b.cap
  if b.data != nil:
    a.data = cast[type(a.data)](alloc(a.cap + 1))
    inc allocCount
    copyMem(a.data, b.data, a.cap+1)

proc resize(self: var mystring) =
  if cap == 0: cap = 8
  else: cap = (cap * 3) shr 1
  if data == nil: inc allocCount
  data = cast[type(data)](realloc(data, cap + 1))

proc add*(self: var mystring; c: char) =
  if self.len >= self.cap: resize(self)
  self.data[self.len] = c
  self.data[self.len+1] = '\0'
  inc self.len

proc ensure(self: var mystring; newLen: int) =
  if newLen >= cap:
    cap = max((cap * 3) shr 1, newLen)
    if cap > 0:
      if data == nil: inc allocCount
      data = cast[type(data)](realloc(data, cap + 1))

proc add*(self: var mystring; y: mystring) =
  let newLen = len + y.len
  ensure(self, newLen)
  copyMem(addr data[len], y.data, y.data.len + 1)
  len = newLen

proc create*(lit: string): mystring =
  let newLen = lit.len
  ensure(result, newLen)
  copyMem(addr result.data[result.len], unsafeAddr lit[0], newLen + 1)
  result.len = newLen

proc `&`*(a, b: mystring): mystring =
  result = a
  result.add b

proc main(n: int) =
  var a: mystring
  let b = create" to append"
  for i in 0..<n:
    if i > 4: break
    a = create"foo bar"
    let c = b & create"more here"
    a.add c
    echo cstring(a.data)

  var x: array[4, mystring]
  for i in 0..high(x): x[i] = create"added to array"

main(1000)
echo "after ", allocCount, " ", deallocCount