framework
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
modular_sum.hpp
Go to the documentation of this file.
1 // Copyright (C) 2012 iwg molw5
2 // For conditions of distribution and use, see copyright notice in COPYING
3 
13 #pragma once
14 
15 #include <string.h>
16 #include <cstdint>
17 #include <cassert>
18 #include <algorithm>
19 
22 
23 namespace framework
24 {
25  namespace serializable
26  {
36  template <std::size_t Bytes, byte_order Order>
38  {
39  static_assert(
40  Order == byte_order::little_endian ||
41  Order == byte_order::big_endian,
42  "Specified byte order not implemented");
43 
44  static_assert(
45  Bytes <= 8,
46  "Specified byte count not implemented");
47 
48  private:
49  enum{ value_mask = (~static_cast <uint64_t> (0)) >> (64 - 8*Bytes) };
50  enum{ value_shift = 8*Bytes };
51  enum{ offset = (Order == byte_order::big_endian ? 8*(Bytes-1) : 0) };
52  enum{ multiplier = (Order == byte_order::big_endian ? -8 : 8) };
53 
54  template <unsigned int State, std::size_t N, std::size_t Index = 0>
55  struct unroll
56  {
58  static uint64_t run (unsigned char const* s)
59  {
60  enum{ shift = offset + multiplier*((State + Index) % Bytes) };
61  return (static_cast <uint64_t> (*s) << shift) | unroll <State, N, Index+1>::run(s+1);
62  }
63  };
64 
65  template <unsigned int State, std::size_t N>
66  struct unroll <State, N, N>
67  {
69  static uint64_t run (unsigned char const*)
70  {
71  return 0;
72  }
73  };
74 
75  template <std::size_t N>
76  struct handler_fixed
77  {
78  template <std::size_t I, typename T>
80  bool operator() (T* this_ptr, unsigned char const* s)
81  {
82  enum{ new_state = (I+N) % Bytes };
83  enum{ loop_count = N / Bytes };
84  enum{ remainder = N % Bytes };
85 
86  for (unsigned int i=0; i < loop_count; ++i, s += Bytes)
87  this_ptr->add(unroll <I, Bytes>::run(s));
88 
89  this_ptr->add(unroll <I, remainder>::run(s));
90  this_ptr->p_iState = new_state;
91  return true;
92  }
93 
94  template <typename T>
96  bool operator() (T*, unsigned char const*)
97  {
98  assert(false);
99  }
100  };
101 
102  struct handler_dynamic
103  {
104  template <std::size_t I, typename T>
106  bool operator() (T* this_ptr, unsigned char const* s, std::size_t n)
107  {
108  this_ptr->p_iState = (I + n) % Bytes;
109 
110  for (; n >= Bytes; s += Bytes, n -= Bytes)
111  this_ptr->add(unroll <I, Bytes>::run(s));
112 
113  switch (n)
114  {
115  case 7: return this_ptr->add(unroll <I, 7>::run(s));
116  case 6: return this_ptr->add(unroll <I, 6>::run(s));
117  case 5: return this_ptr->add(unroll <I, 5>::run(s));
118  case 4: return this_ptr->add(unroll <I, 4>::run(s));
119  case 3: return this_ptr->add(unroll <I, 3>::run(s));
120  case 2: return this_ptr->add(unroll <I, 2>::run(s));
121  case 1: return this_ptr->add(unroll <I, 1>::run(s));
122  case 0: return true;
123  default: assert(false);
124  }
125  }
126 
127  template <typename T>
129  bool operator() (T*, unsigned char const*, std::size_t)
130  {
131  assert(false);
132  }
133  };
134 
135  public:
139  template <std::size_t N>
140  bool write (char const* s)
141  {
142  using values = make_values <std::size_t, Bytes>;
143  auto const ptr = reinterpret_cast <unsigned char const*> (s);
144  return variadic_switch_return <values> (p_iState, handler_fixed <N> (), this, ptr);
145  }
146 
150  bool write (char const* s, std::size_t n)
151  {
152  using values = make_values <std::size_t, Bytes>;
153  auto const ptr = reinterpret_cast <unsigned char const*> (s);
154  return variadic_switch_return <values> (p_iState, handler_dynamic(), this, ptr, n);
155  }
156 
162  uint64_t checksum () const
163  {
164  uint64_t result = p_iSum;
165  while (result >> value_shift)
166  result = (result & value_mask) + (result >> value_shift);
167 
168  return (~result) & value_mask;
169  }
170 
174  void reset ()
175  {
176  p_iSum = 0;
177  }
178 
179  private:
181  bool add (uint64_t x)
182  {
183  auto const result = p_iSum + x;
184  p_iSum = result + (result < x);
185 
186  return true;
187  }
188 
189  private:
190  uint64_t p_iSum {0};
191  unsigned int p_iState {0};
192  };
193 
194  using internet_checksum = modular_sum <2, byte_order::big_endian>;
195  }
196 }
197 
198 #include <framework/serializable/streams/modular_sum.inl>