Best way to reserve inline memory?

I'm currently using "fat" reference types to isolate state across threads. The maximum size of said state is capped to some known-at-compile-time-but-ideally-easy-to-change size. For the most part, I'm using that memory either as raw bytes, or bound to an array of small, fixed-size structs.

My assertions / assumptions are:

  • the number of objects is dynamic but their individual sizes are fixed
  • the number of objects will steadily grow until some arbitrary cpu limit kicks in, then mostly remain constant
  • memory management is fast, but there are probably some locks involved somewhere

For these reasons, I would like to (eventually) use an arena allocator but, while my objects are fixed in size, they are composed out of smaller structs (nominally non-copyable, but I had to relax that a bit and add a reset() method due to known bugs / limitations in the language). Unfortunately, all of them are currently using Buffer.allocate(static_size) which results in another reference. I could use Array but, that too is a reference pretending to be a value under the hood.

Ideally this would work for both structs and references, but since I plan on using pools anyway, I could live with a reference-only solution (I'd just allocate everything once and pool the top-level objects). On references, I could use the undocumented _getUnsafePointerToStoredProperties method, wrap all other state in a local struct and add MemoryLayout<local_state> to get the address of the "trailer" but I still have no way of telling the compiler to reserve some bytes for storage:

class Something {
    struct Header {
        var size = 0
        var isItMonday = true
    }
    private var header = Header()
    private var storage: UnsafeMutableRawPointer { _getUnsafePointerToStoredProperties(self) + MemoryLayout<Header>.stride }
    private var trailer: ???
}

I'd prefer something other than mental bit masking:

struct B16 { var a = Int64(0), b = Int64(0) }
struct B32 { var a = B16(), b = B16() }
struct B64 { var a = B32(), b = B32() }
// ...
struct Trailer { var a = B64(), b = B32(), c = B16(), d = Int8(0) } // 113 (120) bytes

1 Like

Can I interest you in ManagedBuffer ManagedBuffer | Apple Developer Documentation?

5 Likes

Well, I guess it's better than a class containing an array, but it still feels like a non-composable library solution to a language issue: my top level objects are actually actors not classes, so if I want to use implicit isolation, I still end up with an actor containing structures with ManagedBuffer references (e.g. class containing array)

While we're on the subject of ManagedBuffer, shouldn't .create return Self? When subclassing, I have to force-downcast it (which works, but I'm getting _getUnsafePointerToStoredProperties vibes here)

2 Likes