mirror of
https://github.com/dlang/dmd.git
synced 2025-04-25 20:50:41 +03:00
Rip out FileCache and replace with FileManager (#13193)
This commit is contained in:
parent
c0dab2b877
commit
469890bac1
12 changed files with 448 additions and 294 deletions
4
dub.sdl
4
dub.sdl
|
@ -22,7 +22,7 @@ subPackage {
|
|||
"src/dmd/console.d" \
|
||||
"src/dmd/entity.d" \
|
||||
"src/dmd/errors.d" \
|
||||
"src/dmd/filecache.d" \
|
||||
"src/dmd/file_manager.d" \
|
||||
"src/dmd/globals.d" \
|
||||
"src/dmd/id.d" \
|
||||
"src/dmd/identifier.d" \
|
||||
|
@ -92,7 +92,7 @@ subPackage {
|
|||
console,\
|
||||
entity,\
|
||||
errors,\
|
||||
filecache,\
|
||||
file_manager,\
|
||||
globals,\
|
||||
id,\
|
||||
identifier,\
|
||||
|
|
|
@ -1406,7 +1406,7 @@ auto sourceFiles()
|
|||
statement.h staticassert.h target.h template.h tokens.h version.h visitor.h
|
||||
"),
|
||||
lexer: fileArray(env["D"], "
|
||||
console.d entity.d errors.d filecache.d globals.d id.d identifier.d lexer.d tokens.d utf.d
|
||||
console.d entity.d errors.d file_manager.d globals.d id.d identifier.d lexer.d tokens.d utf.d
|
||||
") ~ fileArray(env["ROOT"], "
|
||||
array.d bitarray.d ctfloat.d file.d filename.d hash.d port.d region.d rmem.d
|
||||
rootobject.d stringtable.d
|
||||
|
|
|
@ -245,14 +245,14 @@ Note that these groups have no strict meaning, the category assignments are a bi
|
|||
|
||||
Note: many other utilities are in [dmd/root](https://github.com/dlang/dmd/tree/master/src/dmd/root).
|
||||
|
||||
| File | Purpose |
|
||||
|-----------------------------------------------------------------------------|---------------------------------------------------|
|
||||
| [env.d](https://github.com/dlang/dmd/blob/master/src/dmd/env.d) | Modify environment variables |
|
||||
| [console.d](https://github.com/dlang/dmd/blob/master/src/dmd/console.d) | Print error messages in color |
|
||||
| [utf.d](https://github.com/dlang/dmd/blob/master/src/dmd/utf.d) | Encoding/decoding Unicode text |
|
||||
| [filecache.d](https://github.com/dlang/dmd/blob/master/src/dmd/filecache.d) | Keep file contents in memory |
|
||||
| [utils.d](https://github.com/dlang/dmd/blob/master/src/dmd/utils.d) | Utility functions related to files and file paths |
|
||||
| [complex.d](https://github.com/dlang/dmd/blob/master/src/dmd/complex.d) | A complex number type |
|
||||
| File | Purpose |
|
||||
|-----------------------------------------------------------------------------------|---------------------------------------------------|
|
||||
| [env.d](https://github.com/dlang/dmd/blob/master/src/dmd/env.d) | Modify environment variables |
|
||||
| [console.d](https://github.com/dlang/dmd/blob/master/src/dmd/console.d) | Print error messages in color |
|
||||
| [utf.d](https://github.com/dlang/dmd/blob/master/src/dmd/utf.d) | Encoding/decoding Unicode text |
|
||||
| [file_manager.d](https://github.com/dlang/dmd/blob/master/src/dmd/file_manager.d) | Keep file contents in memory |
|
||||
| [utils.d](https://github.com/dlang/dmd/blob/master/src/dmd/utils.d) | Utility functions related to files and file paths |
|
||||
| [complex.d](https://github.com/dlang/dmd/blob/master/src/dmd/complex.d) | A complex number type |
|
||||
|
||||
| File | Purpose |
|
||||
|---------------------------------------------------------------------------------|---------------------------------------------------------------|
|
||||
|
|
|
@ -31,6 +31,7 @@ import dmd.dsymbolsem;
|
|||
import dmd.errors;
|
||||
import dmd.expression;
|
||||
import dmd.expressionsem;
|
||||
import dmd.file_manager;
|
||||
import dmd.globals;
|
||||
import dmd.id;
|
||||
import dmd.identifier;
|
||||
|
@ -50,113 +51,6 @@ import dmd.target;
|
|||
import dmd.utils;
|
||||
import dmd.visitor;
|
||||
|
||||
enum package_d = "package." ~ mars_ext;
|
||||
enum package_di = "package." ~ hdr_ext;
|
||||
|
||||
/********************************************
|
||||
* Look for the source file if it's different from filename.
|
||||
* Look for .di, .d, directory, and along global.path.
|
||||
* Does not open the file.
|
||||
* Params:
|
||||
* filename = as supplied by the user
|
||||
* path = path to look for filename
|
||||
* Returns:
|
||||
* the found file name or
|
||||
* `null` if it is not different from filename.
|
||||
*/
|
||||
private const(char)[] lookForSourceFile(const char[] filename, const char*[] path)
|
||||
{
|
||||
//printf("lookForSourceFile(`%.*s`)\n", cast(int)filename.length, filename.ptr);
|
||||
/* Search along path[] for .di file, then .d file, then .i file, then .c file.
|
||||
*/
|
||||
const sdi = FileName.forceExt(filename, hdr_ext);
|
||||
if (FileName.exists(sdi) == 1)
|
||||
return sdi;
|
||||
scope(exit) FileName.free(sdi.ptr);
|
||||
|
||||
const sd = FileName.forceExt(filename, mars_ext);
|
||||
if (FileName.exists(sd) == 1)
|
||||
return sd;
|
||||
scope(exit) FileName.free(sd.ptr);
|
||||
|
||||
const si = FileName.forceExt(filename, i_ext);
|
||||
if (FileName.exists(si) == 1)
|
||||
return si;
|
||||
scope(exit) FileName.free(si.ptr);
|
||||
|
||||
const sc = FileName.forceExt(filename, c_ext);
|
||||
if (FileName.exists(sc) == 1)
|
||||
return sc;
|
||||
scope(exit) FileName.free(sc.ptr);
|
||||
|
||||
if (FileName.exists(filename) == 2)
|
||||
{
|
||||
/* The filename exists and it's a directory.
|
||||
* Therefore, the result should be: filename/package.d
|
||||
* iff filename/package.d is a file
|
||||
*/
|
||||
const ni = FileName.combine(filename, package_di);
|
||||
if (FileName.exists(ni) == 1)
|
||||
return ni;
|
||||
FileName.free(ni.ptr);
|
||||
|
||||
const n = FileName.combine(filename, package_d);
|
||||
if (FileName.exists(n) == 1)
|
||||
return n;
|
||||
FileName.free(n.ptr);
|
||||
}
|
||||
if (FileName.absolute(filename))
|
||||
return null;
|
||||
if (!path.length)
|
||||
return null;
|
||||
foreach (entry; path)
|
||||
{
|
||||
const p = entry.toDString();
|
||||
|
||||
const(char)[] n = FileName.combine(p, sdi);
|
||||
if (FileName.exists(n) == 1) {
|
||||
return n;
|
||||
}
|
||||
FileName.free(n.ptr);
|
||||
|
||||
n = FileName.combine(p, sd);
|
||||
if (FileName.exists(n) == 1) {
|
||||
return n;
|
||||
}
|
||||
FileName.free(n.ptr);
|
||||
|
||||
n = FileName.combine(p, si);
|
||||
if (FileName.exists(n) == 1) {
|
||||
return n;
|
||||
}
|
||||
FileName.free(n.ptr);
|
||||
|
||||
n = FileName.combine(p, sc);
|
||||
if (FileName.exists(n) == 1) {
|
||||
return n;
|
||||
}
|
||||
FileName.free(n.ptr);
|
||||
|
||||
const b = FileName.removeExt(filename);
|
||||
n = FileName.combine(p, b);
|
||||
FileName.free(b.ptr);
|
||||
if (FileName.exists(n) == 2)
|
||||
{
|
||||
const n2i = FileName.combine(n, package_di);
|
||||
if (FileName.exists(n2i) == 1)
|
||||
return n2i;
|
||||
FileName.free(n2i.ptr);
|
||||
const n2 = FileName.combine(n, package_d);
|
||||
if (FileName.exists(n2) == 1) {
|
||||
return n2;
|
||||
}
|
||||
FileName.free(n2.ptr);
|
||||
}
|
||||
FileName.free(n.ptr);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// function used to call semantic3 on a module's dependencies
|
||||
void semantic3OnDependencies(Module m)
|
||||
{
|
||||
|
@ -414,7 +308,7 @@ extern (C++) class Package : ScopeDsymbol
|
|||
packages ~= s.ident;
|
||||
reverse(packages);
|
||||
|
||||
if (lookForSourceFile(getFilename(packages, ident), global.path ? (*global.path)[] : null))
|
||||
if (FileManager.lookForSourceFile(getFilename(packages, ident), global.path ? (*global.path)[] : null))
|
||||
Module.load(Loc.initial, packages, this.ident);
|
||||
else
|
||||
isPkgMod = PKG.package_;
|
||||
|
@ -612,7 +506,7 @@ extern (C++) final class Module : Package
|
|||
// foo\bar\baz
|
||||
const(char)[] filename = getFilename(packages, ident);
|
||||
// Look for the source file
|
||||
if (const result = lookForSourceFile(filename, global.path ? (*global.path)[] : null))
|
||||
if (const result = FileManager.lookForSourceFile(filename, global.path ? (*global.path)[] : null))
|
||||
filename = result; // leaks
|
||||
|
||||
auto m = new Module(loc, filename, ident, 0, 0);
|
||||
|
@ -781,14 +675,25 @@ extern (C++) final class Module : Package
|
|||
return true; // already read
|
||||
|
||||
//printf("Module::read('%s') file '%s'\n", toChars(), srcfile.toChars());
|
||||
auto readResult = File.read(srcfile.toChars());
|
||||
|
||||
if (global.params.emitMakeDeps)
|
||||
{
|
||||
global.params.makeDeps.push(srcfile.toChars());
|
||||
}
|
||||
|
||||
return loadSourceBuffer(loc, readResult);
|
||||
if (auto readResult = FileManager.fileManager.lookup(srcfile))
|
||||
{
|
||||
srcBuffer = readResult;
|
||||
return true;
|
||||
}
|
||||
|
||||
auto readResult = File.read(srcfile.toChars());
|
||||
if (loadSourceBuffer(loc, readResult))
|
||||
{
|
||||
FileManager.fileManager.add(srcfile, srcBuffer);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// syntactic parse
|
||||
|
|
|
@ -387,29 +387,33 @@ private void verrorPrint(const ref Loc loc, Color headerColor, const(char)* head
|
|||
!loc.filename.strstr(".d-mixin-") &&
|
||||
!global.params.mixinOut)
|
||||
{
|
||||
import dmd.filecache : FileCache;
|
||||
auto fllines = FileCache.fileCache.addOrGetFile(loc.filename.toDString());
|
||||
|
||||
if (loc.linnum - 1 < fllines.lines.length)
|
||||
import dmd.file_manager : FileManager;
|
||||
import dmd.root.filename : FileName;
|
||||
const fileName = FileName(loc.filename.toDString);
|
||||
if (auto file = FileManager.fileManager.lookup(fileName))
|
||||
{
|
||||
auto line = fllines.lines[loc.linnum - 1];
|
||||
if (loc.charnum < line.length)
|
||||
const(char)[][] lines = FileManager.fileManager.getLines(fileName);
|
||||
if (loc.linnum - 1 < lines.length)
|
||||
{
|
||||
fprintf(stderr, "%.*s\n", cast(int)line.length, line.ptr);
|
||||
// The number of column bytes and the number of display columns
|
||||
// occupied by a character are not the same for non-ASCII charaters.
|
||||
// https://issues.dlang.org/show_bug.cgi?id=21849
|
||||
size_t c = 0;
|
||||
while (c < loc.charnum - 1)
|
||||
auto line = lines[loc.linnum - 1];
|
||||
if (loc.charnum < line.length)
|
||||
{
|
||||
import dmd.utf : utf_decodeChar;
|
||||
dchar u;
|
||||
const msg = utf_decodeChar(line, c, u);
|
||||
assert(msg is null, msg);
|
||||
fputc(' ', stderr);
|
||||
fprintf(stderr, "%.*s\n", cast(int)line.length, line.ptr);
|
||||
// The number of column bytes and the number of display columns
|
||||
// occupied by a character are not the same for non-ASCII charaters.
|
||||
// https://issues.dlang.org/show_bug.cgi?id=21849
|
||||
size_t c = 0;
|
||||
while (c < loc.charnum - 1)
|
||||
{
|
||||
import dmd.utf : utf_decodeChar;
|
||||
dchar u;
|
||||
const msg = utf_decodeChar(line, c, u);
|
||||
assert(msg is null, msg);
|
||||
fputc(' ', stderr);
|
||||
}
|
||||
fputc('^', stderr);
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
fputc('^', stderr);
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ import dmd.dtemplate;
|
|||
import dmd.errors;
|
||||
import dmd.escape;
|
||||
import dmd.expression;
|
||||
import dmd.file_manager;
|
||||
import dmd.func;
|
||||
import dmd.globals;
|
||||
import dmd.hdrgen;
|
||||
|
@ -6051,17 +6052,29 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
|
|||
}
|
||||
|
||||
{
|
||||
auto readResult = File.read(name);
|
||||
if (!readResult.success)
|
||||
auto fileName = FileName(name.toDString);
|
||||
if (auto fmResult = FileManager.fileManager.lookup(fileName))
|
||||
{
|
||||
e.error("cannot read file `%s`", name);
|
||||
return setError();
|
||||
se = new StringExp(e.loc, fmResult.data);
|
||||
}
|
||||
else
|
||||
{
|
||||
// take ownership of buffer (probably leaking)
|
||||
auto data = readResult.extractSlice();
|
||||
se = new StringExp(e.loc, data);
|
||||
auto readResult = File.read(name);
|
||||
if (!readResult.success)
|
||||
{
|
||||
e.error("cannot read file `%s`", name);
|
||||
return setError();
|
||||
}
|
||||
else
|
||||
{
|
||||
// take ownership of buffer (probably leaking)
|
||||
auto data = readResult.extractSlice();
|
||||
se = new StringExp(e.loc, data);
|
||||
|
||||
FileBuffer* fileBuffer = FileBuffer.create();
|
||||
fileBuffer.data = data;
|
||||
FileManager.fileManager.add(fileName, fileBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
result = se.expressionSemantic(sc);
|
||||
|
|
301
src/dmd/file_manager.d
Normal file
301
src/dmd/file_manager.d
Normal file
|
@ -0,0 +1,301 @@
|
|||
/**
|
||||
* Read a file from disk and store it in memory.
|
||||
*
|
||||
* Copyright: Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
|
||||
* 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/file_manager.d, _file_manager.d)
|
||||
* Documentation: https://dlang.org/phobos/dmd_file_manager.html
|
||||
* Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/file_manager.d
|
||||
*/
|
||||
|
||||
module dmd.file_manager;
|
||||
|
||||
import dmd.root.stringtable : StringTable;
|
||||
import dmd.root.file : File, FileBuffer;
|
||||
import dmd.root.filename : FileName;
|
||||
import dmd.root.string : toDString;
|
||||
import dmd.globals;
|
||||
import dmd.identifier;
|
||||
|
||||
enum package_d = "package." ~ mars_ext;
|
||||
enum package_di = "package." ~ hdr_ext;
|
||||
|
||||
extern(C++) struct FileManager
|
||||
{
|
||||
private StringTable!(FileBuffer*) files;
|
||||
private __gshared bool initialized = false;
|
||||
|
||||
nothrow:
|
||||
extern(D) private FileBuffer* readToFileBuffer(const(char)[] filename)
|
||||
{
|
||||
if (!initialized)
|
||||
FileManager._init();
|
||||
|
||||
auto readResult = File.read(filename);
|
||||
if (readResult.success)
|
||||
{
|
||||
FileBuffer* fb;
|
||||
if (auto val = files.lookup(filename))
|
||||
fb = val.value;
|
||||
|
||||
if (!fb)
|
||||
fb = FileBuffer.create();
|
||||
|
||||
fb.data = readResult.extractSlice();
|
||||
|
||||
return files.insert(filename, fb) == null ? null : fb;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/********************************************
|
||||
* Look for the source file if it's different from filename.
|
||||
* Look for .di, .d, directory, and along global.path.
|
||||
* Does not open the file.
|
||||
* Params:
|
||||
* filename = as supplied by the user
|
||||
* path = path to look for filename
|
||||
* Returns:
|
||||
* the found file name or
|
||||
* `null` if it is not different from filename.
|
||||
*/
|
||||
extern(D) static const(char)[] lookForSourceFile(const char[] filename, const char*[] path)
|
||||
{
|
||||
//printf("lookForSourceFile(`%.*s`)\n", cast(int)filename.length, filename.ptr);
|
||||
/* Search along path[] for .di file, then .d file, then .i file, then .c file.
|
||||
*/
|
||||
const sdi = FileName.forceExt(filename, hdr_ext);
|
||||
if (FileName.exists(sdi) == 1)
|
||||
return sdi;
|
||||
scope(exit) FileName.free(sdi.ptr);
|
||||
|
||||
const sd = FileName.forceExt(filename, mars_ext);
|
||||
if (FileName.exists(sd) == 1)
|
||||
return sd;
|
||||
scope(exit) FileName.free(sd.ptr);
|
||||
|
||||
const si = FileName.forceExt(filename, i_ext);
|
||||
if (FileName.exists(si) == 1)
|
||||
return si;
|
||||
scope(exit) FileName.free(si.ptr);
|
||||
|
||||
const sc = FileName.forceExt(filename, c_ext);
|
||||
if (FileName.exists(sc) == 1)
|
||||
return sc;
|
||||
scope(exit) FileName.free(sc.ptr);
|
||||
|
||||
if (FileName.exists(filename) == 2)
|
||||
{
|
||||
/* The filename exists and it's a directory.
|
||||
* Therefore, the result should be: filename/package.d
|
||||
* iff filename/package.d is a file
|
||||
*/
|
||||
const ni = FileName.combine(filename, package_di);
|
||||
if (FileName.exists(ni) == 1)
|
||||
return ni;
|
||||
FileName.free(ni.ptr);
|
||||
|
||||
const n = FileName.combine(filename, package_d);
|
||||
if (FileName.exists(n) == 1)
|
||||
return n;
|
||||
FileName.free(n.ptr);
|
||||
}
|
||||
if (FileName.absolute(filename))
|
||||
return null;
|
||||
if (!path.length)
|
||||
return null;
|
||||
foreach (entry; path)
|
||||
{
|
||||
const p = entry.toDString();
|
||||
|
||||
const(char)[] n = FileName.combine(p, sdi);
|
||||
if (FileName.exists(n) == 1) {
|
||||
return n;
|
||||
}
|
||||
FileName.free(n.ptr);
|
||||
|
||||
n = FileName.combine(p, sd);
|
||||
if (FileName.exists(n) == 1) {
|
||||
return n;
|
||||
}
|
||||
FileName.free(n.ptr);
|
||||
|
||||
n = FileName.combine(p, si);
|
||||
if (FileName.exists(n) == 1) {
|
||||
return n;
|
||||
}
|
||||
FileName.free(n.ptr);
|
||||
|
||||
n = FileName.combine(p, sc);
|
||||
if (FileName.exists(n) == 1) {
|
||||
return n;
|
||||
}
|
||||
FileName.free(n.ptr);
|
||||
|
||||
const b = FileName.removeExt(filename);
|
||||
n = FileName.combine(p, b);
|
||||
FileName.free(b.ptr);
|
||||
if (FileName.exists(n) == 2)
|
||||
{
|
||||
const n2i = FileName.combine(n, package_di);
|
||||
if (FileName.exists(n2i) == 1)
|
||||
return n2i;
|
||||
FileName.free(n2i.ptr);
|
||||
const n2 = FileName.combine(n, package_d);
|
||||
if (FileName.exists(n2) == 1) {
|
||||
return n2;
|
||||
}
|
||||
FileName.free(n2.ptr);
|
||||
}
|
||||
FileName.free(n.ptr);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up the given filename from the internal file buffer table.
|
||||
* If the file does not already exist within the table, it will be read from the filesystem.
|
||||
* If it has been read before,
|
||||
*
|
||||
* Returns: the loaded source file if it was found in memory,
|
||||
* otherwise `null`
|
||||
*/
|
||||
extern(D) FileBuffer* lookup(FileName filename)
|
||||
{
|
||||
if (!initialized)
|
||||
FileManager._init();
|
||||
|
||||
if (auto val = files.lookup(filename.toString))
|
||||
{
|
||||
// There is a chance that the buffer could've been
|
||||
// stolen by a reader with extractSlice, so we should
|
||||
// try and do our reading logic if that happens.
|
||||
if (val !is null && val.value.data !is null)
|
||||
{
|
||||
return val.value;
|
||||
}
|
||||
}
|
||||
|
||||
const name = filename.toString;
|
||||
auto res = FileName.exists(name);
|
||||
if (res == 1)
|
||||
return readToFileBuffer(name);
|
||||
|
||||
const fullName = lookForSourceFile(name, global.path ? (*global.path)[] : null);
|
||||
if (!fullName)
|
||||
return null;
|
||||
|
||||
return readToFileBuffer(fullName);
|
||||
}
|
||||
|
||||
extern(C++) FileBuffer* lookup(const(char)* filename)
|
||||
{
|
||||
return lookup(FileName(filename.toDString));
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks up the given filename from the internal file buffer table, and returns the lines within the file.
|
||||
* If the file does not already exist within the table, it will be read from the filesystem.
|
||||
* If it has been read before,
|
||||
*
|
||||
* Returns: the loaded source file if it was found in memory,
|
||||
* otherwise `null`
|
||||
*/
|
||||
extern(D) const(char)[][] getLines(FileName file)
|
||||
{
|
||||
if (!initialized)
|
||||
FileManager._init();
|
||||
|
||||
const(char)[][] lines;
|
||||
if (FileBuffer* buffer = lookup(file))
|
||||
{
|
||||
ubyte[] slice = buffer.data[0 .. buffer.data.length];
|
||||
size_t start, end;
|
||||
ubyte c;
|
||||
for (auto i = 0; i < slice.length; i++)
|
||||
{
|
||||
c = slice[i];
|
||||
if (c == '\n' || c == '\r')
|
||||
{
|
||||
if (i != 0)
|
||||
{
|
||||
end = i;
|
||||
lines ~= cast(const(char)[])slice[start .. end];
|
||||
}
|
||||
// Check for Windows-style CRLF newlines
|
||||
if (c == '\r')
|
||||
{
|
||||
if (slice.length > i + 1 && slice[i + 1] == '\n')
|
||||
{
|
||||
// This is a CRLF sequence, skip over two characters
|
||||
start = i + 2;
|
||||
i++;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Just a CR sequence
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// The next line should start after the LF sequence
|
||||
start = i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (slice[$ - 1] != '\r' && slice[$ - 1] != '\n')
|
||||
{
|
||||
end = slice.length;
|
||||
lines ~= cast(const(char)[])slice[start .. end];
|
||||
}
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a FileBuffer to the table.
|
||||
*
|
||||
* Returns: The FileBuffer added, or null
|
||||
*/
|
||||
extern(D) FileBuffer* add(FileName filename, FileBuffer* filebuffer)
|
||||
{
|
||||
if (!initialized)
|
||||
FileManager._init();
|
||||
|
||||
auto val = files.insert(filename.toString, filebuffer);
|
||||
return val == null ? null : val.value;
|
||||
}
|
||||
|
||||
extern(C++) FileBuffer* add(const(char)* filename, FileBuffer* filebuffer)
|
||||
{
|
||||
if (!initialized)
|
||||
FileManager._init();
|
||||
|
||||
auto val = files.insert(filename.toDString, filebuffer);
|
||||
return val == null ? null : val.value;
|
||||
}
|
||||
|
||||
__gshared fileManager = FileManager();
|
||||
|
||||
// Initialize the global FileManager singleton
|
||||
extern(C++) static __gshared void _init()
|
||||
{
|
||||
if (!initialized)
|
||||
{
|
||||
fileManager.initialize();
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
void initialize()
|
||||
{
|
||||
files._init();
|
||||
}
|
||||
}
|
19
src/dmd/file_manager.h
Normal file
19
src/dmd/file_manager.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
|
||||
/* Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
|
||||
* written by Walter Bright
|
||||
* http://www.digitalmars.com
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* http://www.boost.org/LICENSE_1_0.txt
|
||||
* https://github.com/dlang/dmd/blob/master/src/dmd/file_manager.h
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "root/file.h"
|
||||
|
||||
struct FileManager
|
||||
{
|
||||
static void _init();
|
||||
FileBuffer* lookup(const char* filename);
|
||||
FileBuffer* add(const char* filename, FileBuffer* filebuffer);
|
||||
};
|
|
@ -1,137 +0,0 @@
|
|||
/**
|
||||
* Cache the contents from files read from disk into memory.
|
||||
*
|
||||
* Copyright: Copyright (C) 1999-2021 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!(FileAndLines) 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 payload.value;
|
||||
}
|
||||
|
||||
auto lines = new FileAndLines(file);
|
||||
files.insert(file, 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();
|
||||
}
|
||||
}
|
|
@ -116,7 +116,6 @@ void initDMD(
|
|||
import dmd.cond : VersionCondition;
|
||||
import dmd.dmodule : Module;
|
||||
import dmd.expression : Expression;
|
||||
import dmd.filecache : FileCache;
|
||||
import dmd.globals : CHECKENABLE, global;
|
||||
import dmd.id : Id;
|
||||
import dmd.identifier : Identifier;
|
||||
|
@ -148,7 +147,6 @@ void initDMD(
|
|||
Module._init();
|
||||
Expression._init();
|
||||
Objc._init();
|
||||
FileCache._init();
|
||||
|
||||
addDefaultVersionIdentifiers(global.params, target);
|
||||
|
||||
|
@ -401,7 +399,12 @@ Tuple!(Module, "module_", Diagnostics, "diagnostics") parseModule(AST = ASTCodeg
|
|||
buffer: FileBuffer(cast(ubyte[]) code.dup ~ '\0')
|
||||
};
|
||||
|
||||
m.loadSourceBuffer(Loc.initial, readResult);
|
||||
if (m.loadSourceBuffer(Loc.initial, readResult))
|
||||
{
|
||||
import dmd.file_manager : FileManager;
|
||||
import dmd.root.filename : FileName;
|
||||
FileManager.fileManager.add(FileName(fileName), m.srcBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
m.parseModule!AST();
|
||||
|
|
|
@ -2488,10 +2488,6 @@ struct MatchAccumulator final
|
|||
{}
|
||||
};
|
||||
|
||||
static const char* const package_d = "package.d";
|
||||
|
||||
static const char* const package_di = "package.di";
|
||||
|
||||
enum class StructFlags
|
||||
{
|
||||
none = 0,
|
||||
|
@ -4987,6 +4983,40 @@ enum class CPU
|
|||
native = 12,
|
||||
};
|
||||
|
||||
struct StringEntry final
|
||||
{
|
||||
uint32_t hash;
|
||||
uint32_t vptr;
|
||||
StringEntry() :
|
||||
hash(),
|
||||
vptr()
|
||||
{
|
||||
}
|
||||
StringEntry(uint32_t hash, uint32_t vptr = 0u) :
|
||||
hash(hash),
|
||||
vptr(vptr)
|
||||
{}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct StringTable final
|
||||
{
|
||||
// Ignoring var table alignment 0
|
||||
_d_dynamicArray< StringEntry > table;
|
||||
// Ignoring var pools alignment 0
|
||||
_d_dynamicArray< uint8_t* > pools;
|
||||
// Ignoring var nfill alignment 0
|
||||
size_t nfill;
|
||||
// Ignoring var count alignment 0
|
||||
size_t count;
|
||||
// Ignoring var countTrigger alignment 0
|
||||
size_t countTrigger;
|
||||
~StringTable();
|
||||
StringTable()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
typedef _d_real longdouble;
|
||||
|
||||
class AggregateDeclaration : public ScopeDsymbol
|
||||
|
@ -7883,6 +7913,22 @@ extern void fatal();
|
|||
|
||||
extern void halt();
|
||||
|
||||
struct FileManager final
|
||||
{
|
||||
private:
|
||||
StringTable<FileBuffer* > files;
|
||||
static bool initialized;
|
||||
public:
|
||||
FileBuffer* lookup(const char* filename);
|
||||
FileBuffer* add(const char* filename, FileBuffer* filebuffer);
|
||||
static FileManager fileManager;
|
||||
static void _init();
|
||||
void initialize();
|
||||
FileManager()
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct Id final
|
||||
{
|
||||
static Identifier* IUnknown;
|
||||
|
|
|
@ -38,6 +38,7 @@ import dmd.dtemplate;
|
|||
import dmd.dtoh;
|
||||
import dmd.errors;
|
||||
import dmd.expression;
|
||||
import dmd.file_manager;
|
||||
import dmd.globals;
|
||||
import dmd.hdrgen;
|
||||
import dmd.id;
|
||||
|
@ -300,8 +301,6 @@ private int tryMain(size_t argc, const(char)** argv, ref Param params)
|
|||
Module._init();
|
||||
Expression._init();
|
||||
Objc._init();
|
||||
import dmd.filecache : FileCache;
|
||||
FileCache._init();
|
||||
|
||||
reconcileLinkRunLib(params, files.dim);
|
||||
version(CRuntime_Microsoft)
|
||||
|
@ -362,6 +361,7 @@ private int tryMain(size_t argc, const(char)** argv, ref Param params)
|
|||
{
|
||||
auto buffer = readFromStdin();
|
||||
m.srcBuffer = new FileBuffer(buffer.extractSlice());
|
||||
FileManager.fileManager.add(m.srcfile, m.srcBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue