forked from crystal-lang/crystal
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add
ReferenceStorage
for manual allocation of references (crystal-l…
…ang#14106) Co-authored-by: Sijawusz Pur Rahnama <sija@sija.pl>
- Loading branch information
1 parent
a3bedf9
commit 15010d3
Showing
7 changed files
with
132 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
require "../../spec_helper" | ||
|
||
describe "Semantic: ReferenceStorage" do | ||
it "errors if T is a struct type" do | ||
assert_error <<-CRYSTAL, "Can't instantiate ReferenceStorage(T) with T = Foo (T must be a reference type)" | ||
struct Foo | ||
@x = 1 | ||
end | ||
ReferenceStorage(Foo) | ||
CRYSTAL | ||
end | ||
|
||
it "errors if T is a value type" do | ||
assert_error <<-CRYSTAL, "Can't instantiate ReferenceStorage(T) with T = Int32 (T must be a reference type)" | ||
ReferenceStorage(Int32) | ||
CRYSTAL | ||
end | ||
|
||
it "errors if T is a union type" do | ||
assert_error <<-CRYSTAL, "Can't instantiate ReferenceStorage(T) with T = (Bar | Foo) (T must be a reference type)" | ||
class Foo | ||
end | ||
class Bar | ||
end | ||
ReferenceStorage(Foo | Bar) | ||
CRYSTAL | ||
end | ||
|
||
it "errors if T is a nilable type" do | ||
assert_error <<-CRYSTAL, "Can't instantiate ReferenceStorage(T) with T = (Foo | Nil) (T must be a reference type)" | ||
class Foo | ||
end | ||
ReferenceStorage(Foo?) | ||
CRYSTAL | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
# a `ReferenceStorage(T)` provides the minimum storage for the instance data of | ||
# an object of type `T`. The compiler guarantees that | ||
# `sizeof(ReferenceStorage(T)) == instance_sizeof(T)` and | ||
# `alignof(ReferenceStorage(T)) == instance_alignof(T)` always hold, which means | ||
# `Pointer(ReferenceStorage(T))` and `T` are binary-compatible. | ||
# | ||
# `T` must be a non-union reference type. | ||
# | ||
# WARNING: `ReferenceStorage` is only necessary for manual memory management, | ||
# such as creating instances of `T` with a non-default allocator. Therefore, | ||
# this type is unsafe and no public constructors are defined. | ||
# | ||
# WARNING: `ReferenceStorage` is unsuitable when instances of `T` require more | ||
# than `instance_sizeof(T)` bytes, such as `String` and `Log::Metadata`. | ||
@[Experimental("This type's API is still under development. Join the discussion about custom reference allocation at [#13481](https://github.com/crystal-lang/crystal/issues/13481).")] | ||
struct ReferenceStorage(T) | ||
private def initialize | ||
end | ||
|
||
# Returns whether `self` and *other* are bytewise equal. | ||
# | ||
# NOTE: This does not call `T#==`, so it works even if `self` or *other* does | ||
# not represent a valid instance of `T`. If validity is guaranteed, call | ||
# `to_reference == other.to_reference` instead to use `T#==`. | ||
def ==(other : ReferenceStorage(T)) : Bool | ||
to_bytes == other.to_bytes | ||
end | ||
|
||
def ==(other) : Bool | ||
false | ||
end | ||
|
||
def hash(hasher) | ||
to_bytes.hash(hasher) | ||
end | ||
|
||
def to_s(io : IO) : Nil | ||
io << "ReferenceStorage(#<" << T << ":0x" | ||
pointerof(@type_id).address.to_s(io, 16) | ||
io << ">)" | ||
end | ||
|
||
# Returns a `T` whose instance data refers to `self`. | ||
# | ||
# WARNING: The caller is responsible for ensuring that the instance data is | ||
# correctly initialized and outlives the returned `T`. | ||
def to_reference : T | ||
pointerof(@type_id).as(T) | ||
end | ||
|
||
protected def to_bytes | ||
Slice.new(pointerof(@type_id).as(UInt8*), instance_sizeof(T)) | ||
end | ||
end |