Skip to content
This repository was archived by the owner on Oct 12, 2026. It is now read-only.

Commit c87a95c

Browse files
committed
REFACTOR: Clean up Buffer and BufferManager.
- Simplify Buffer implementation. - Fix compiler warnings. - Add TODOs for future improvements. Ref #1
1 parent 7ee9168 commit c87a95c

7 files changed

Lines changed: 91 additions & 69 deletions

File tree

‎include/lbd/source/Buffer.hpp‎

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,40 @@
11
#pragma once
22

33
#include <string>
4-
#include <string_view>
54
#include <vector>
65
#include <lbd/source/BufferId.hpp>
76
#include <lbd/source/Location.hpp>
87

98
namespace lbd::source
109
{
11-
struct Buffer
10+
class Buffer
1211
{
13-
BufferId id;
14-
std::string name;
15-
std::string contents;
16-
std::vector<Offset> lineOffsets;
12+
public:
13+
Buffer(BufferId id, std::string name, std::string contents);
1714

18-
[[nodiscard]] size_t getSize() const;
15+
[[nodiscard]] BufferId getId() const noexcept { return m_id; }
1916

20-
[[nodiscard]] char operator[](size_t index) const;
17+
[[nodiscard]] std::string_view getName() const noexcept { return m_name; }
2118

19+
[[nodiscard]] std::string_view getContents() const noexcept { return m_contents; }
20+
21+
[[nodiscard]] const std::vector<Offset> &getLineOffsets() const noexcept { return m_lineOffsets; }
22+
23+
[[nodiscard]] size_t getSize() const noexcept { return m_contents.size(); }
24+
25+
[[nodiscard]] char operator[](const size_t index) const noexcept { return m_contents[index]; }
26+
27+
/**
28+
*Computes the starting offset of each line.
29+
*
30+
* The first entry is always `0`, representing the start of the first line.
31+
*/
2232
void computeLineOffsets() noexcept;
33+
34+
private:
35+
BufferId m_id;
36+
std::string m_name;
37+
std::string m_contents;
38+
std::vector<Offset> m_lineOffsets;
2339
};
24-
}
40+
}

‎include/lbd/source/BufferManager.hpp‎

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,18 @@ namespace lbd::source
1616
[[nodiscard]] BufferId createBuffer(std::string name, std::string contents) noexcept;
1717

1818
// Access Buffers.
19-
[[nodiscard]] const Buffer &getBuffer(BufferId id) const noexcept;
19+
[[nodiscard]] const Buffer &getBuffer(const BufferId id) const noexcept { return m_buffers[id]; }
2020

21-
[[nodiscard]] std::string_view getBufferName(BufferId id) const noexcept;
21+
[[nodiscard]] std::string_view getBufferName(const BufferId id) const noexcept { return m_buffers[id].getName(); }
2222

23-
[[nodiscard]] std::string_view getBufferContents(BufferId id) const noexcept;
23+
[[nodiscard]] size_t getBufferSize(const BufferId id) const noexcept { return m_buffers[id].getSize(); }
2424

25-
[[nodiscard]] size_t getBufferSize(BufferId id) const noexcept;
25+
[[nodiscard]] char atOffset(const BufferId id, const Offset offset) const noexcept { return m_buffers[id][offset]; }
2626

27-
[[nodiscard]] char atOffset(BufferId id, Offset offset) const noexcept;
27+
[[nodiscard]] std::string_view getBufferContents(const BufferId id) const noexcept
28+
{
29+
return m_buffers[id].getContents();
30+
}
2831

2932
// Location utilities.
3033
[[nodiscard]] RowNumber getRow(BufferId id, Offset offset) const noexcept;
@@ -39,9 +42,9 @@ namespace lbd::source
3942
private:
4043
[[nodiscard]] BufferId addBuffer(std::string name, std::string contents) noexcept;
4144

42-
std::deque<Buffer> buffers;
43-
std::unordered_map<std::string, BufferId> nameToBufferIdMap;
45+
std::deque<Buffer> m_buffers;
46+
std::unordered_map<std::string, BufferId> m_bufferToIdMap;
4447
};
4548

46-
std::string getAbsolutePath(const std::string &path) noexcept;
47-
}
49+
[[nodiscard]] std::string getAbsolutePath(const std::string &path) noexcept;
50+
}

‎src/Driver.cpp‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#include <iostream>
22
#include <lbd/Driver.hpp>
3+
#include <lbd/frontend/Program.hpp>
34
#include <lbd/frontend/lexer/Lexer.hpp>
45
#include <lbd/frontend/parser/Parser.hpp>
5-
#include <lbd/frontend/Program.hpp>
66
#include <lbd/runtime/Interpreter.hpp>
77

