Is there a simpler way of initializing it with the correct alignment?
    
    
    proc getAlignPadding(p: pointer, align: int): BiggestUInt =
      cast[BiggestUInt](p) mod BiggestUInt(align)
    
    # same interface as std::align
    proc align(align: int, size: int, p: var pointer, space: var BiggestUInt): 
bool =
      let padding = getAlignPadding(p, align)
      if padding + BiggestUInt(size) > space:
        p = nil
        false
      else:
        p = cast[pointer](cast[BiggestUInt](p) + padding)
        space -= padding
        true
    
    proc align[T](p: var pointer, space: var BiggestUInt): bool =
      align(alignof(T), sizeof(T), p, space)
    
    proc inPlaceAligned[T](p: pointer, value: sink T) {.nodestroy.} =
      var dest = cast[ptr T](p)
      dest[] = value
    
    template inPlace[T](p: pointer, space: SomeInteger, value: sink T): pointer 
=
      block:
        var p = p
        var space = BiggestUInt(space)
        if align[T](p, space):
          inPlaceAligned(p, value)
        p
    
    template inPlace[T](buffer: openArray[byte], value: sink T): pointer =
      block:
        var p: pointer = buffer[0].addr()
        var space = BiggestUInt(buffer.len())
        if align[T](p, space):
          inPlaceAligned(p, value)
        p
    
    proc bufferAs[T](buffer: openArray[byte]): ptr T =
      var p: pointer = buffer[0].addr()
      var space = BiggestUInt(buffer.len())
      if align[T](p, space):
        cast[ptr T](p)
      else:
        nil
    
    proc getDestroyAt[T](): proc(p: pointer) =
      proc(p: pointer) = cast[ptr T](p)[].`=destroy`()
    
    
    Run
    
    
    type Person = object
      age: int
      name: string
    
    type Dog = object
      age {.align(128).}: int
      name: string
    
    proc `=destroy`(x: Person) =
      debugEcho "Person destroyed"
    
    proc `=destroy`(x: Dog) =
      debugEcho "Dog destroyed"
    
    block:
      var buffer: array[sizeof(Person), byte]
      
      echo "initializing Person"
      var p = inPlace[Person](buffer, Person(age: 30, name: "Shaggy"))
      var destroyAt = getDestroyAt[Person]()
      
      if p.isNil():
        echo "buffer too small"
      else:
        echo bufferAs[Person](buffer)[]
        destroyAt(p)
      echo ""
    
    block:
      var buffer: array[sizeof(Dog), byte]
      
      echo "initializing Dog"
      var p = inPlace[Dog](buffer, Dog(age: 30, name: "Scooby"))
      var destroyAt = getDestroyAt[Dog]()
      
      if p.isNil():
        echo "buffer too small"
      else:
        echo bufferAs[Dog](buffer)[]
        destroyAt(p)
      echo ""
    
    
    Run
    
    
    initializing Person
    (age: 30, name: "Shaggy")
    Person destroyed
    
    initializing Dog
    buffer too small
    
    
    Run

Reply via email to