Skip to content

Instantly share code, notes, and snippets.

@bew
Created September 22, 2018 22:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bew/b816c76613574389445ba43b8f7110eb to your computer and use it in GitHub Desktop.
Save bew/b816c76613574389445ba43b8f7110eb to your computer and use it in GitHub Desktop.
Class pre-allocation in Crystal
class Object
alias TypeIdType = Int32
end
#
# This is unsafe to store any class created through the ObjectPool, as as
# soon the ObjectPool is GC-ed, all pointers to classes inside that pool
# will have unknown behavior if used.
class ObjectPool(T)
@buffer : Pointer(UInt8)
# Returns the size of the object pool.
getter size : Int32
# Creates an object pool with *size* number of pre-allocated class T.
def initialize(size : Int)
{% unless T < Reference %}
{% raise "Object type must be a class" %}
{% end %}
@size = size.to_i
@buffer = Pointer(UInt8).malloc(instance_sizeof(T) * size)
# NOTE: memory buffer is all 0
# Set type_id of each allocated T instances
@size.times do |index|
object_raw_ptr = unsafe_raw_ptr_at(index)
object_raw_ptr.as(Object::TypeIdType*).value = T.crystal_instance_type_id
end
end
# Returns the object at *index* as the given object type.
#
# Note that the object might not be initialized at this point,
# it is recommended to always initialize the instance when you
# get it for the first time.
def object_at(index) : T
object_raw_ptr = unsafe_raw_ptr_at(index)
object_raw_ptr.unsafe_as(T)
end
private def unsafe_raw_ptr_at(index)
# TODO: check *index* is in range
first_byte_index = instance_sizeof(T) * index
@buffer + first_byte_index
end
end
class Person
property name : String
property age : Int32
def initialize(@name, @age)
end
def init(*args, **kwargs)
# This is needed because `initialize` is protected,
# thus I can't call it from the outside.
#
# NOTE for me: this is one way to initialize the instance, but
# this `init` method should be explicitely declared by
# the user, not generated by some macros.
initialize(*args, **kwargs)
end
end
# ---------------------------------------------
def init_person_by_ref(person : Person)
person.name = "bew"
person.age = 3
end
def try_pre_alloc
pool = ObjectPool(Person).new 5
person = pool.object_at 1
person.init("init", -1)
p! person
init_person_by_ref(person)
p! person
end
try_pre_alloc
@bew
Copy link
Author

bew commented Oct 3, 2018

Copy link

ghost commented Oct 3, 2018

interesting might use this

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment