1313# include < unistd.h>
1414#endif
1515
16- #include < ipr/input>
16+ #include < assert.h>
17+ #include < iostream>
18+ #include " ipr/input"
1719
1820namespace ipr ::input {
1921#ifdef _WIN32
@@ -46,13 +48,13 @@ namespace ipr::input {
4648 LARGE_INTEGER s { };
4749 if (not GetFileSizeEx (file.get_handle (), &s))
4850 throw AccessError{ path, GetLastError () };
49- if (s.QuadPart )
51+ if (s.QuadPart == 0 )
5052 return ;
5153 SystemHandle mapping = CreateFileMapping (file.get_handle (), nullptr , PAGE_READONLY, 0 , 0 , nullptr );
5254 if (mapping.get_handle () == nullptr )
5355 throw FileMappingError{ path, GetLastError () };
5456 auto start = MapViewOfFile (mapping.get_handle (), FILE_MAP_READ, 0 , 0 , 0 );
55- view = { reinterpret_cast <const std::byte *>(start), static_cast <View::size_type>(s.QuadPart ) };
57+ view = { reinterpret_cast <const char8_t *>(start), static_cast <View::size_type>(s.QuadPart ) };
5658#else
5759 struct stat s { };
5860 errno = 0 ;
@@ -72,7 +74,7 @@ namespace ipr::input {
7274 close (fd);
7375 if (start == MAP_FAILED)
7476 throw FileMappingError{ path };
75- view = { reinterpret_cast <std::byte *>(start), static_cast <View::size_type>(s.st_size ) };
77+ view = { reinterpret_cast <const char8_t *>(start), static_cast <View::size_type>(s.st_size ) };
7678#endif
7779 }
7880
@@ -88,8 +90,69 @@ namespace ipr::input {
8890#ifdef _WIN32
8991 UnmapViewOfFile (view.data ());
9092#else
91- munmap (const_cast <std::byte *>(view.data ()), view.size ());
93+ munmap (const_cast <char8_t *>(view.data ()), view.size ());
9294#endif
9395 }
9496 }
97+
98+ SourceFile::View SourceFile::contents (Morsel m) const noexcept
99+ {
100+ assert (m.length < view.size ());
101+ return { view.data () + m.offset , m.length };
102+ }
103+
104+ // All code fragments directly indexable must have offsets and extents less than these limits.
105+ constexpr auto max_offset = std::uint64_t {1 } << 48 ;
106+ constexpr auto max_extent = std::uint64_t {1 } << 16 ;
107+
108+ // Characters from a raw input source file marking new lines: either CR+LR or just LF.
109+ constexpr char8_t carriage_return = 0x0D ; // '\r';
110+ constexpr char8_t line_feed = 0x0A ; // '\n';
111+
112+ void SourceFile::LineRange::next_line () noexcept
113+ {
114+ const auto offset = static_cast <std::uint64_t >(ptr - src->view .data ());
115+ assert (offset < max_offset);
116+ const auto limit = src->view .size ();
117+ std::uint64_t idx = 0 ;
118+ while (idx < limit and ptr[idx] != carriage_return and ptr[idx] != line_feed)
119+ ++idx;
120+ assert (idx < max_extent);
121+ cache.offset = offset;
122+ cache.length = idx;
123+
124+ // Skip the new line marker.
125+ if (idx < limit)
126+ {
127+ if (ptr[idx] == carriage_return and idx+1 < limit and ptr[idx+1 ] == line_feed)
128+ ++idx;
129+ ++idx;
130+ }
131+ ptr += idx;
132+ }
133+
134+ SourceFile::LineRange::LineRange (const SourceFile& src) : src{&src}, ptr{src.view .data ()}
135+ {
136+ // Skip a possible misguided UTF-8 BOM.
137+ if (src.view .size () >= 3 and ptr[0 ] == 0xEF and ptr[1 ] == 0xBB and ptr[2 ] == 0xBF )
138+ ptr += 3 ;
139+ next_line ();
140+ }
141+
142+ Morsel SourceFile::LineRange::iterator::operator *() const noexcept
143+ {
144+ assert (range != nullptr );
145+ return range->cache ;
146+ }
147+
148+ SourceFile::LineRange::iterator& SourceFile::LineRange::iterator::operator ++() noexcept
149+ {
150+ assert (range != nullptr );
151+ if (range->ptr >= range->src ->view .data () + range->src ->view .size ())
152+ range = nullptr ;
153+ else
154+ range->next_line ();
155+
156+ return *this ;
157+ }
95158}
0 commit comments