1515
1616#include < assert.h>
1717#include < iostream>
18+ #include < utility>
1819#include " ipr/input"
1920
2021namespace ipr ::input {
22+ static constexpr std::uint32_t index_watermark { 1u << 31 };
23+
24+
25+ LineIndex::LineIndex (LineSort s, std::uint32_t i)
26+ : srt{(assert (s == LineSort::Simple || s == LineSort::Composite), std::to_underlying (s))},
27+ idx{(assert (i < index_watermark), i)}
28+ {
29+ }
30+
31+
32+
2133#ifdef _WIN32
2234 // Helper type for automatically closing a handle on scope exit.
2335 struct SystemHandle {
@@ -109,6 +121,17 @@ namespace ipr::input {
109121 constexpr char8_t carriage_return = 0x0D ; // '\r';
110122 constexpr char8_t line_feed = 0x0A ; // '\n';
111123
124+ static inline bool white_space (char8_t c)
125+ {
126+ switch (c)
127+ {
128+ case u' ' : case u8 ' \t ' : case u8 ' \v ' : case u8 ' \f ' :
129+ return true ;
130+ default :
131+ return false ;
132+ }
133+ }
134+
112135 void SourceFile::LineRange::next_line () noexcept
113136 {
114137 const auto offset = static_cast <std::uint64_t >(ptr - src->view .data ());
@@ -156,4 +179,68 @@ namespace ipr::input {
156179
157180 return *this ;
158181 }
182+
183+ namespace {
184+ LineDepot read_lines (const SourceFile& src)
185+ {
186+ LineDepot depot { };
187+ const auto file_start = src.contents ().data ();
188+
189+ CompositeLine composite { };
190+ for (auto line: src.lines ())
191+ {
192+ if (line.empty ())
193+ continue ;
194+ // Trim any trailing whitespace character when determining logical line continuation.
195+ const auto line_start = file_start + line.morsel .offset ;
196+ auto cursor = line_start + line.morsel .length ;
197+ while (--cursor > line_start and white_space (*cursor))
198+ ;
199+ if (cursor <= line_start)
200+ continue ; // skip entirely blank lines.
201+ if (*cursor == u8 ' \\ ' )
202+ {
203+ line.morsel .length = cursor - line_start;
204+ composite.lines .push_back (line);
205+ continue ;
206+ }
207+ else if (not composite.lines .empty ())
208+ {
209+ composite.lines .push_back (line);
210+ auto idx = depot.composites .size ();
211+ depot.composites .push_back (composite);
212+ depot.indices .emplace_back (LineSort::Composite, idx);
213+ composite.lines .clear ();
214+ }
215+ else
216+ {
217+ auto idx = depot.simples .size ();
218+ depot.indices .emplace_back (LineSort::Simple, idx);
219+ depot.simples .emplace_back (line);
220+ }
221+ }
222+
223+ return depot;
224+ }
225+ }
226+
227+ SourceListing::SourceListing (const SystemPath& path)
228+ : SourceFile{path}, depot{read_lines (*this )}
229+ { }
230+
231+ const SimpleLine& SourceListing::simple_line (LineIndex line) const
232+ {
233+ assert (idx.sort () == LineSort::Simple);
234+ auto n = line.index ();
235+ assert (n < depot.simples .size ());
236+ return depot.simples [n];
237+ }
238+
239+ const CompositeLine& SourceListing::composite_line (LineIndex line) const
240+ {
241+ assert (idx.sort () == LineSort::Composite);
242+ auto n = line.index ();
243+ assert (n < depot.composites .size ());
244+ return depot.composites [n];
245+ }
159246}
0 commit comments