Disk ARchive  2.4.2
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups
limitint.hpp
Go to the documentation of this file.
1 /*********************************************************************/
2 // dar - disk archive - a backup/restoration program
3 // Copyright (C) 2002-2052 Denis Corbin
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
18 //
19 // to contact the author : http://dar.linux.free.fr/email.html
20 /*********************************************************************/
21 // $Id: limitint.hpp,v 1.38 2011/03/20 21:02:50 edrusb Rel $
22 //
23 /*********************************************************************/
24 
33 
34 
35 #ifndef LIMITINT_HPP
36 #define LIMITINT_HPP
37 
38 #include "../my_config.h"
39 
40 extern "C"
41 {
42 #if HAVE_SYS_TYPES_H
43 #include <sys/types.h>
44 #endif
45 
46 #if HAVE_UNISTD_H
47 #include <unistd.h>
48 #endif
49 
50 #if HAVE_STRING_H
51 #include <string.h>
52 #endif
53 
54 #if HAVE_STRINGS_H
55 #include <strings.h>
56 #endif
57 } // end extern "C"
58 
59 #include <typeinfo>
60 #include "integers.hpp"
61 #include "erreurs.hpp"
62 #include "special_alloc.hpp"
63 #include "int_tools.hpp"
64 
65 
66 #define ZEROED_SIZE 50
67 
68 namespace libdar
69 {
70 
73 
74 
75  class generic_file;
76  class user_interaction;
77 
89 
90  template<class B> class limitint
91  {
92  public :
93 
94 #if SIZEOF_OFF_T > SIZEOF_TIME_T
95 #if SIZEOF_OFF_T > SIZEOF_SIZE_T
96  limitint(off_t a = 0)
97  { E_BEGIN; limitint_from(a); E_END("limitint::limitint", "off_t"); };
98 #else
99  limitint(size_t a = 0)
100  { E_BEGIN; limitint_from(a); E_END("limitint::limitint", "size_t"); };
101 #endif
102 #else
103 #if SIZEOF_TIME_T > SIZEOF_SIZE_T
104  limitint(time_t a = 0)
105  { E_BEGIN; limitint_from(a); E_END("limitint::limitint", "time_t"); };
106 #else
107  limitint(size_t a = 0)
108  { E_BEGIN; limitint_from(a); E_END("limitint::limitint", "size_t"); };
109 #endif
110 #endif
111 
112  // read an limitint from a file
113  limitint(user_interaction & dialog, S_I fd);
114  limitint(generic_file & x);
115 
116  void dump(user_interaction & dialog, S_I fd) const; // write byte sequence to file
117  void dump(generic_file &x) const; // write byte sequence to file
118  void read(generic_file &f) { build_from_file(f); };
119 
120  limitint & operator += (const limitint & ref);
121  limitint & operator -= (const limitint & ref);
122  limitint & operator *= (const limitint & ref);
123  template <class T> limitint power(const T & exponent) const;
124  limitint & operator /= (const limitint & ref);
125  limitint & operator %= (const limitint & ref);
126  limitint & operator &= (const limitint & ref);
127  limitint & operator |= (const limitint & ref);
128  limitint & operator ^= (const limitint & ref);
129  limitint & operator >>= (U_32 bit);
130  limitint & operator >>= (limitint bit);
131  limitint & operator <<= (U_32 bit);
132  limitint & operator <<= (limitint bit);
133  limitint operator ++(int a)
134  { E_BEGIN; limitint ret = *this; ++(*this); return ret; E_END("limitint::operator ++", "int"); };
135  limitint operator --(int a)
136  { E_BEGIN; limitint ret = *this; --(*this); return ret; E_END("limitint::operator --", "int"); };
137  limitint & operator ++()
138  { E_BEGIN; return *this += 1; E_END("limitint::operator ++", "()"); };
139  limitint & operator --()
140  { E_BEGIN; return *this -= 1; E_END("limitint::operator --", "()"); };
141 
142  U_32 operator % (U_32 arg) const;
143 
144  // increment the argument up to a legal value for its storage type and decrement the object in consequence
145  // note that the initial value of the argument is not ignored !
146  // when the object is null the value of the argument stays the same as before
147  template <class T>void unstack(T &v)
148  { E_BEGIN; limitint_unstack_to(v); E_END("limitint::unstack", typeid(v).name()); }
149 
150  limitint get_storage_size() const;
151  // it returns number of byte of information necessary to store the integer
152 
153  unsigned char operator [] (const limitint & position) const;
154  // return in big endian order the information bytes storing the integer
155 
156 
157  bool operator < (const limitint &x) const { return field < x.field; };
158  bool operator == (const limitint &x) const { return field == x.field; };
159  bool operator > (const limitint &x) const { return field > x.field; };
160  bool operator <= (const limitint &x) const { return field <= x.field; };
161  bool operator != (const limitint &x) const { return field != x.field; };
162  bool operator >= (const limitint &x) const { return field >= x.field; };
163 
164  static bool is_system_big_endian();
165 
166 #ifdef LIBDAR_SPECIAL_ALLOC
167  USE_SPECIAL_ALLOC(limitint);
168 #endif
169 
170  B debug_get_max() const { return max_value; };
171  B debug_get_bytesize() const { return bytesize; };
172 
173  private :
174  static const int TG = 4;
175  static const U_32 sizeof_field = sizeof(B); // number of bytes
176 
177  enum endian { big_endian, little_endian, not_initialized };
178  typedef unsigned char group[TG];
179 
180  B field;
181 
182  void build_from_file(generic_file & x);
183  template <class T> void limitint_from(T a);
184  template <class T> T max_val_of(T x);
185  template <class T> void limitint_unstack_to(T &a);
186 
188  // static statments
189  //
190  static endian used_endian;
191  static const U_I bytesize = sizeof(B);
192  static const B max_value = ~B(0) > 0 ? ~B(0) : ~(B(1) << (bytesize*8 - 1));
193  static U_8 zeroed_field[ZEROED_SIZE];
194 
195  static void setup_endian();
196  };
197 
198  template <class B> U_8 limitint<B>::zeroed_field[ZEROED_SIZE];
199 
200  template <class B> limitint<B> operator + (const limitint<B> &, const limitint<B> &);
201  template <class B> inline limitint<B> operator + (const limitint<B> & a, U_I b)
202  { return a + limitint<B>(b); }
203  template <class B> limitint<B> operator - (const limitint<B> &, const limitint<B> &);
204  template <class B> inline limitint<B> operator - (const limitint<B> & a, U_I b)
205  { return a - limitint<B>(b); }
206  template <class B> limitint<B> operator * (const limitint<B> &, const limitint<B> &);
207  template <class B> inline limitint<B> operator * (const limitint<B> & a, U_I b)
208  { return a * limitint<B>(b); }
209  template <class B> limitint<B> operator / (const limitint<B> &, const limitint<B> &);
210  template <class B> limitint<B> operator / (const limitint<B> & a, U_I b)
211  { return a / limitint<B>(b); }
212  template <class B> limitint<B> operator % (const limitint<B> &, const limitint<B> &);
213  template <class B> limitint<B> operator >> (const limitint<B> & a, U_32 bit);
214  template <class B> limitint<B> operator >> (const limitint<B> & a, const limitint<B> & bit);
215  template <class B> limitint<B> operator << (const limitint<B> & a, U_32 bit);
216  template <class B> limitint<B> operator << (const limitint<B> & a, const limitint<B> & bit);
217  template <class B> limitint<B> operator & (const limitint<B> & a, U_32 bit);
218  template <class B> limitint<B> operator & (const limitint<B> & a, const limitint<B> & bit);
219  template <class B> limitint<B> operator | (const limitint<B> & a, U_32 bit);
220  template <class B> limitint<B> operator | (const limitint<B> & a, const limitint<B> & bit);
221  template <class B> limitint<B> operator ^ (const limitint<B> & a, U_32 bit);
222  template <class B> limitint<B> operator ^ (const limitint<B> & a, const limitint<B> & bit);
223 
224  template <class T> inline void euclide(T a, T b, T & q, T &r)
225  {
226  E_BEGIN;
227  q = a/b; r = a%b;
228  E_END("euclide", "");
229  }
230 
231  template <class B> inline void euclide(limitint<B> a, U_I b, limitint<B> & q, limitint<B> &r)
232  {
233  euclide(a, limitint<B>(b), q, r);
234  }
235 
236 #ifndef INFININT_BASE_TYPE
237 #error INFININT_BASE_TYPE not defined cannot instantiate template
238 #else
239  typedef limitint<INFININT_BASE_TYPE> infinint;
240 #endif
241 } // end of namespace
245 
246 #include "generic_file.hpp"
247 #include "fichier.hpp"
248 #include "user_interaction.hpp"
249 
250 namespace libdar
251 {
252 
253  template <class B> typename limitint<B>::endian limitint<B>::used_endian = not_initialized;
254 
255 
256 
257  template <class B> limitint<B>::limitint(user_interaction & dialog, S_I fd)
258  {
259  fichier f = fichier(dialog, dup(fd));
260  build_from_file(f);
261  }
262 
263  template <class B> limitint<B>::limitint(generic_file & x)
264  {
265  build_from_file(x);
266  }
267 
268  template <class B> void limitint<B>::dump(user_interaction & dialog, S_I fd) const
269  {
270  fichier f = fichier(dialog, dup(fd));
271  dump(f);
272  }
273 
274  template <class B> void limitint<B>::build_from_file(generic_file & x)
275  {
276  E_BEGIN;
277  unsigned char a;
278  bool fin = false;
279  limitint<B> skip = 0;
280  char *ptr = (char *)&field;
281  S_I lu;
282  int_tools_bitfield bf;
283 
284  while(!fin)
285  {
286  lu = x.read((char *)&a, 1);
287 
288  if(lu <= 0)
289  throw Erange("limitint::build_from_file(generic_file)", gettext("Reached end of file before all data could be read"));
290 
291  if(a == 0)
292  ++skip;
293  else // end of size field
294  {
295  // computing the size to read
296  U_I pos = 0;
297 
298  int_tools_expand_byte(a, bf);
299  for(S_I i = 0; i < 8; ++i)
300  pos += bf[i];
301  if(pos != 1)
302  throw Erange("limitint::build_from_file(generic_file)", gettext("Badly formed \"infinint\" or not supported format")); // more than 1 bit is set to 1
303 
304  pos = 0;
305  while(bf[pos] == 0)
306  ++pos;
307  pos += 1; // bf starts at zero, but bit zero means 1 TG of length
308 
309  skip *= 8;
310  skip += pos;
311  skip *= TG;
312 
313  if(skip.field > bytesize)
314  throw Elimitint();
315 
316  field = 0; // important to also clear "unread" bytes by this call
317  lu = x.read(ptr, skip.field);
318 
319  if(used_endian == not_initialized)
320  setup_endian();
321  if(used_endian == little_endian)
322  int_tools_swap_bytes((unsigned char *)ptr, skip.field);
323  else
324  field >>= (bytesize - skip.field)*8;
325  fin = true;
326  }
327  }
328  E_END("limitint::read_from_file", "generic_file");
329  }
330 
331 
332  template <class B> void limitint<B>::dump(generic_file & x) const
333  {
334  E_BEGIN;
335  B width = bytesize;
336  B pos;
337  unsigned char last_width;
338  B justification;
339  S_I direction = +1;
340  unsigned char *ptr, *fin;
341 
342 
343  if(used_endian == not_initialized)
344  setup_endian();
345 
346  if(used_endian == little_endian)
347  {
348  direction = -1;
349  ptr = (unsigned char *)(&field) + (bytesize - 1);
350  fin = (unsigned char *)(&field) - 1;
351  }
352  else
353  {
354  direction = +1;
355  ptr = (unsigned char *)(&field);
356  fin = (unsigned char *)(&field) + bytesize;
357  }
358 
359  while(ptr != fin && *ptr == 0)
360  {
361  ptr += direction;
362  --width;
363  }
364  if(width == 0)
365  width = 1; // minimum size of information is 1 byte
366 
367  // "width" is the informational field size in byte
368  // TG is the width in TG, thus the number of bit that must have
369  // the preamble
370  euclide(width, (const B)(TG), width, justification);
371  if(justification != 0)
372  // in case we need to add some bytes to have a width multiple of TG
373  ++width; // we need then one more group to have a width multiple of TG
374 
375  euclide(width, (const B)(8), width, pos);
376  if(pos == 0)
377  {
378  width--; // division is exact, only last bit of the preambule is set
379  last_width = 0x80 >> 7;
380  // as we add the last byte separately width gets shorter by 1 byte
381  }
382  else // division non exact, the last_width (last byte), make the rounding
383  {
384  U_16 pos_s = (U_16)(0xFFFF & pos);
385  last_width = 0x80 >> (pos_s - 1);
386  }
387 
388  // now we write the preamble except the last byte. All these are zeros.
389 
390  while(width != 0)
391  if(width > ZEROED_SIZE)
392  {
393  x.write((char *)zeroed_field, ZEROED_SIZE);
394  width -= ZEROED_SIZE;
395  }
396  else
397  {
398  x.write((char *)zeroed_field, width);
399  width = 0;
400  }
401 
402  // now we write the last byte of the preambule, which as only one bit set
403 
404  x.write((char *)&last_width, 1);
405 
406  // we need now to write some justification byte to have an informational field multiple of TG
407 
408  if(justification != 0)
409  {
410  justification = TG - justification;
411  if(justification > ZEROED_SIZE)
412  throw SRC_BUG;
413  else
414  x.write((char *)zeroed_field, justification);
415  }
416 
417  // now we continue dumping the informational bytes:
418  if(ptr == fin) // field is equal to zero
419  x.write((char *)zeroed_field, 1);
420  else // we have some bytes to write down
421  while(ptr != fin)
422  {
423  x.write((char *)ptr, 1);
424  ptr += direction;
425  }
426 
427  E_END("limitint::dump", "generic_file");
428  }
429 
430  template<class B> limitint<B> & limitint<B>::operator += (const limitint & arg)
431  {
432  E_BEGIN;
433  B res = field + arg.field;
434  if(res < field || res < arg.field)
435  throw Elimitint();
436  else
437  field = res;
438 
439  return *this;
440  E_END("limitint::operator +=", "");
441  }
442 
443  template <class B> limitint<B> & limitint<B>::operator -= (const limitint & arg)
444  {
445  E_BEGIN;
446  if(field < arg.field)
447  throw Erange("limitint::operator", gettext("Subtracting an \"infinint\" greater than the first, \"infinint\" cannot be negative"));
448 
449  // now processing the operation
450 
451  field -= arg.field;
452  return *this;
453  E_END("limitint::operator -=", "");
454  }
455 
456 
457  template <class B> limitint<B> & limitint<B>::operator *= (const limitint & arg)
458  {
459  E_BEGIN;
460  static const B max_power = bytesize*8 - 1;
461 
462  B total = int_tools_higher_power_of_2(field) + int_tools_higher_power_of_2(arg.field) + 1; // for an explaination about "+2" see NOTES
463  if(total > max_power) // this is a bit too much restrictive, but unless remaking bit by bit, the operation,
464  // I don't see how to simply (and fast) know the result has not overflowed.
465  // of course, it would be fast and easy to access the CPU flag register to check for overflow,
466  // but that would not be portable, and unfortunately I haven't found any standart C++ expression that
467  // could transparently access to it.
468  throw Elimitint();
469 
470  total = field*arg.field;
471  if(field != 0 && arg.field != 0)
472  if(total < field || total < arg.field)
473  throw Elimitint();
474  field = total;
475  return *this;
476  E_END("limitint::operator *=", "");
477  }
478 
479  template <class B> template<class T> limitint<B> limitint<B>::power(const T & exponent) const
480  {
481  limitint ret = 1;
482  for(T count = 0; count < exponent; ++count)
483  ret *= *this;
484 
485  return ret;
486  }
487 
488  template <class B> limitint<B> & limitint<B>::operator /= (const limitint & arg)
489  {
490  E_BEGIN;
491  if(arg == 0)
492  throw Einfinint("limitint.cpp : operator /=", gettext("Division by zero"));
493 
494  field /= arg.field;
495  return *this;
496  E_END("limitint::operator /=", "");
497  }
498 
499  template <class B> limitint<B> & limitint<B>::operator %= (const limitint & arg)
500  {
501  E_BEGIN;
502  if(arg == 0)
503  throw Einfinint("limitint.cpp : operator %=", gettext("Division by zero"));
504 
505  field %= arg.field;
506  return *this;
507  E_END("limitint::operator /=", "");
508  }
509 
510  template <class B> limitint<B> & limitint<B>::operator >>= (U_32 bit)
511  {
512  E_BEGIN;
513  if(bit >= sizeof_field*8)
514  field = 0;
515  else
516  field >>= bit;
517  return *this;
518  E_END("limitint::operator >>=", "U_32");
519  }
520 
521  template <class B> limitint<B> & limitint<B>::operator >>= (limitint bit)
522  {
523  E_BEGIN;
524  field >>= bit.field;
525  return *this;
526  E_END("limitint::operator >>=", "limitint");
527  }
528 
529  template <class B> limitint<B> & limitint<B>::operator <<= (U_32 bit)
530  {
531  E_BEGIN;
532  if(bit + int_tools_higher_power_of_2(field) >= bytesize*8)
533  throw Elimitint();
534  field <<= bit;
535  return *this;
536  E_END("limitint::operator <<=", "U_32");
537  }
538 
539  template <class B> limitint<B> & limitint<B>::operator <<= (limitint bit)
540  {
541  E_BEGIN;
542  if(bit.field + int_tools_higher_power_of_2(field) >= bytesize*8)
543  throw Elimitint();
544  field <<= bit.field;
545  return *this;
546  E_END("limitint::operator <<=", "limitint");
547  }
548 
549  template <class B> limitint<B> & limitint<B>::operator &= (const limitint & arg)
550  {
551  E_BEGIN;
552  field &= arg.field;
553  return *this;
554  E_END("limitint::operator &=", "");
555  }
556 
557  template <class B> limitint<B> & limitint<B>::operator |= (const limitint & arg)
558  {
559  E_BEGIN;
560  field |= arg.field;
561  return *this;
562  E_END("limitint::operator |=", "");
563  }
564 
565  template <class B> limitint<B> & limitint<B>::operator ^= (const limitint & arg)
566  {
567  E_BEGIN;
568  field ^= arg.field;
569  return *this;
570  E_END("limitint::operator ^=", "");
571  }
572 
573  template <class B> U_32 limitint<B>::operator % (U_32 arg) const
574  {
575  E_BEGIN;
576  return U_32(field % arg);
577  E_END("limitint::modulo", "");
578  }
579 
580  template <class B> template <class T> void limitint<B>::limitint_from(T a)
581  {
582  E_BEGIN;
583  if(sizeof(a) <= bytesize || a <= (T)(max_value))
584  field = B(a);
585  else
586  throw Elimitint();
587  E_END("limitint::limitint_from", "");
588  }
589 
590  template <class B> template <class T> T limitint<B>::max_val_of(T x)
591  {
592  x = 0;
593  x = ~x;
594 
595  if(x < 1) // T is a signed integer type, we are not comparing to zero to avoid compiler warning when the template is used against unsigned integers
596  {
597  x = 1;
598  x = int_tools_rotate_right_one_bit(x);
599  x = ~x;
600  }
601 
602  return x;
603  }
604 
605  template <class B> template <class T> void limitint<B>::limitint_unstack_to(T &a)
606  {
607  E_BEGIN;
608  // T is supposed to be an unsigned "integer"
609  // (ie.: sizeof returns the width of the storage bit field and no sign bit is present)
610  // Note : static here avoids the recalculation of max_T at each call
611  static const T max_T = max_val_of(a);
612  T step = max_T - a;
613 
614  if(field < (B)(step) && (T)(field) < step)
615  {
616  a += field;
617  field = 0;
618  }
619  else
620  {
621  field -= step;
622  a = max_T;
623  }
624 
625  E_END("limitint::limitint_unstack_to", "");
626  }
627 
628  template <class B> limitint<B> limitint<B>::get_storage_size() const
629  {
630  B tmp = field;
631  B ret = 0;
632 
633  while(tmp != 0)
634  {
635  tmp >>= 8;
636  ret++;
637  }
638 
639  return limitint<B>(ret);
640  }
641 
642  template <class B> unsigned char limitint<B>::operator [] (const limitint & position) const
643  {
644  B tmp = field;
645  B index = position.field; // C++ has only class protection, not object protection
646 
647  while(index > 0)
648  {
649  tmp >>= 8;
650  index--;
651  }
652 
653  return (unsigned char)(tmp & 0xFF);
654  }
655 
656  template <class B> void limitint<B>::setup_endian()
657  {
658  E_BEGIN;
660  used_endian = big_endian;
661  else
662  used_endian = little_endian;
663 
664  bzero(zeroed_field, ZEROED_SIZE);
665  E_END("limitint::setup_endian", "");
666  }
667 
668 
669  template <class B> bool limitint<B>::is_system_big_endian()
670  {
671  if(used_endian == not_initialized)
672  setup_endian();
673 
674  switch(used_endian)
675  {
676  case big_endian:
677  return true;
678  case little_endian:
679  return false;
680  case not_initialized:
681  throw SRC_BUG;
682  default:
683  throw SRC_BUG;
684  }
685  }
686 
687 
691 
692  template <class B> limitint<B> operator + (const limitint<B> & a, const limitint<B> & b)
693  {
694  E_BEGIN;
695  limitint<B> ret = a;
696  ret += b;
697 
698  return ret;
699  E_END("operator +", "limitint");
700  }
701 
702  template <class B> limitint<B> operator - (const limitint<B> & a, const limitint<B> & b)
703  {
704  E_BEGIN;
705  limitint<B> ret = a;
706  ret -= b;
707 
708  return ret;
709  E_END("operator -", "limitint");
710  }
711 
712  template <class B> limitint<B> operator * (const limitint<B> & a, const limitint<B> & b)
713  {
714  E_BEGIN;
715  limitint<B> ret = a;
716  ret *= b;
717 
718  return ret;
719  E_END("operator *", "limitint");
720  }
721 
722  template <class B> limitint<B> operator / (const limitint<B> & a, const limitint<B> & b)
723  {
724  E_BEGIN;
725  limitint<B> ret = a;
726  ret /= b;
727 
728  return ret;
729  E_END("operator / ", "limitint");
730  }
731 
732  template <class B> limitint<B> operator % (const limitint<B> & a, const limitint<B> & b)
733  {
734  E_BEGIN;
735  limitint<B> ret = a;
736  ret %= b;
737 
738  return ret;
739  E_END("operator %", "limitint");
740  }
741 
742  template <class B> limitint<B> operator >> (const limitint<B> & a, U_32 bit)
743  {
744  E_BEGIN;
745  limitint<B> ret = a;
746  ret >>= bit;
747  return ret;
748  E_END("operator >>", "limitint, U_32");
749  }
750 
751  template <class B> limitint<B> operator >> (const limitint<B> & a, const limitint<B> & bit)
752  {
753  E_BEGIN;
754  limitint<B> ret = a;
755  ret >>= bit;
756  return ret;
757  E_END("operator >>", "limitint");
758  }
759 
760  template <class B> limitint<B> operator << (const limitint<B> & a, U_32 bit)
761  {
762  E_BEGIN;
763  limitint<B> ret = a;
764  ret <<= bit;
765  return ret;
766  E_END("operator <<", "limitint, U_32");
767  }
768 
769  template <class B> limitint<B> operator << (const limitint<B> & a, const limitint<B> & bit)
770  {
771  E_BEGIN;
772  limitint<B> ret = a;
773  ret <<= bit;
774  return ret;
775  E_END("operator <<", "limitint");
776  }
777 
778  template <class B> limitint<B> operator & (const limitint<B> & a, U_32 bit)
779  {
780  E_BEGIN;
781  limitint<B> ret = a;
782  ret &= bit;
783  return ret;
784  E_END("operator &", "limitint");
785  }
786 
787  template <class B> limitint<B> operator & (const limitint<B> & a, const limitint<B> & bit)
788  {
789  E_BEGIN;
790  limitint<B> ret = a;
791  ret &= bit;
792  return ret;
793  E_END("operator &", "limitint");
794  }
795 
796  template <class B> limitint<B> operator | (const limitint<B> & a, U_32 bit)
797  {
798  E_BEGIN;
799  limitint<B> ret = a;
800  ret |= bit;
801  return ret;
802  E_END("operator |", "U_32");
803  }
804 
805  template <class B> limitint<B> operator | (const limitint<B> & a, const limitint<B> & bit)
806  {
807  E_BEGIN;
808  limitint<B> ret = a;
809  ret |= bit;
810  return ret;
811  E_END("operator |", "limitint");
812  }
813 
814  template <class B> limitint<B> operator ^ (const limitint<B> & a, U_32 bit)
815  {
816  E_BEGIN;
817  limitint<B> ret = a;
818  ret ^= bit;
819  return ret;
820  E_END("operator ^", "U_32");
821  }
822 
823  template <class B> limitint<B> operator ^ (const limitint<B> & a, const limitint<B> & bit)
824  {
825  E_BEGIN;
826  limitint<B> ret = a;
827  ret ^= bit;
828  return ret;
829  E_END("operator ^", "limitint");
830  }
831 
833 
834 } // end of namespace
835 
836 #endif