Ruby  3.4.0dev (2024-11-05 revision e440268d51fe02b303e3817a7a733a0dac1c5091)
pm_newline_list.c
2 
7 bool
8 pm_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 
25 void
27  list->size = 1;
28 }
29 
34 bool
35 pm_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 
61 int32_t
62 pm_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 
92 pm_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 
122 void
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.
pm_line_column_t pm_newline_list_line_column(const pm_newline_list_t *list, const uint8_t *cursor, int32_t start_line)
Returns the line and column of the given offset.
void pm_newline_list_free(pm_newline_list_t *list)
Free the internal memory allocated for the newline list.
int32_t pm_newline_list_line(const pm_newline_list_t *list, const uint8_t *cursor, int32_t start_line)
Returns the line of the given offset.
bool pm_newline_list_init(pm_newline_list_t *list, const uint8_t *start, size_t capacity)
Initialize a new newline list with the given capacity.
bool pm_newline_list_append(pm_newline_list_t *list, const uint8_t *cursor)
Append a new offset to the newline list.
void pm_newline_list_clear(pm_newline_list_t *list)
Clear out the newlines that have been appended to the list.
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.