Skip to content

Commit 4a0bcff

Browse files
committed
Replace copies with loads.
No measurable speed-up but slightly simplifies the implementation.
1 parent bd4c132 commit 4a0bcff

File tree

1 file changed

+33
-38
lines changed

1 file changed

+33
-38
lines changed

src/UDF.jl

Lines changed: 33 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -55,15 +55,16 @@ function scalarfunc(expr::Expr)
5555
return scalarfunc(f)
5656
end
5757

58-
# convert a bytearray to an int arr[1] is 256^0, arr[2] is 256^1...
59-
# TODO: would making this a method of convert needlessly pollute the Base namespace?
60-
function bytestoint(arr::Vector{UInt8})
61-
l = length(arr)
58+
# convert a byteptr to an int, ptr[start] -> 256^0, ptr[start+1] -> 256^1...
59+
# TODO: this assumes little-endian
60+
function bytestoint(ptr::Ptr{UInt8}, start::Int, len::Int)
6261
s = 0
63-
for (i, v) in enumerate(arr)
64-
s += v * 256^(i - 1)
62+
for i in start:start+len-1
63+
v = unsafe_load(ptr, i)
64+
s += v * 256^(i - start)
6565
end
66-
s
66+
67+
return s
6768
end
6869

6970
function stepfunc(init, func, fsym=symbol(string(func)*"_step"))
@@ -74,31 +75,25 @@ function stepfunc(init, func, fsym=symbol(string(func)*"_step"))
7475
intsize = sizeof(Int)
7576
ptrsize = sizeof(Ptr)
7677
acsize = intsize + ptrsize
77-
acarr = pointer_to_array(
78-
convert(Ptr{UInt8}, sqlite3_aggregate_context(context, acsize)),
79-
acsize,
80-
false,
81-
)
82-
# acarr will be zeroed-out if this is the first iteration
78+
acptr = convert(Ptr{UInt8}, sqlite3_aggregate_context(context, acsize))
79+
# acptr will be zeroed-out if this is the first iteration
8380
ret = ccall(
8481
:memcmp, Cint, (Ptr{UInt8}, Ptr{UInt8}, Cuint),
85-
zeros(UInt8, acsize), acarr, acsize,
82+
zeros(UInt8, acsize), acptr, acsize,
8683
)
8784
try
8885
if ret == 0
8986
acval = $(init)
90-
# TODO: i'm sure there's a better way
87+
# TODO: allocate 256 byte
9188
valsize = sizeof(sqlserialize(acval))
9289
valptr = convert(Ptr{UInt8}, c_malloc(valsize))
9390
else
94-
# retrieve the size of the serialized value (first sizeof(Int) bytes)
95-
sizebuf = zeros(UInt8, intsize)
96-
unsafe_copy!(sizebuf, 1, acarr, 1, intsize)
97-
valsize = bytestoint(sizebuf)
98-
# retrieve the ptr to the serialized value (last sizeof(Ptr) bytes)
99-
ptrbuf = zeros(UInt8, ptrsize)
100-
unsafe_copy!(ptrbuf, 1, acarr, intsize+1, ptrsize)
101-
valptr = reinterpret(Ptr{UInt8}, bytestoint(ptrbuf))
91+
# size of serialized value is first sizeof(Int) bytes
92+
valsize = bytestoint(acptr, 1, intsize)
93+
# ptr to serialized value is last sizeof(Ptr) bytes
94+
valptr = reinterpret(
95+
Ptr{UInt8}, bytestoint(acptr, intsize+1, ptrsize)
96+
)
10297
# deserialize the value pointed to by valptr
10398
acvalbuf = zeros(UInt8, valsize)
10499
unsafe_copy!(pointer(acvalbuf), valptr, valsize)
@@ -110,21 +105,24 @@ function stepfunc(init, func, fsym=symbol(string(func)*"_step"))
110105
newsize > valsize && (valptr = convert(Ptr{UInt8}, c_realloc(valptr, newsize)))
111106
# copy serialized return value
112107
unsafe_copy!(valptr, pointer(funcret), newsize)
108+
# following copies are easier with arrays
109+
acptr = pointer_to_array(acptr, acsize, false)
113110
# copy the size of the serialized value
114111
unsafe_copy!(
115-
acarr, 1,
112+
acptr, 1,
116113
reinterpret(UInt8, [newsize]), 1,
117114
intsize,
118115
)
119-
# copy the value of the pointer to the serialized value
120-
# TODO: can we just use ptrbuf here?
116+
# copy the address of the pointer to the serialized value
121117
unsafe_copy!(
122-
acarr, intsize+1,
118+
acptr, intsize+1,
123119
reinterpret(UInt8, [valptr]), 1,
124120
ptrsize,
125121
)
126122
catch
127-
# TODO: this won't catch all memory leaks so add an else clause
123+
# TODO:
124+
# this won't catch all memory leaks so add an else clause
125+
# alternatively use c-style checking in this function
128126
if isdefined(:valptr)
129127
c_free(valptr)
130128
end
@@ -140,28 +138,25 @@ function finalfunc(init, func, fsym=symbol(string(func)*"_final"))
140138
nm = isdefined(Base,fsym) ? :(Base.$fsym) : fsym
141139
return quote
142140
function $(nm)(context::Ptr{Void}, nargs::Cint, values::Ptr{Ptr{Void}})
143-
acptr = sqlite3_aggregate_context(context, 0)
141+
acptr = convert(Ptr{UInt8}, sqlite3_aggregate_context(context, 0))
144142
# step function wasn't run
145-
if acptr === C_NULL
143+
if acptr == C_NULL
146144
sqlreturn(context, $(init))
147145
else
148146
intsize = sizeof(Int)
149147
ptrsize = sizeof(Ptr)
150148
acsize = intsize + ptrsize
151-
acarr = pointer_to_array(convert(Ptr{UInt8}, acptr), acsize, false)
152149
# load size
153-
sizebuf = zeros(UInt8, intsize)
154-
unsafe_copy!(sizebuf, 1, acarr, 1, intsize)
155-
valsize = bytestoint(sizebuf)
150+
valsize = bytestoint(acptr, 1, intsize)
156151
# load ptr
157-
ptrbuf = zeros(UInt8, ptrsize)
158-
unsafe_copy!(ptrbuf, 1, acarr, intsize+1, ptrsize)
159-
valptr = reinterpret(Ptr{UInt8}, bytestoint(ptrbuf))
152+
valptr = reinterpret(
153+
Ptr{UInt8}, bytestoint(acptr, intsize+1, ptrsize)
154+
)
160155
# load value
161156
acvalbuf = zeros(UInt8, valsize)
162157
unsafe_copy!(pointer(acvalbuf), valptr, valsize)
163-
164158
acval = sqldeserialize(acvalbuf)
159+
165160
ret = $(func)(acval)
166161
c_free(valptr)
167162
sqlreturn(context, ret)

0 commit comments

Comments
 (0)