Skip to content

Commit 3cffc44

Browse files
committed
Lazily build offsets from a packed array
1 parent 7ac0c85 commit 3cffc44

5 files changed

Lines changed: 40 additions & 26 deletions

File tree

ext/prism/extension.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -802,16 +802,14 @@ parse_lex_input(const uint8_t *input, size_t input_length, const pm_options_t *o
802802

803803
pm_node_t *node = pm_parse(parser);
804804

805-
// Here we need to update the Source object to have the correct
806-
// encoding for the source string and the correct newline offsets.
807-
// We do it here because we've already created the Source object and given
808-
// it over to all of the tokens, and both of these are only set after pm_parse().
805+
/* Update the Source object with the correct encoding and line offsets,
806+
* which are only available after pm_parse() completes. */
809807
rb_encoding *encoding = rb_enc_find(pm_parser_encoding_name(parser));
810808
rb_enc_associate(source_string, encoding);
811809

812810
const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(parser);
813811
for (size_t index = 0; index < line_offsets->size; index++) {
814-
rb_ary_push(offsets, ULONG2NUM(line_offsets->offsets[index]));
812+
rb_ary_store(offsets, (long) index, ULONG2NUM(line_offsets->offsets[index]));
815813
}
816814

817815
if (pm_options_freeze(options)) {

lib/prism/parse_result.rb

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -58,16 +58,26 @@ def self.for(source, start_line, offsets)
5858
# The line number where this source starts.
5959
attr_reader :start_line #: Integer
6060

61-
# The list of newline byte offsets in the source code.
62-
attr_reader :offsets #: Array[Integer]
61+
# The list of newline byte offsets in the source code. When initialized from
62+
# the C extension, this may be a packed binary string of uint32_t values
63+
# that is lazily unpacked on first access.
64+
#--
65+
#: () -> Array[Integer]
66+
def offsets
67+
offsets = @offsets
68+
return offsets if offsets.is_a?(Array)
69+
@offsets = offsets.unpack("L*")
70+
end
6371

64-
# Create a new source object with the given source code.
72+
# Create a new source object with the given source code. The offsets
73+
# parameter can be either an Array of Integer byte offsets or a packed
74+
# binary string of uint32_t values (from the C extension).
6575
#--
66-
#: (String source, Integer start_line, Array[Integer] offsets) -> void
76+
#: (String source, Integer start_line, Array[Integer] | String offsets) -> void
6777
def initialize(source, start_line, offsets)
6878
@source = source
69-
@start_line = start_line # set after parsing is done
70-
@offsets = offsets # set after parsing is done
79+
@start_line = start_line
80+
@offsets = offsets
7181
end
7282

7383
# Replace the value of start_line with the given value.
@@ -81,7 +91,7 @@ def replace_start_line(start_line)
8191
#--
8292
#: (Array[Integer] offsets) -> void
8393
def replace_offsets(offsets)
84-
@offsets.replace(offsets)
94+
@offsets = offsets
8595
end
8696

8797
# Returns the encoding of the source code, which is set by parameters to the

rbi/generated/prism/parse_result.rbi

Lines changed: 8 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sig/generated/prism/parse_result.rbs

Lines changed: 11 additions & 5 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

templates/ext/prism/api_node.c.erb

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,7 @@ pm_source_new(const pm_parser_t *parser, rb_encoding *encoding, bool freeze) {
8181
VALUE source_string = rb_enc_str_new((const char *) start, pm_parser_end(parser) - start, encoding);
8282

8383
const pm_line_offset_list_t *line_offsets = pm_parser_line_offsets(parser);
84-
VALUE offsets = rb_ary_new_capa(line_offsets->size);
85-
86-
for (size_t index = 0; index < line_offsets->size; index++) {
87-
rb_ary_push(offsets, ULONG2NUM(line_offsets->offsets[index]));
88-
}
84+
VALUE offsets = rb_str_new((const char *) line_offsets->offsets, line_offsets->size * sizeof(uint32_t));
8985

9086
if (freeze) {
9187
rb_obj_freeze(source_string);

0 commit comments

Comments
 (0)