yarp 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/src/serialize.c CHANGED
@@ -67,10 +67,16 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
67
67
  // it is not part of the AST
68
68
  case YP_SCOPE_NODE:
69
69
  return;
70
- case YP_ALIAS_NODE: {
71
- yp_serialize_node(parser, (yp_node_t *)((yp_alias_node_t *)node)->new_name, buffer);
72
- yp_serialize_node(parser, (yp_node_t *)((yp_alias_node_t *)node)->old_name, buffer);
73
- yp_serialize_location(parser, &((yp_alias_node_t *)node)->keyword_loc, buffer);
70
+ case YP_ALIAS_GLOBAL_VARIABLE_NODE: {
71
+ yp_serialize_node(parser, (yp_node_t *)((yp_alias_global_variable_node_t *)node)->new_name, buffer);
72
+ yp_serialize_node(parser, (yp_node_t *)((yp_alias_global_variable_node_t *)node)->old_name, buffer);
73
+ yp_serialize_location(parser, &((yp_alias_global_variable_node_t *)node)->keyword_loc, buffer);
74
+ break;
75
+ }
76
+ case YP_ALIAS_METHOD_NODE: {
77
+ yp_serialize_node(parser, (yp_node_t *)((yp_alias_method_node_t *)node)->new_name, buffer);
78
+ yp_serialize_node(parser, (yp_node_t *)((yp_alias_method_node_t *)node)->old_name, buffer);
79
+ yp_serialize_location(parser, &((yp_alias_method_node_t *)node)->keyword_loc, buffer);
74
80
  break;
75
81
  }
76
82
  case YP_ALTERNATION_PATTERN_NODE: {
@@ -323,7 +329,7 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
323
329
  yp_buffer_append_u8(buffer, 1);
324
330
  yp_serialize_location(parser, &((yp_call_and_write_node_t *)node)->closing_loc, buffer);
325
331
  }
326
- yp_buffer_append_u32(buffer, node->flags >> 1);
332
+ yp_buffer_append_u32(buffer, node->flags >> 2);
327
333
  yp_serialize_string(parser, &((yp_call_and_write_node_t *)node)->read_name, buffer);
328
334
  yp_serialize_string(parser, &((yp_call_and_write_node_t *)node)->write_name, buffer);
329
335
  yp_serialize_location(parser, &((yp_call_and_write_node_t *)node)->operator_loc, buffer);
@@ -370,7 +376,7 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
370
376
  } else {
371
377
  yp_serialize_node(parser, (yp_node_t *)((yp_call_node_t *)node)->block, buffer);
372
378
  }
373
- yp_buffer_append_u32(buffer, node->flags >> 1);
379
+ yp_buffer_append_u32(buffer, node->flags >> 2);
374
380
  yp_serialize_string(parser, &((yp_call_node_t *)node)->name, buffer);
375
381
  break;
376
382
  }
@@ -409,7 +415,7 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
409
415
  yp_buffer_append_u8(buffer, 1);
410
416
  yp_serialize_location(parser, &((yp_call_operator_write_node_t *)node)->closing_loc, buffer);
411
417
  }
412
- yp_buffer_append_u32(buffer, node->flags >> 1);
418
+ yp_buffer_append_u32(buffer, node->flags >> 2);
413
419
  yp_serialize_string(parser, &((yp_call_operator_write_node_t *)node)->read_name, buffer);
414
420
  yp_serialize_string(parser, &((yp_call_operator_write_node_t *)node)->write_name, buffer);
415
421
  yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_call_operator_write_node_t *)node)->operator));
@@ -452,7 +458,7 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
452
458
  yp_buffer_append_u8(buffer, 1);
453
459
  yp_serialize_location(parser, &((yp_call_or_write_node_t *)node)->closing_loc, buffer);
454
460
  }
