ビルトインであってほしい関数群

メモとして貼り付けておく。

function string.strip(self)
  return (string.gsub(self, "^%s*(.-)%s*$", "%1"))
end

function string.split(self, delim)
  if delim == '' then error("empty separator") end
  local is, ie
  local t = {}
  -- タブ・空白で分割
  if not delim then
    for v in self:gmatch('(%S+)') do
      table.insert(t, v)
    end
    return t
  end
  -- デリミタで分割
  local init = 1
  while true do
    is, ie = self:find(delim, init)
    if not is then
      table.insert(t, self:sub(init))
      break
    end
    if is == 1 then
      table.insert(t, '')
    else
      table.insert(t, self:sub(init, is-1))
    end
    init = ie+1
  end
  return t
end

function table.keys(self)
  local keys = {}
  for k,v in pairs(self) do
    table.insert(keys, k)
  end
  return keys
end

function table.values(self)
  local vals = {}
  for k,v in pairs(self) do
    table.insert(vals, v)
  end
  return vals
end

function table.ikeys(self)
  local keys = {}
  for k,v in ipairs(self) do
    table.insert(keys, k)
  end
  return keys
end

function table.ivalues(self)
  local vals = {}
  for i,v in ipairs(self) do
    table.insert(vals, v)
  end
  return vals
end

function table.map(self, func)
  local vals = {}
  for i,v in ipairs(self) do
    table.insert(vals, func(v))
  end
  return vals
end

function table.tostring(self)
  local strs = {}
  local idxs = {}
  for i,v in ipairs(self) do
    if tonumber(v) then
      table.insert(strs, v)
    else
      table.insert(strs, '"'..v..'"')
    end
    idxs[i] = true
  end
  for k,v in pairs(self) do
    if not idxs[k] then
      if type(k) == 'number' then
        table.insert(strs, '['..k..']='..tostring(v))
      else
        table.insert(strs, tostring(k)..'='..tostring(v))
      end
    end
  end
  return '{' .. table.concat(strs, ', ') .. '}'
end

function zip(...)
  local args = {...}
  return coroutine.wrap(function ()
    local args2 = {}
    for i, tbl in ipairs(args) do
      args2[i] = {tbl,nil}
    end
    local is_end = false
    while true do
      local vars = {}
      for i, v in ipairs(args2) do
        local tbl2, idx2 = unpack(v)
        local idx3, val3 = next(tbl2, idx2)
        if not val3 then
          is_end = true
          break
        end
        args2[i] = {tbl2,idx3}
        table.insert(vars, val3)
      end
      if is_end then
        break
      end
      coroutine.yield(unpack(vars))
    end
  end)
end

function range(st, ed, step)
  if not ed then
    ed = st
    st = 1
    step = 1
  elseif not step then
    step = 1
  end
  local vals = {}
  for i=st,ed,step do
    table.insert(vals, i)
  end
  return vals
end

function varg_tostring(...)
  local s = select(1, ...)
  for n = 2, select('#', ...) do
    s = s..","..select(n,...)
  end
  return s
end

function memoize(f)
  local cache = {}
  return function (...)
    local al = varg_tostring(...)
    if cache[al] then
      return cache[al]
    else
      local y = f(...)
      cache[al] = y
      return y
    end
  end
end