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
|
if not modules then modules = { } end modules ['data-con'] = {
version = 1.100,
comment = "companion to luat-lib.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
}
local format, lower, gsub = string.format, string.lower, string.gsub
local trace_cache = false trackers.register("resolvers.cache", function(v) trace_cache = v end)
local trace_containers = false trackers.register("resolvers.containers", function(v) trace_containers = v end)
local trace_storage = false trackers.register("resolvers.storage", function(v) trace_storage = v end)
--[[ldx--
<p>Once we found ourselves defining similar cache constructs
several times, containers were introduced. Containers are used
to collect tables in memory and reuse them when possible based
on (unique) hashes (to be provided by the calling function).</p>
<p>Caching to disk is disabled by default. Version numbers are
stored in the saved table which makes it possible to change the
table structures without bothering about the disk cache.</p>
<p>Examples of usage can be found in the font related code.</p>
--ldx]]--
containers = containers or { }
containers.usecache = true
local report_cache = logs.new("cache")
local function report(container,tag,name)
if trace_cache or trace_containers then
report_cache("container: %s, tag: %s, name: %s",container.subcategory,tag,name or 'invalid')
end
end
local allocated = { }
local mt = {
__index = function(t,k)
if k == "writable" then
local writable = caches.getwritablepath(t.category,t.subcategory) or { "." }
t.writable = writable
return writable
elseif k == "readables" then
local readables = caches.getreadablepaths(t.category,t.subcategory) or { "." }
t.readables = readables
return readables
end
end
}
function containers.define(category, subcategory, version, enabled)
if category and subcategory then
local c = allocated[category]
if not c then
c = { }
allocated[category] = c
end
local s = c[subcategory]
if not s then
s = {
category = category,
subcategory = subcategory,
storage = { },
enabled = enabled,
version = version or math.pi, -- after all, this is TeX
trace = false,
-- writable = caches.getwritablepath and caches.getwritablepath (category,subcategory) or { "." },
-- readables = caches.getreadablepaths and caches.getreadablepaths(category,subcategory) or { "." },
}
setmetatable(s,mt)
c[subcategory] = s
end
return s
end
end
function containers.is_usable(container, name)
return container.enabled and caches and caches.iswritable(container.writable, name)
end
function containers.is_valid(container, name)
if name and name ~= "" then
local storage = container.storage[name]
return storage and storage.cache_version == container.version
else
return false
end
end
function containers.read(container,name)
local storage = container.storage
local stored = storage[name]
if not stored and container.enabled and caches and containers.usecache then
stored = caches.loaddata(container.readables,name)
if stored and stored.cache_version == container.version then
report(container,"loaded",name)
else
stored = nil
end
storage[name] = stored
elseif stored then
report(container,"reusing",name)
end
return stored
end
function containers.write(container, name, data)
if data then
data.cache_version = container.version
if container.enabled and caches then
local unique, shared = data.unique, data.shared
data.unique, data.shared = nil, nil
caches.savedata(container.writable, name, data)
report(container,"saved",name)
data.unique, data.shared = unique, shared
end
report(container,"stored",name)
container.storage[name] = data
end
return data
end
function containers.content(container,name)
return container.storage[name]
end
function containers.cleanname(name)
return (gsub(lower(name),"[^%w%d]+","-"))
end
|