88
namespace lbd

‎src/frontend/lexer/Lexer.cpp‎

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
#include <cctype>
2-
#include <fstream>
31
#include <lbd/diagnostics/ContextGuard.hpp>
42
#include <lbd/frontend/lexer/Lexer.hpp>
53
#include <lbd/source/Range.hpp>
@@ -50,13 +48,13 @@ namespace lbd::frontend::lexer
5048
{
5149
while (std::isspace(static_cast<unsigned char>(getCurrentCharacter()))) advanceCursor();
5250

53-
const source::Location beginLocation{buffer.id, cursor};
51+
const source::Location beginLocation{buffer.getId(), cursor};
5452

5553
// Adding Context Guard for diagnostics.
5654
diagnostics::ContextGuard contextGuard(
5755
context.getDiagnosticEmitter(),
58-
source::Range(beginLocation, {buffer.id, static_cast<source::Offset>(buffer.getSize())}),
59-
fmt::format("While lexing `{}`.", buffer.name));
56+
source::Range(beginLocation, {buffer.getId(), static_cast<source::Offset>(buffer.getSize())}),
57+
fmt::format("While lexing `{}`.", buffer.getName()));
6058

6159
if (isEof()) return {token::TokenKind::END_OF_FILE, "", {beginLocation, beginLocation}};
6260

@@ -65,8 +63,9 @@ namespace lbd::frontend::lexer
6563
{
6664
const source::Offset beginOffset = cursor;
6765
while (!isEof() && isIdentifier(getCurrentCharacter())) advanceCursor();
68-
const auto lexeme = buffer.contents.substr(beginOffset, cursor - beginOffset);
69-
return {token::TokenKind::IDENTIFIER, lexeme, {beginLocation, {buffer.id, cursor}}};
66+
// TODO: Relook whether Lexer should create a copy of lexeme or refer to buffer.
67+
const auto lexeme = std::string(buffer.getContents().substr(beginOffset, cursor - beginOffset));
68+
return {token::TokenKind::IDENTIFIER, lexeme, {beginLocation, {buffer.getId(), cursor}}};
7069
}
7170

7271
// Number.
@@ -79,7 +78,7 @@ namespace lbd::frontend::lexer
7978
if (getCurrentCharacter() == '-' && !std::isdigit(peekNextCurrentCharacter()))
8079
{
8180
context.getDiagnosticEmitter().error(
82-
{beginLocation, {buffer.id, cursor}},
81+
{beginLocation, {buffer.getId(), cursor}},
8382
diagnostics::DiagnosticId::LEXER_UNEXPECTED_CHARACTER, '-'
8483
);
8584
}
@@ -91,8 +90,8 @@ namespace lbd::frontend::lexer
9190
advanceCursor(); // Consume '.'
9291
while (!isEof() && std::isdigit(getCurrentCharacter())) advanceCursor();
9392
}
94-
const auto lexeme = buffer.contents.substr(beginOffset, cursor - beginOffset);
95-
return {token::TokenKind::NUMBER, lexeme, {beginLocation, {buffer.id, cursor}}};
93+
const auto lexeme = std::string(buffer.getContents().substr(beginOffset, cursor - beginOffset));
94+
return {token::TokenKind::NUMBER, lexeme, {beginLocation, {buffer.getId(), cursor}}};
9695
}
9796

9897
// String literal.
@@ -104,14 +103,14 @@ namespace lbd::frontend::lexer
104103
if (getCurrentCharacter() != '"')
105104
{
106105
context.getDiagnosticEmitter().error(
107-
{beginLocation, {buffer.id, cursor}},
106+
{beginLocation, {buffer.getId(), cursor}},
108107
diagnostics::DiagnosticId::LEXER_UNBALANCED_QUOTE
109108
);
110109
}
111-
advanceCursor(); // Consume '"'
110+
advanceCursor(); // Consume double-quote.
112111
// +1 and -1 for excluding the quotes.
113-
const auto lexeme = buffer.contents.substr(beginOffset + 1, cursor - beginOffset - 2);
114-
return {token::TokenKind::STRING, lexeme, {beginLocation, {buffer.id, cursor}}};
112+
const auto lexeme = std::string(buffer.getContents().substr(beginOffset + 1, cursor - beginOffset - 2));
113+
return {token::TokenKind::STRING, lexeme, {beginLocation, {buffer.getId(), cursor}}};
115114
}
116115

117116
LexSymbol:
@@ -128,7 +127,7 @@ namespace lbd::frontend::lexer
128127
{
129128
advanceCursor();
130129
const auto lexeme = std::string(1, symbol);
131-
return {symbolToTokenKind(symbol), lexeme, {beginLocation, {buffer.id, cursor}}};
130+
return {symbolToTokenKind(symbol), lexeme, {beginLocation, {buffer.getId(), cursor}}};
132131
}
133132
case '=':
134133
{
@@ -137,9 +136,9 @@ namespace lbd::frontend::lexer
137136
{
138137
// FAT_ARROW
139138
advanceCursor(); // Consume '>'
140-
return {token::TokenKind::FAT_ARROW, "=>", {beginLocation, {buffer.id, cursor}}};
139+
return {token::TokenKind::FAT_ARROW, "=>", {beginLocation, {buffer.getId(), cursor}}};
141140
}
142-
return {token::TokenKind::ASSIGNMENT, "=", {beginLocation, {buffer.id, cursor}}};
141+
return {token::TokenKind::ASSIGNMENT, "=", {beginLocation, {buffer.getId(), cursor}}};
143142
}
144143
case '-':
145144
{
@@ -154,7 +153,7 @@ namespace lbd::frontend::lexer
154153
{
155154
// Arrow.
156155
advanceCursor(); // Consume '>'.
157-
return {token::TokenKind::ARROW, "->", {beginLocation, {buffer.id, cursor}}};
156+
return {token::TokenKind::ARROW, "->", {beginLocation, {buffer.getId(), cursor}}};
158157
}
159158
default:
160159
break;
@@ -164,7 +163,7 @@ namespace lbd::frontend::lexer
164163
break;
165164
}
166165
context.getDiagnosticEmitter().error(
167-
{beginLocation, {buffer.id, cursor}},
166+
{beginLocation, {buffer.getId(), cursor}},
168167
diagnostics::DiagnosticId::LEXER_UNEXPECTED_CHARACTER, getCurrentCharacter()
169168
);
170169
}
@@ -205,11 +204,11 @@ namespace lbd::frontend::lexer
205204
case '(': return token::TokenKind::OPEN_PARENTHESIS;
206205
case ')': return token::TokenKind::CLOSE_PARENTHESIS;
207206
default:
208-
const source::Location location{buffer.id, cursor};
207+
const source::Location location{buffer.getId(), cursor};
209208
context.getDiagnosticEmitter().error(
210209
{location, location},
211210
diagnostics::DiagnosticId::LEXER_UNEXPECTED_CHARACTER, symbol
212211
);
213212
}
214213
}
215-
}
214+
}

‎src/frontend/parser/Parser.cpp‎

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include <filesystem>
2+
// ReSharper disable once CppUnusedIncludeDirective
23
#include <fmt/core.h>
34
#include <lbd/diagnostics/ContextGuard.hpp>
45
#include <lbd/frontend/ast/expression/FunctionApplicationExpression.hpp>
@@ -23,7 +24,7 @@ namespace lbd::frontend::parser
2324
diagnostics::ContextGuard contextGuard(
2425
context.getDiagnosticEmitter(),
2526
lexer.peek().range,
26-
fmt::format("While parsing `{}`.", lexer.getBuffer().name));
27+
fmt::format("While parsing `{}`.", lexer.getBuffer().getName()));
2728

2829
while (lexer.hasNext())
2930
{

‎src/source/Buffer.cpp‎

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,19 @@
22

33
namespace lbd::source
44
{
5-
size_t Buffer::getSize() const { return contents.size(); }
6-
char Buffer::operator[](const size_t index) const { return contents[index]; }
5+
Buffer::Buffer(const BufferId id, std::string name, std::string contents)
6+
: m_id(id), m_name(std::move(name)), m_contents(std::move(contents))
7+
{
8+
computeLineOffsets();
9+
}
710

811
void Buffer::computeLineOffsets() noexcept
912
{
10-
lineOffsets.clear();
11-
lineOffsets.push_back(0);
12-
for (uint32_t i = 0; i < contents.size(); ++i)
13+
m_lineOffsets.clear();
14+
m_lineOffsets.push_back(0);
15+
for (uint32_t i = 0; i < m_contents.size(); ++i)
1316
{
14-
if (contents[i] == '\n') lineOffsets.push_back(i + 1);
17+
if (m_contents[i] == '\n') m_lineOffsets.push_back(i + 1);
1518
}
1619
}
17-
}
20+
}

‎src/source/BufferManager.cpp‎

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,15 @@ namespace lbd::source
88
BufferId BufferManager::loadFile(const std::string &path) noexcept
99
{
1010
const std::string absolutePath = getAbsolutePath(path);
11-
if (nameToBufferIdMap.contains(absolutePath)) return nameToBufferIdMap[absolutePath];
11+
if (const auto it = m_bufferToIdMap.find(absolutePath); it != m_bufferToIdMap.end()) return it->second;
1212

13+
// TODO: Read file in binary mode, as it may translate the line-endings to LF, making offset incorrect.
1314
std::ifstream file(absolutePath);
15+
// TODO: emit diagnostic / return invalid BufferId, upon failure to open a file.
1416
std::string contents((std::istreambuf_iterator(file)), std::istreambuf_iterator<char>());
1517

1618
const BufferId id = addBuffer(absolutePath, std::move(contents));
17-
nameToBufferIdMap[absolutePath] = id;
19+
m_bufferToIdMap.emplace(absolutePath, id);
1820
return id;
1921
}
2022

@@ -23,53 +25,51 @@ namespace lbd::source
2325
return addBuffer(std::move(name), std::move(contents));
2426
}
2527

26-
const Buffer &BufferManager::getBuffer(const BufferId id) const noexcept { return buffers[id]; }
27-
std::string_view BufferManager::getBufferName(const BufferId id) const noexcept { return buffers[id].name; }
28-
std::string_view BufferManager::getBufferContents(const BufferId id) const noexcept { return buffers[id].contents; }
29-
size_t BufferManager::getBufferSize(const BufferId id) const noexcept { return buffers[id].getSize(); }
30-
char BufferManager::atOffset(const BufferId id, const Offset offset) const noexcept { return buffers[id][offset]; }
31-
3228
RowNumber BufferManager::getRow(const BufferId id, const Offset offset) const noexcept
3329
{
34-
const auto &lines = buffers[id].lineOffsets;
30+
const auto &lines = m_buffers[id].getLineOffsets();
3531
const auto it = std::ranges::upper_bound(lines, offset);
3632
return static_cast<RowNumber>(it - lines.begin());
3733
}
3834

3935
ColumnNumber BufferManager::getColumn(const BufferId id, const Offset offset) const noexcept
4036
{
41-
const auto &lines = buffers[id].lineOffsets;
37+
const auto &lines = m_buffers[id].getLineOffsets();
4238
const auto it = std::ranges::upper_bound(lines, offset);
4339
const RowNumber row = static_cast<RowNumber>(it - lines.begin());
4440
return offset - lines[row - 1] + 1;
4541
}
4642

4743
std::string_view BufferManager::getLine(const BufferId id, const Offset offset) const noexcept
4844
{
49-
const auto &buffer = buffers[id];
50-
const auto &lines = buffer.lineOffsets;
45+
const auto &buffer = getBuffer(id);
46+
const auto &lines = buffer.getLineOffsets();
5147

5248
const auto it = std::ranges::upper_bound(lines, offset);
53-
const size_t row = it - lines.begin();
49+
const size_t row = static_cast<size_t>(it - lines.begin());
5450
const size_t lineStart = lines[row - 1];
55-
const size_t lineEnd = row < lines.size() ? lines[row] - 1 : buffer.contents.size();
51+
// TODO: Relook whether this works for Windows CRLF (may need to subtract 2 in that case.)
52+
const size_t lineEnd = row < lines.size() ? lines[row] - 1 : buffer.getSize();
5653

57-
return {buffer.contents.data() + lineStart, lineEnd - lineStart};
54+
return buffer.getContents().substr(lineStart, lineEnd - lineStart);
5855
}
5956

6057
bool BufferManager::isBufferLoaded(const std::string &name) const noexcept
6158
{
6259
const std::string absolutePath = getAbsolutePath(name);
63-
return nameToBufferIdMap.contains(absolutePath);
60+
return m_bufferToIdMap.contains(absolutePath);
6461
}
6562

6663
BufferId BufferManager::addBuffer(std::string name, std::string contents) noexcept
6764
{
68-
const auto id = static_cast<BufferId>(buffers.size());
69-
buffers.push_back(Buffer{id, std::move(name), std::move(contents)});
70-
buffers.back().computeLineOffsets();
65+
const auto id = static_cast<BufferId>(m_buffers.size());
66+
m_buffers.emplace_back(id, std::move(name), std::move(contents));
7167
return id;
7268
}
7369

74-
std::string getAbsolutePath(const std::string &path) noexcept { return std::filesystem::absolute(path).string(); }
75-
}
70+
std::string getAbsolutePath(const std::string &path) noexcept
71+
{
72+
// TODO: Handle thrown exception.
73+
return std::filesystem::weakly_canonical(path).string();
74+
}
75+
}

0 commit comments

Comments
 (0)