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