lua

Lua元方法(Metamethod)

方法名 含义
__index 这是 metatable 最常用的键。当你通过键来访问 table 的时候,如果这个键没有值,那么Lua就会寻找该table的metatable(假定有metatable)中的index 键。如果index包含一个表格,Lua会在表格中查找相应的键
__newindex newindex 元方法用来对表更新。当你给表的一个缺少的索引赋值,解释器就会查找 newindex 元方法:如果存在则调用这个函数而不进行赋值操作。
__add + 操作。 如果任何不是数字的值(包括不能转换为数字的字符串)做加法, Lua 就会尝试调用元方法。 首先、Lua 检查第一个操作数(即使它是合法的), 如果这个操作数没有为 "__add" 事件定义元方法, Lua 就会接着检查第二个操作数。 一旦 Lua 找到了元方法, 它将把两个操作数作为参数传入元方法, 元方法的结果(调整为单个值)作为这个操作的结果。 如果找不到元方法,将抛出一个错误。
__sub - 操作。 行为和 "add" 操作类似。
__mul * 操作。 行为和 "add" 操作类似。
__div / 操作。 行为和 "add" 操作类似。
__mod % 操作。 行为和 "add" 操作类似。
__pow ^ (次方)操作。 行为和 "add" 操作类似。
__unm - (取负)操作。 行为和 "add" 操作类似。
__idiv // (向下取整除法)操作。 行为和 "add" 操作类似。
__band & (按位与)操作。 行为和 "add" 操作类似, 不同的是 Lua 会在任何一个操作数无法转换为整数时 (参见 §3.4.3)尝试取元方法。
__bor (按位或)操作。 行为和 "band" 操作类似。
__bxor ~ (按位异或)操作。 行为和 "band" 操作类似。
__bnot ~ (按位非)操作。 行为和 "band" 操作类似。
__shl << (左移)操作。 行为和 "band" 操作类似。
__shr >> (右移)操作。 行为和 "band" 操作类似。
__concat .. (连接)操作。 行为和 "add" 操作类似, 不同的是 Lua 在任何操作数即不是一个字符串 也不是数字(数字总能转换为对应的字符串)的情况下尝试元方法。
__len # (取长度)操作。 如果对象不是字符串,Lua 会尝试它的元方法。 如果有元方法,则调用它并将对象以参数形式传入, 而返回值(被调整为单个)则作为结果。 如果对象是一张表且没有元方法, Lua 使用表的取长度操作(参见 §3.4.7)。 其它情况,均抛出错误。
__eq == (等于)操作。 和 "add" 操作行为类似, 不同的是 Lua 仅在两个值都是表或都是完全用户数据 且它们不是同一个对象时才尝试元方法。 调用的结果总会被转换为布尔量。
__lt < (小于)操作。 和 "add" 操作行为类似, 不同的是 Lua 仅在两个值不全为整数也不全为字符串时才尝试元方法。 调用的结果总会被转换为布尔量。
__le <= (小于等于)操作。 和其它操作不同, 小于等于操作可能用到两个不同的事件。 首先,像 "lt" 操作的行为那样,Lua 在两个操作数中查找 "le" 元方法。 如果一个元方法都找不到,就会再次查找 "lt" 事件, 它会假设 a <= b 等价于 not (b < a)。 而其它比较操作符类似,其结果会被转换为布尔量。
__index 索引 table[key]。 当 table 不是表或是表 table 中不存在 key 这个键时,这个事件被触发。 此时,会读出 table 相应的元方法。

斜方向分割二维数组(lua简易实现)

分析规律(下图为11行-5列示例)

  • 同颜色数字相差值为列数-1
  • 可以产生(行数+列数-1)组数字(如图是15)
  • 每组数字中,每一行最多只有一个(同行号应舍去)

function formatVal(val)
    if val < 10 then return " " .. tostring(val) end
    return tostring(val)
end

local cols = 5
local rows = 11
local t = {}
local gap = " "
for r = 1, rows do
    local line = ""
    for c = 1, cols do
        local val = (r - 1) * cols + c
        table.insert(t, val, val)
        line = line .. " " .. formatVal(val)
    end
    print(line)
end

function SplitBySlash(t, cols, rows)
    local arr2 = {}
    local offset = cols - 1
    for c = 1, rows + cols - 1 do
        local arr = {}
        for r = 1, rows do
            local n = c + (r - 1) * offset
            local fakeR = math.ceil(n / cols)
            if fakeR == r then
                table.insert(arr, n)
                print(n, r, fakeR)
            end

        end
        print("================")
        table.insert(arr2, arr)
    end
    return arr2
