사용자 도구

사이트 도구


kb:luasnippets

차이

문서의 선택한 두 판 사이의 차이를 보여줍니다.

차이 보기로 링크

kb:luasnippets [2014/11/10 16:23] (현재)
줄 1: 줄 1:
 +{{INLINETOC}}
 +\\
 +
 +====== Lua Snippets ======
 +루아 코드 조각 모음
 +
 +====== 함수 오버라이드 검사 ======
 +베이스 클래스에 있는 함수를 지정된 인덱스에 있는 테이블에서 오버라이드했는가?​
 +<code cpp>
 +/// \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;
 +}
 +</​code>​
 +
 +====== 모듈 패스 등록하기 ======
 +5.0 버전까지는 LUA_PATH 라는 이름의 전역 변수에다 설정하면 됐는데, 5.1 버전부터 package 테이블 안의 path 변수(package.path)를 이용해야한다.
 +<code cpp>
 +/// \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);
 +    }
 +}
 +</​code>​
 +
 +====== 비트 연산 ======
 +<code lua>
 +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)
 +</​code>​
 +        ​
 +너무 길다. 루아를 잘 알지 못해서 그런 것일수도 있겠으나,​ 개인적으로는 mathlib.c 파일을 수정해서 C 함수 하나 추가하는 편이 나을 거라고 생각한다.
 +        ​
 +<code cpp>
 +...
 +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}
 +};
 +</​code>​
 +
 +====== CSV 파서 ======
 +"​Programming in Lua"​란 책에 나오는 CSV 파서를 약간 수정한 파서
 +<code lua>
 +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"​)
 +</​code> ​
 +----
 +  * see also [[Lua]]
  
kb/luasnippets.txt · 마지막으로 수정됨: 2014/11/10 16:23 (바깥 편집)