455
- yp_buffer_append_u32(buffer, node->flags >> 1);
461
+ yp_buffer_append_u32(buffer, node->flags >> 2);
456
462
  yp_serialize_string(parser, &((yp_call_or_write_node_t *)node)->read_name, buffer);
457
463
  yp_serialize_string(parser, &((yp_call_or_write_node_t *)node)->write_name, buffer);
458
464
  yp_serialize_location(parser, &((yp_call_or_write_node_t *)node)->operator_loc, buffer);
@@ -799,7 +805,7 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
799
805
  yp_serialize_node(parser, (yp_node_t *)((yp_flip_flop_node_t *)node)->right, buffer);
800
806
  }
801
807
  yp_serialize_location(parser, &((yp_flip_flop_node_t *)node)->operator_loc, buffer);
802
- yp_buffer_append_u32(buffer, node->flags >> 1);
808
+ yp_buffer_append_u32(buffer, node->flags >> 2);
803
809
  break;
804
810
  }
805
811
  case YP_FLOAT_NODE: {
@@ -945,6 +951,10 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
945
951
  yp_serialize_node(parser, (yp_node_t *)((yp_imaginary_node_t *)node)->numeric, buffer);
946
952
  break;
947
953
  }
954
+ case YP_IMPLICIT_NODE: {
955
+ yp_serialize_node(parser, (yp_node_t *)((yp_implicit_node_t *)node)->value, buffer);
956
+ break;
957
+ }
948
958
  case YP_IN_NODE: {
949
959
  yp_serialize_node(parser, (yp_node_t *)((yp_in_node_t *)node)->pattern, buffer);
950
960
  if (((yp_in_node_t *)node)->statements == NULL) {
@@ -999,6 +1009,18 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
999
1009
  break;
1000
1010
  }
1001
1011
  case YP_INTEGER_NODE: {
1012
+ yp_buffer_append_u32(buffer, node->flags >> 2);
1013
+ break;
1014
+ }
1015
+ case YP_INTERPOLATED_MATCH_LAST_LINE_NODE: {
1016
+ yp_serialize_location(parser, &((yp_interpolated_match_last_line_node_t *)node)->opening_loc, buffer);
1017
+ uint32_t parts_size = yp_sizet_to_u32(((yp_interpolated_match_last_line_node_t *)node)->parts.size);
1018
+ yp_buffer_append_u32(buffer, parts_size);
1019
+ for (uint32_t index = 0; index < parts_size; index++) {
1020
+ yp_serialize_node(parser, (yp_node_t *) ((yp_interpolated_match_last_line_node_t *)node)->parts.nodes[index], buffer);
1021
+ }
1022
+ yp_serialize_location(parser, &((yp_interpolated_match_last_line_node_t *)node)->closing_loc, buffer);
1023
+ yp_buffer_append_u32(buffer, node->flags >> 2);
1002
1024
  break;
1003
1025
  }
1004
1026
  case YP_INTERPOLATED_REGULAR_EXPRESSION_NODE: {
@@ -1009,7 +1031,7 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
1009
1031
  yp_serialize_node(parser, (yp_node_t *) ((yp_interpolated_regular_expression_node_t *)node)->parts.nodes[index], buffer);
1010
1032
  }
1011
1033
  yp_serialize_location(parser, &((yp_interpolated_regular_expression_node_t *)node)->closing_loc, buffer);
1012
- yp_buffer_append_u32(buffer, node->flags >> 1);
1034
+ yp_buffer_append_u32(buffer, node->flags >> 2);
1013
1035
  break;
1014
1036
  }
1015
1037
  case YP_INTERPOLATED_STRING_NODE: {
@@ -1155,6 +1177,14 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
1155
1177
  yp_serialize_location(parser, &((yp_local_variable_write_node_t *)node)->operator_loc, buffer);
1156
1178
  break;
1157
1179
  }
