source: trunk/Mars/mcore/checksum.h@ 16546

Last change on this file since 16546 was 16546, checked in by tbretz, 11 years ago
Improved performance of checksum calculation by partly unrolling the loop (avoiding modulo operation, which avoids the integert and an improved byte-swap).
File size: 4.8 KB
Line 
1#ifndef MARS_checksum
2#define MARS_checksum
3
4#include <arpa/inet.h>
5
6namespace std
7{
8
9class Checksum
10{
11public:
12 uint64_t buffer;
13
14 void reset() { buffer = 0; }
15 Checksum() : buffer(0) { }
16 Checksum(const Checksum &sum) : buffer(sum.buffer) { }
17 Checksum(uint64_t v) : buffer(((v>>16)&0xffff) | ((v&0xffff)<<32)) { }
18
19 uint32_t val() const { return (((buffer&0xffff)<<16) | ((buffer>>32)&0xffff)); }
20
21 bool valid() const { return buffer==0xffff0000ffff; }
22
23 void HandleCarryBits()
24 {
25 while (1)
26 {
27 const uint64_t carry = ((buffer>>48)&0xffff) | ((buffer&0xffff0000)<<16);
28 if (!carry)
29 break;
30
31 buffer = (buffer&0xffff0000ffff) + carry;
32 }
33 }
34
35 Checksum &operator+=(const Checksum &sum)
36 {
37 buffer += sum.buffer;
38 HandleCarryBits();
39 return *this;
40 }
41 Checksum operator+(Checksum sum) const
42 {
43 return (sum += *this);
44 }
45
46
47 bool add(const char *buf, size_t len)
48 {
49 // Avoid overflows in carry bits
50 if (len>262140) // 2^18-4
51 {
52 add(buf, 262140);
53 return add(buf+262140, len-262140);
54 }
55
56 if (len%4>0)
57 {
58 ostringstream sout;
59 sout << "Length " << len << " not dividable by 4." << endl;
60
61#ifdef __EXCEPTIONS
62 throw runtime_error(sout.str());
63#else
64 gLog << ___err___ << "ERROR - " << sout.str() << endl;
65 return false;
66#endif
67 }
68
69 const uint32_t *sbuf = reinterpret_cast<const uint32_t*>(buf);
70
71 uint32_t *hilo = reinterpret_cast<uint32_t*>(&buffer);
72
73 /*
74 for (size_t i = 0; i < len/2; i++)
75 {
76 //swap the bytes of the 32 bits value. but...
77 //the hi and lo values are stored in fits-like order. do not swap them
78 hilo[i%2] += ntohs(sbuf[i]); //(sbuf[i]&0xff00)>>8 | (sbuf[i]&0x00ff)<<8;
79 }*/
80
81 // This is about as twice as fast as the loop above
82 // ntohs is CPU optimized, hilo[n] doesn't need to be computed
83 const uint32_t *end = sbuf + len/2;
84 while (1)
85 {
86 hilo[0] += ntohs(*sbuf++);
87 if (sbuf==end)
88 break;
89
90 hilo[1] += ntohs(*sbuf++);
91 if (sbuf==end)
92 break;
93 }
94
95 HandleCarryBits();
96
97 return true;
98 }
99
100 bool add(const vector<char> &v)
101 {
102 return add(v.data(), v.size());
103 }
104
105 string str(bool complm=true) const
106 {
107 string rc(16,0);
108
109 const uint8_t exclude[13] =
110 {
111 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40,
112 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60
113 };
114
115 const uint32_t value = complm ? ~val() : val(); // complement each bit of the value
116
117 for (int ii = 0; ii < 4; ii++)
118 {
119 uint8_t byte = (value >> (24 - (8 * ii)));
120
121 const uint8_t quotient = byte / 4 + '0';
122 const uint8_t remainder = byte % 4;
123
124 uint32_t ch[4] = { quotient+remainder, quotient, quotient, quotient };
125
126 // avoid ASCII punctuation
127 while (1)
128 {
129 bool check = false;
130 for (int kk = 0; kk < 13; kk++)
131 {
132 for (int jj = 0; jj < 4; jj += 2)
133 {
134 if (ch[jj] != exclude[kk] && ch[jj+1] != exclude[kk])
135 continue;
136
137 ch[jj]++;
138 ch[jj+1]--;
139 check++;
140 }
141 }
142
143 if (!check)
144 break;
145 }
146
147 for (int jj = 0; jj < 4; jj++) // assign the bytes
148 rc[4*jj+ii] = ch[jj];
149 }
150
151 const char lastChar = rc[15];
152 for (int i=15;i>0;i--)
153 rc[i] = rc[i-1];
154 rc[0] = lastChar;
155 return rc;
156/*
157 uint8_t *p = reinterpret_cast<uint8_t*>(&value);
158 //swap the bytes of the value
159 uint8_t temp;
160 temp = p[0];
161 p[0] = p[3];
162 p[3] = temp;
163 temp = p[1];
164 p[1] = p[2];
165 p[2] = temp;
166
167 for (int i=0; i<4; i++)
168 {
169 rc[i+ 0] = '0' + p[i]/4 + p[i]%4;
170 rc[i+ 4] = '0' + p[i]/4;
171 rc[i+ 8] = '0' + p[i]/4;
172 rc[i+12] = '0' + p[i]/4;
173 }
174
175 while(1)
176 {
177 bool ok = true;
178 for (int i=0; i<16-4; i++)
179 {
180 for (int j=0; j<13; j++)
181 if (rc[i]==exclude[j] || rc[(i+4)%16]==exclude[j])
182 {
183 rc[i]++;
184 rc[(i+4)%16]--;
185 ok = false;
186 }
187 }
188
189 if (ok)
190 break;
191 }
192
193
194 return rc;
195 */
196 }
197};
198}
199
200#endif
Note: See TracBrowser for help on using the repository browser.