1
/**
2
 * Cache the contents from files read from disk into memory.
3
 *
4
 * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
5
 * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
6
 * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7
 * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/filecache.d, filecache.d)
8
 * Documentation:  https://dlang.org/phobos/dmd_filecache.html
9
 * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/filecache.d
10
 */
11

12
module dmd.filecache;
13

14
import dmd.root.stringtable;
15
import dmd.root.array;
16
import dmd.root.file;
17
import dmd.root.filename;
18

19
import core.stdc.stdio;
20

21
/**
22
A line-by-line representation of a $(REF File, dmd,root,file).
23
*/
24
class FileAndLines
25
{
26
    FileName* file;
27
    FileBuffer* buffer;
28
    const(char[])[] lines;
29

30
  nothrow:
31

32
    /**
33
    File to read and split into its lines.
34
    */
35 1
    this(const(char)[] filename)
36
    {
37 1
        file = new FileName(filename);
38 1
        readAndSplit();
39
    }
40

41
    // Read a file and split the file buffer linewise
42
    private void readAndSplit()
43
    {
44 1
        auto readResult = File.read(file.toChars());
45
        // FIXME: check success
46
        // take ownership of buffer
47 1
        buffer = new FileBuffer(readResult.extractSlice());
48 1
        ubyte* buf = buffer.data.ptr;
49
        // slice into lines
50 1
        while (*buf)
51
        {
52 1
            auto prevBuf = buf;
53 1
            for (; *buf != '\n' && *buf != '\r'; buf++)
54
            {
55 1
                if (!*buf)
56 0
                    break;
57
            }
58
            // handle Windows line endings
59 1
            if (*buf == '\r' && *(buf + 1) == '\n')
60 0
                buf++;
61 1
            lines ~= cast(const(char)[]) prevBuf[0 .. buf - prevBuf];
62 1
            buf++;
63
        }
64
    }
65

66
    void destroy()
67
    {
68 0
        if (file)
69
        {
70 0
            file.destroy();
71 0
            file = null;
72 0
            buffer.destroy();
73 0
            buffer = null;
74 0
            lines.destroy();
75 0
            lines = null;
76
        }
77
    }
78

79
    ~this()
80
    {
81 0
        destroy();
82
    }
83
}
84

85
/**
86
A simple file cache that can be used to avoid reading the same file multiple times.
87
It stores its cached files as $(LREF FileAndLines)
88
*/
89
struct FileCache
90
{
91
    private StringTable!(FileAndLines) files;
92

93
  nothrow:
94

95
    /**
96
    Add or get a file from the file cache.
97
    If the file isn't part of the cache, it will be read from the filesystem.
98
    If the file has been read before, the cached file object will be returned
99

100
    Params:
101
        file = file to load in (or get from) the cache
102

103
    Returns: a $(LREF FileAndLines) object containing a line-by-line representation of the requested file
104
    */
105
    FileAndLines addOrGetFile(const(char)[] file)
106
    {
107 1
        if (auto payload = files.lookup(file))
108
        {
109 1
            if (payload !is null)
110 1
                return payload.value;
111
        }
112

113 1
        auto lines = new FileAndLines(file);
114 1
        files.insert(file, lines);
115 1
        return lines;
116
    }
117

118
    __gshared fileCache = FileCache();
119

120
    // Initializes the global FileCache singleton
121
    static __gshared void _init()
122
    {
123 1
        fileCache.initialize();
124
    }
125

126
    void initialize()
127
    {
128 1
        files._init();
129
    }
130

131
    void deinitialize()
132
    {
133 0
        foreach (sv; files)
134 0
            sv.destroy();
135 0
        files.reset();
136
    }
137
}

Read our documentation on viewing source code .

Loading