+--------- Built-in place transformation functions --------------------------
+
+local PlaceTransform = {}
+
+-- Special transform meanings which are interpreted elsewhere
+PlaceTransform.fallback = 'fallback'
+PlaceTransform.delete = 'delete'
+PlaceTransform.extra = 'extra'
+
+-- always: unconditionally use that place
+function PlaceTransform.always(place)
+ return place
+end
+
+-- never: unconditionally drop the place
+function PlaceTransform.never()
+ return nil
+end
+
+-- named: use the place if it has a fully-qualified name
+function PlaceTransform.named(place)
+ if place.has_name then
+ return place
+ end
+end
+
+-- named_with_key: use place if there is a name with the main key prefix
+function PlaceTransform.named_with_key(place, k)
+ local names = {}
+ local prefix = k .. ':name'
+ for namek, namev in pairs(place.intags) do
+ if namek:sub(1, #prefix) == prefix
+ and (#namek == #prefix
+ or namek:sub(#prefix + 1, #prefix + 1) == ':') then
+ names[namek:sub(#k + 2)] = namev
+ end
+ end
+
+ if next(names) ~= nil then
+ return place:clone{names=names}
+ end
+end
+
+----------------- other helper functions -----------------------------
+
+local function lookup_prefilter_classification(k, v)
+ -- full matches
+ local desc = MAIN_KEYS[k]
+ local fullmatch = desc and (desc[v] or desc[1])
+ if fullmatch ~= nil then
+ return fullmatch
+ end
+ -- suffixes
+ for slen, slist in pairs(PRE_FILTER.suffix) do
+ if #k >= slen then
+ local group = slist[k:sub(-slen)]
+ if group ~= nil then
+ return group
+ end
+ end
+ end
+ -- prefixes
+ for slen, slist in pairs(PRE_FILTER.prefix) do
+ if #k >= slen then
+ local group = slist[k:sub(1, slen)]
+ if group ~= nil then
+ return group
+ end
+ end
+ end
+end
+
+
+local function merge_filters_into_main(group, keys, tags)
+ if keys ~= nil then
+ for _, key in pairs(keys) do
+ -- ignore suffix and prefix matches
+ if key:sub(1, 1) ~= '*' and key:sub(#key, #key) ~= '*' then
+ if MAIN_KEYS[key] == nil then
+ MAIN_KEYS[key] = {}
+ end
+ MAIN_KEYS[key][1] = group
+ end
+ end
+ end
+
+ if tags ~= nil then
+ for key, values in pairs(tags) do
+ if MAIN_KEYS[key] == nil then
+ MAIN_KEYS[key] = {}
+ end
+ for _, v in pairs(values) do
+ MAIN_KEYS[key][v] = group
+ end
+ end
+ end
+end
+
+
+local function remove_group_from_main(group)
+ for key, values in pairs(MAIN_KEYS) do
+ for _, ttype in pairs(values) do
+ if ttype == group then
+ values[ttype] = nil
+ end
+ end
+ if next(values) == nil then
+ MAIN_KEYS[key] = nil
+ end
+ end
+end
+
+
+local function add_pre_filter(data)
+ for group, keys in pairs(data) do
+ for _, key in pairs(keys) do
+ local klen = #key - 1
+ if key:sub(1, 1) == '*' then
+ if klen > 0 then
+ if PRE_FILTER.suffix[klen] == nil then
+ PRE_FILTER.suffix[klen] = {}
+ end
+ PRE_FILTER.suffix[klen][key:sub(2)] = group
+ end
+ elseif key:sub(#key, #key) == '*' then
+ if PRE_FILTER.prefix[klen] == nil then
+ PRE_FILTER.prefix[klen] = {}
+ end
+ PRE_FILTER.prefix[klen][key:sub(1, klen)] = group
+ end
+ end
+ end
+end
+