end

local function __dump(var, level)
    local rval = {}
    table.insert(rval, "{")
    for k, v in pairs(var) do
        if type(v) == "table" and getmetatable(var) ~= v then
            if k ~= "__base" then
                table.insert(rval, string.format("%s%s=%s",
                                                 string.rep("    ", level), k,
                                                 __dump(v, level + 1)))
            end
        elseif type(v) ~= "function" then
            table.insert(rval, string.format("%s%s=%s",
                                             string.rep("    ", level), k,
                                             tostring(v)))
        end
    end
    table.insert(rval, string.format("%s}", string.rep("    ", level - 1)))
    return table.concat(rval, "\n")
end

local function log(inst)
    if inst == nil then
        print(nil)
        return
    end
    print(__dump(inst, 1))
end

local array2 = SplitBySlash(t, cols, rows)
log(array2)

最终效果

在lua5.3 使用 zrong 和ByteArray

  1. lua 5.3 string.pack 和 string.unpack

http://cloudwu.github.io/lua53doc/manual.html#6.4.2

用于 string.pack, string.packsize, string.unpack 的第一个参数。 它是一个描述了需要创建或读取的结构之布局。

格式串是由转换选项构成的序列。 这些转换选项列在后面:

<: 设为小端编码
>: 设为大端编码
=: 大小端遵循本地设置
![n]: 将最大对齐数设为 n (默认遵循本地对齐设置)
b: 一个有符号字节 (char)
B: 一个无符号字节 (char)
h: 一个有符号 short (本地大小)
H: 一个无符号 short (本地大小)
l: 一个有符号 long (本地大小)
L: 一个无符号 long (本地大小)
j: 一个 lua_Integer
J: 一个 lua_Unsigned
T: 一个 size_t (本地大小)
i[n]: 一个 n 字节长(默认为本地大小)的有符号 int
I[n]: 一个 n 字节长(默认为本地大小)的无符号 int
f: 一个 float (本地大小)
d: 一个 double (本地大小)
n: 一个 lua_Number
cn: n字节固定长度的字符串
z: 零结尾的字符串
s[n]: 长度加内容的字符串,其长度编码为一个 n 字节(默认是个 size_t) 长的无符号整数。
x: 一个字节的填充
Xop: 按选项 op 的方式对齐(忽略它的其它方面)的一个空条目
' ': (空格)忽略
( "[n]" 表示一个可选的整数。) 除填充、空格、配置项(选项 "xX <=>!")外, 每个选项都关联一个参数(对于 string.pack) 或结果(对于 string.unpack)。

对于选项 "!n", "sn", "in", "In", n 可以是 1 到 16 间的整数。 所有的整数选项都将做溢出检查; string.pack 检查提供的值是否能用指定的字长表示; string.unpack 检查读出的值能否置入 Lua 整数中。

任何格式串都假设有一个 "!1=" 前缀, 即最大对齐为 1 (无对齐)且采用本地大小端设置。

对齐行为按如下规则工作: 对每个选项,格式化时都会填充一些字节直到数据从一个特定偏移处开始, 这个位置是该选项的大小和最大对齐数中较小的那个数的倍数; 这个较小值必须是 2 个整数次方。 选项 "c" 及 "z" 不做对齐处理; 选项 "s" 对对齐遵循其开头的整数。

string.pack 用零去填充 (string.unpack 则忽略它)。
  1. lpack
http://www.luteus.biz/Download/LoriotPro_Doc/LUA/LUA_For_Windows/lpack/

z : zero-terminated string 
p : string preceded by length byte 
P : string preceded by length word 
a : string preceded by length size_t 
A : string 
f : float 
d : double 
n : Lua number 
c : char 
b : byte (unsigned char) 
h : short 
H : unsigned short 
i : int 
I : unsigned int 
l : long 
L : unsigned long

< : little endian 
> : big endian 
= : native endian

3.查看了lpack和 lua5.3 的string.pack,string.unpack后发现两者 有些差别

3.1 lpack.pack 的fmt b10 在 string.pack fmt bbbbbbbbbb

3.2 lpack.unpack 和 string.unpack 参数位置不一样, lpack fmt 在后面, string.pack在前面

3.3 unpack 在5.3移到table下了,所以unpack 修改成 table.unpack

要想使用zrong的ByteArray必需修改

下面是修改后代码 暂时没有报错。主要是 

string.pack 和 string.unpack的修改

