data-con.lua /size: 5733 b    last modification: 2025-02-21 11:03
1if not modules then modules = { } end modules ['data-con'] = {
2    version   = 1.100,
3    comment   = "companion to luat-lib.mkiv",
4    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5    copyright = "PRAGMA ADE / ConTeXt Development Team",
6    license   = "see context related readme files"
7}
8
9local setmetatable = setmetatable
10local format, lower, gsub = string.format, string.lower, string.gsub
11
12local trace_cache      = false  trackers.register("resolvers.cache",      function(v) trace_cache      = v end)
13local trace_containers = false  trackers.register("resolvers.containers", function(v) trace_containers = v end)
14local trace_storage    = false  trackers.register("resolvers.storage",    function(v) trace_storage    = v end)
15
16-- Once we found ourselves defining similar cache constructs several times,
17-- containers were introduced. Containers are used to collect tables in memory and
18-- reuse them when possible based on (unique) hashes (to be provided by the calling
19-- function).
20--
21-- Caching to disk is disabled by default. Version numbers are stored in the saved
22-- table which makes it possible to change the table structures without bothering
23-- about the disk cache.
24--
25-- Examples of usage can be found in the font related code. This code is not ideal
26-- but we need it in generic too so we compromise.
27
28containers              = containers or { }
29local containers        = containers
30containers.usecache     = true
31
32local getwritablepath   = caches.getwritablepath
33local getreadablepaths  = caches.getreadablepaths
34local cacheiswritable   = caches.is_writable
35local loaddatafromcache = caches.loaddata
36local savedataincache   = caches.savedata
37
38local report_containers = logs.reporter("resolvers","containers")
39
40local allocated = { }
41
42local cache_format = 1.001 -- for subtle bytecode changes during betas
43
44local mt = {
45    __index = function(t,k)
46        if k == "writable" then
47            local writable = getwritablepath(t.category,t.subcategory) or { "." }
48            t.writable = writable
49            return writable
50        elseif k == "readables" then
51            local readables = getreadablepaths(t.category,t.subcategory) or { "." }
52            t.readables = readables
53            return readables
54        end
55    end,
56    __storage__ = true
57}
58
59function containers.define(category, subcategory, version, enabled, reload)
60    if category and subcategory then
61        local c = allocated[category]
62        if not c then
63            c  = { }
64            allocated[category] = c
65        end
66        local s = c[subcategory]
67        if not s then
68            s = {
69                category    = category,
70                subcategory = subcategory,
71                storage     = { },
72                enabled     = enabled,
73                reload      = reload,
74                version     = version or math.pi, -- after all, this is TeX
75                trace       = false,
76             -- writable    = getwritablepath  and getwritablepath (category,subcategory) or { "." },
77             -- readables   = getreadablepaths and getreadablepaths(category,subcategory) or { "." },
78            }
79            setmetatable(s,mt)
80            c[subcategory] = s
81        end
82        return s
83    end
84end
85
86function containers.is_usable(container,name)
87    return container.enabled and caches and cacheiswritable(container.writable, name)
88end
89
90function containers.is_valid(container,name)
91    if name and name ~= "" then
92        local storage = container.storage[name]
93        return storage
94            and storage.cache_format  == cache_format -- extra safeguard for bytecode change
95            and storage.cache_version == container.version
96    else
97        return false
98    end
99end
100
101function containers.read(container,name)
102    local storage = container.storage
103    local reload  = container.reload
104    local stored  = not reload and storage[name]
105    if not stored and container.enabled and caches and containers.usecache then
106        stored = loaddatafromcache(container.readables,name,container.writable)
107        if stored and stored.cache_format == cache_format and stored.cache_version == container.version then
108            if trace_cache or trace_containers then
109                report_containers("action %a, category %a, name %a","load",container.subcategory,name)
110            end
111        else
112            stored = nil
113        end
114        storage[name] = stored
115    elseif stored then
116        if trace_cache or trace_containers then
117            report_containers("action %a, category %a, name %a","reuse",container.subcategory,name)
118        end
119    end
120    return stored
121end
122
123function containers.write(container,name,data,fast)
124    if data then
125        data.cache_format  = cache_format
126        data.cache_version = container.version
127        if container.enabled and caches then
128            local unique = data.unique
129            local shared = data.shared
130            data.unique  = nil
131            data.shared  = nil
132            savedataincache(container.writable, name, data, fast)
133            if trace_cache or trace_containers then
134                report_containers("action %a, category %a, name %a","save",container.subcategory,name)
135            end
136            data.unique = unique
137            data.shared = shared
138        end
139        if trace_cache or trace_containers then
140            report_containers("action %a, category %a, name %a","store",container.subcategory,name)
141        end
142        container.storage[name] = data
143    end
144    return data
145end
146
147function containers.content(container,name)
148    return container.storage[name]
149end
150
151function containers.cleanname(name)
152 -- return (gsub(lower(name),"[^%w]+","-"))
153    return (gsub(lower(name),"[^%w\128-\255]+","-")) -- more utf friendly
154end
155