root/trunk/whisperlib/common/io/num_streaming.h

Revision 7, 10.1 kB (checked in by whispercastorg, 2 years ago)

version 0.2.0

Line 
1 // Copyright (c) 2009, Whispersoft s.r.l.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Whispersoft s.r.l. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 //
30 // Author: Cosmin Tudorache & Catalin Popescu
31 //
32 // This contains utility functions for straming numbers
33 //  (in your given endianess)
34 //
35 #ifndef __COMMON_IO_NUM_STREAMING_H__
36 #define __COMMON_IO_NUM_STREAMING_H__
37
38 #include <algorithm>
39 #include <whisperlib/common/io/output_stream.h>
40 #include <whisperlib/common/io/input_stream.h>
41 #include <whisperlib/common/base/system.h>
42 #include <whisperlib/common/base/log.h>
43
44 namespace io {
45
46 template<class R, class W>
47 class BaseNumStreamer {
48  private:
49   struct uint24 {
50     uint8 data0_;
51     uint8 data1_;
52     uint8 data2_;
53     uint24() : data0_(0), data1_(0), data2_(0) {
54     }
55 #   if __BYTE_ORDER == __LITTLE_ENDIAN
56     explicit uint24(int32 x)
57         : data0_(x),
58           data1_(x >> 8),
59           data2_(x >> 16) {
60     }
61 #   elif __BYTE_ORDER == __BIG_ENDIAN
62     explicit uint24(int32 x)
63         : data0_((x >> 16) & 0xFF),
64           data1_((x >> 8) & 0xFF),
65           data2_(x & 0xFF) {
66     }
67 #   endif
68     operator int32() const {
69       return (data0_ +
70               (static_cast<int32>(data1_) << 8) +
71               (static_cast<int32>(data2_) << 16));
72     }
73     operator uint32() const {
74       return (data0_ +
75               (static_cast<uint32>(data1_) << 8) +
76               (static_cast<uint32>(data2_) << 16));
77     }
78   };
79  public:
80   template<typename N> static void SwapBytes(N* data) {
81     uint8* p1 = reinterpret_cast<uint8*>(data);
82     uint8* p2 = p1 + sizeof(*data) - 1;
83     while ( p1 < p2 ) {
84       swap(*p1++, *p2--);
85     }
86   }
87
88   // max size of numbers that we can read / write
89   static const size_t kMaxSize = sizeof(uint64);
90
91  public:
92   //////////////////////////////////////////////////////////////////////
93   //
94   // Input streaming -- by default we use the stream default endianess
95   //
96   template<typename N> static N ReadNumber(R* is,
97                                            common::ByteOrder order) {
98     COMPILE_ASSERT(sizeof(N) <= kMaxSize, size_too_big_for_ReadNumber);
99     N result;
100     int32 i = is->Read(&result, sizeof(N));
101     CHECK_EQ(sizeof(N), i) << sizeof(N) << " vs. " << i;
102     if ( order == common::UNKNOWNENDIAN ) {
103       if ( common::kByteOrder != is->byte_order() ) {
104         SwapBytes(&result);
105       }
106     } else {
107       if ( common::kByteOrder != order ) {
108         SwapBytes(&result);
109       }
110     }
111     return result;
112   }
113
114   // Pops a single byte from the buffer. If the stream is empty, it returns 0.
115   // The number of bytes read are written in "bytes_read" if not NULL.
116   static uint8 ReadByte(R* is,
117                         common::ByteOrder order = common::UNKNOWNENDIAN) {
118     return ReadNumber<uint8>(is, order);
119   }
120   // Functions for poping various number types from the stream (written in
121   // the given byteorder)
122   static int16 ReadInt16(R* is,
123                          common::ByteOrder order = common::UNKNOWNENDIAN) {
124     return ReadNumber<int16>(is, order);
125   }
126   static uint16 ReadUInt16(R* is,
127                            common::ByteOrder order = common::UNKNOWNENDIAN) {
128     return ReadNumber<uint16>(is, order);
129   }
130   static uint32 ReadUInt24(R* is,
131                            common::ByteOrder order = common::UNKNOWNENDIAN) {
132     return static_cast<uint32>(ReadNumber<uint24>(is, order));
133   }
134   static int32 ReadInt32(R* is,
135                          common::ByteOrder order = common::UNKNOWNENDIAN) {
136     return ReadNumber<int32>(is, order);
137   }
138   static uint32 ReadUInt32(R* is,
139                            common::ByteOrder order = common::UNKNOWNENDIAN) {
140     return ReadNumber<uint32>(is, order);
141   }
142   static int64 ReadInt64(R* is,
143                          common::ByteOrder order = common::UNKNOWNENDIAN) {
144     return ReadNumber<int64>(is, order);
145   }
146   static uint64 ReadUInt64(R* is,
147                           common::ByteOrder order = common::UNKNOWNENDIAN) {
148     return ReadNumber<uint64>(is, order);
149   }
150   static float ReadFloat(R* is,
151                          common::ByteOrder order = common::UNKNOWNENDIAN) {
152     return ReadNumber<float>(is, order);
153   }
154   static double ReadDouble(R* is,
155                            common::ByteOrder order = common::UNKNOWNENDIAN) {
156     return ReadNumber<double>(is, order);
157   }
158
159
160   //////////////////////////////////////////////////////////////////////
161   //
162   // Output streaming -- by default we use the stream default endianess
163   //
164   template<typename N> static int32 WriteNumber(W* os, N data,
165                                                 common::ByteOrder order) {
166     // COMPILE_CHECK(sizeof(data) <= kMaxSize);
167     if ( order == common::UNKNOWNENDIAN ) {
168       if ( common::kByteOrder != os->byte_order() ) {
169         SwapBytes(&data);
170       }
171     } else {
172       if ( common::kByteOrder != order ) {
173         SwapBytes(&data);
174       }
175     }
176     return os->Write(&data, sizeof(data));
177   }
178
179   // Functions for writing various number types to the stream.
180   static int32 WriteByte(W* os, uint8 byte,
181                          common::ByteOrder order = common::UNKNOWNENDIAN) {
182     return WriteNumber(os, byte, order);
183   }
184   static int32 WriteInt16(W* os, int16 data,
185                           common::ByteOrder order = common::UNKNOWNENDIAN) {
186     return WriteNumber<int16>(os, data, order);
187   }
188   static int32 WriteUInt16(W* os, uint16 data,
189                            common::ByteOrder order = common::UNKNOWNENDIAN) {
190     return WriteNumber<uint16>(os, data, order);
191   }
192   static int32 WriteUInt24(W* os, int32 data,
193                            common::ByteOrder order = common::UNKNOWNENDIAN) {
194     return WriteNumber<uint24>(os, uint24(data), order);
195   }
196   static int32 WriteInt32(W* os, int32 data,
197                           common::ByteOrder order = common::UNKNOWNENDIAN) {
198     return WriteNumber<int32>(os, data, order);
199   }
200   static int32 WriteUInt32(W* os, uint32 data,
201                            common::ByteOrder order = common::UNKNOWNENDIAN) {
202     return WriteNumber<uint32>(os, data, order);
203   }
204   static int32 WriteInt64(W* os, int64 data,
205                           common::ByteOrder order = common::UNKNOWNENDIAN) {
206     return WriteNumber<int64>(os, data, order);
207   }
208   static int32 WriteUInt64(W* os, uint64 data,
209                            common::ByteOrder order = common::UNKNOWNENDIAN) {
210     return WriteNumber<uint64>(os, data, order);
211   }
212   static int32 WriteFloat(W* os, float data,
213                           common::ByteOrder order = common::UNKNOWNENDIAN) {
214     return WriteNumber<float>(os, data, order);
215   }
216   static int32 WriteDouble(W* os, double data,
217                            common::ByteOrder order = common::UNKNOWNENDIAN) {
218     return WriteNumber<double>(os, data, order);
219   }
220
221  private:
222   DISALLOW_EVIL_CONSTRUCTORS(BaseNumStreamer);
223 };
224 typedef BaseNumStreamer<InputStream, OutputStream> IONumStreamer;
225
226 class BitArray {
227 public:
228   BitArray();
229   virtual ~BitArray();
230
231   // Use an external data buffer.
232   void Wrap(const void* data, uint32 size);
233   // Make an internal copy of the data buffer.
234   void Put(const void* data, uint32 size);
235
236   // Read next 'bit_count' bits, and assemble them as a T number.
237   // e.g. If current data_ contains: "01010000.."
238   //      and bit_count = 4, and T = uint8 => returns: 0x05
239   // e.g. If current data_ contains: "0101000110.."
240   //      and bit_count = 10, and T = uint16 => returns: 0x0146
241   template <typename T>
242   T Peek(uint32 bit_count) {
243     T t = 0;
244
245     CHECK( bit_count <= sizeof(T) * 8 )
246       << "bit_count: " << bit_count << " is bigger than return"
247          " type size: " << sizeof(T) << " bytes";
248     CHECK( bit_count <= Size() ) << "Not enough data, bit_count: " << bit_count
249                                  << ", available bits: " << Size();
250
251     uint32 bit_index = sizeof(T) * 8 - bit_count;
252     bit_index = (bit_index / 8) * 8 + (7 - (bit_index % 8));
253
254     BitCopy(data_ + head_, head_bit_, &t, bit_index, bit_count);
255
256     if ( common::kByteOrder == common::LILENDIAN ) {
257       BaseNumStreamer<void, void>::SwapBytes(&t);
258     }
259
260     return t;
261   }
262   template <typename T>
263   T Read(uint32 bit_count) {
264     T t = Peek<T>(bit_count);
265     Skip(bit_count);
266     return t;
267   }
268
269   void Skip(uint32 bit_count);
270
271   // returns the number of available bits
272   uint32 Size();
273
274   // src_bit_index: 7 - is the first bit in '*src' (MSB)
275   //                0 - is the last bit in '*src'  (LSB)
276   // If you want to copy src right from the begining, use src_bit_index: 7.
277   static void BitCopy(const void* void_src, uint32 src_bit_index,
278                       void* void_dst, uint32 dst_bit_index,
279                       uint32 bit_count);
280
281 private:
282   const uint8* data_;
283   uint32 data_size_;
284
285   // true if we own the "data_" buffer
286   bool data_owned_;
287
288   // current byte index inside "data_"
289   uint32 head_;
290   // bit index inside current byte (i.e. inside data_[head_])
291   uint32 head_bit_; // [7..0] . 7 is MSB, 0 is LSB
292 };
293 } // namespace io
294
295 #endif  // __COMMON_IO_NUM_STREAMING_H__
Note: See TracBrowser for help on using the browser.