--[[
Serialzation bytes stream like ActionScript flash.utils.ByteArray.
It depends on lpack.
A sample: https://github.com/zrong/lua#ByteArray

@see http://underpop.free.fr/l/lua/lpack/
@see http://help.adobe.com/en_US/FlashPlatform/reference/actionscript/3/flash/utils/ByteArray.html
@author zrong(zengrong.net)

Creation 2013-11-14
Last Modification 2014-07-09
]]
local ByteArray = cc.class("ByteArray")

ByteArray.ENDIAN_LITTLE = "ENDIAN_LITTLE"
ByteArray.ENDIAN_BIG = "ENDIAN_BIG"
ByteArray.radix = {[10]="%03u",[8]="%03o",[16]="%02X"}

-- require("pack")

--- Return a string to display.
-- If self is ByteArray, read string from self.
-- Else, treat self as byte string.
-- @param __radix radix of display, value is 8, 10 or 16, default is 10.
-- @param __separator default is " ".
-- @return string, number
function ByteArray.toString(self, __radix, __separator)
    __radix = __radix or 16 
    __radix = ByteArray.radix[__radix] or "%02X"
    __separator = __separator or " "
    local __fmt = __radix..__separator
    local __format = function(__s)
        return string.format(__fmt, string.byte(__s))
    end
    if type(self) == "string" then
        return string.gsub(self, "(.)", __format)
    end
    local __bytes = {}
    for i=1,#self._buf do
        __bytes[i] = __format(self._buf[i])
    end
    return table.concat(__bytes) ,#__bytes
end

function ByteArray:ctor(__endian)
    self._endian = __endian
    self._buf = {}
    self._pos = 1
end

function ByteArray:getLen()
    return #self._buf
end

function ByteArray:getAvailable()
    return #self._buf - self._pos + 1
end

function ByteArray:getPos()
    return self._pos
end

function ByteArray:setPos(__pos)
    self._pos = __pos
    return self
end

function ByteArray:getEndian()
    return self._endian
end

function ByteArray:setEndian(__endian)
    self._endian = __endian
end

--- Get all byte array as a lua string.
-- Do not update position.
function ByteArray:getBytes(__offset, __length)
    __offset = __offset or 1
    __length = __length or #self._buf
    --printf("getBytes,offset:%u, length:%u", __offset, __length)
    return table.concat(self._buf, "", __offset, __length)
end

