루아 코드 조각 모음
베이스 클래스에 있는 함수를 지정된 인덱스에 있는 테이블에서 오버라이드했는가?
/// \brief 베이스 클래스에 있는 함수를 지정된 인덱스에 있는 테이블에서 오버라이드했는가? /// \param baseName 베이스 클래스 이름. ex) "SkillHandler" /// \param funcName 함수 이름. ex) "OnStartCast" /// \param tableName 전역 테이블 이름. ex) "g_SkillHandlers" /// \param tableIndex 테이블 멤버 인덱스. ex) 스킬 인덱스 /// \return bool 오버라이드했다면 true bool IsOverriden(lua_State* L, const char* baseName, const char* funcName, const char* tableName, int tableIndex) { bool result = false; int top = lua_gettop(L); do { // 기본 함수를 가지는 테이블을 가져온다. lua_getglobal(L, baseName); if (lua_type(L, -1) != LUA_TTABLE) break; // 테이블에 있는 함수를 가져온다. lua_pushstring(L, funcName); lua_gettable(L, -2); if (lua_type(L, -1) != LUA_TFUNCTION) break; // 함수 인덱스를 저장해둔다. int baseFuncIndex = lua_gettop(L); // 비교할 전역 테이블을 가져온다. lua_getglobal(L, tableName); if (lua_type(L, -1) != LUA_TTABLE) break; // 전역 테이블 아이템 중에 해당하는 인덱스의 테이블을 다시 가져온다. lua_pushinteger(L, tableIndex); lua_gettable(L, -2) if (lua_type(L, -1) != LUA_TTABLE) break; // 해당 인덱스의 테이블의 같은 이름의 함수를 가져온다. lua_pushstring(L, funcName); lua_gettable(L, -2); if (lua_type(L, -1) != LUA_TFUNCTION) break; result = lua_equal(L, baseFuncIndex, -1) == 0; } while (0); if (top < lua_gettop(L)) lua_pop(L, lua_gettop(L) - top); return result; }
5.0 버전까지는 LUA_PATH 라는 이름의 전역 변수에다 설정하면 됐는데, 5.1 버전부터 package 테이블 안의 path 변수(package.path)를 이용해야한다.
/// \brief 루아 모듈 패스를 등록한다. /// \param L 루아 상태 객체 /// \param path 패스 문자열. 각각의 디렉토리를 ';'로 구분지은 문자열로 들어가 있어야 한다. /// \param bAppend 기존 경로에 추가하는가의 여부 void SetModulePath(lua_State* L, const char* path, bool bAppend) { size_t before = 0; size_t current = 0; std::string original(path); std::string modified; while (current < original.size()) { current = original.find_first_of(';', before); if (current == std::string::npos) current = original.size(); std::string token = original.substr(before, current - before); if (!token.empty()) { if (token[token.size()-1] != '\\') token += '\\'; #ifdef _DEBUG assert(::PathFileExists(token.c_str()) && "path not found"); #endif modified += token + "?.lua;"; modified += token + "?.dll;"; } before = current + 1; } if (!modified.empty()) { if (bAppend) { lua_getfield(L, LUA_GLOBALSINDEX, "package"); assert(lua_istable(L, -1)); lua_getfield(L, -1, "path"); std::string old_path = lua_tostring(L, -1); if (old_path[old_path.size()-1] != ';') old_path += ';'; modified = old_path + modified; lua_pop(L, 2); } lua_getfield(L, LUA_GLOBALSINDEX, "package"); assert(lua_istable(L, -1)); lua_pushstring(L, modified.c_str()); lua_setfield(L, -2, "path"); lua_pop(L, 1); } }
function extract(value, index) local v = value local m = 0 for i=1,index do m = math.mod(v, 2) v = v / 2 end if m >= 1 then return 1 end return 0 end function bitwise_and(n1, n2) local rvalue = 0 for i=1,32 do if extract(n1, i) == 1 and extract(n2, i) == 1 then rvalue = rvalue + math.pow(2, i-1) end end return rvalue end function bitwise_or(n1, n2) local rvalue = 0 for i=1,32 do if extract(n1, i) == 1 or extract(n2, i) == 1 then rvalue = rvalue + math.pow(2, i-1) end end return rvalue end assert(bitwise_or(4, 1) == 5) assert(bitwise_or(4, 2) == 6) assert(bitwise_or(4, 4) == 4) assert(bitwise_and(4, 1) == 0) assert(bitwise_and(4, 2) == 0) assert(bitwise_and(4, 4) == 4)
너무 길다. 루아를 잘 알지 못해서 그런 것일수도 있겠으나, 개인적으로는 mathlib.c 파일을 수정해서 C 함수 하나 추가하는 편이 나을 거라고 생각한다.
... static int math_bwand(lua_State* L) { int lhs = (int)luaL_checknumber(L, 1); int rhs = (int)luaL_checknumber(L, 2); lua_pushnumber(L, lhs & rhs); return 1; } static int math_bwor(lua_State* L) { int lhs = (int)luaL_checknumber(L, 1); int rhs = (int)luaL_checknumber(L, 2); lua_pushnumber(L, lhs | rhs); return 1; } ... static const luaL_reg mathlib[] = { {"abs", math_abs}, ...생략... {"randomseed", math_randomseed}, + {"bwand", math_bwand}, + {"bwor", math_bwor}, {NULL, NULL} };
“Programming in Lua”란 책에 나오는 CSV 파서를 약간 수정한 파서
CSVRow = { Columns = {}, -- 컬럼 문자열들 new = function (self) o = {} setmetatable(o, self) self.__index = self return o end, parse = function(self, line) self.Columns = {} s = line .. ',' -- ending comma local fieldstart = 1 repeat -- next field is quoted? (start with `"'?) if string.find(s, '^"', fieldstart) then local a, c local i = fieldstart repeat -- find closing quote a, i, c = string.find(s, '"("?)', i+1) until c ~= '"' -- quote not followed by quote? if not i then error('unmatched "') end local f = string.sub(s, fieldstart+1, i-1) table.insert(self.Columns, (string.gsub(f, '""', '"'))) fieldstart = string.find(s, ',', i) + 1 else -- unquoted; find next comma local nexti = string.find(s, ',', fieldstart) table.insert(self.Columns, string.sub(s, fieldstart, nexti-1)) fieldstart = nexti + 1 end until fieldstart > string.len(s) end, to_string = function(self) local line = "" for _, token in ipairs(self.Columns) do line = line .. "," if string.find(token, '[,"]') then line = line .. '"' .. string.gsub(token, '"', '""') .. '"' else line = line .. token end end return string.sub(line, 2) end } CSVFile = { Rows = {}, new = function (self) o = {} setmetatable(o, self) self.__index = self return o end, load = function(self, filename) local file = assert(io.open(filename, "r")) while true do local line = file:read("*line") if line == nil then break end local row = CSVRow:new() row:parse(line) table.insert(self.Rows, row) end file:close() end, save = function(self, filename) local file = assert(io.open(filename, "w")) for _, row in pairs(self.Rows) do file:write(row:to_string() .. "\n") end end } -- 여기서부터는 샘플 코드 f = CSVFile:new() f:load("test.csv") print(f.Rows[1].Columns[1]) f:save("output.csv")
—-