COVERAGE SUMMARY
FILE SUMMARY
NameExecutedRoutines%ExecutedLines%Unexecuted
/home/matt/eu/rds/include/std/serialize.e88100.00%10812685.71%18
ROUTINE SUMMARY
RoutineExecutedLinesUnexecuted
deserialize_object()222878.57%6
serialize()172373.91%6
deserialize_file()212487.50%3
deserialize()5683.33%1
dump()7887.50%1
load()6785.71%1
get4()66100.00%0
getp4()66100.00%0
LINE COVERAGE DETAIL
#Executed
1
-- (c) Copyright - See License.txt
2
--
3
namespace serialize
4
5
--****
6
-- == Serialization of Euphoria Objects
7
--
8
-- <>
9
10
include std/convert.e
11
include std/machine.e
12
13
-- Serialized format of Euphoria objects
14
--
15
-- First byte:
16
-- 0..248 -- immediate small integer, -9 to 239
17
-- since small negative integers -9..-1 might be common
18101
constant I2B = 249, -- 2-byte signed integer follows
19101
I3B = 250, -- 3-byte signed integer follows
20101
I4B = 251, -- 4-byte signed integer follows
21101
F4B = 252, -- 4-byte f.p. number follows
22101
F8B = 253, -- 8-byte f.p. number follows
23101
S1B = 254, -- sequence, 1-byte length follows, then elements
24101
S4B = 255 -- sequence, 4-byte length follows, then elements
25
26101
constant MIN1B = -9,
27101
MAX1B = 239,
28101
MIN2B = -power(2, 15),
29101
MAX2B = power(2, 15)-1,
30101
MIN3B = -power(2, 23),
31101
MAX3B = power(2, 23)-1,
32101
MIN4B = -power(2, 31)
33
34
atom mem0, mem1, mem2, mem3
35101
mem0 = allocate(4)
36101
mem1 = mem0 + 1
37101
mem2 = mem0 + 2
38101
mem3 = mem0 + 3
39
404
41
-- read 4-byte value at current position in database file
424
poke(mem0, getc(fh))
434
poke(mem1, getc(fh))
444
poke(mem2, getc(fh))
454
poke(mem3, getc(fh))
464
return peek4u(mem0)
47
end function
48
49187
50
-- read a serialized Euphoria object from disk
51
52
sequence s
53
atom len
54
55187
if c = 0 then
5621
c = getc(fh)
5721
if c < I2B then
580
return c + MIN1B
59
end if
60
end if
61
62187
switch c with fallthru do
63
case I2B then
6448
return getc(fh) +
65
#100 * getc(fh) +
66
MIN2B
67
68
case I3B then
690
return getc(fh) +
70
#100 * getc(fh) +
71
#10000 * getc(fh) +
72
MIN3B
73
74
case I4B then
753
return get4(fh) + MIN4B
76
77
case F4B then
780
return float32_to_atom({getc(fh), getc(fh),
79
getc(fh), getc(fh)})
80
81
case F8B then
829
return float64_to_atom({getc(fh), getc(fh),
83
getc(fh), getc(fh),
84
getc(fh), getc(fh),
85
getc(fh), getc(fh)})
86
87
case else
88
-- sequence
89127
if c = S1B then
90126
len = getc(fh)
91
else
921
len = get4(fh)
93
end if
94127
if len < 0 or not integer(len) then
951
return 0
96
end if
97126
s = repeat(0, len)
98126
for i = 1 to len do
99
-- in-line small integer for greater speed on strings
1001029
c = getc(fh)
1011029
if c < I2B then
102863
s[i] = c + MIN1B
103
else
104166
s[i] = deserialize_file(fh, c)
105
end if
1061029
end for
107126
return s
108
end switch
109
end function
110
1112
1122
poke(mem0, sdata[pos+0])
1132
poke(mem1, sdata[pos+1])
1142
poke(mem2, sdata[pos+2])
1152
poke(mem3, sdata[pos+3])
1162
return peek4u(mem0)
117
end function
118
11911
120
-- read a serialized Euphoria object from a sequence
121
122
sequence s
123
integer len
124
12511
if c = 0 then
1266
c = sdata[pos]
1276
pos += 1
1286
if c < I2B then
1290
return {c + MIN1B, pos}
130
end if
131
end if
132
13311
switch c with fallthru do
134
case I2B then
1350
return {sdata[pos] +
136
#100 * sdata[pos+1] +
137
MIN2B, pos + 2}
138
139
case I3B then
1400
return {sdata[pos] +
141
#100 * sdata[pos+1] +
142
#10000 * sdata[pos+2] +
143
MIN3B, pos + 3}
144
145
case I4B then
1462
return {getp4(sdata, pos) + MIN4B, pos + 4}
147
148
case F4B then
1490
return {float32_to_atom({sdata[pos], sdata[pos+1],
150
sdata[pos+2], sdata[pos+3]}), pos + 4}
151
152
case F8B then
1532
return {float64_to_atom({sdata[pos], sdata[pos+1],
154
sdata[pos+2], sdata[pos+3],
155
sdata[pos+4], sdata[pos+5],
156
sdata[pos+6], sdata[pos+7]}), pos + 8}
157
158
case else
159
-- sequence
1607
if c = S1B then
1617
len = sdata[pos]
1627
pos += 1
163
else
1640
len = getp4(sdata, pos)
1650
pos += 4
166
end if
1677
s = repeat(0, len)
1687
for i = 1 to len do
169
-- in-line small integer for greater speed on strings
17081
c = sdata[pos]
17181
pos += 1
17281
if c < I2B then
17376
s[i] = c + MIN1B
174
else
1755
sequence temp = deserialize_object(sdata, pos, c)
1765
s[i] = temp[1]
1775
pos = temp[2]
178
end if
17981
end for
1807
return {s, pos}
181
end switch
182
end function
183
184
--****
185
-- === Routines
186
187
--**
188
-- Convert a serialized object in to a standard Euphoria object.
189
--
190
-- Parameters:
191
-- # ##sdata## : either a sequence containing one or more concatenated serialized objects or
192
-- an open file handle. If this is a file handle, the current position in the
193
-- file is assumed to be at a serialized object in the file.
194
-- # ##pos## : optional index into ##sdata##. If omitted 1 is assumed. The index must
195
-- point to the start of a serialized object.
196
--
197
-- Returns:
198
-- The return **value**, depends on the input type.
199
-- * If ##sdata## is a file handle then
200
-- this function returns a Euphoria object that had been stored in the file, and
201
-- moves the current file to the first byte after the stored object.
202
-- * If ##sdata## is a sequence then this returns a two-element sequence.
203
-- The //first// element is the Euphoria object that corresponds to the serialized
204
-- object that begins at index ##pos##, and the //second// element is the index
205
-- position in the input parameter just after the serialized object.
206
--
207
--
208
-- Comments:
209
-- A serialized object is one that has been returned from the [[:serialize]] function.
210
--
211
-- Example 1:
212
--
213
-- sequence objcache
214
-- objcache = serialize(FirstName) &
215
-- serialize(LastName) &
216
-- serialize(PhoneNumber) &
217
-- serialize(Address)
218
--
219
-- sequence res
220
-- integer pos = 1
221
-- res = deserialize( objcache , pos)
222
-- FirstName = res[1] pos = res[2]
223
-- res = deserialize( objcache , pos)
224
-- LastName = res[1] pos = res[2]
225
-- res = deserialize( objcache , pos)
226
-- PhoneNumber = res[1] pos = res[2]
227
-- res = deserialize( objcache , pos)
228
-- Address = res[1] pos = res[2]
229
--
230
--
231
-- Example 2:
232
--
233
-- sequence objcache
234
-- objcache = serialize({FirstName,
235
-- LastName,
236
-- PhoneNumber,
237
-- Address})
238
--
239
-- sequence res
240
-- res = deserialize( objcache )
241
-- FirstName = res[1][1]
242
-- LastName = res[1][2]
243
-- PhoneNumber = res[1][3]
244
-- Address = res[1][4]
245
--
246
--
247
-- Example 3:
248
--
249
-- integer fh
250
-- fh = open("cust.dat", "wb")
251
-- puts(fh, serialize(FirstName))
252
-- puts(fh, serialize(LastName))
253
-- puts(fh, serialize(PhoneNumber))
254
-- puts(fh, serialize(Address))
255
-- close(fh)
256
--
257
-- fh = open("cust.dat", "rb")
258
-- FirstName = deserialize(fh)
259
-- LastName = deserialize(fh)
260
-- PhoneNumber = deserialize(fh)
261
-- Address = deserialize(fh)
262
-- close(fh)
263
--
264
--
265
-- Example 4:
266
--
267
-- integer fh
268
-- fh = open("cust.dat", "wb")
269
-- puts(fh, serialize({FirstName,
270
-- LastName,
271
-- PhoneNumber,
272
-- Address}))
273
-- close(fh)
274
--
275
-- sequence res
276
-- fh = open("cust.dat", "rb")
277
-- res = deserialize(fh)
278
-- close(fh)
279
-- FirstName = res[1]
280
-- LastName = res[2]
281
-- PhoneNumber = res[3]
282
-- Address = res[4]
283
--
284
--
285
28627
287
-- read a serialized Euphoria object
288
28927
if integer(sdata) then
29021
return deserialize_file(sdata, 0)
291
end if
292
2936
if atom(sdata) then
2940
return 0
295
end if
296
2976
return deserialize_object(sdata, pos, 0)
298
299
end function
300
301
--**
302
-- Convert a standard Euphoria object in to a serialized version of it.
303
--
304
-- Parameters:
305
-- # ##euobj## : any Euphoria object.
306
--
307
-- Returns:
308
-- A **sequence**, this is the serialized version of the input object.
309
--
310
-- Comments:
311
-- A serialized object is one that has been converted to a set of byte values. This
312
-- can then by written directly out to a file for storage.
313
--
314
-- You can use the [[:deserialize]] function to convert it back into a standard
315
-- Euphoria object.
316
--
317
-- Example 1:
318
--
319
-- integer fh
320
-- fh = open("cust.dat", "wb")
321
-- puts(fh, serialize(FirstName))
322
-- puts(fh, serialize(LastName))
323
-- puts(fh, serialize(PhoneNumber))
324
-- puts(fh, serialize(Address))
325
-- close(fh)
326
--
327
-- fh = open("cust.dat", "rb")
328
-- FirstName = deserialize(fh)
329
-- LastName = deserialize(fh)
330
-- PhoneNumber = deserialize(fh)
331
-- Address = deserialize(fh)
332
-- close(fh)
333
--
334
--
335
-- Example 2:
336
--
337
-- integer fh
338
-- fh = open("cust.dat", "wb")
339
-- puts(fh, serialize({FirstName,
340
-- LastName,
341
-- PhoneNumber,
342
-- Address}))
343
-- close(fh)
344
--
345
-- sequence res
346
-- fh = open("cust.dat", "rb")
347
-- res = deserialize(fh)
348
-- close(fh)
349
-- FirstName = res[1]
350
-- LastName = res[2]
351
-- PhoneNumber = res[3]
352
-- Address = res[4]
353
--
354
--
355730
356
-- return the serialized representation of a Euphoria object
357
-- as a sequence of bytes
358
sequence x4, s
359
360730
if integer(x) then
361628
if x >= MIN1B and x <= MAX1B then
362623
return {x - MIN1B}
363
3645
elsif x >= MIN2B and x <= MAX2B then
3650
x -= MIN2B
3660
return {I2B, and_bits(x, #FF), floor(x / #100)}
367
3685
elsif x >= MIN3B and x <= MAX3B then
3690
x -= MIN3B
3700
return {I3B, and_bits(x, #FF), and_bits(floor(x / #100), #FF), floor(x / #10000)}
371
372
else
3735
return I4B & int_to_bytes(x-MIN4B)
374
375
end if
376
377102
elsif atom(x) then
378
-- floating point
37911
x4 = atom_to_float32(x)
38011
if x = float32_to_atom(x4) then
381
-- can represent as 4-byte float
3820
return F4B & x4
383
else
38411
return F8B & atom_to_float64(x)
385
end if
386
387
else
388
-- sequence
38991
if length(x) <= 255 then
39091
s = {S1B, length(x)}
391
else
3920
s = S4B & int_to_bytes(length(x))
393
end if
39491
for i = 1 to length(x) do
395708
s &= serialize(x[i])
396708
end for
39791
return s
398
end if
399
end function
400
401
--**
402
-- Saves a Euphoria object to disk in a binary format.
403
--
404
-- Parameters:
405
-- # ##data## : any Euphoria object.
406
-- # ##filename## : the name of the file to save it to.
407
--
408
-- Returns:
409
-- An **integer**, 0 if the function fails, otherwise the number of bytes in the
410
-- created file.
411
--
412
-- Comments:
413
-- If the named file doesn't exist it is created, otherwise it is overwritten.
414
--
415
-- You can use the [[:load]] function to recover the data from the file.
416
--
417
-- Example :
418
--
419
-- include std/serialize.e
420
-- integer size = dump(myData, theFileName)
421
-- if size = 0 then
422
-- puts(1, "Failed to save data to file\n")
423
-- else
424
-- printf(1, "Saved file is %d bytes long\n", size)
425
-- end if
426
--
427
--
4281
429
integer fh
430
sequence sdata
431
4321
fh = open(filename, "wb")
4331
if fh < 0 then
4340
return 0
435
end if
436
4371
sdata = serialize(data)
4381
puts(fh, sdata)
439
4401
close(fh)
441
4421
return length(sdata) -- Length is always > 0
443
end function
444
445
--**
446
-- Restores a Euphoria object that has been saved to disk by [[:dump]].
447
--
448
-- Parameters:
449
-- # ##filename## : the name of the file to restore it from.
450
--
451
-- Returns:
452
-- A **sequence**, the first element is the result code. If the result code is 0
453
-- then it means that the function failed, otherwise the restored data is in the
454
-- second element.
455
--
456
-- Comments:
457
-- This is used to load back data from a file created by the [[:dump]]
458
-- function.
459
--
460
-- Example :
461
--
462
-- include std/serialize.e
463
-- sequence mydata = load(theFileName)
464
-- if mydata[1] = 0 then
465
-- puts(1, "Failed to load data from file\n")
466
-- else
467
-- mydata = mydata[2] -- Restored data is in second element.
468
-- end if
469
--
470
--
4711
472
integer fh
473
sequence sdata
474
4751
fh = open(filename, "rb")
4761
if fh < 0 then
4770
return {0}
478
end if
479
4801
sdata = deserialize(fh)
481
4821
close(fh)
4831
return {1, sdata}
484
end function