lua_oop/oop/types.lua

503 lines
11 KiB
Lua

local oop = require("oop")
local Types = {}
local function freeze_table(t)
return setmetatable({}, {
__index = t,
__newindex = function()
error("Tuple is immutable", 2)
end,
__len = function()
return #t
end,
__pairs = function()
return pairs(t)
end,
__ipairs = function()
return ipairs(t)
end
})
end
local function IntDef(cls)
local base_newindex = cls.__newindex
function cls.__init(this, value)
rawset(this, "__frozen", false)
this.value = math.floor(tonumber(value) or 0)
rawset(this, "__frozen", true)
end
function cls.__add(a, b)
return Types.Int(a.value + b.value)
end
function cls.__sub(a, b)
return Types.Int(a.value - b.value)
end
function cls.__mul(a, b)
if type(a) == "number" then
return Types.Int(a * b.value)
end
if type(b) == "number" then
return Types.Int(a.value * b)
end
return Types.Int(a.value * b.value)
end
function cls.__eq(a, b)
return a.value == b.value
end
function cls.__tostring(this)
return tostring(this.value)
end
function cls.to_number(this)
return this.value
end
function cls.__newindex(this, key, value)
if rawget(this, "__frozen") and key ~= "__fields" then
error("Int is immutable", 2)
end
return base_newindex(this, key, value)
end
end
local function FloatDef(cls)
local base_newindex = cls.__newindex
function cls.__init(this, value)
rawset(this, "__frozen", false)
this.value = tonumber(value) or 0.0
rawset(this, "__frozen", true)
end
function cls.__add(a, b)
return Types.Float(a.value + b.value)
end
function cls.__sub(a, b)
return Types.Float(a.value - b.value)
end
function cls.__mul(a, b)
if type(a) == "number" then
return Types.Float(a * b.value)
end
if type(b) == "number" then
return Types.Float(a.value * b)
end
return Types.Float(a.value * b.value)
end
function cls.__eq(a, b)
return a.value == b.value
end
function cls.__tostring(this)
return tostring(this.value)
end
function cls.to_number(this)
return this.value
end
function cls.__newindex(this, key, value)
if rawget(this, "__frozen") and key ~= "__fields" then
error("Float is immutable", 2)
end
return base_newindex(this, key, value)
end
end
local function ListDef(cls)
function cls.__init(this, items)
this.head = nil
this.tail = nil
this.size = 0
if type(items) == "table" then
for _, v in ipairs(items) do
this.append(v)
end
end
end
function cls.__len(this)
return this.size
end
function cls.__tostring(this)
local parts = {}
local node = this.head
while node do
parts[#parts + 1] = tostring(node.value)
node = node.next
end
return "[" .. table.concat(parts, ", ") .. "]"
end
function cls.append(this, value)
local node = { value = value, next = nil }
if this.tail then
this.tail.next = node
else
this.head = node
end
this.tail = node
this.size = this.size + 1
end
function cls.get(this, index)
if type(index) ~= "number" or index < 1 or index > this.size then
return nil
end
local node = this.head
local i = 1
while node do
if i == index then
return node.value
end
node = node.next
i = i + 1
end
return nil
end
function cls.set(this, index, value)
if type(index) ~= "number" or index < 1 or index > this.size then
return false
end
local node = this.head
local i = 1
while node do
if i == index then
node.value = value
return true
end
node = node.next
i = i + 1
end
return false
end
function cls.iter(this)
local node = this.head
return function()
if not node then
return nil
end
local value = node.value
node = node.next
return value
end
end
end
local function TupleDef(cls)
local base_newindex = cls.__newindex
function cls.__init(this, items)
rawset(this, "__frozen", false)
if type(items) == "table" then
this.items = freeze_table({ table.unpack(items) })
else
this.items = freeze_table({})
end
rawset(this, "__frozen", true)
end
function cls.__len(this)
return #this.items
end
function cls.__tostring(this)
local parts = {}
for i, v in ipairs(this.items) do
parts[i] = tostring(v)
end
return "(" .. table.concat(parts, ", ") .. ")"
end
function cls.get(this, index)
return this.items[index]
end
function cls.iter(this)
return ipairs(this.items)
end
function cls.__newindex(this, key, value)
if rawget(this, "__frozen") and key ~= "__fields" then
error("Tuple is immutable", 2)
end
return base_newindex(this, key, value)
end
end
local function QueueDef(cls)
function cls.__init(this, items)
if type(items) == "table" then
this.items = { table.unpack(items) }
else
this.items = {}
end
this.head = 1
end
function cls.__len(this)
return #this.items - this.head + 1
end
function cls.__tostring(this)
local parts = {}
for i = this.head, #this.items do
parts[#parts + 1] = tostring(this.items[i])
end
return "Queue([" .. table.concat(parts, ", ") .. "])"
end
function cls.enqueue(this, value)
this.items[#this.items + 1] = value
end
function cls.dequeue(this)
if this.head > #this.items then
return nil
end
local value = this.items[this.head]
this.items[this.head] = nil
this.head = this.head + 1
if this.head > 32 and this.head > (#this.items / 2) then
local new_items = {}
for i = this.head, #this.items do
new_items[#new_items + 1] = this.items[i]
end
this.items = new_items
this.head = 1
end
return value
end
function cls.peek(this)
return this.items[this.head]
end
end
local function StackDef(cls)
function cls.__init(this, items)
if type(items) == "table" then
this.items = { table.unpack(items) }
else
this.items = {}
end
end
function cls.__len(this)
return #this.items
end
function cls.__tostring(this)
local parts = {}
for i, v in ipairs(this.items) do
parts[i] = tostring(v)
end
return "Stack([" .. table.concat(parts, ", ") .. "])"
end
function cls.push(this, value)
this.items[#this.items + 1] = value
end
function cls.pop(this)
local n = #this.items
if n == 0 then
return nil
end
local value = this.items[n]
this.items[n] = nil
return value
end
function cls.peek(this)
return this.items[#this.items]
end
end
local function DictDef(cls)
function cls.__init(this, items)
if type(items) == "table" then
this.items = items
else
this.items = {}
end
end
function cls.__len(this)
local count = 0
for _ in pairs(this.items) do
count = count + 1
end
return count
end
function cls.__tostring(this)
local parts = {}
for k, v in pairs(this.items) do
parts[#parts + 1] = tostring(k) .. "=" .. tostring(v)
end
return "Dict({" .. table.concat(parts, ", ") .. "})"
end
function cls.get(this, key, default)
local val = this.items[key]
if val == nil then
return default
end
return val
end
function cls.set(this, key, value)
this.items[key] = value
end
function cls.keys(this)
local keys = {}
for k in pairs(this.items) do
keys[#keys + 1] = k
end
return keys
end
end
local function SetDef(cls)
function cls.__init(this, items)
this.items = {}
if type(items) == "table" then
for _, v in ipairs(items) do
this.items[v] = true
end
end
end
function cls.__len(this)
local count = 0
for _ in pairs(this.items) do
count = count + 1
end
return count
end
function cls.__tostring(this)
local parts = {}
for k in pairs(this.items) do
parts[#parts + 1] = tostring(k)
end
return "Set({" .. table.concat(parts, ", ") .. "})"
end
function cls.add(this, value)
this.items[value] = true
end
function cls.has(this, value)
return this.items[value] == true
end
function cls.remove(this, value)
this.items[value] = nil
end
end
local function BoolDef(cls)
local base_newindex = cls.__newindex
function cls.__init(this, value)
rawset(this, "__frozen", false)
this.value = not not value
rawset(this, "__frozen", true)
end
function cls.__tostring(this)
return tostring(this.value)
end
function cls.__eq(a, b)
return a.value == b.value
end
function cls.__newindex(this, key, value)
if rawget(this, "__frozen") and key ~= "__fields" then
error("Bool is immutable", 2)
end
return base_newindex(this, key, value)
end
end
local function StrDef(cls)
local base_newindex = cls.__newindex
function cls.__init(this, value)
rawset(this, "__frozen", false)
this.value = tostring(value or "")
rawset(this, "__frozen", true)
end
function cls.__len(this)
return #this.value
end
function cls.__concat(a, b)
return Types.Str(tostring(a) .. tostring(b))
end
function cls.__tostring(this)
return this.value
end
function cls.__newindex(this, key, value)
if rawget(this, "__frozen") and key ~= "__fields" then
error("Str is immutable", 2)
end
return base_newindex(this, key, value)
end
end
Types.Int = oop.class(IntDef)
Types.Int.__name = "Int"
Types.Float = oop.class(FloatDef)
Types.Float.__name = "Float"
Types.List = oop.class(ListDef)
Types.List.__name = "List"
Types.Tuple = oop.class(TupleDef)
Types.Tuple.__name = "Tuple"
Types.Tupple = Types.Tuple
Types.Queue = oop.class(QueueDef)
Types.Queue.__name = "Queue"
Types.Que = Types.Queue
Types.Stack = oop.class(StackDef)
Types.Stack.__name = "Stack"
Types.Dict = oop.class(DictDef)
Types.Dict.__name = "Dict"
Types.Set = oop.class(SetDef)
Types.Set.__name = "Set"
Types.Bool = oop.class(BoolDef)
Types.Bool.__name = "Bool"
Types.Str = oop.class(StrDef)
Types.Str.__name = "Str"
Types.String = Types.Str
return Types