-
-
Notifications
You must be signed in to change notification settings - Fork 594
/
filecache.d
138 lines (119 loc) · 3.32 KB
/
filecache.d
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
133
134
135
136
137
138
/**
* Compiler implementation of the
* $(LINK2 http://www.dlang.org, D programming language).
*
* Copyright: Copyright (C) 1999-2019 by The D Language Foundation, All Rights Reserved
* Authors: $(LINK2 http://www.digitalmars.com, Walter Bright)
* License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
* Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/filecache.d, filecache.d)
* Documentation: https://dlang.org/phobos/dmd_filecache.html
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/filecache.d
*/
module dmd.filecache;
import dmd.root.stringtable;
import dmd.root.array;
import dmd.root.file;
import dmd.root.filename;
import core.stdc.stdio;
/**
A line-by-line representation of a $(REF File, dmd,root,file).
*/
class FileAndLines
{
FileName* file;
FileBuffer* buffer;
const(char[])[] lines;
nothrow:
/**
File to read and split into its lines.
*/
this(const(char)[] filename)
{
file = new FileName(filename);
readAndSplit();
}
// Read a file and split the file buffer linewise
private void readAndSplit()
{
auto readResult = File.read(file.toChars());
// FIXME: check success
// take ownership of buffer
buffer = new FileBuffer(readResult.extractSlice());
ubyte* buf = buffer.data.ptr;
// slice into lines
while (*buf)
{
auto prevBuf = buf;
for (; *buf != '\n' && *buf != '\r'; buf++)
{
if (!*buf)
break;
}
// handle Windows line endings
if (*buf == '\r' && *(buf + 1) == '\n')
buf++;
lines ~= cast(const(char)[]) prevBuf[0 .. buf - prevBuf];
buf++;
}
}
void destroy()
{
if (file)
{
file.destroy();
file = null;
buffer.destroy();
buffer = null;
lines.destroy();
lines = null;
}
}
~this()
{
destroy();
}
}
/**
A simple file cache that can be used to avoid reading the same file multiple times.
It stores its cached files as $(LREF FileAndLines)
*/
struct FileCache
{
private StringTable files;
nothrow:
/**
Add or get a file from the file cache.
If the file isn't part of the cache, it will be read from the filesystem.
If the file has been read before, the cached file object will be returned
Params:
file = file to load in (or get from) the cache
Returns: a $(LREF FileAndLines) object containing a line-by-line representation of the requested file
*/
FileAndLines addOrGetFile(const(char)[] file)
{
if (auto payload = files.lookup(file))
{
if (payload !is null)
return cast(typeof(return)) payload.ptrvalue;
}
auto lines = new FileAndLines(file);
files.insert(file, cast(void*) lines);
return lines;
}
__gshared fileCache = FileCache();
// Initializes the global FileCache singleton
static __gshared void _init()
{
fileCache.initialize();
}
void initialize()
{
files._init();
}
void deinitialize()
{
foreach (sv; files)
sv.destroy();
files.reset();
}
}