Skip to content

Commit

Permalink
More usage of concepts on lib sources
Browse files Browse the repository at this point in the history
  • Loading branch information
edubart committed Feb 15, 2020
1 parent c3fc0ef commit 0b89f88
Show file tree
Hide file tree
Showing 12 changed files with 146 additions and 190 deletions.
4 changes: 2 additions & 2 deletions lib/allocators/generic.nelua
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
require 'allocators.interface'

local function memset(s: pointer, c: cint, n: csize): pointer <cimport'memset',cinclude'<string.h>',nodecl> end
local function malloc(size: csize): pointer <cimport'malloc',cinclude'<stdlib.h>',nodecl> end
local function calloc(nmemb: csize, size: csize): pointer <cimport'calloc',cinclude'<stdlib.h>',nodecl> end
Expand Down Expand Up @@ -43,4 +41,6 @@ function generic_allocator.dealloc(p: pointer)
free(p)
end

require 'allocators.interface'

## implement_allocator_interface(generic_allocator)
150 changes: 62 additions & 88 deletions lib/allocators/interface.nelua
Original file line number Diff line number Diff line change
@@ -1,103 +1,77 @@
##[[
--------------------------------------------------------------------------------
-- compile time checks utilities
local function check_span_subtype(v)
staticassert(v.type:is_span(),
"in argument '%s': expected 'span(T)' but got type '%s'",
v.name, v.type)
return v.type.subtype
end
local function check_type_match(a, b)
staticassert(a.type == b.type,
"argument '%s' type '%s' differs from argument '%s' type '%s",
a.name, b.name, a.type, b.type)
end
local function check_span_subtype_match(s, x)
local stype = check_span_subtype(s)
staticassert(stype == x.type,
"in argument '%s': type '%s' differs from argument '%s' type '%s",
s.name, x.name, stype, x.type)
end
]]

## function implement_allocator_interface(allocator)
local is_span = #[concept(function(x) return x.type:is_span() end)]#
local allocator = #[allocator]#

