@@ -27,6 +27,7 @@ There are quite a few different ways to go:
27
27
- Option C: CIDs as an interface with multiple implementors.
28
28
- Option D: CIDs as a struct; multihash also as a struct or string.
29
29
- Option E: CIDs as a struct; content as strings plus offsets.
30
+ - Option F: CIDs as a struct wrapping only a string.
30
31
31
32
The current approach on the master branch is Option A.
32
33
@@ -42,6 +43,10 @@ the binary format of the cid internally, and so could yield it again without
42
43
malloc, while still potentially having faster access to components than
43
44
Option B since it wouldn't need to re-parse varints to access later fields.
44
45
46
+ Option F is actually a varation of Option B; it's distinctive from the other
47
+ struct options because it is proposing * literally* ` struct{ x string } ` as
48
+ the type, with no additional fields for components nor offsets.
49
+
45
50
Option C is the avoid-choices choice, but note that interfaces are not free;
46
51
since "minimize mallocs" is one of our major goals, we cannot use interfaces
47
52
whimsically.
@@ -72,6 +77,7 @@ When using `*Cid`, the nil value is a clear sentinel for 'invalid';
72
77
when using ` type Cid string ` , the zero value is a clear sentinel;
73
78
when using ` type Cid struct ` per Option A or D... the only valid check is
74
79
for a nil multihash field, since version=0 and codec=0 are both valid values.
80
+ When using ` type Cid struct{string} ` per Option F, zero is a clear sentinel.
75
81
76
82
### usability as a map key is important
77
83
@@ -82,6 +88,7 @@ We already covered this in the criteria section, but for clarity:
82
88
- Option C: ~ (caveats, and depends on concrete impl)
83
89
- Option D: ✔
84
90
- Option E: ✔
91
+ - Option F: ✔
85
92
86
93
### living without offsets requires parsing
87
94
@@ -106,7 +113,7 @@ How much this overhead is significant is hard to say from microbenchmarking;
106
113
it depends largely on usage patterns. If these traversals are a significant
107
114
timesink, it would be an argument for Option D/E.
108
115
If these traversals are * not* a significant timesink, we might be wiser
109
- to keep to Option B, because keeping a struct full of offsets will add several
116
+ to keep to Option B/F , because keeping a struct full of offsets will add several
110
117
words of memory usage per CID, and we keep a * lot* of CIDs.
111
118
112
119
### interfaces cause boxing which is a significant performance cost
@@ -129,6 +136,23 @@ if a situation is at the scale where it's become important to mind whether
129
136
or not pointers are a performance impact, then that situation also
130
137
is one where you have to think twice before using interfaces.
131
138
139
+ ### struct wrappers can be used in place of typedefs with zero overhead
140
+
141
+ See ` TestSizeOf ` .
142
+
143
+ Using the ` unsafe.Sizeof ` feature to inspect what the Go runtime thinks,
144
+ we can see that ` type Foo string ` and ` type Foo struct{x string} ` consume
145
+ precisely the same amount of memory.
146
+
147
+ This is interesting because it means we can choose between either
148
+ type definition with no significant overhead anywhere we use it:
149
+ thus, we can choose freely between Option B and Option F based on which
150
+ we feel is more pleasant to work with.
151
+
152
+ Option F (a struct wrapper) means we can prevent casting into our Cid type.
153
+ Option B (typedef string) can be declared a ` const ` .
154
+ Are there any other concerns that would separate the two choices?
155
+
132
156
### one way or another: let's get rid of that star
133
157
134
158
We should switch completely to handling ` Cid ` and remove ` *Cid ` completely.
0 commit comments