Skip to content

Commit

Permalink
Rename arraytable to sequence, add tests and comment its functions
Browse files Browse the repository at this point in the history
  • Loading branch information
edubart committed Feb 15, 2020
1 parent c064c42 commit cb017d3
Show file tree
Hide file tree
Showing 15 changed files with 265 additions and 189 deletions.
6 changes: 3 additions & 3 deletions benchmarks/heapsort.nelua
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
require 'arraytable'
require 'sequence'

local function heapsort(a: arraytable(number))
local function heapsort(a: sequence(number))
local n = #a
local j, i, t
local l = (n // 2) + 1
Expand Down Expand Up @@ -41,7 +41,7 @@ local function random_int(seed: integer)
end

local N = 1000000
local a: arraytable(number)
local a: sequence(number)
local rand = 123456789
for i=1,N do
rand = random_int(rand)
Expand Down
4 changes: 2 additions & 2 deletions benchmarks/sieve.nelua
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
require 'arraytable'
require 'sequence'

local function sieve(N: integer)
local is_prime: arraytable(boolean)
local is_prime: sequence(boolean)
is_prime[1] = false
for n=2,N do
is_prime[n] = true
Expand Down
4 changes: 2 additions & 2 deletions examples/matmul.nelua
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
require 'arraytable'
require 'sequence'

local Matrix = @arraytable(arraytable(number))
local Matrix = @sequence(sequence(number))

local function matrix_transpose(a: Matrix, n: integer): Matrix
local x: Matrix = {}
Expand Down
7 changes: 2 additions & 5 deletions lib/allocators/allocator_interface.nelua
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ function allocator.spanrealloc(s: auto, size: usize)
s.size = 0
else
s.data = (@T*)(allocator.realloc(s.data, size * #T))
check(s.data, 'allocator.spanrealloc0: allocation fail')
check(s.data, 'allocator.spanrealloc: allocation fail')
s.size = size
end
return s
Expand All @@ -69,11 +69,8 @@ function allocator.spanrealloc0(s: auto, size: usize)
s.data = nilptr
s.size = 0
else
s.data = (@T*)(allocator.realloc(s.data, size * #T))
s.data = (@T*)(allocator.realloc0(s.data, size * #T, s.size * #T))
check(s.data, 'allocator.spanrealloc0: allocation fail')
if likely(size > s.size) then
memset(&s[s.size], 0, (size - s.size) * #T)
end
s.size = size
end
return s
Expand Down
140 changes: 0 additions & 140 deletions lib/arraytable.nelua

This file was deleted.

1 change: 1 addition & 0 deletions lib/gc.nelua
Original file line number Diff line number Diff line change
Expand Up @@ -364,6 +364,7 @@ function GC:start(stack: pointer)
end

function GC:stop()
self:_unmark_all()
self:_sweep()
allocator.spandealloc(self.items)
allocator.spandealloc(self.frees)
Expand Down
152 changes: 152 additions & 0 deletions lib/sequence.nelua
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
-- Sequence type
--
-- This type is typically used as a more efficient lua table that can hold only sequences.
-- Its elements starts at index 1 and go up to its length (like lua tables),
-- internally it just contains a pointer, so it's passed by reference by default
-- (like lua tables again).
--
-- By default its use the garbage collector unless explicitly told not to do so,
-- thus by default there is no need to manually reset the sequence.


## unitname = 'nelua'

require 'memory'

## local make_sequence = generalize(function(T, allocator)
## staticassert(traits.is_type(T), "invalid type '%s'", T)
## local codenameprefix = 'nelua_sequence_'..T.name
## if allocator then
local allocator: type = #[allocator]#
## codenameprefix = codenameprefix..'_'..allocator.nick
## else
require 'allocators.gc_allocator'
local allocator: type = @gc_allocator
## end

local T = @#[T]#
local SequenceImplT <codename #[codenameprefix..'_impl']#> = @record {
size: usize,
data: span(T)
}
local SequenceT <codename #[codenameprefix]#> = @record{
impl: SequenceImplT*
}

-- Resets and removes all elements from the sequence.
function SequenceT:clear()
if not self.impl then return end
if self.impl.data.size ~= 0 then
local zero: T
for i:usize=0,self.impl.size do
self.impl.data[i] = zero
end
end
self.impl.size = 0
end

-- Reset sequence to zeroed state, freeing all used resources.
-- This is more useful free resources when not using the garbage collector.
function SequenceT:reset()
if not self.impl then return end
self:clear()
allocator.spandealloc(self.impl.data)
allocator.dealloc(self.impl)
self.impl = nilptr
end

function SequenceT:_grow()
local cap: usize = 2
if likely(self.impl.data.size ~= 0) then cap = self.impl.data.size * 2 end
self.impl.data = allocator.spanrealloc0(self.impl.data, cap)
end

-- Initializes sequence internal implementation if needed.
-- This is already implicitly called by other sequence functions when needed.
function SequenceT:init() <inline>
if likely(self.impl) then return end
self.impl = (@SequenceImplT*)(allocator.alloc0(#SequenceImplT))
end

-- Reserve at least `n` elements on the sequence capacity.
function SequenceT:reserve(n: usize <autocast>)
self:init()
local cap: usize = n + 1
if self.impl.data.size >= cap then return end
self.impl.data = allocator.spanrealloc0(self.impl.data, cap)
end

-- Resizes the sequence so that it contains `n` elements as copies of `v`.
function SequenceT:resize(n: usize <autocast>, v: T)
self:init()
if n <= self.impl.size then return end
self:reserve(n)
for i=self.impl.size+1,<n do
self.impl.data[i+1] = v
end
self.impl.size = n
end

-- Adds a new element at the end of the sequence.
function SequenceT:push(v: T) <inline>
self:init()
self.impl.size = self.impl.size + 1
if unlikely(self.impl.size + 1 >= self.impl.data.size) then
self:_grow()
end
self.impl.data[self.impl.size] = v
end

-- Removes the last element in the sequence and returns its value.
-- If the sequence is empty, then throws a runtime error.
function SequenceT:pop(): T <inline>
check(self.impl and self.impl.size > 0, 'sequence.pop: length is 0')
local zero: T
local ret: T = self.impl.data[self.impl.size]
self.impl.data[self.impl.size] = zero
self.impl.size = self.impl.size - 1
return ret
end

-- Return reference to element at index `i`.
-- If `i` is the sequence size plus 1, then a zeroed element is added and return its reference.
-- If `i` is larger then the sequence size plus 1, then throws a runtime error.
function SequenceT:__atindex(i: usize <autocast>): T* <inline>
self:init()
if unlikely(i > self.impl.size) then
check(i == self.impl.size + 1, 'sequence.at: index out of range')
self.impl.size = self.impl.size + 1
end
if unlikely(self.impl.size + 1 > self.impl.data.size) then
self:_grow()
end
return &self.impl.data[i]
end

-- Return the number of elements in the sequence. It never counts the element at 0.
function SequenceT:__len(): isize <inline>
if unlikely(not self.impl) then return 0 end
return (@isize)(self.impl.size)
end

-- Initialize a sequence elements from a fixed array.
-- This allows to use sequence initialization with braces.
function SequenceT.__convert(values: #[concept(function(x)
if x.type:is_array_of(T) then return true end
end)]#): SequenceT <inline>
local self: SequenceT
self:reserve(#values)
self.impl.size = #values
for i:usize=1,#values do
self.impl.data[i] = values[i-1]
end
return self
end
##[[SequenceT.value.choose_braces_type = function(node)
return types.ArrayType(nil, T, #node[1])
end]]

## return SequenceT
## end)

global sequence = #[make_sequence]#
Loading

0 comments on commit cb017d3

Please sign in to comment.