]> Dogcows Code - chaz/yoink/blob - src/stlplus/persistence/persistent_int.cpp
archiving support for releases
[chaz/yoink] / src / stlplus / persistence / persistent_int.cpp
1 ////////////////////////////////////////////////////////////////////////////////
2
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
7
8 ////////////////////////////////////////////////////////////////////////////////
9 #include "persistent_int.hpp"
10
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
17
18 #define INDEX(index) ((context.little_endian()) ? (index) : ((bytes) - (index) - 1))
19
20 ////////////////////////////////////////////////////////////////////////////////
21 // Integer types
22 // format: {size}{byte}*size
23 // size can be zero!
24 //
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.
33 //
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.
37
38 static void dump_unsigned(stlplus::dump_context& context, unsigned bytes, unsigned char* data)
39 throw(stlplus::persistent_dump_failed)
40 {
41 // first skip zero bytes - this may reduce the data to zero bytes long
42 unsigned i = bytes;
43 while(i >= 1 && data[INDEX(i-1)] == 0)
44 i--;
45 // put the remaining size
46 context.put((unsigned char)i);
47 // and put the bytes
48 while(i--)
49 context.put(data[INDEX(i)]);
50 }
51
52 static void dump_signed(stlplus::dump_context& context, unsigned bytes, unsigned char* data)
53 throw(stlplus::persistent_dump_failed)
54 {
55 // first skip all-zero or all-one bytes but only if doing so does not change the sign
56 unsigned i = bytes;
57 if (data[INDEX(i-1)] < 128)
58 {
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)
61 i--;
62 }
63 else
64 {
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)
67 i--;
68 }
69 // put the remaining size
70 context.put((unsigned char)i);
71 // and put the bytes
72 while(i--)
73 context.put(data[INDEX(i)]);
74 }
75
76 static void restore_unsigned(stlplus::restore_context& context, unsigned bytes, unsigned char* data)
77 throw(stlplus::persistent_restore_failed)
78 {
79 // get the dumped size from the file
80 unsigned dumped_bytes = (unsigned)context.get();
81 // zero fill any empty space
82 unsigned i = bytes;
83 for (; i > dumped_bytes; i--)
84 data[INDEX(i-1)] = 0;
85 // restore the dumped bytes but discard any that don't fit
86 while(i--)
87 {
88 int ch = context.get();
89 if (i < bytes)
90 data[INDEX(i)] = (unsigned char)ch;
91 else
92 throw stlplus::persistent_restore_failed(std::string("integer overflow"));
93 }
94 }
95
96 static void restore_signed(stlplus::restore_context& context, unsigned bytes, unsigned char* data)
97 throw(stlplus::persistent_restore_failed)
98 {
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;
103 while(i--)
104 {
105 int ch = context.get();
106 if (i < bytes)
107 data[INDEX(i)] = (unsigned char)ch;
108 else
109 throw stlplus::persistent_restore_failed(std::string("integer overflow"));
110 }
111 // sign extend if the dumped integer was smaller
112 if (dumped_bytes < bytes)
113 {
114 if (data[INDEX(dumped_bytes-1)] < 128)
115 {
116 // positive so zero fill
117 for (i = dumped_bytes; i < bytes; i++)
118 data[INDEX(i)] = 0;
119 }
120 else
121 {
122 // negative so one fill
123 for (i = dumped_bytes; i < bytes; i++)
124 data[INDEX(i)] = 0xff;
125 }
126 }
127 }
128
129 ////////////////////////////////////////////////////////////////////////////////
130 // exported functions
131
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)
134 {
135 context.put((unsigned char)data);
136 }
137
138 void stlplus::restore_char(restore_context& context, char& data) throw(stlplus::persistent_restore_failed)
139 {
140 data = (char)(unsigned char)context.get();
141 }
142
143 void stlplus::dump_signed_char(stlplus::dump_context& context, const signed char& data) throw(stlplus::persistent_dump_failed)
144 {
145 context.put((unsigned char)data);
146 }
147
148 void stlplus::restore_signed_char(restore_context& context, signed char& data) throw(stlplus::persistent_restore_failed)
149 {
150 data = (signed char)(unsigned char)context.get();
151 }
152
153 void stlplus::dump_unsigned_char(stlplus::dump_context& context, const unsigned char& data) throw(stlplus::persistent_dump_failed)
154 {
155 context.put((unsigned char)data);
156 }
157
158 void stlplus::restore_unsigned_char(restore_context& context, unsigned char& data) throw(stlplus::persistent_restore_failed)
159 {
160 data = (signed char)(unsigned char)context.get();
161 }
162
163 void stlplus::dump_short(stlplus::dump_context& context, const short& data) throw(stlplus::persistent_dump_failed)
164 {
165 ::dump_signed(context, sizeof(short), (unsigned char*)&data);
166 }
167
168 void stlplus::restore_short(restore_context& context, short& data) throw(stlplus::persistent_restore_failed)
169 {
170 ::restore_signed(context, sizeof(short),(unsigned char*)&data);
171 }
172
173 void stlplus::dump_unsigned_short(stlplus::dump_context& context, const unsigned short& data) throw(stlplus::persistent_dump_failed)
174 {
175 ::dump_unsigned(context, sizeof(unsigned short), (unsigned char*)&data);
176 }
177
178 void stlplus::restore_unsigned_short(restore_context& context, unsigned short& data) throw(stlplus::persistent_restore_failed)
179 {
180 ::restore_unsigned(context, sizeof(unsigned short),(unsigned char*)&data);
181 }
182
183 void stlplus::dump_int(stlplus::dump_context& context, const int& data) throw(stlplus::persistent_dump_failed)
184 {
185 ::dump_signed(context, sizeof(int), (unsigned char*)&data);
186 }
187
188 void stlplus::restore_int(restore_context& context, int& data) throw(stlplus::persistent_restore_failed)
189 {
190 ::restore_signed(context, sizeof(int),(unsigned char*)&data);
191 }
192
193 void stlplus::dump_unsigned(stlplus::dump_context& context, const unsigned& data) throw(stlplus::persistent_dump_failed)
194 {
195 ::dump_unsigned(context, sizeof(unsigned), (unsigned char*)&data);
196 }
197
198 void stlplus::restore_unsigned(restore_context& context, unsigned& data) throw(stlplus::persistent_restore_failed)
199 {
200 ::restore_unsigned(context, sizeof(unsigned),(unsigned char*)&data);
201 }
202
203 void stlplus::dump_long(stlplus::dump_context& context, const long& data) throw(stlplus::persistent_dump_failed)
204 {
205 ::dump_signed(context, sizeof(long), (unsigned char*)&data);
206 }
207
208 void stlplus::restore_long(restore_context& context, long& data) throw(stlplus::persistent_restore_failed)
209 {
210 ::restore_signed(context, sizeof(long),(unsigned char*)&data);
211 }
212
213 void stlplus::dump_unsigned_long(stlplus::dump_context& context, const unsigned long& data) throw(stlplus::persistent_dump_failed)
214 {
215 ::dump_unsigned(context, sizeof(unsigned long), (unsigned char*)&data);
216 }
217
218 void stlplus::restore_unsigned_long(restore_context& context, unsigned long& data) throw(stlplus::persistent_restore_failed)
219 {
220 ::restore_unsigned(context, sizeof(unsigned long),(unsigned char*)&data);
221 }
222
223 ////////////////////////////////////////////////////////////////////////////////
This page took 0.042563 seconds and 4 git commands to generate.