> C and C++ have aligned_alloc for a while now, which should work everywhere as 
> long as the compiler is somewhat up to date (C11/C++17).

Just be aware of the different argument order on Windows. These are my 
aligned_alloc primitives: 
<https://github.com/mratsim/weave-io/blob/8672f1cc4182633a9e31a2eb6641e941926b869d/weave_io/primitives/allocs.nim#L42-L55>
    
    
    when defined(windows):
      proc aligned_alloc_windows(size, alignment: int): pointer 
{.tags:[HeapAlloc],importc:"_aligned_malloc", header:"<malloc.h>".}
        # Beware of the arg order!
      proc aligned_alloc(alignment, size: int): pointer {.inline.} =
        aligned_alloc_windows(size, alignment)
      proc aligned_free(p: pointer){.tags:[HeapAlloc],importc:"_aligned_free", 
header:"<malloc.h>".}
    elif defined(osx):
      proc posix_memalign(mem: var pointer, alignment, size: 
int){.tags:[HeapAlloc],importc, header:"<stdlib.h>".}
      proc aligned_alloc(alignment, size: int): pointer {.inline.} =
        posix_memalign(result, alignment, size)
      proc aligned_free(p: pointer) {.tags:[HeapAlloc], importc: "free", 
header: "<stdlib.h>".}
    else:
      proc aligned_alloc(alignment, size: int): pointer 
{.tags:[HeapAlloc],importc, header:"<stdlib.h>".}
      proc aligned_free(p: pointer) {.tags:[HeapAlloc], importc: "free", 
header: "<stdlib.h>".}
    
    
    Run

and then I build these high-level wrappers on top: 
<https://github.com/mratsim/weave-io/blob/8672f1cc4182633a9e31a2eb6641e941926b869d/weave_io/primitives/allocs.nim#L100-L133>
    
    
    proc allocHeapAligned*(T: typedesc, alignment: static Natural): ptr T 
{.inline.} =
      # aligned_alloc requires allocating in multiple of the alignment.
      let # Cannot be static with bitfields. Workaround 
https://github.com/nim-lang/Nim/issues/19040
        size = sizeof(T)
        requiredMem = size.roundNextMultipleOf(alignment)
      
      cast[ptr T](aligned_alloc(alignment, requiredMem))
    
    proc allocHeapUncheckedAligned*(T: typedesc, size: int, alignment: static 
Natural): ptr T {.inline.} =
      ## Aligned heap allocation for types containing a variable-sized 
UncheckedArray field
      ## or an importc type with missing size information
      # aligned_alloc requires allocating in multiple of the alignment.
      let requiredMem = size.roundNextMultipleOf(alignment)
      
      cast[ptr T](aligned_alloc(alignment, requiredMem))
    
    proc allocHeapArrayAligned*(T: typedesc, len: int, alignment: static 
Natural): ptr UncheckedArray[T] {.inline.} =
      # aligned_alloc requires allocating in multiple of the alignment.
      let
        size = sizeof(T) * len
        requiredMem = size.roundNextMultipleOf(alignment)
      
      cast[ptr UncheckedArray[T]](aligned_alloc(alignment, requiredMem))
    
    proc allocHeapAlignedPtr*(T: typedesc[ptr], alignment: static Natural): T 
{.inline.} =
      allocHeapAligned(typeof(default(T)[]), alignment)
    
    proc allocHeapUncheckedAlignedPtr*(T: typedesc[ptr], size: int, alignment: 
static Natural): T {.inline.} =
      ## Aligned heap allocation for types containing a variable-sized 
UncheckedArray field
      ## or an importc type with missing size information
      allocHeapUncheckedAligned(typeof(default(T)[]), size, alignment)
    
    proc freeHeapAligned*(p: pointer) {.inline.} =
      aligned_free(p)
    
    
    Run

Reply via email to