data-con.lua /size: 5477 b    last modification: 2023-12-21 09:44
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 mt = {
43    __index = function(t,k)
44        if k == "writable" then
45            local writable = getwritablepath(t.category,t.subcategory) or { "." }
46            t.writable = writable
47            return writable
48        elseif k == "readables" then
49            local readables = getreadablepaths(t.category,t.subcategory) or { "." }
50            t.readables = readables
51            return readables
52        end
53    end,
54    __storage__ = true
55}
56
57function containers.define(category, subcategory, version, enabled, reload)
58    if category and subcategory then
59        local c = allocated[category]
60        if not c then
61            c  = { }
62            allocated[category] = c
63        end
64        local s = c[subcategory]
65        if not s then
66            s = {
67                category    = category,
68                subcategory = subcategory,
69                storage     = { },
70                enabled     = enabled,
71                reload      = reload,
72                version     = version or math.pi, -- after all, this is TeX
73                trace       = false,
74             -- writable    = getwritablepath  and getwritablepath (category,subcategory) or { "." },
75             -- readables   = getreadablepaths and getreadablepaths(category,subcategory) or { "." },
76            }
77            setmetatable(s,mt)
78            c[subcategory] = s
79        end
80        return s
81    end
82end
83
84function containers.is_usable(container,name)
85    return container.enabled and caches and cacheiswritable(container.writable, name)
86end
87
88function containers.is_valid(container,name)
89    if name and name ~= "" then
90        local storage = container.storage[name]
91        return storage and storage.cache_version == container.version
92    else
93        return false
94    end
95end
96
97function containers.read(container,name)
98    local storage = container.storage
99    local reload  = container.reload
100    local stored  = not reload and storage[name]
101    if not stored and container.enabled and caches and containers.usecache then
102        stored = loaddatafromcache(container.readables,name,container.writable)
103        if stored and stored.cache_version == container.version then
104            if trace_cache or trace_containers then
105                report_containers("action %a, category %a, name %a","load",container.subcategory,name)
106            end
107        else
108            stored = nil
109        end
110        storage[name] = stored
111    elseif stored then
112        if trace_cache or trace_containers then
113            report_containers("action %a, category %a, name %a","reuse",container.subcategory,name)
114        end
115    end
116    return stored
117end
118
119function containers.write(container, name, data, fast)
120    if data then
121        data.cache_version = container.version
122        if container.enabled and caches then
123            local unique = data.unique
124            local shared = data.shared
125            data.unique  = nil
126            data.shared  = nil
127            savedataincache(container.writable, name, data, fast)
128            if trace_cache or trace_containers then
129                report_containers("action %a, category %a, name %a","save",container.subcategory,name)
130            end
131            data.unique = unique
132            data.shared = shared
133        end
134        if trace_cache or trace_containers then
135            report_containers("action %a, category %a, name %a","store",container.subcategory,name)
136        end
137        container.storage[name] = data
138    end
139    return data
140end
141
142function containers.content(container,name)
143    return container.storage[name]
144end
145
146function containers.cleanname(name)
147 -- return (gsub(lower(name),"[^%w]+","-"))
148    return (gsub(lower(name),"[^%w\128-\255]+","-")) -- more utf friendly
149end
150