local allocator = #[allocator]#
function allocator.spanalloc(T: type, size: usize)
local s: span(T)
if likely(size > 0_u) then
s.data = (@T*)(allocator.alloc(size * #T))
check(s.data, 'allocator.spanalloc: allocation fail')
s.size = size
end
return s
end

function allocator.spanalloc(T: type, size: usize)
local s: span(T)
if likely(size > 0_u) then
s.data = (@T*)(allocator.alloc(size * #T))
check(s.data, 'allocator.spanalloc: allocation fail')
s.size = size
function allocator.spanalloc0(T: type, size: usize)
local s: span(T)
if likely(size > 0_u) then
s.data = (@T*)(allocator.alloc0(size * #T))
check(s.data, 'allocator.spanalloc0: allocation fail')
s.size = size
end
return s
end
return s
end

function allocator.spanalloc0(T: type, size: usize)
local s: span(T)
if likely(size > 0_u) then
s.data = (@T*)(allocator.alloc0(size * #T))
check(s.data, 'allocator.spanalloc0: allocation fail')
s.size = size
function allocator.spanrealloc(s: is_span, size: usize)
local T: type = #[s.type.subtype]#
if unlikely(size == 0) then
allocator.dealloc(s.data)
s.data = nilptr
s.size = 0
else
s.data = (@T*)(allocator.realloc(s.data, size * #T))
check(s.data, 'allocator.spanrealloc: allocation fail')
s.size = size
end
return s
end
return s
end

function allocator.spanrealloc(s: auto, size: usize)
local T: type = #[check_span_subtype(s)]#
if unlikely(size == 0) then
allocator.dealloc(s.data)
s.data = nilptr
s.size = 0
else
s.data = (@T*)(allocator.realloc(s.data, size * #T))
check(s.data, 'allocator.spanrealloc: allocation fail')
s.size = size
function allocator.spanrealloc0(s: is_span, size: usize)
local T: type = #[s.type.subtype]#
if unlikely(size == 0) then
allocator.dealloc(s.data)
s.data = nilptr
s.size = 0
else
s.data = (@T*)(allocator.realloc0(s.data, size * #T, s.size * #T))
check(s.data, 'allocator.spanrealloc0: allocation fail')
s.size = size
end
return s
end
return s
end

function allocator.spanrealloc0(s: auto, size: usize)
local T: type = #[check_span_subtype(s)]#
if unlikely(size == 0) then
function allocator.spandealloc(s: is_span)
allocator.dealloc(s.data)
s.data = nilptr
s.size = 0
else
s.data = (@T*)(allocator.realloc0(s.data, size * #T, s.size * #T))
check(s.data, 'allocator.spanrealloc0: allocation fail')
s.size = size
end
return s
end

function allocator.spandealloc(s: auto)
## check_span_subtype(s)
allocator.dealloc(s.data)
end

function allocator.new(T: type, size: auto)
## if not size.type:is_nil() then
## staticassert(size.type:is_integral(), 'allocator.new: size must be an integral type')
## if not size.type:is_unsigned() then
check(size > 0, 'allocator.new: size must be greater than 0')
function allocator.new(T: type, size: auto)
## if not size.type:is_nil() then
## staticassert(size.type:is_integral(), 'allocator.new: size must be an integral type')
## if not size.type:is_unsigned() then
check(size > 0, 'allocator.new: size must be greater than 0')
## end
return allocator.spanalloc0(T, (@usize)(size))
## else
return (@T*)(allocator.alloc0(#T))
## end
return allocator.spanalloc0(T, (@usize)(size))
## else
return (@T*)(allocator.alloc0(#T))
## end
end

function allocator.delete(s: auto)
## staticassert(s.type:is_pointer() or s.type:is_span(), "allocator.delete: invalid type '%s'", s.type)
## if s.type:is_span() then
allocator.spandealloc(s)
## else -- pointer
allocator.dealloc(s)
## end
end
end

function allocator.delete(s: auto)
## staticassert(s.type:is_pointer() or s.type:is_span(), "allocator.delete: invalid type '%s'", s.type)
## if s.type:is_span() then
allocator.spandealloc(s)
## else -- pointer
allocator.dealloc(s)
## end
end
## end
20 changes: 1 addition & 19 deletions lib/io.nelua
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
--TODO: optional arguments/returns

--------------------------------------------------------------------------------
-- C imports

Expand Down Expand Up @@ -81,7 +79,7 @@ end
--------------------------------------------------------------------------------
-- io module

local io = @record{}
global io = @record{}

function io.close(file: filestream)
--TODO: optional argument
Expand Down Expand Up @@ -141,19 +139,3 @@ end

-- io.lines
-- io.type

--------------------------------------------------------------------------------
-- tests

local f = io.open('testfile', 'r')
assert(f.f == nilptr)

f = io.open('LICENSE', 'r')
assert(f.f ~= nilptr)
assert(f:flush() == true)
assert(f:flush() == true)
assert(f:close() == true)

f = io.open('LICENSE', 'r')
assert(io.flush(f) == true)
assert(io.close(f) == true)
55 changes: 24 additions & 31 deletions lib/math.nelua
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
-- Math library
--
-- The math library tries to follow all math functions from Lua

global math = @record{}

-- constants
Expand All @@ -6,15 +10,16 @@ global math.huge: float64 <const,cimport'HUGE_VAL',cinclude'<math.h>',nodecl>
global math.maxinteger: integer <comptime> = 9223372036854775807
global math.mininteger: integer <comptime> = -9223372036854775808

-- concepts
local is_arithmetic = #[concept(function(x)
return x.type:is_arithmetic()
end)]#
local is_optional_arithmetic = #[concept(function(x)
return x.type:is_arithmetic() or x.type:is_nil()
end)]#

-- compile time utilities
##[[
local function check_arithmetic(...)
for i=1,select('#',...) do
local x = select(i,...)
staticassert(x.type:is_arithmetic(), "variable '%s' isn't an arithmetic type", x)
end
end
local function choose_float_type(x)
if x.type:is_float32() then
return primtypes.float32
Expand Down Expand Up @@ -68,8 +73,7 @@ local mathfuncs1 = {'abs','ceil','floor','sqrt','exp','acos','asin','cos','sin',
for _,name in ipairs(mathfuncs1) do
local namef64, namef32 = name..'_f64', name..'_f32'
]]
function math.#(name)#(x: auto) <inline,nosideeffect>
## check_arithmetic(x)
function math.#(name)#(x: is_arithmetic) <inline,nosideeffect>
## if x.type:is_float32() then
return #(namef32)#(x)
## elseif x.type:is_float() then
Expand All @@ -92,8 +96,7 @@ local mathfuncs2 = { 'max', 'min', 'fmod', 'pow' }
for _,name in ipairs(mathfuncs2) do
local namef64, namef32 = name..'_f64', name..'_f32'
]]
function math.#(name)#(x: auto, y: auto) <inline,nosideeffect>
## check_arithmetic(x, y)
function math.#(name)#(x: is_arithmetic, y: is_arithmetic) <inline,nosideeffect>
## if x.type:is_float32() then
return #(namef32)#(x, y)
## elseif x.type:is_float() then
Expand All @@ -110,10 +113,8 @@ function math.#(name)#(x: auto, y: auto) <inline,nosideeffect>
end
## end

function math.atan(y: auto, x: auto) <inline,nosideeffect>
## check_arithmetic(y)
function math.atan(y: is_arithmetic, x: is_optional_arithmetic) <inline,nosideeffect>
## if not x.type:is_nil() then
## check_arithmetic(x)
## if y.type:is_float32() and x.type:is_float32() then
return atan2_f32(y, x)
## else
Expand All @@ -128,8 +129,7 @@ function math.atan(y: auto, x: auto) <inline,nosideeffect>
## end
end

function math.log(x: auto, base: auto) <inline,nosideeffect>
## check_arithmetic(x)
function math.log(x: is_arithmetic, base: is_optional_arithmetic) <inline,nosideeffect>
## local suffix = x.type:is_float32() and '_f32' or '_f64'
## local log2, log10, log = 'log2'..suffix, 'log10'..suffix, 'log'..suffix
## if not base.type:is_nil() then
Expand All @@ -145,22 +145,19 @@ function math.log(x: auto, base: auto) <inline,nosideeffect>
## end
end

function math.deg(x: auto) <inline,nosideeffect>
## check_arithmetic(x)
function math.deg(x: is_arithmetic) <inline,nosideeffect>
local R: type = #[choose_float_type(x)]#
local factor: R <comptime> = 180 / math.pi
return x * factor
end

function math.rad(x: auto) <inline,nosideeffect>
## check_arithmetic(x)
function math.rad(x: is_arithmetic) <inline,nosideeffect>
local R: type = #[choose_float_type(x)]#
local factor: R <comptime> = math.pi / 180.0
return x * factor
end

function math.modf(x: auto) <inline,nosideeffect>
## check_arithmetic(x)
function math.modf(x: is_arithmetic) <inline,nosideeffect>
local R: type = #[choose_float_type(x)]#
local i: R
local f: R <noinit>
Expand All @@ -172,7 +169,7 @@ function math.modf(x: auto) <inline,nosideeffect>
return i, f
end

function math.tointeger(x: auto) <inline,nosideeffect>
function math.tointeger(x: is_arithmetic) <inline,nosideeffect>
## if x.type:is_integral() then
return (@integer)(x)
## elseif x.type:is_float() then
Expand All @@ -187,7 +184,7 @@ function math.tointeger(x: auto) <inline,nosideeffect>
## end
end

function math.type(x: auto) <inline,nosideeffect>
function math.type(x: is_arithmetic) <inline,nosideeffect>
## if x.type:is_float() then
return 'float'
## elseif x.type:is_integral() then
Expand All @@ -197,8 +194,7 @@ function math.type(x: auto) <inline,nosideeffect>
## end
end

function math.ult(m: auto, n: auto): boolean <inline>
## check_arithmetic(m, n)
function math.ult(m: is_arithmetic, n: is_arithmetic): boolean <inline>
## if m.type:is_integral() and n.type:is_integral() then
return (@uinteger)(m) < (@uinteger)(n)
## elseif x.type:is_float() then
Expand Down Expand Up @@ -255,15 +251,13 @@ local default_random: xoshiro256 = {state={
0x65CE039BAEBE74B4, 0x4911ADA153B51EEF, 0xFB71FBB497C00950, 0xF83CCF6AC1B74755
}}

function math.randomseed(x: auto) <inline>
## check_arithmetic(x)
function math.randomseed(x: is_arithmetic) <inline>
default_random:seed((@uint64)(x), 0)
end

function math.random(m: auto, n: auto) <inline>
function math.random(m: is_optional_arithmetic, n: is_optional_arithmetic) <inline>
local r: number = default_random:random()
## if not m.type:is_nil() and not n.type:is_nil() then
## check_arithmetic(m, n)
local low: integer, up: integer = (@integer)(m), (@integer)(n)
if not likely(low < up) then
panic("random: interval is empty")
Expand All @@ -273,7 +267,6 @@ function math.random(m: auto, n: auto) <inline>
r = r * ((@number)(up - low) + 1.0)
return (@integer)(r) + low
## elseif not m.type:is_nil() then
## check_arithmetic(m)
local low: integer = (@integer)(m)
r = r * (@number)(low)
return (@integer)(r)
Expand Down
Loading

0 comments on commit 0b89f88

Please sign in to comment.