1 ////////////////////////////////////////////////////////////////////////////////
3 // Author: Andy Rushton
4 // Copyright: (c) Southampton University 1999-2004
5 // (c) Andy Rushton 2004-2009
6 // License: BSD License, see ../docs/license.html
8 ////////////////////////////////////////////////////////////////////////////////
9 #include "persistent_int.hpp"
11 ////////////////////////////////////////////////////////////////////////////////
12 // Macro for mapping either endian data onto little-endian addressing to make
13 // my life easier in writing this code! I think better in little-endian mode
14 // so the macro does nothing in that mode but maps little-endian onto
15 // big-endian addressing in big-endian mode
16 // TODO - make this compile-time configurable so it's more efficient
18 #define INDEX(index) ((context.little_endian()) ? (index) : ((bytes) - (index) - 1))
20 ////////////////////////////////////////////////////////////////////////////////
22 // format: {size}{byte}*size
25 // A major problem is that integer types may be different sizes on different
26 // machines or even with different compilers on the same machine (though I
27 // haven't come across that yet). Neither the C nor the C++ standards specify
28 // the size of integer types. Dumping an int on one machine might dump 16
29 // bits. Restoring it on another machine might try to restore 32 bits. These
30 // functions must therefore handle different type sizes. It does this by
31 // writing the size to the file as well as the data, so the restore can
32 // therefore know how many bytes to restore independent of the type size.
34 // In fact, the standard does not even specify the size of char (true! And
35 // mind-numbingly stupid...). However, to be able to do anything at all, I've
36 // had to assume that a char is 1 byte.
38 static void dump_unsigned(stlplus::dump_context
& context
, unsigned bytes
, unsigned char* data
)
39 throw(stlplus::persistent_dump_failed
)
41 // first skip zero bytes - this may reduce the data to zero bytes long
43 while(i
>= 1 && data
[INDEX(i
-1)] == 0)
45 // put the remaining size
46 context
.put((unsigned char)i
);
49 context
.put(data
[INDEX(i
)]);
52 static void dump_signed(stlplus::dump_context
& context
, unsigned bytes
, unsigned char* data
)
53 throw(stlplus::persistent_dump_failed
)
55 // first skip all-zero or all-one bytes but only if doing so does not change the sign
57 if (data
[INDEX(i
-1)] < 128)
59 // positive number so discard leading zeros but only if the following byte is positive
60 while(i
>= 2 && data
[INDEX(i
-1)] == 0 && data
[INDEX(i
-2)] < 128)
65 // negative number so discard leading ones but only if the following byte is negative
66 while(i
>= 2 && data
[INDEX(i
-1)] == 255 && data
[INDEX(i
-2)] >= 128)
69 // put the remaining size
70 context
.put((unsigned char)i
);
73 context
.put(data
[INDEX(i
)]);
76 static void restore_unsigned(stlplus::restore_context
& context
, unsigned bytes
, unsigned char* data
)
77 throw(stlplus::persistent_restore_failed
)
79 // get the dumped size from the file
80 unsigned dumped_bytes
= (unsigned)context
.get();
81 // zero fill any empty space
83 for (; i
> dumped_bytes
; i
--)
85 // restore the dumped bytes but discard any that don't fit
88 int ch
= context
.get();
90 data
[INDEX(i
)] = (unsigned char)ch
;
92 throw stlplus::persistent_restore_failed(std::string("integer overflow"));
96 static void restore_signed(stlplus::restore_context
& context
, unsigned bytes
, unsigned char* data
)
97 throw(stlplus::persistent_restore_failed
)
99 // get the dumped size from the file
100 unsigned dumped_bytes
= (unsigned)context
.get();
101 // restore the dumped bytes but discard any that don't fit
102 unsigned i
= dumped_bytes
;
105 int ch
= context
.get();
107 data
[INDEX(i
)] = (unsigned char)ch
;
109 throw stlplus::persistent_restore_failed(std::string("integer overflow"));
111 // sign extend if the dumped integer was smaller
112 if (dumped_bytes
< bytes
)
114 if (data
[INDEX(dumped_bytes
-1)] < 128)
116 // positive so zero fill
117 for (i
= dumped_bytes
; i
< bytes
; i
++)
122 // negative so one fill
123 for (i
= dumped_bytes
; i
< bytes
; i
++)
124 data
[INDEX(i
)] = 0xff;
129 ////////////////////////////////////////////////////////////////////////////////
130 // exported functions
132 // char is dumped and restored as an unsigned char because the signedness of char is not defined and can vary
133 void stlplus::dump_char(stlplus::dump_context
& context
, const char& data
) throw(stlplus::persistent_dump_failed
)
135 context
.put((unsigned char)data
);
138 void stlplus::restore_char(restore_context
& context
, char& data
) throw(stlplus::persistent_restore_failed
)
140 data
= (char)(unsigned char)context
.get();
143 void stlplus::dump_signed_char(stlplus::dump_context
& context
, const signed char& data
) throw(stlplus::persistent_dump_failed
)
145 context
.put((unsigned char)data
);
148 void stlplus::restore_signed_char(restore_context
& context
, signed char& data
) throw(stlplus::persistent_restore_failed
)
150 data
= (signed char)(unsigned char)context
.get();
153 void stlplus::dump_unsigned_char(stlplus::dump_context
& context
, const unsigned char& data
) throw(stlplus::persistent_dump_failed
)
155 context
.put((unsigned char)data
);
158 void stlplus::restore_unsigned_char(restore_context
& context
, unsigned char& data
) throw(stlplus::persistent_restore_failed
)
160 data
= (signed char)(unsigned char)context
.get();
163 void stlplus::dump_short(stlplus::dump_context
& context
, const short& data
) throw(stlplus::persistent_dump_failed
)
165 ::dump_signed(context
, sizeof(short), (unsigned char*)&data
);
168 void stlplus::restore_short(restore_context
& context
, short& data
) throw(stlplus::persistent_restore_failed
)
170 ::restore_signed(context
, sizeof(short),(unsigned char*)&data
);
173 void stlplus::dump_unsigned_short(stlplus::dump_context
& context
, const unsigned short& data
) throw(stlplus::persistent_dump_failed
)
175 ::dump_unsigned(context
, sizeof(unsigned short), (unsigned char*)&data
);
178 void stlplus::restore_unsigned_short(restore_context
& context
, unsigned short& data
) throw(stlplus::persistent_restore_failed
)
180 ::restore_unsigned(context
, sizeof(unsigned short),(unsigned char*)&data
);
183 void stlplus::dump_int(stlplus::dump_context
& context
, const int& data
) throw(stlplus::persistent_dump_failed
)
185 ::dump_signed(context
, sizeof(int), (unsigned char*)&data
);
188 void stlplus::restore_int(restore_context
& context
, int& data
) throw(stlplus::persistent_restore_failed
)
190 ::restore_signed(context
, sizeof(int),(unsigned char*)&data
);
193 void stlplus::dump_unsigned(stlplus::dump_context
& context
, const unsigned& data
) throw(stlplus::persistent_dump_failed
)
195 ::dump_unsigned(context
, sizeof(unsigned), (unsigned char*)&data
);
198 void stlplus::restore_unsigned(restore_context
& context
, unsigned& data
) throw(stlplus::persistent_restore_failed
)
200 ::restore_unsigned(context
, sizeof(unsigned),(unsigned char*)&data
);
203 void stlplus::dump_long(stlplus::dump_context
& context
, const long& data
) throw(stlplus::persistent_dump_failed
)
205 ::dump_signed(context
, sizeof(long), (unsigned char*)&data
);
208 void stlplus::restore_long(restore_context
& context
, long& data
) throw(stlplus::persistent_restore_failed
)
210 ::restore_signed(context
, sizeof(long),(unsigned char*)&data
);
213 void stlplus::dump_unsigned_long(stlplus::dump_context
& context
, const unsigned long& data
) throw(stlplus::persistent_dump_failed
)
215 ::dump_unsigned(context
, sizeof(unsigned long), (unsigned char*)&data
);
218 void stlplus::restore_unsigned_long(restore_context
& context
, unsigned long& data
) throw(stlplus::persistent_restore_failed
)
220 ::restore_unsigned(context
, sizeof(unsigned long),(unsigned char*)&data
);
223 ////////////////////////////////////////////////////////////////////////////////