Ruby 3.5.0dev (2025-02-22 revision 412997300569c1853c09813e4924b6df3d7e8669)
pm_newline_list.c
2
7bool
8pm_newline_list_init(pm_newline_list_t *list, const uint8_t *start, size_t capacity) {
9 list->offsets = (size_t *) xcalloc(capacity, sizeof(size_t));
10 if (list->offsets == NULL) return false;
11
12 list->start = start;
13
14 // This is 1 instead of 0 because we want to include the first line of the
15 // file as having offset 0, which is set because of calloc.
16 list->size = 1;
17 list->capacity = capacity;
18
19 return true;
20}
21
25void
26pm_newline_list_clear(pm_newline_list_t *list) {
27 list->size = 1;
28}
29
34bool
35pm_newline_list_append(pm_newline_list_t *list, const uint8_t *cursor) {
36 if (list->size == list->capacity) {
37 size_t *original_offsets = list->offsets;
38
39 list->capacity = (list->capacity * 3) / 2;
40 list->offsets = (size_t *) xcalloc(list->capacity, sizeof(size_t));
41 if (list->offsets == NULL) return false;
42
43 memcpy(list->offsets, original_offsets, list->size * sizeof(size_t));
44 xfree(original_offsets);
45 }
46
47 assert(*cursor == '\n');
48 assert(cursor >= list->start);
49 size_t newline_offset = (size_t) (cursor - list->start + 1);
50
51 assert(list->size == 0 || newline_offset > list->offsets[list->size - 1]);
52 list->offsets[list->size++] = newline_offset;
53
54 return true;
55}
56
61int32_t
62pm_newline_list_line(const pm_newline_list_t *list, const uint8_t *cursor, int32_t start_line) {
63 assert(cursor >= list->start);
64 size_t offset = (size_t) (cursor - list->start);
65
66 size_t left = 0;
67 size_t right = list->size - 1;
68
69 while (left <= right) {
70 size_t mid = left + (right - left) / 2;
71
72 if (list->offsets[mid] == offset) {
73 return ((int32_t) mid) + start_line;
74 }
75
76 if (list->offsets[mid] < offset) {
77 left = mid + 1;
78 } else {
79 right = mid - 1;
80 }
81 }
82
83 return ((int32_t) left) + start_line - 1;
84}
85
92pm_newline_list_line_column(const pm_newline_list_t *list, const uint8_t *cursor, int32_t start_line) {
93 assert(cursor >= list->start);
94 size_t offset = (size_t) (cursor - list->start);
95
96 size_t left = 0;
97 size_t right = list->size - 1;
98
99 while (left <= right) {
100 size_t mid = left + (right - left) / 2;
101
102 if (list->offsets[mid] == offset) {
103 return ((pm_line_column_t) { ((int32_t) mid) + start_line, 0 });
104 }
105
106 if (list->offsets[mid] < offset) {
107 left = mid + 1;
108 } else {
109 right = mid - 1;
110 }
111 }
112
113 return ((pm_line_column_t) {
114 .line = ((int32_t) left) + start_line - 1,
115 .column = (uint32_t) (offset - list->offsets[left - 1])
116 });
117}
118
122void
123pm_newline_list_free(pm_newline_list_t *list) {
124 xfree(list->offsets);
125}
#define xfree
Old name of ruby_xfree.
Definition xmalloc.h:58
#define xcalloc
Old name of ruby_xcalloc.
Definition xmalloc.h:55
A list of byte offsets of newlines in a string.
A line and column in a string.
A list of offsets of newlines in a string.
const uint8_t * start
A pointer to the start of the source string.
size_t capacity
The capacity of the list that has been allocated.
size_t * offsets
The list of offsets.
size_t size
The number of offsets in the list.