--- Get pack style string by lpack.
-- The result use ByteArray.getBytes to get is unavailable for lua socket.
-- E.g. the #self:_buf is 18, but #ByteArray.getBytes is 63.
-- I think the cause is the table.concat treat every item in ByteArray._buf as a general string, not a char.
-- So, I use lpack repackage the ByteArray._buf, theretofore, I must convert them to a byte number.
function ByteArray:getPack(__offset, __length)
    __offset = __offset or 1
    __length = __length or #self._buf

    local __fmt = self:_getLC("c" .. (__length - __offset + 1))
    -- print("fmt:", __fmt, #__t)
    local __s = string.pack(__fmt, self:getBytes(__offset, __length))
    return __s
end

--- rawUnPack perform like lpack.pack, but return the ByteArray.
function ByteArray:rawPack(__fmt, ...)
    local __s = string.pack(__fmt, ...)
    self:writeBuf(__s)
    return self
end

--- rawUnPack perform like lpack.unpack, but it is only support FORMAT parameter.
-- Because ByteArray include a position itself, so we haven't to save another.
function ByteArray:rawUnPack(__fmt)
    -- read all of bytes.
    local __s = self:getBytes(self._pos)
    local __next, __val = string.unpack(__fmt, __s)
    -- update position of the ByteArray
    self._pos = self._pos + __next
    -- Alternate value and next
    return __val, __next
end

function ByteArray:readBool()
    -- When char > 256, the readByte method will show an error.
    -- So, we have to use readChar
    return self:readChar() ~= 0
end

function ByteArray:writeBool(__bool)
    if __bool then 
        self:writeByte(1)
    else
        self:writeByte(0)
    end
    return self
end

function ByteArray:readDouble()
    local __v, __ = string.unpack(self:_getLC("d"), self:readBuf(8))
    return __v
end

function ByteArray:writeDouble(__double)
    local __s = string.pack( self:_getLC("d"), __double)
    self:writeBuf(__s)
    return self
end

function ByteArray:readFloat()
    local __v, __ = string.unpack(self:_getLC("f"), self:readBuf(4))
    return __v
end

function ByteArray:writeFloat(__float)
    local __s = string.pack( self:_getLC("f"),  __float)
    self:writeBuf(__s)
    return self
end

function ByteArray:readInt()
    local __v, __ = string.unpack(self:_getLC("i"), self:readBuf(4))
    return __v
end

function ByteArray:writeInt(__int)
    local __s = string.pack( self:_getLC("i"),  __int)
    self:writeBuf(__s)
    return self
end

function ByteArray:readUInt()
    local __v, __ = string.unpack(self:_getLC("I"), self:readBuf(4))
    return __v
end

function ByteArray:writeUInt(__uint)
    local __s = string.pack(self:_getLC("I"), __uint)
    self:writeBuf(__s)
    return self
end

function ByteArray:readShort()
    local __v, __ = string.unpack(self:_getLC("h"), self:readBuf(2))
    return __v
end

function ByteArray:writeShort(__short)
    local __s = string.pack( self:_getLC("h"),  __short)
    self:writeBuf(__s)
    return self
end

function ByteArray:readUShort()
    local __v, __ = string.unpack(self:_getLC("H"), self:readBuf(2))
    return __v
end

function ByteArray:writeUShort(__ushort)
    local __s = string.pack(self:_getLC("H"),  __ushort)
    self:writeBuf(__s)
    return self
end

--[[
-- 2014-07-09 Remove all of methods about Long in ByteArray.
-- @see http://zengrong.net/post/2134.htm
function ByteArray:readLong()
    local __v, __ = string.unpack(self:_getLC("l"), self:readBuf(8))
    return __v
end

function ByteArray:writeLong(__long)
    local __s = string.pack( self:_getLC("l"),  __long)
    self:writeBuf(__s)
    return self
end

function ByteArray:readULong()
    local __v, __ = string.unpack(self:_getLC("L"), self:readBuf(4))
    return __v
end

function ByteArray:writeULong(__ulong)
    local __s = string.pack( self:_getLC("L"), __ulong)
    self:writeBuf(__s)
    return self
end
]]

function ByteArray:readUByte()
    local __v, __al = string.unpack("b", self:readRawByte())
    return __val
end

function ByteArray:writeUByte(__ubyte)
    local __s = string.pack("b", __ubyte)
    self:writeBuf(__s)
    return self
end

function ByteArray:readLuaNumber(__number)
    local __v, __ = string.unpack(self:_getLC("n"), self:readBuf(8))
    return __v
end

function ByteArray:writeLuaNumber(__number)
    local __s = string.pack(self:_getLC("n"), __number)
    self:writeBuf(__s)
    return self
end

--- The differently about (read/write)StringBytes and (read/write)String
-- are use pack libraty or not.
function ByteArray:readStringBytes(__len)
    assert(__len, "Need a length of the string!")
    if __len == 0 then return "" end
    self:_checkAvailable()
    local __v, __ = string.unpack(self:_getLC("A"..__len), self:readBuf(__len))
    return __v
end

function ByteArray:writeStringBytes(__string)
    local __s = string.pack(self:_getLC("A"), __string)
    self:writeBuf(__s)
    return self
end

function ByteArray:readString(__len)
    assert(__len, "Need a length of the string!")
    if __len == 0 then return "" end
    self:_checkAvailable()
    return self:readBuf(__len)
end

function ByteArray:writeString(__string)
    self:writeBuf(__string)
    return self
end

function ByteArray:readStringUInt()
    self:_checkAvailable()
    local __len = self:readUInt()
    return self:readStringBytes(__len)
end

function ByteArray:writeStringUInt(__string)
    self:writeUInt(#__string)
    self:writeStringBytes(__string)
    return self
end

--- The length of size_t in C/C++ is mutable.
-- In 64bit os, it is 8 bytes.
-- In 32bit os, it is 4 bytes.
function ByteArray:readStringSizeT()
    self:_checkAvailable()
    local __s = self:rawUnPack(self:_getLC("a"))
    return  __s
end

--- Perform rawPack() simply.
function ByteArray:writeStringSizeT(__string)
    self:rawPack(self:_getLC("a"), __string)
    return self
end

function ByteArray:readStringUShort()
    self:_checkAvailable()
    local __len = self:readUShort()
    return self:readStringBytes(__len)
end

function ByteArray:writeStringUShort(__string)
    local __s = string.pack(self:_getLC("P"), __string)
    self:writeBuf(__s)
    return self
end

--- Read some bytes from buf
-- @return a bit string
function ByteArray:readBytes(__bytes, __offset, __length)
    assert(cc.iskindof(__bytes, "ByteArray"), "Need a ByteArray instance!")
    local __selfLen = #self._buf
    local __availableLen = __selfLen - self._pos
    __offset = __offset or 1
    if __offset > __selfLen then __offset = 1 end
    __length = __length or 0
    if __length == 0 or __length > __availableLen then __length = __availableLen end
    __bytes:setPos(__offset)
    for i=__offset,__offset+__length do
        __bytes:writeRawByte(self:readRawByte())
    end
end

--- Write some bytes into buf
function ByteArray:writeBytes(__bytes, __offset, __length)
    assert(cc.iskindof(__bytes, "ByteArray"), "Need a ByteArray instance!")
    local __bytesLen = __bytes:getLen()
    if __bytesLen == 0 then return end
    __offset = __offset or 1
    if __offset > __bytesLen then __offset = 1 end
    local __availableLen = __bytesLen - __offset
    __length = __length or __availableLen
    if __length == 0 or __length > __availableLen then __length = __availableLen end
    local __oldPos = __bytes:getPos()
    __bytes:setPos(__offset)
    for i=__offset,__offset+__length do
        self:writeRawByte(__bytes:readRawByte())
    end
    __bytes:setPos(__oldPos)
    return self
end

--- Actionscript3 readByte == lpack readChar
-- A signed char
function ByteArray:readChar()
    local __v, __al = string.unpack("c", self:readRawByte())
    return __val
end

function ByteArray:writeChar(__char)
    self:writeRawByte(string.pack("c", __char))
    return self
end

--- Use the lua string library to get a byte
-- A unsigned char
function ByteArray:readByte()
    return string.byte(self:readRawByte())
end

--- Use the lua string library to write a byte.
-- The byte is a number between 0 and 255, otherwise, the lua will get an error.
function ByteArray:writeByte(__byte)
    self:writeRawByte(string.char(__byte))
    return self
end

function ByteArray:readRawByte()
    self:_checkAvailable()
    local __byte = self._buf[self._pos]
    self._pos = self._pos + 1
    return __byte
end

function ByteArray:writeRawByte(__rawByte)
    if self._pos > #self._buf+1 then
        for i=#self._buf+1,self._pos-1 do
            self._buf[i] = string.char(0)
        end
    end
    self._buf[self._pos] = string.sub(__rawByte, 1,1)
    self._pos = self._pos + 1
    return self
end

--- Read a byte array as string from current position, then update the position.
function ByteArray:readBuf(__len)
    --printf("readBuf,len:%u, pos:%u", __len, self._pos)
    local __ba = self:getBytes(self._pos, self._pos + __len - 1)
    self._pos = self._pos + __len
    return __ba
end

--- Write a encoded char array into buf
function ByteArray:writeBuf(__s)
    for i=1,#__s do
        self:writeRawByte(string.sub(__s,i,i))
    end
    return self
end

----------------------------------------
-- private
----------------------------------------
function ByteArray:_checkAvailable()
    assert(#self._buf >= self._pos, string.format("End of file was encountered. pos: %d, len: %d.", self._pos, #self._buf))
end

--- Get Letter Code
function ByteArray:_getLC(__fmt)
    __fmt = __fmt or ""
    if self._endian == ByteArray.ENDIAN_LITTLE then
        return "<"..__fmt
    elseif self._endian == ByteArray.ENDIAN_BIG then
        return ">"..__fmt
    end
    return "="..__fmt
end

return ByteArray

原文链接:https://blog.csdn.net/lovehappy108/java/article/details/52070737

lua protobuf 使用整理(二)

最近写了一个函数, table自动编码为protobuf格式

local parse
parse = function(args, msg)
    for k, v in pairs(args) do
        if type(v) == 'table' then --table类型判断是否是数组
            if #v > 0 then
                for index, ele in ipairs(v) do --遍历数组元素
                    if type(ele) == 'table' then --数组元素是table, 递归解析内容
                        local emsg = msg[k]:add()
                        parse(ele, emsg)
                    else --数组元素是基本数据类型,直接添加
                        msg[k]:append(ele)
                    end
                end
            else --非数组,递归解析内容
                parse(v, msg[k])
            end
        else
            msg[k] = args[k]
        end
    end
end

lua protobuf 使用整理(一)

准备工作

使用源码A,protobuf-master/python,运行以下命令:

    python setup.py build
    python setup.py test
    python setup.py install

注意:xxx.proto文件必须为UTF-8格式

生成proto_pb文件

cd %~dp0
set PROTO_FILE_FOLER=XXXX
set OUTPUT_FOLDER=XXX

cd %PROTO_FILE_FOLER%
for %%i in (*.proto) do (    
"%~dp0protoc.exe" --plugin=protoc-gen-lua="%~dp0run_plugin.bat" --lua_out=%OUTPUT_FOLDER% %%i 
echo %%i successfully converted
) 
run_plugin.bat
@python "%~dp0protoc-gen-lua-master\plugin\protoc-gen-lua"