1180
+ case YP_MATCH_LAST_LINE_NODE: {
1181
+ yp_serialize_location(parser, &((yp_match_last_line_node_t *)node)->opening_loc, buffer);
1182
+ yp_serialize_location(parser, &((yp_match_last_line_node_t *)node)->content_loc, buffer);
1183
+ yp_serialize_location(parser, &((yp_match_last_line_node_t *)node)->closing_loc, buffer);
1184
+ yp_serialize_string(parser, &((yp_match_last_line_node_t *)node)->unescaped, buffer);
1185
+ yp_buffer_append_u32(buffer, node->flags >> 2);
1186
+ break;
1187
+ }
1158
1188
  case YP_MATCH_PREDICATE_NODE: {
1159
1189
  yp_serialize_node(parser, (yp_node_t *)((yp_match_predicate_node_t *)node)->value, buffer);
1160
1190
  yp_serialize_node(parser, (yp_node_t *)((yp_match_predicate_node_t *)node)->pattern, buffer);
@@ -1167,6 +1197,15 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
1167
1197
  yp_serialize_location(parser, &((yp_match_required_node_t *)node)->operator_loc, buffer);
1168
1198
  break;
1169
1199
  }
1200
+ case YP_MATCH_WRITE_NODE: {
1201
+ yp_serialize_node(parser, (yp_node_t *)((yp_match_write_node_t *)node)->call, buffer);
1202
+ uint32_t locals_size = yp_sizet_to_u32(((yp_match_write_node_t *)node)->locals.size);
1203
+ yp_buffer_append_u32(buffer, locals_size);
1204
+ for (uint32_t index = 0; index < locals_size; index++) {
1205
+ yp_buffer_append_u32(buffer, yp_sizet_to_u32(((yp_match_write_node_t *)node)->locals.ids[index]));
1206
+ }
1207
+ break;
1208
+ }
1170
1209
  case YP_MISSING_NODE: {
1171
1210
  break;
1172
1211
  }
@@ -1274,16 +1313,16 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
1274
1313
  for (uint32_t index = 0; index < optionals_size; index++) {
1275
1314
  yp_serialize_node(parser, (yp_node_t *) ((yp_parameters_node_t *)node)->optionals.nodes[index], buffer);
1276
1315
  }
1277
- uint32_t posts_size = yp_sizet_to_u32(((yp_parameters_node_t *)node)->posts.size);
1278
- yp_buffer_append_u32(buffer, posts_size);
1279
- for (uint32_t index = 0; index < posts_size; index++) {
1280
- yp_serialize_node(parser, (yp_node_t *) ((yp_parameters_node_t *)node)->posts.nodes[index], buffer);
1281
- }
1282
1316
  if (((yp_parameters_node_t *)node)->rest == NULL) {
1283
1317
  yp_buffer_append_u8(buffer, 0);
1284
1318
  } else {
1285
1319
  yp_serialize_node(parser, (yp_node_t *)((yp_parameters_node_t *)node)->rest, buffer);
1286
1320
  }
1321
+ uint32_t posts_size = yp_sizet_to_u32(((yp_parameters_node_t *)node)->posts.size);
1322
+ yp_buffer_append_u32(buffer, posts_size);
1323
+ for (uint32_t index = 0; index < posts_size; index++) {
1324
+ yp_serialize_node(parser, (yp_node_t *) ((yp_parameters_node_t *)node)->posts.nodes[index], buffer);
1325
+ }
1287
1326
  uint32_t keywords_size = yp_sizet_to_u32(((yp_parameters_node_t *)node)->keywords.size);
1288
1327
  yp_buffer_append_u32(buffer, keywords_size);
1289
1328
  for (uint32_t index = 0; index < keywords_size; index++) {
@@ -1366,7 +1405,7 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
1366
1405
  yp_serialize_node(parser, (yp_node_t *)((yp_range_node_t *)node)->right, buffer);
1367
1406
  }
1368
1407
  yp_serialize_location(parser, &((yp_range_node_t *)node)->operator_loc, buffer);
