RDKit
Open-source cheminformatics and machine learning.
StreamOps.h
Go to the documentation of this file.
1 //
2 // Copyright (C) 2002-2008 Greg Landrum and Rational Discovery LLC
3 //
4 // @@ All Rights Reserved @@
5 // This file is part of the RDKit.
6 // The contents are covered by the terms of the BSD license
7 // which is included in the file license.txt, found at the root
8 // of the RDKit source tree.
9 //
10 //
11 #ifndef _RD_STREAMOPS_H
12 #define _RD_STREAMOPS_H
13 
14 #include "types.h"
15 #include <string>
16 #include <sstream>
17 #include <iostream>
18 #include <boost/cstdint.hpp>
19 #include <boost/detail/endian.hpp>
20 
21 namespace RDKit{
22  // this code block for handling endian problems is from :
23  // http://stackoverflow.com/questions/105252/how-do-i-convert-between-big-endian-and-little-endian-values-in-c
24  enum EEndian
25  {
28 #if defined(BOOST_LITTLE_ENDIAN)
29  HOST_ENDIAN_ORDER = LITTLE_ENDIAN_ORDER
30 #elif defined(BOOST_BIG_ENDIAN)
31  HOST_ENDIAN_ORDER = BIG_ENDIAN_ORDER
32 #else
33 #error "Failed to determine the system endian value"
34 #endif
35  };
36 
37  // this function swap the bytes of values given it's size as a template
38  // parameter (could sizeof be used?).
39  template <class T, unsigned int size>
40  inline T SwapBytes(T value)
41  {
42  union
43  {
44  T value;
45  char bytes[size];
46  } in, out;
47 
48  in.value = value;
49 
50  for (unsigned int i = 0; i < size / 2; ++i)
51  {
52  out.bytes[i] = in.bytes[size - 1 - i];
53  out.bytes[size - 1 - i] = in.bytes[i];
54  }
55 
56  return out.value;
57  }
58 
59  // Here is the function you will use. Again there is two compile-time assertion
60  // that use the boost librarie. You could probably comment them out, but if you
61  // do be cautious not to use this function for anything else than integers
62  // types. This function need to be calles like this :
63  //
64  // int x = someValue;
65  // int i = EndianSwapBytes<HOST_ENDIAN_ORDER, BIG_ENDIAN_ORDER>(x);
66  //
67  template<EEndian from, EEndian to, class T>
68  inline T EndianSwapBytes(T value)
69  {
70  // A : La donnée à swapper à une taille de 2, 4 ou 8 octets
71  BOOST_STATIC_ASSERT(sizeof(T)==1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8);
72  if(sizeof(T)==1) return value;
73 
74  // A : La donnée à swapper est d'un type arithmetic
75  //BOOST_STATIC_ASSERT(boost::is_arithmetic<T>::value);
76 
77  // Si from et to sont du même type on ne swap pas.
78  if (from == to)
79  return value;
80 
81  return SwapBytes<T, sizeof(T)>(value);
82  }
83  template<EEndian from, EEndian to>
84  inline char EndianSwapBytes(char value)
85  {
86  return value;
87  }
88  template<EEndian from, EEndian to>
89  inline unsigned char EndianSwapBytes(unsigned char value)
90  {
91  return value;
92  }
93  template<EEndian from, EEndian to>
94  inline signed char EndianSwapBytes(signed char value)
95  {
96  return value;
97  }
98  // --------------------------------------
99 
100  //! Packs an integer and outputs it to a stream
101  inline void appendPackedIntToStream(std::stringstream &ss, boost::uint32_t num) {
102  int nbytes, bix;
103  unsigned int val, res;
104  char tc;
105 
106  CHECK_INVARIANT(num >= 0, "");
107  res=num;
108  while (1) {
109  if (res < (1<<7)) {
110  val = (res<<1);
111  nbytes = 1;
112  break;
113  }
114  res -= (1<<7);
115  if (res < (1<<14)) {
116  val = ((res<<2) | 1);
117  nbytes = 2;
118  break;
119  }
120  res -= (1<<14);
121  if (res < (1<<21)) {
122  val = ((res<<3) | 3);
123  nbytes = 3;
124  break;
125  }
126  res -= (1<<21);
127  if ( res < (1<<29)) {
128  val = ((res<<3) | 7);
129  nbytes = 4;
130  break;
131  }
132  else {
133  CHECK_INVARIANT(0, "ERROR: Integer too big to pack\n");
134  }
135  }
136  //val = EndianSwapBytes<HOST_ENDIAN_ORDER,LITTLE_ENDIAN_ORDER>(val);
137 
138  for (bix = 0; bix < nbytes; bix++) {
139  tc = (char) (val & 255);
140  ss.write(&tc, 1);
141  val >>= 8;
142  }
143  }
144 
145  //! Reads an integer from a stream in packed format and returns the result.
146  inline boost::uint32_t readPackedIntFromStream(std::stringstream &ss) {
147  boost::uint32_t val, num;
148  int shift, offset;
149  char tmp;
150  ss.read(&tmp, sizeof(tmp));
151  val = UCHAR(tmp);
152  offset = 0;
153  if ((val&1) == 0) {
154  shift = 1;
155  }
156  else if ((val&3) == 1) {
157  ss.read((char *)&tmp, sizeof(tmp));
158  val |= (UCHAR(tmp) << 8);
159  shift = 2;
160  offset = (1<<7);
161  }
162  else if ((val&7) == 3) {
163  ss.read((char *)&tmp, sizeof(tmp));
164  val |= (UCHAR(tmp) << 8);
165  ss.read((char *)&tmp, sizeof(tmp));
166  val |= (UCHAR(tmp) << 16);
167  shift = 3;
168  offset = (1<<7) + (1<<14);
169  }
170  else {
171  ss.read((char *)&tmp, sizeof(tmp));
172  val |= (UCHAR(tmp) << 8);
173  ss.read((char *)&tmp, sizeof(tmp));
174  val |= (UCHAR(tmp) << 16);
175  ss.read((char *)&tmp, sizeof(tmp));
176  val |= (UCHAR(tmp) << 24);
177  shift = 3;
178  offset = (1<<7) + (1<<14) + (1<<21);
179  }
180  num = (val >> shift) + offset;
181  //num = EndianSwapBytes<LITTLE_ENDIAN_ORDER,HOST_ENDIAN_ORDER>(num);
182  return num;
183  }
184 
185  //! Reads an integer from a char * in packed format and returns the result.
186  //! The argument is advanced
187  inline boost::uint32_t pullPackedIntFromString(const char *&text) {
188  boost::uint32_t val, num;
189  int shift, offset;
190  char tmp;
191  tmp = *text;
192  text++;
193  val = UCHAR(tmp);
194  offset = 0;
195  if ((val&1) == 0) {
196  shift = 1;
197  }
198  else if ((val&3) == 1) {
199  tmp = *text;
200  text++;
201  val |= (UCHAR(tmp) << 8);
202  shift = 2;
203  offset = (1<<7);
204  }
205  else if ((val&7) == 3) {
206  tmp = *text;
207  text++;
208  val |= (UCHAR(tmp) << 8);
209  tmp = *text;
210  text++;
211  val |= (UCHAR(tmp) << 16);
212  shift = 3;
213  offset = (1<<7) + (1<<14);
214  }
215  else {
216  tmp = *text;
217  text++;
218  val |= (UCHAR(tmp) << 8);
219  tmp = *text;
220  text++;
221  val |= (UCHAR(tmp) << 16);
222  tmp = *text;
223  text++;
224  val |= (UCHAR(tmp) << 24);
225  shift = 3;
226  offset = (1<<7) + (1<<14) + (1<<21);
227  }
228  num = (val >> shift) + offset;
229  //num = EndianSwapBytes<LITTLE_ENDIAN_ORDER,HOST_ENDIAN_ORDER>(num);
230  return num;
231  }
232 
233  //! does a binary write of an object to a stream
234  template <typename T>
235  void streamWrite(std::ostream &ss,const T &val){
236  T tval=EndianSwapBytes<HOST_ENDIAN_ORDER,LITTLE_ENDIAN_ORDER>(val);
237  ss.write((const char *)&tval,sizeof(T));
238  }
239  //! does a binary read of an object from a stream
240  template <typename T>
241  void streamRead(std::istream &ss,T &loc){
242  T tloc;
243  ss.read((char *)&tloc,sizeof(T));
244  loc = EndianSwapBytes<LITTLE_ENDIAN_ORDER,HOST_ENDIAN_ORDER>(tloc);
245  }
246 
247  //! grabs the next line from an instream and returns it.
248  inline std::string getLine(std::istream *inStream) {
249  std::string res;
250  std::getline(*inStream,res);
251  if ((res.length() > 0) && (res[res.length()-1]=='\r')){
252  res.erase(res.length()-1);
253  }
254  return res;
255  }
256  //! grabs the next line from an instream and returns it.
257  inline std::string getLine(std::istream &inStream) {
258  return getLine(&inStream);
259  }
260 }
261 
262 
263 
264 #endif
T EndianSwapBytes(T value)
Definition: StreamOps.h:68
#define CHECK_INVARIANT(expr, mess)
Definition: Invariant.h:114
unsigned char UCHAR
Definition: types.h:144
EEndian
Definition: StreamOps.h:24
void streamRead(std::istream &ss, T &loc)
does a binary read of an object from a stream
Definition: StreamOps.h:241
boost::uint32_t readPackedIntFromStream(std::stringstream &ss)
Reads an integer from a stream in packed format and returns the result.
Definition: StreamOps.h:146
boost::uint32_t pullPackedIntFromString(const char *&text)
Definition: StreamOps.h:187
T SwapBytes(T value)
Definition: StreamOps.h:40
Includes a bunch of functionality for handling Atom and Bond queries.
Definition: Atom.h:28
void streamWrite(std::ostream &ss, const T &val)
does a binary write of an object to a stream
Definition: StreamOps.h:235
std::string getLine(std::istream *inStream)
grabs the next line from an instream and returns it.
Definition: StreamOps.h:248
void appendPackedIntToStream(std::stringstream &ss, boost::uint32_t num)
Packs an integer and outputs it to a stream.
Definition: StreamOps.h:101