forked from google/cpu_features
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathstack_line_reader.c
132 lines (118 loc) · 4.04 KB
/
stack_line_reader.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
// Copyright 2017 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "internal/stack_line_reader.h"
#include <assert.h>
#include <errno.h>
#include <stdio.h>
#include "internal/filesystem.h"
void StackLineReader_Initialize(StackLineReader* reader, int fd) {
reader->view.ptr = reader->buffer;
reader->view.size = 0;
reader->skip_mode = false;
reader->fd = fd;
}
// Replaces the content of buffer with bytes from the file.
static int LoadFullBuffer(StackLineReader* reader) {
const int read = CpuFeatures_ReadFile(reader->fd, reader->buffer,
STACK_LINE_READER_BUFFER_SIZE);
assert(read >= 0);
reader->view.ptr = reader->buffer;
reader->view.size = read;
return read;
}
// Appends with bytes from the file to buffer, filling the remaining space.
static int LoadMore(StackLineReader* reader) {
char* const ptr = reader->buffer + reader->view.size;
const size_t size_to_read = STACK_LINE_READER_BUFFER_SIZE - reader->view.size;
const int read = CpuFeatures_ReadFile(reader->fd, ptr, size_to_read);
assert(read >= 0);
assert(read <= (int)size_to_read);
reader->view.size += read;
return read;
}
static int IndexOfEol(StackLineReader* reader) {
return CpuFeatures_StringView_IndexOfChar(reader->view, '\n');
}
// Relocate buffer's pending bytes at the beginning of the array and fills the
// remaining space with bytes from the file.
static int BringToFrontAndLoadMore(StackLineReader* reader) {
if (reader->view.size && reader->view.ptr != reader->buffer) {
memmove(reader->buffer, reader->view.ptr, reader->view.size);
}
reader->view.ptr = reader->buffer;
return LoadMore(reader);
}
// Loads chunks of buffer size from disks until it contains a newline character
// or end of file.
static void SkipToNextLine(StackLineReader* reader) {
for (;;) {
const int read = LoadFullBuffer(reader);
if (read == 0) {
break;
} else {
const int eol_index = IndexOfEol(reader);
if (eol_index >= 0) {
reader->view =
CpuFeatures_StringView_PopFront(reader->view, eol_index + 1);
break;
}
}
}
}
static LineResult CreateLineResult(bool eof, bool full_line, StringView view) {
LineResult result;
result.eof = eof;
result.full_line = full_line;
result.line = view;
return result;
}
// Helper methods to provide clearer semantic in StackLineReader_NextLine.
static LineResult CreateEOFLineResult(StringView view) {
return CreateLineResult(true, true, view);
}
static LineResult CreateTruncatedLineResult(StringView view) {
return CreateLineResult(false, false, view);
}
static LineResult CreateValidLineResult(StringView view) {
return CreateLineResult(false, true, view);
}
LineResult StackLineReader_NextLine(StackLineReader* reader) {
if (reader->skip_mode) {
SkipToNextLine(reader);
reader->skip_mode = false;
}
{
const bool can_load_more =
reader->view.size < STACK_LINE_READER_BUFFER_SIZE;
int eol_index = IndexOfEol(reader);
if (eol_index < 0 && can_load_more) {
const int read = BringToFrontAndLoadMore(reader);
if (read == 0) {
return CreateEOFLineResult(reader->view);
}
eol_index = IndexOfEol(reader);
}
if (eol_index < 0) {
reader->skip_mode = true;
return CreateTruncatedLineResult(reader->view);
}
{
StringView line =
CpuFeatures_StringView_KeepFront(reader->view, eol_index);
reader->view =
CpuFeatures_StringView_PopFront(reader->view, eol_index + 1);
return CreateValidLineResult(line);
}
}
}