1369
- yp_buffer_append_u32(buffer, node->flags >> 1);
1408
+ yp_buffer_append_u32(buffer, node->flags >> 2);
1370
1409
  break;
1371
1410
  }
1372
1411
  case YP_RATIONAL_NODE: {
@@ -1381,7 +1420,7 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
1381
1420
  yp_serialize_location(parser, &((yp_regular_expression_node_t *)node)->content_loc, buffer);
1382
1421
  yp_serialize_location(parser, &((yp_regular_expression_node_t *)node)->closing_loc, buffer);
1383
1422
  yp_serialize_string(parser, &((yp_regular_expression_node_t *)node)->unescaped, buffer);
1384
- yp_buffer_append_u32(buffer, node->flags >> 1);
1423
+ yp_buffer_append_u32(buffer, node->flags >> 2);
1385
1424
  break;
1386
1425
  }
1387
1426
  case YP_REQUIRED_DESTRUCTURED_PARAMETER_NODE: {
@@ -1510,6 +1549,7 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
1510
1549
  break;
1511
1550
  }
1512
1551
  case YP_STRING_NODE: {
1552
+ yp_buffer_append_u32(buffer, node->flags >> 2);
1513
1553
  if (((yp_string_node_t *)node)->opening_loc.start == NULL) {
1514
1554
  yp_buffer_append_u8(buffer, 0);
1515
1555
  } else {
@@ -1621,7 +1661,7 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
1621
1661
  } else {
1622
1662
  yp_serialize_node(parser, (yp_node_t *)((yp_until_node_t *)node)->statements, buffer);
1623
1663
  }
1624
- yp_buffer_append_u32(buffer, node->flags >> 1);
1664
+ yp_buffer_append_u32(buffer, node->flags >> 2);
1625
1665
  break;
1626
1666
  }
1627
1667
  case YP_WHEN_NODE: {
@@ -1652,7 +1692,7 @@ yp_serialize_node(yp_parser_t *parser, yp_node_t *node, yp_buffer_t *buffer) {
1652
1692
  } else {
1653
1693
  yp_serialize_node(parser, (yp_node_t *)((yp_while_node_t *)node)->statements, buffer);
1654
1694
  }
1655
- yp_buffer_append_u32(buffer, node->flags >> 1);
1695
+ yp_buffer_append_u32(buffer, node->flags >> 2);
1656
1696
  break;
1657
1697
  }
