struct Pointer(T)
Overview
A typed pointer to some memory.
This is the only unsafe type in Crystal. If you are using a pointer, you are writing
unsafe code because a pointer doesn't know where it's pointing to nor how much memory
starting from it is valid. However, pointers make it possible to interface with C and
to implement efficient data structures. For example, bothArray andHash are
implemented using pointers.
You can obtain pointers in four ways:#new,#malloc,pointerof, or by calling a C
function that returns a pointer.
pointerof(x), wherex is a variable or an instance variable, returns a pointer to
that variable:
x = 1
ptr = pointerof(x)
ptr.value = 2
x # => 2
Use#value to dereference the pointer.
Note that a pointer isfalsey if it's null (if its address is zero).
When calling a C function that expects a pointer you can also passnil instead of using
Pointer.null to construct a null pointer.
For a safe alternative, seeSlice, which is a pointer with a size and with bounds checking.
Included Modules
Defined in:
pointer.crprimitives.cr
Constructors
-
.new(address : UInt64)
Returns a pointer that points to the given memory address.
-
.new(address : Int)
Returns a pointer that points to the given memory address.
DEPRECATED Call
.new(UInt64)directly instead - .new
Class Method Summary
-
.malloc(size : Int, value : T) : Pointer(T)
Allocates
size * sizeof(T)bytes from the system's heap initialized tovalue and returns a pointer to the first byte from that memory. -
.malloc(size : UInt64)
Allocates
size * sizeof(T)bytes from the system's heap initialized to zero and returns a pointer to the first byte from that memory. -
.malloc(size : Int = 1)
Allocates
size * sizeof(T)bytes from the system's heap initialized to zero and returns a pointer to the first byte from that memory. -
.malloc(size : Int, & : Int32 -> T) : Pointer(T)
Allocates
size * sizeof(T)bytes from the system's heap initialized to the value returned by the block (which is invoked once with each index in the range0...size) and returns a pointer to the first byte from that memory. -
.null
Returns a pointer whose memory address is zero.
Instance Method Summary
-
#+(offset : Int64) : self
Returns a new pointer whose address is this pointer's address incremented by
offset * sizeof(T). -
#+(other : Int)
Returns a new pointer whose address is this pointer's address incremented by
other * sizeof(T). -
#-(other : self) : Int64
Returns how many T elements are there between this pointer andother.
-
#-(other : Int)
Returns a new pointer whose address is this pointer's address decremented by
other * sizeof(T). -
#<=>(other : self)
Returns
-1,0or1depending on whether this pointer's address is less, equal or greater thanother's address, respectively. -
#[](offset)
Gets the value pointed at this pointer's address plus
offset * sizeof(T). -
#[]=(offset, value : T)
Sets the value pointed at this pointer's address plus
offset * sizeof(T). -
#address : UInt64
Returns the address of this pointer.
-
#appender : Pointer::Appender
Returns a
Pointer::Appenderfor this pointer. -
#clear(count = 1)
Clears (sets to"zero" bytes) a number of values pointed by this pointer.
- #clone
-
#copy_from(source : Pointer(T), count : Int)
Copiescount elements fromsource into
self. -
#copy_to(target : Pointer, count : Int)
Copiescount elements from
selfintotarget. -
#fill(count : Int, value : T) : self
Replacescount elements in
selfwithvalue. -
#fill(count : Int, *, offset : Int = 0, &) : self
Yieldscount indices starting from
selfto the given block and then assigns the block's output value in that position. -
#hash(hasher)
Returns the address of this pointer.
- #initialize
-
#map!(count : Int, & : T -> T) : self
Setscount consecutive values pointed by this pointer to the values returned by the block.
-
#map_with_index!(count : Int, offset = 0, &) : self
Like
#map!, but yields 2 arguments, the element and its index -
#memcmp(other : Pointer(T), count : Int) : Int32
Comparescount elements from this pointer andother, lexicographically.
-
#move_from(source : Pointer(T), count : Int)
Copiescount elements fromsource into
self. -
#move_to(target : Pointer, count : Int)
Copiescount elements from
selfintotarget. -
#null? : Bool
Returns
trueif this pointer's address is zero. -
#realloc(size : UInt64) : self
Tries to change the size of the allocation pointed to by this pointer tosize, and returns that pointer.
-
#realloc(size : Int)
Tries to change the size of the allocation pointed to by this pointer tosize, and returns that pointer.
-
#shuffle!(count : Int, random : Random | Nil = nil)
Shufflescount consecutive values pointed by this pointer.
-
#swap(i, j)
Swaps the contents pointed at the offsetsi andj.
-
#to_s(io : IO) : Nil
Appends a string representation of this pointer to the given
IO, including its type and address in hexadecimal. -
#to_slice(size) : Slice(T)
Returns a
Slicethat points to this pointer and is bounded by the givensize. -
#value : T
Gets the value pointed by this pointer.
-
#value=(value : T)
Sets the value pointed by this pointer.
Instance methods inherited from module Comparable(Pointer(T))
<(other : T(T)) : Bool
<,
<=(other : T(T))
<=,
<=>(other : T(T))
<=>,
==(other : T(T))
==,
>(other : T(T)) : Bool
>,
>=(other : T(T))
>=,
clamp(min, max)clamp(range : Range) clamp
Instance methods inherited from struct Value
==(other : Log::Metadata::Value)==(other : JSON::Any)
==(other : YAML::Any)
==(other) ==, dup dup
Instance methods inherited from class Object
! : Bool
!,
!=(other)
!=,
!~(other)
!~,
==(other)
==,
===(other : JSON::Any)===(other : YAML::Any)
===(other) ===, =~(other) =~, as(type : Class) as, as?(type : Class) as?, class class, dup dup, hash(hasher)
hash hash, in?(collection : Object) : Bool
in?(*values : Object) : Bool in?, inspect(io : IO) : Nil
inspect : String inspect, is_a?(type : Class) : Bool is_a?, itself itself, nil? : Bool nil?, not_nil!(message)
not_nil! not_nil!, pretty_inspect(width = 79, newline = "\n", indent = 0) : String pretty_inspect, pretty_print(pp : PrettyPrint) : Nil pretty_print, responds_to?(name : Symbol) : Bool responds_to?, tap(&) tap, to_json(io : IO) : Nil
to_json : String to_json, to_pretty_json(indent : String = " ") : String
to_pretty_json(io : IO, indent : String = " ") : Nil to_pretty_json, to_s(io : IO) : Nil
to_s : String to_s, to_yaml(io : IO) : Nil
to_yaml : String to_yaml, try(&) try, unsafe_as(type : T.class) forall T unsafe_as
Class methods inherited from class Object
from_json(string_or_io : String | IO, root : String)from_json(string_or_io : String | IO) from_json, from_yaml(string_or_io : String | IO) from_yaml
Macros inherited from class Object
class_getter(*names, &block)
class_getter,
class_getter!(*names)
class_getter!,
class_getter?(*names, &block)
class_getter?,
class_property(*names, &block)
class_property,
class_property!(*names)
class_property!,
class_property?(*names, &block)
class_property?,
class_setter(*names)
class_setter,
def_clone
def_clone,
def_equals(*fields)
def_equals,
def_equals_and_hash(*fields)
def_equals_and_hash,
def_hash(*fields)
def_hash,
delegate(*methods, to object)
delegate,
forward_missing_to(delegate)
forward_missing_to,
getter(*names, &block)
getter,
getter!(*names)
getter!,
getter?(*names, &block)
getter?,
property(*names, &block)
property,
property!(*names)
property!,
property?(*names, &block)
property?,
setter(*names)
setter
Constructor Detail
Returns a pointer that points to the given memory address. This doesn't allocate memory.
ptr = Pointer(Int32).new(5678_u64)
ptr.address # => 5678
Returns a pointer that points to the given memory address. This doesn't allocate memory.
ptr = Pointer(Int32).new(5678)
ptr.address # => 5678
DEPRECATED Call.new(UInt64) directly instead
Class Method Detail
Allocatessize * sizeof(T) bytes from the system's heap initialized
tovalue and returns a pointer to the first byte from that memory.
The memory is allocated by theGC, so when there are
no pointers to this memory, it will be automatically freed.
# An Int32 occupies 4 bytes, so here we are requesting 8 bytes
# initialized to the number 42
ptr = Pointer.malloc(2, 42)
ptr[0] # => 42
ptr[1] # => 42
Allocatessize * sizeof(T) bytes from the system's heap initialized
to zero and returns a pointer to the first byte from that memory.
The memory is allocated by theGC, so when there are
no pointers to this memory, it will be automatically freed.
# Allocate memory for an Int32: 4 bytes
ptr = Pointer(Int32).malloc(1_u64)
ptr.value # => 0
# Allocate memory for 10 Int32: 40 bytes
ptr = Pointer(Int32).malloc(10_u64)
ptr[0] # => 0
# ...
ptr[9] # => 0
The implementation usesGC.malloc if the compiler is aware that the
allocated type contains inner address pointers. See
Crystal::Macros::TypeNode#has_inner_pointers? for details.
To override this implicit behaviour,GC.malloc andGC.malloc_atomic
can be used directly instead.
Allocatessize * sizeof(T) bytes from the system's heap initialized
to zero and returns a pointer to the first byte from that memory.
The memory is allocated by theGC, so when there are
no pointers to this memory, it will be automatically freed.
# Allocate memory for an Int32: 4 bytes
ptr = Pointer(Int32).malloc
ptr.value # => 0
# Allocate memory for 10 Int32: 40 bytes
ptr = Pointer(Int32).malloc(10)
ptr[0] # => 0
# ...
ptr[9] # => 0
Allocatessize * sizeof(T) bytes from the system's heap initialized
to the value returned by the block (which is invoked once with each index in the range0...size)
and returns a pointer to the first byte from that memory.
The memory is allocated by theGC, so when there are
no pointers to this memory, it will be automatically freed.
# An Int32 occupies 4 bytes, so here we are requesting 16 bytes.
# i is an index in the range 0 .. 3
ptr = Pointer.malloc(4) { |i| i + 10 }
ptr[0] # => 10
ptr[1] # => 11
ptr[2] # => 12
ptr[3] # => 13
Returns a pointer whose memory address is zero. This doesn't allocate memory.
When calling a C function you can also passnil instead of constructing a
null pointer with this method.
ptr = Pointer(Int32).null
ptr.address # => 0
Instance Method Detail
Returns a new pointer whose address is this pointer's address
incremented byoffset * sizeof(T).
ptr = Pointer(Int32).new(1234)
ptr.address # => 1234
# An Int32 occupies four bytes
ptr2 = ptr + 1_u64
ptr2.address # => 1238
Returns a new pointer whose address is this pointer's address incremented byother * sizeof(T).
ptr = Pointer(Int32).new(1234)
ptr.address # => 1234
# An Int32 occupies four bytes
ptr2 = ptr + 1
ptr2.address # => 1238
Returns how many T elements are there between this pointer andother.
That is, this is(self.address - other.address) / sizeof(T).
ptr1 = Pointer(Int32).malloc(4)
ptr2 = ptr1 + 2
ptr2 - ptr1 # => 2
Returns a new pointer whose address is this pointer's address decremented byother * sizeof(T).
ptr = Pointer(Int32).new(1234)
ptr.address # => 1234
# An Int32 occupies four bytes
ptr2 = ptr - 1
ptr2.address # => 1230
Returns-1,0 or1 depending on whether this pointer's address is less, equal or greater thanother's address,
respectively.
Gets the value pointed at this pointer's address plusoffset * sizeof(T).
ptr = Pointer.malloc(4) { |i| i + 10 }
ptr[0] # => 10
ptr[1] # => 11
ptr[2] # => 12
ptr[3] # => 13
Sets the value pointed at this pointer's address plusoffset * sizeof(T).
ptr = Pointer(Int32).malloc(4)
ptr.to_slice(4) # => Slice[0, 0, 0, 0]
ptr[1] = 42
ptr2 = ptr + 1
ptr2.value # => 42
ptr1.to_slice(4) # => Slice[0, 42, 0, 0]
Returns the address of this pointer.
ptr = Pointer(Int32).new(1234)
ptr.address # => 1234
Clears (sets to"zero" bytes) a number of values pointed by this pointer.
ptr = Pointer.malloc(6) { |i| i + 10 } # [10, 11, 12, 13, 14, 15]
ptr.clear(3)
ptr.to_slice(6) # => Slice[0, 0, 0, 13, 14, 15]
Copiescount elements fromsource intoself.
Ifsource andself overlap, behaviour is undefined.
Use#move_from if they overlap (slower but always works).
ptr1 = Pointer.malloc(4) { |i| i + 1 }
ptr2 = Pointer.malloc(4) { |i| i + 11 }
ptr1.to_slice(4) # => Slice[1, 2, 3, 4]
ptr2.to_slice(4) # => Slice[11, 12, 13, 14]
# ptr2 -> [11, 12, 13, 14]
# ^---^ <- copy this
# ptr1 -> [1, 2, 3, 4]
# ^---^ <- here
ptr1.copy_from(ptr2, 2)
ptr1.to_slice(4) # => Slice[1, 12, 3, 4]
Copiescount elements fromself intotarget.
Ifself andtarget overlap, behaviour is undefined.
Use#move_to if they overlap (slower but always works).
ptr1 = Pointer.malloc(4) { |i| i + 1 }
ptr2 = Pointer.malloc(4) { |i| i + 11 }
ptr1.to_slice(4) # => Slice[1, 2, 3, 4]
ptr2.to_slice(4) # => Slice[11, 12, 13, 14]
# ptr1 -> [1, 2, 3, 4]
# ^---^ <- copy this
# ptr2 -> [11, 12, 13, 14]
# ^---^ <- here
ptr1.copy_to(ptr2, 2)
ptr2.to_slice(4) # => Slice[1, 2, 13, 14]
Replacescount elements inself withvalue. Returnsself.
ptr = Pointer(Int32).malloc(5) { |i| i }
ptr.to_slice(5) # => Slice[0, 1, 2, 3, 4]
ptr.fill(3, 0)
ptr.to_slice(5) # => Slice[0, 0, 0, 0, 4]
Yieldscount indices starting fromself to the given block and then
assigns the block's output value in that position. Returnsself.
ptr = Pointer(Int32).malloc(5) { |i| i }
ptr.to_slice(5) # => Slice[0, 1, 2, 3, 4]
(ptr + 1).fill(3) { |i| i * i }
ptr.to_slice(5) # => Slice[0, 0, 1, 4, 4]
(ptr + 1).fill(3, offset: 3) { |i| i * i }
ptr.to_slice(5) # => Slice[0, 9, 16, 25, 4]
Returns the address of this pointer.
ptr = Pointer(Int32).new(1234)
ptr.hash # => 1234
Setscount consecutive values pointed by this pointer to the values returned by the block.
ptr = Pointer.malloc(4) { |i| i + 1 }
ptr.to_slice(4) # => Slice[1, 2, 3, 4]
ptr.map!(4) { |value| value * 2 }
ptr.to_slice(4) # => Slice[2, 4, 6, 8]
Like#map!, but yields 2 arguments, the element and its index
Accepts an optionaloffset parameter, which tells it to start counting from there.
Comparescount elements from this pointer andother, lexicographically.
Returns 0 if both pointers point to the same sequence ofcount bytes.
Otherwise, if the first two differing bytes (treated as UInt8) fromself
andother arex andy respectively, returns a negative value if
x < y, or a positive value ifx > y.
ptr1 = Pointer.malloc(4) { |i| i + 1 }
ptr2 = Pointer.malloc(4) { |i| i + 11 }
ptr1.to_slice(4) # => Slice[1, 2, 3, 4]
ptr2.to_slice(4) # => Slice[11, 12, 13, 14]
ptr1.memcmp(ptr2, 4) < 0 # => true
ptr2.memcmp(ptr1, 4) > 0 # => true
ptr1.memcmp(ptr1, 4) == 0 # => true
Copiescount elements fromsource intoself.
source andself may overlap; the copy is always done in a non-destructive manner.
ptr1 = Pointer.malloc(4) { |i| i + 1 }
ptr1.to_slice(4) # => Slice[1, 2, 3, 4]
# ^-- ptr2
ptr2 = ptr1 + 1
# [1, 2, 3, 4]
# ^-----^ <- copy this
# ^------^ <- here
ptr2.move_from(ptr1, 3)
ptr1.to_slice(4) # => Slice[1, 1, 2, 3]
Copiescount elements fromself intotarget.
target andself may overlap; the copy is always done in a non-destructive manner.
ptr1 = Pointer.malloc(4) { |i| i + 1 }
ptr1.to_slice(4) # => Slice[1, 2, 3, 4]
# ^-- ptr2
ptr2 = ptr1 + 1
# [1, 2, 3, 4]
# ^-----^ <- copy this
# ^------^ <- here
ptr1.move_to(ptr2, 3)
ptr1.to_slice(4) # => Slice[1, 1, 2, 3]
Returnstrue if this pointer's address is zero.
a = 1
pointerof(a).null? # => false
b = Pointer(Int32).new(0)
b.null? # => true
Tries to change the size of the allocation pointed to by this pointer tosize, and returns that pointer.
Since the space after the end of the block may be in use, realloc may find it necessary to copy the block to a new address where more free space is available. The value of realloc is the new address of the block. If the block needs to be moved, realloc copies the old contents.
Remember to always assign the value of realloc.
ptr = Pointer.malloc(4) { |i| i + 1 } # [1, 2, 3, 4]
ptr = ptr.realloc(8_u8)
ptr # [1, 2, 3, 4, 0, 0, 0, 0]
Tries to change the size of the allocation pointed to by this pointer tosize, and returns that pointer.
Since the space after the end of the block may be in use, realloc may find it necessary to copy the block to a new address where more free space is available. The value of realloc is the new address of the block. If the block needs to be moved, realloc copies the old contents.
Remember to always assign the value of realloc.
ptr = Pointer.malloc(4) { |i| i + 1 }
ptr.to_slice(4) # => Slice[1, 2, 3, 4]
ptr = ptr.realloc(8)
ptr.to_slice(8) # => Slice[1, 2, 3, 4, 0, 0, 0, 0]
WARNING Memory allocated usingGC.malloc orGC.malloc_atomic must be
reallocated usingGC.realloc instead.
Shufflescount consecutive values pointed by this pointer.
ptr = Pointer.malloc(4) { |i| i + 1 }
ptr.to_slice(4) # => Slice[1, 2, 3, 4]
ptr.shuffle!(4)
ptr.to_slice(4) # => Slice[3, 4, 1, 2]
Swaps the contents pointed at the offsetsi andj.
ptr = Pointer.malloc(4) { |i| i + 1 }
ptr[2] # => 3
ptr[3] # => 4
ptr.swap(2, 3)
ptr[2] # => 4
ptr[3] # => 3
Appends a string representation of this pointer to the givenIO,
including its type and address in hexadecimal.
ptr1 = Pointer(Int32).new(1234)
ptr1.to_s # => "Pointer(Int32)@0x4d2"
ptr2 = Pointer(Int32).new(0)
ptr2.to_s # => "Pointer(Int32).null"
Returns aSlice that points to this pointer and is bounded by the givensize.
ptr = Pointer.malloc(6) { |i| i + 10 } # [10, 11, 12, 13, 14, 15]
slice = ptr.to_slice(4) # => Slice[10, 11, 12, 13]
slice.class # => Slice(Int32)
Gets the value pointed by this pointer.
ptr = Pointer(Int32).malloc(4)
ptr.value = 42
ptr.value # => 42
WARNING The pointer must be appropriately aligned, i.e.#address must be
a multiple ofalignof(T). It is undefined behavior to load from a
misaligned pointer. Such reads should instead be done via a cast to
Pointer(UInt8), which is guaranteed to have byte alignment:
# raises SIGSEGV on X86 if `ptr` is misaligned
x = ptr.as(UInt128*).value
# okay, `ptr` can have any alignment
x = uninitialized UInt128
ptr.as(UInt8*).copy_to(pointerof(x).as(UInt8*), sizeof(typeof(x)))
Sets the value pointed by this pointer.
ptr = Pointer(Int32).malloc(4)
ptr.value = 42
ptr.value # => 42
WARNING The pointer must be appropriately aligned, i.e.#address must be
a multiple ofalignof(T). It is undefined behavior to store to a
misaligned pointer. Such writes should instead be done via a cast to
Pointer(UInt8), which is guaranteed to have byte alignment:
# raises SIGSEGV on X86 if `ptr` is misaligned
x = 123_u128
ptr.as(UInt128*).value = x
# okay, `ptr` can have any alignment
ptr.as(UInt8*).copy_from(pointerof(x).as(UInt8*), sizeof(typeof(x)))