diff --git a/src/flex-lua-expire-output.cpp b/src/flex-lua-expire-output.cpp index e3609de33..49d8d876c 100644 --- a/src/flex-lua-expire-output.cpp +++ b/src/flex-lua-expire-output.cpp @@ -99,31 +99,14 @@ int setup_flex_expire_output(lua_State *lua_state, */ void lua_wrapper_expire_output::init(lua_State *lua_state) { - lua_getglobal(lua_state, "osm2pgsql"); - if (luaL_newmetatable(lua_state, OSM2PGSQL_EXPIRE_OUTPUT_CLASS) != 1) { - throw std::runtime_error{"Internal error: Lua newmetatable failed."}; - } - lua_pushvalue(lua_state, -1); // Copy of new metatable - - // Add metatable as osm2pgsql.ExpireOutput so we can access it from Lua - lua_setfield(lua_state, -3, "ExpireOutput"); - - // Now add functions to metatable - lua_pushvalue(lua_state, -1); - lua_setfield(lua_state, -2, "__index"); - luaX_add_table_func(lua_state, "__tostring", - lua_trampoline_expire_output_tostring); - luaX_add_table_func(lua_state, "filename", - lua_trampoline_expire_output_filename); - luaX_add_table_func(lua_state, "maxzoom", - lua_trampoline_expire_output_maxzoom); - luaX_add_table_func(lua_state, "minzoom", - lua_trampoline_expire_output_minzoom); - luaX_add_table_func(lua_state, "schema", - lua_trampoline_expire_output_schema); - luaX_add_table_func(lua_state, "table", lua_trampoline_expire_output_table); - - lua_pop(lua_state, 2); + luaX_set_up_metatable( + lua_state, "ExpireOutput", OSM2PGSQL_EXPIRE_OUTPUT_CLASS, + {{"__tostring", lua_trampoline_expire_output_tostring}, + {"filename", lua_trampoline_expire_output_filename}, + {"maxzoom", lua_trampoline_expire_output_maxzoom}, + {"minzoom", lua_trampoline_expire_output_minzoom}, + {"schema", lua_trampoline_expire_output_schema}, + {"table", lua_trampoline_expire_output_table}}); } int lua_wrapper_expire_output::tostring() const diff --git a/src/flex-lua-geom.cpp b/src/flex-lua-geom.cpp index 4fc2880ee..3aa0788da 100644 --- a/src/flex-lua-geom.cpp +++ b/src/flex-lua-geom.cpp @@ -300,37 +300,25 @@ int geom_transform(lua_State *lua_state) void init_geometry_class(lua_State *lua_state) { - lua_getglobal(lua_state, "osm2pgsql"); - if (luaL_newmetatable(lua_state, OSM2PGSQL_GEOMETRY_CLASS) != 1) { - throw std::runtime_error{"Internal error: Lua newmetatable failed."}; - } - lua_pushvalue(lua_state, -1); // Copy of new metatable - - // Add metatable as osm2pgsql.Geometry so we can access it from Lua - lua_setfield(lua_state, -3, "Geometry"); - - luaX_add_table_func(lua_state, "__gc", geom_gc); - luaX_add_table_func(lua_state, "__len", geom_num_geometries); - luaX_add_table_func(lua_state, "__tostring", geom_tostring); - lua_pushvalue(lua_state, -1); - lua_setfield(lua_state, -2, "__index"); - luaX_add_table_func(lua_state, "area", geom_area); - luaX_add_table_func(lua_state, "length", geom_length); - luaX_add_table_func(lua_state, "centroid", geom_centroid); - luaX_add_table_func(lua_state, "get_bbox", geom_get_bbox); - luaX_add_table_func(lua_state, "geometry_n", geom_geometry_n); - luaX_add_table_func(lua_state, "geometry_type", geom_geometry_type); - luaX_add_table_func(lua_state, "is_null", geom_is_null); - luaX_add_table_func(lua_state, "line_merge", geom_line_merge); - luaX_add_table_func(lua_state, "reverse", geom_reverse); - luaX_add_table_func(lua_state, "num_geometries", geom_num_geometries); - luaX_add_table_func(lua_state, "pole_of_inaccessibility", - geom_pole_of_inaccessibility); - luaX_add_table_func(lua_state, "segmentize", geom_segmentize); - luaX_add_table_func(lua_state, "simplify", geom_simplify); - luaX_add_table_func(lua_state, "spherical_area", geom_spherical_area); - luaX_add_table_func(lua_state, "srid", geom_srid); - luaX_add_table_func(lua_state, "transform", geom_transform); - - lua_pop(lua_state, 2); // __index, global osmp2gsql + luaX_set_up_metatable( + lua_state, "Geometry", OSM2PGSQL_GEOMETRY_CLASS, + {{"__gc", geom_gc}, + {"__len", geom_num_geometries}, + {"__tostring", geom_tostring}, + {"area", geom_area}, + {"length", geom_length}, + {"centroid", geom_centroid}, + {"get_bbox", geom_get_bbox}, + {"geometry_n", geom_geometry_n}, + {"geometry_type", geom_geometry_type}, + {"is_null", geom_is_null}, + {"line_merge", geom_line_merge}, + {"reverse", geom_reverse}, + {"num_geometries", geom_num_geometries}, + {"pole_of_inaccessibility", geom_pole_of_inaccessibility}, + {"segmentize", geom_segmentize}, + {"simplify", geom_simplify}, + {"spherical_area", geom_spherical_area}, + {"srid", geom_srid}, + {"transform", geom_transform}}); } diff --git a/src/flex-lua-locator.cpp b/src/flex-lua-locator.cpp index 65bc7bfb5..002e1c000 100644 --- a/src/flex-lua-locator.cpp +++ b/src/flex-lua-locator.cpp @@ -70,30 +70,14 @@ void lua_wrapper_locator::init(lua_State *lua_state, { s_connection_params = connection_params; - lua_getglobal(lua_state, "osm2pgsql"); - if (luaL_newmetatable(lua_state, OSM2PGSQL_LOCATOR_CLASS) != 1) { - throw std::runtime_error{"Internal error: Lua newmetatable failed."}; - } - lua_pushvalue(lua_state, -1); // Copy of new metatable - - // Add metatable as osm2pgsql.Locator so we can access it from Lua - lua_setfield(lua_state, -3, "Locator"); - - // Now add functions to metatable - lua_pushvalue(lua_state, -1); - lua_setfield(lua_state, -2, "__index"); - luaX_add_table_func(lua_state, "__tostring", - lua_trampoline_locator_tostring); - luaX_add_table_func(lua_state, "name", lua_trampoline_locator_name); - luaX_add_table_func(lua_state, "add_bbox", lua_trampoline_locator_add_bbox); - luaX_add_table_func(lua_state, "add_from_db", - lua_trampoline_locator_add_from_db); - luaX_add_table_func(lua_state, "all_intersecting", - lua_trampoline_locator_all_intersecting); - luaX_add_table_func(lua_state, "first_intersecting", - lua_trampoline_locator_first_intersecting); - - lua_pop(lua_state, 2); + luaX_set_up_metatable( + lua_state, "Locator", OSM2PGSQL_LOCATOR_CLASS, + {{"__tostring", lua_trampoline_locator_tostring}, + {"name", lua_trampoline_locator_name}, + {"add_bbox", lua_trampoline_locator_add_bbox}, + {"add_from_db", lua_trampoline_locator_add_from_db}, + {"all_intersecting", lua_trampoline_locator_all_intersecting}, + {"first_intersecting", lua_trampoline_locator_first_intersecting}}); } int lua_wrapper_locator::tostring() const diff --git a/src/flex-lua-table.cpp b/src/flex-lua-table.cpp index 9bff4d543..ea82beed8 100644 --- a/src/flex-lua-table.cpp +++ b/src/flex-lua-table.cpp @@ -457,27 +457,13 @@ int setup_flex_table(lua_State *lua_state, std::vector *tables, */ void lua_wrapper_table::init(lua_State *lua_state) { - lua_getglobal(lua_state, "osm2pgsql"); - if (luaL_newmetatable(lua_state, OSM2PGSQL_TABLE_CLASS) != 1) { - throw std::runtime_error{"Internal error: Lua newmetatable failed."}; - } - lua_pushvalue(lua_state, -1); // Copy of new metatable - - // Add metatable as osm2pgsql.Table so we can access it from Lua - lua_setfield(lua_state, -3, "Table"); - - // Now add functions to metatable - lua_pushvalue(lua_state, -1); - lua_setfield(lua_state, -2, "__index"); - luaX_add_table_func(lua_state, "__tostring", - lua_trampoline_table_tostring); - luaX_add_table_func(lua_state, "insert", lua_trampoline_table_insert); - luaX_add_table_func(lua_state, "name", lua_trampoline_table_name); - luaX_add_table_func(lua_state, "schema", lua_trampoline_table_schema); - luaX_add_table_func(lua_state, "cluster", lua_trampoline_table_cluster); - luaX_add_table_func(lua_state, "columns", lua_trampoline_table_columns); - - lua_pop(lua_state, 2); + luaX_set_up_metatable(lua_state, "Table", OSM2PGSQL_TABLE_CLASS, + {{"__tostring", lua_trampoline_table_tostring}, + {"insert", lua_trampoline_table_insert}, + {"name", lua_trampoline_table_name}, + {"schema", lua_trampoline_table_schema}, + {"cluster", lua_trampoline_table_cluster}, + {"columns", lua_trampoline_table_columns}}); } int lua_wrapper_table::tostring() const diff --git a/src/init.lua b/src/init.lua index 9d0c76413..1b2ab61e2 100644 --- a/src/init.lua +++ b/src/init.lua @@ -176,20 +176,16 @@ function osm2pgsql.split_string(str, separator) return result end --- This will be the metatable for the OSM objects given to the process callback --- functions. -object_metatable = { - __index = { - grab_tag = function(data, tag) - if not tag then - error("Missing tag key", 2) - end - local v = data.tags[tag] - data.tags[tag] = nil - return v +if osm2pgsql.OSMObject then + osm2pgsql.OSMObject.__index.grab_tag = function(data, tag) + if not tag then + error("Missing tag key", 2) end - } -} + local v = data.tags[tag] + data.tags[tag] = nil + return v + end +end -- This is used to iterate over (multi)geometries. function osm2pgsql.Geometry.geometries(geom) diff --git a/src/lua-utils.cpp b/src/lua-utils.cpp index c843ec375..6b5b0ff6f 100644 --- a/src/lua-utils.cpp +++ b/src/lua-utils.cpp @@ -115,6 +115,32 @@ void luaX_add_table_func(lua_State *lua_state, char const *key, lua_rawset(lua_state, -3); } +void luaX_set_up_metatable( + lua_State *lua_state, char const *name, char const *luaclass, + std::initializer_list> map) + +{ + lua_getglobal(lua_state, "osm2pgsql"); + if (luaL_newmetatable(lua_state, luaclass) != 1) { + throw std::runtime_error{"Internal error: Lua newmetatable failed."}; + } + lua_pushvalue(lua_state, -1); // Copy of new metatable + + // Add metatable under the specified name so we can access it from Lua + lua_setfield(lua_state, -3, name); + + // Now add functions to metatable + lua_pushvalue(lua_state, -1); + lua_setfield(lua_state, -2, "__index"); + for (auto const &[key, func] : map) { + lua_pushstring(lua_state, key); + lua_pushcfunction(lua_state, func); + lua_rawset(lua_state, -3); + } + + lua_settop(lua_state, 0); +} + char const *luaX_get_table_string(lua_State *lua_state, char const *key, int table_index, char const *error_msg) { diff --git a/src/lua-utils.hpp b/src/lua-utils.hpp index cd0919f12..d595b4eed 100644 --- a/src/lua-utils.hpp +++ b/src/lua-utils.hpp @@ -17,6 +17,7 @@ #include #include +#include #include #include @@ -38,6 +39,10 @@ void luaX_add_table_bool(lua_State *lua_state, char const *key, void luaX_add_table_func(lua_State *lua_state, char const *key, lua_CFunction func) noexcept; +void luaX_set_up_metatable( + lua_State *lua_state, char const *name, char const *luaclass, + std::initializer_list> map); + template void luaX_add_table_array(lua_State *lua_state, char const *key, COLLECTION const &collection, FUNC const &func) diff --git a/src/output-flex.cpp b/src/output-flex.cpp index a806a5c80..31980384c 100644 --- a/src/output-flex.cpp +++ b/src/output-flex.cpp @@ -1305,45 +1305,23 @@ void output_flex_t::init_lua(std::string const &filename, assert(lua_gettop(lua_state()) == 0); + luaX_set_up_metatable( + lua_state(), "OSMObject", OSM2PGSQL_OSMOBJECT_CLASS, + {{"get_bbox", lua_trampoline_app_get_bbox}, + {"as_linestring", lua_trampoline_app_as_linestring}, + {"as_point", lua_trampoline_app_as_point}, + {"as_polygon", lua_trampoline_app_as_polygon}, + {"as_multipoint", lua_trampoline_app_as_multipoint}, + {"as_multilinestring", lua_trampoline_app_as_multilinestring}, + {"as_multipolygon", lua_trampoline_app_as_multipolygon}, + {"as_geometrycollection", lua_trampoline_app_as_geometrycollection}}); + // Load compiled in init.lua if (luaL_dostring(lua_state(), lua_init())) { throw fmt_error("Internal error in Lua setup: {}.", lua_tostring(lua_state(), -1)); } - // Store the methods on OSM objects in its metatable. - lua_getglobal(lua_state(), "object_metatable"); - lua_pushstring(lua_state(), OSM2PGSQL_OSMOBJECT_CLASS); - lua_setfield(lua_state(), -2, "__name"); - lua_getfield(lua_state(), -1, "__index"); - luaX_add_table_func(lua_state(), "get_bbox", lua_trampoline_app_get_bbox); - luaX_add_table_func(lua_state(), "as_linestring", - lua_trampoline_app_as_linestring); - luaX_add_table_func(lua_state(), "as_point", - lua_trampoline_app_as_point); - luaX_add_table_func(lua_state(), "as_polygon", - lua_trampoline_app_as_polygon); - luaX_add_table_func(lua_state(), "as_multipoint", - lua_trampoline_app_as_multipoint); - luaX_add_table_func(lua_state(), "as_multilinestring", - lua_trampoline_app_as_multilinestring); - luaX_add_table_func(lua_state(), "as_multipolygon", - lua_trampoline_app_as_multipolygon); - luaX_add_table_func(lua_state(), "as_geometrycollection", - lua_trampoline_app_as_geometrycollection); - lua_settop(lua_state(), 0); - - // Store the global object "object_metatable" defined in the init.lua - // script in the registry and then remove the global object. It will - // later be used as metatable for OSM objects. - lua_pushstring(lua_state(), OSM2PGSQL_OSMOBJECT_CLASS); - lua_getglobal(lua_state(), "object_metatable"); - lua_settable(lua_state(), LUA_REGISTRYINDEX); - lua_pushnil(lua_state()); - lua_setglobal(lua_state(), "object_metatable"); - - assert(lua_gettop(lua_state()) == 0); - // Load user config file luaX_set_context(lua_state(), this); if (luaL_dofile(lua_state(), filename.c_str())) {