1658
1698
  case YP_X_STRING_NODE: {
data/src/util/yp_char.c CHANGED
@@ -123,6 +123,9 @@ yp_char_is_inline_whitespace(const uint8_t b) {
123
123
  return yp_char_is_char_kind(b, YP_CHAR_BIT_INLINE_WHITESPACE);
124
124
  }
125
125
 
126
+ // Scan through the string and return the number of characters at the start of
127
+ // the string that match the given kind. Disallows searching past the given
128
+ // maximum number of characters.
126
129
  static inline size_t
127
130
  yp_strspn_number_kind(const uint8_t *string, ptrdiff_t length, uint8_t kind) {
128
131
  if (length <= 0) return 0;
@@ -134,20 +137,57 @@ yp_strspn_number_kind(const uint8_t *string, ptrdiff_t length, uint8_t kind) {
134
137
  return size;
135
138
  }
136
139
 
140
+ // Scan through the string and return the number of characters at the start of
141
+ // the string that match the given kind. Disallows searching past the given
142
+ // maximum number of characters.
143
+ //
144
+ // Additionally, report the location of the last invalid underscore character
145
+ // found in the string through the out invalid parameter.
146
+ static inline size_t
147
+ yp_strspn_number_kind_underscores(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid, uint8_t kind) {
148
+ if (length <= 0) return 0;
149
+
150
+ size_t size = 0;
151
+ size_t maximum = (size_t) length;
152
+
153
+ bool underscore = false;
154
+ while (size < maximum && (yp_number_table[string[size]] & kind)) {
155
+ if (string[size] == '_') {
156
+ if (underscore) *invalid = string + size;
157
+ underscore = true;
158
+ } else {
159
+ underscore = false;
160
+ }
161
+
162
+ size++;
163
+ }
164
+
165
+ if (string[size - 1] == '_') *invalid = string + size - 1;
166
+ return size;
167
+ }
168
+
137
169
  // Returns the number of characters at the start of the string that are binary
138
170
  // digits or underscores. Disallows searching past the given maximum number of
139
171
  // characters.
172
+ //
173
+ // If multiple underscores are found in a row or if an underscore is
174
+ // found at the end of the number, then the invalid pointer is set to the index
175
+ // of the first invalid underscore.
140
176
  size_t
141
- yp_strspn_binary_number(const uint8_t *string, ptrdiff_t length) {
142
- return yp_strspn_number_kind(string, length, YP_NUMBER_BIT_BINARY_NUMBER);
177
+ yp_strspn_binary_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid) {
178
+ return yp_strspn_number_kind_underscores(string, length, invalid, YP_NUMBER_BIT_BINARY_NUMBER);
143
179
  }
144
180
 
145
181
  // Returns the number of characters at the start of the string that are octal
146
- // digits or underscores. Disallows searching past the given maximum number of
182
+ // digits or underscores. Disallows searching past the given maximum number of
147
183
  // characters.
184
+ //
185
+ // If multiple underscores are found in a row or if an underscore is
186
+ // found at the end of the number, then the invalid pointer is set to the index
187
+ // of the first invalid underscore.
148
188
  size_t
149
- yp_strspn_octal_number(const uint8_t *string, ptrdiff_t length) {
150
- return yp_strspn_number_kind(string, length, YP_NUMBER_BIT_OCTAL_NUMBER);
189
+ yp_strspn_octal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid) {
190
+ return yp_strspn_number_kind_underscores(string, length, invalid, YP_NUMBER_BIT_OCTAL_NUMBER);
151
191
  }
152
192
 
153
193
  // Returns the number of characters at the start of the string that are decimal
@@ -160,9 +200,13 @@ yp_strspn_decimal_digit(const uint8_t *string, ptrdiff_t length) {
160
200
  // Returns the number of characters at the start of the string that are decimal
161
201
  // digits or underscores. Disallows searching past the given maximum number of
162
202
  // characters.
203
+ //
204
+ // If multiple underscores are found in a row or if an underscore is
205
+ // found at the end of the number, then the invalid pointer is set to the index
206
+ // of the first invalid underscore.
163
207
  size_t
164
- yp_strspn_decimal_number(const uint8_t *string, ptrdiff_t length) {
165
- return yp_strspn_number_kind(string, length, YP_NUMBER_BIT_DECIMAL_NUMBER);
208
+ yp_strspn_decimal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid) {
209
+ return yp_strspn_number_kind_underscores(string, length, invalid, YP_NUMBER_BIT_DECIMAL_NUMBER);
166
210
  }
167
211
 
168
212
  // Returns the number of characters at the start of the string that are
@@ -176,9 +220,13 @@ yp_strspn_hexadecimal_digit(const uint8_t *string, ptrdiff_t length) {
176
220
  // Returns the number of characters at the start of the string that are
177
221
  // hexadecimal digits or underscores. Disallows searching past the given maximum
178
222
  // number of characters.
223
+ //
224
+ // If multiple underscores are found in a row or if an underscore is
225
+ // found at the end of the number, then the invalid pointer is set to the index
226
+ // of the first invalid underscore.
179
227
  size_t
180
- yp_strspn_hexadecimal_number(const uint8_t *string, ptrdiff_t length) {
181
- return yp_strspn_number_kind(string, length, YP_NUMBER_BIT_HEXADECIMAL_NUMBER);
228
+ yp_strspn_hexadecimal_number(const uint8_t *string, ptrdiff_t length, const uint8_t **invalid) {
229
+ return yp_strspn_number_kind_underscores(string, length, invalid, YP_NUMBER_BIT_HEXADECIMAL_NUMBER);
182
230
  }
183
231
 
184
232
  static inline bool
@@ -59,10 +59,42 @@ yp_constant_pool_hash(const uint8_t *start, size_t length) {
59
59
  return value;
60
60
  }
61
61
 
62
+ // https://graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
63
+ static size_t
64
+ next_power_of_two(size_t v) {
65
+ // Avoid underflow in subtraction on next line.
66
+ if (v == 0) {
67
+ // 1 is the nearest power of 2 to 0 (2^0)
68
+ return 1;
69
+ }
70
+ v--;
71
+ v |= v >> 1;
72
+ v |= v >> 2;
73
+ v |= v >> 4;
74
+ v |= v >> 8;
75
+ v |= v >> 16;
76
+ #if defined(__LP64__) || defined(_WIN64)
77
+ v |= v >> 32;
78
+ #endif
79
+ v++;
80
+ return v;
81
+ }
82
+
83
+ #ifndef NDEBUG
84
+ static bool
85
+ is_power_of_two(size_t size) {
86
+ return (size & (size - 1)) == 0;
87
+ }
88
+ #endif
89
+
62
90
  // Resize a constant pool to a given capacity.
63
91
  static inline bool
64
92
  yp_constant_pool_resize(yp_constant_pool_t *pool) {
93
+ assert(is_power_of_two(pool->capacity));
65
94
  size_t next_capacity = pool->capacity * 2;
95
+ if (next_capacity < pool->capacity) return false;
96
+
97
+ const size_t mask = next_capacity - 1;
66
98
  yp_constant_t *next_constants = calloc(next_capacity, sizeof(yp_constant_t));
67
99
  if (next_constants == NULL) return false;
68
100
 
@@ -74,13 +106,13 @@ yp_constant_pool_resize(yp_constant_pool_t *pool) {
74
106
  // If an id is set on this constant, then we know we have content here.
75
107
  // In this case we need to insert it into the next constant pool.
76
108
  if (constant->id != 0) {
77
- size_t next_index = constant->hash % next_capacity;
109
+ size_t next_index = constant->hash & mask;
78
110
 
79
111
  // This implements linear scanning to find the next available slot
80
112
  // in case this index is already taken. We don't need to bother
81
113
  // comparing the values since we know that the hash is unique.
82
114
  while (next_constants[next_index].id != 0) {
83
- next_index = (next_index + 1) % next_capacity;
115
+ next_index = (next_index + 1) & mask;
84
116
  }
85
117
 
86
118
  // Here we copy over the entire constant, which includes the id so
@@ -98,6 +130,10 @@ yp_constant_pool_resize(yp_constant_pool_t *pool) {
98
130
  // Initialize a new constant pool with a given capacity.
99
131
  bool
100
132
  yp_constant_pool_init(yp_constant_pool_t *pool, size_t capacity) {
133
+ const size_t size_t_max = (~((size_t) 0));
134
+ if (capacity >= ((size_t_max / 2) + 1)) return false;
135
+
136
+ capacity = next_power_of_two(capacity);
101
137
  pool->constants = calloc(capacity, sizeof(yp_constant_t));
102
138
  if (pool->constants == NULL) return false;
103
139
 
@@ -107,14 +143,16 @@ yp_constant_pool_init(yp_constant_pool_t *pool, size_t capacity) {
107
143
  }
108
144
 
109
145
  // Insert a constant into a constant pool and return its index in the pool.
110
- static size_t
111
- yp_constant_pool_insert(yp_constant_pool_t *pool, const uint8_t *start, size_t length) {
146
+ static inline yp_constant_id_t
147
+ yp_constant_pool_insert(yp_constant_pool_t *pool, const uint8_t *start, size_t length, bool owned) {
112
148
  if (pool->size >= (pool->capacity / 4 * 3)) {
113
- if (!yp_constant_pool_resize(pool)) return pool->capacity;
149
+ if (!yp_constant_pool_resize(pool)) return 0;
114
150
  }
115
151
 
152
+ assert(is_power_of_two(pool->capacity));
153
+ const size_t mask = pool->capacity - 1;
116
154
  size_t hash = yp_constant_pool_hash(start, length);
117
- size_t index = hash % pool->capacity;
155
+ size_t index = hash & mask;
118
156
  yp_constant_t *constant;
119
157
 
120
158
  while (constant = &pool->constants[index], constant->id != 0) {
@@ -122,31 +160,49 @@ yp_constant_pool_insert(yp_constant_pool_t *pool, const uint8_t *start, size_t l
122
160
  // same as the content we are trying to insert. If it is, then we can
123
161
  // return the id of the existing constant.
124
162
  if ((constant->length == length) && memcmp(constant->start, start, length) == 0) {
125
- return index;
163
+ // Since we have found a match, we need to check if this is
164
+ // attempting to insert a shared or an owned constant. We want to
165
+ // prefer shared constants since they don't require allocations.
166
+ if (owned) {
167
+ // If we're attempting to insert an owned constant and we have
168
+ // an existing constant, then either way we don't want the given
169
+ // memory. Either it's duplicated with the existing constant or
170
+ // it's not necessary because we have a shared version.
171
+ free((void *) start);
172
+ } else if (constant->owned) {
173
+ // If we're attempting to insert a shared constant and the
174
+ // existing constant is owned, then we can free the owned
175
+ // constant and replace it with the shared constant.
176
+ free((void *) constant->start);
177
+ constant->start = start;
178
+ constant->owned = false;
179
+ }
180
+
181
+ return constant->id;
126
182
  }
127
183
 
128
- index = (index + 1) % pool->capacity;
184
+ index = (index + 1) & mask;
129
185
  }
130
186
 
131
187
  pool->size++;
132
188
  assert(pool->size < ((size_t) (1 << 31)));
133
189
 
134
- pool->constants[index] = (yp_constant_t) {
190
+ *constant = (yp_constant_t) {
135
191
  .id = (unsigned int) (pool->size & 0x7FFFFFFF),
192
+ .owned = owned,
136
193
  .start = start,
137
194
  .length = length,
138
195
  .hash = hash
139
196
  };
140
197
 
141
- return index;
198
+ return constant->id;
142
199
  }
143
200
 
144
201
  // Insert a constant into a constant pool. Returns the id of the constant, or 0
145
202
  // if any potential calls to resize fail.
146
203
  yp_constant_id_t
147
204
  yp_constant_pool_insert_shared(yp_constant_pool_t *pool, const uint8_t *start, size_t length) {
148
- size_t index = yp_constant_pool_insert(pool, start, length);
149
- return index == pool->capacity ? 0 : ((yp_constant_id_t) pool->constants[index].id);
205
+ return yp_constant_pool_insert(pool, start, length, false);
150
206
  }
151
207
 
152
208
  // Insert a constant into a constant pool from memory that is now owned by the
@@ -154,12 +210,7 @@ yp_constant_pool_insert_shared(yp_constant_pool_t *pool, const uint8_t *start, s
154
210
  // resize fail.
155
211
  yp_constant_id_t
156
212
  yp_constant_pool_insert_owned(yp_constant_pool_t *pool, const uint8_t *start, size_t length) {
157
- size_t index = yp_constant_pool_insert(pool, start, length);
158
- if (index == pool->capacity) return 0;
159
-
160
- yp_constant_t *constant = &pool->constants[index];
161
- constant->owned = true;
162
- return ((yp_constant_id_t) constant->id);
213
+ return yp_constant_pool_insert(pool, start, length, true);
163
214
  }
164
215
 
165
216
  // Free the memory associated with a constant pool.