line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
/* byte_order.c - byte order related platform dependent routines, |
2
|
|
|
|
|
|
|
* |
3
|
|
|
|
|
|
|
* Copyright: 2008-2012 Aleksey Kravchenko |
4
|
|
|
|
|
|
|
* |
5
|
|
|
|
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a |
6
|
|
|
|
|
|
|
* copy of this software and associated documentation files (the "Software"), |
7
|
|
|
|
|
|
|
* to deal in the Software without restriction, including without limitation |
8
|
|
|
|
|
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
9
|
|
|
|
|
|
|
* and/or sell copies of the Software, and to permit persons to whom the |
10
|
|
|
|
|
|
|
* Software is furnished to do so. |
11
|
|
|
|
|
|
|
* |
12
|
|
|
|
|
|
|
* This program is distributed in the hope that it will be useful, but |
13
|
|
|
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
14
|
|
|
|
|
|
|
* or FITNESS FOR A PARTICULAR PURPOSE. Use this program at your own risk! |
15
|
|
|
|
|
|
|
*/ |
16
|
|
|
|
|
|
|
#include "byte_order.h" |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
#ifndef rhash_ctz |
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
# if _MSC_VER >= 1300 && (_M_IX86 || _M_AMD64 || _M_IA64) /* if MSVC++ >= 2002 on x86/x64 */ |
21
|
|
|
|
|
|
|
# include |
22
|
|
|
|
|
|
|
# pragma intrinsic(_BitScanForward) |
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
/** |
25
|
|
|
|
|
|
|
* Returns index of the trailing bit of x. |
26
|
|
|
|
|
|
|
* |
27
|
|
|
|
|
|
|
* @param x the number to process |
28
|
|
|
|
|
|
|
* @return zero-based index of the trailing bit |
29
|
|
|
|
|
|
|
*/ |
30
|
|
|
|
|
|
|
unsigned rhash_ctz(unsigned x) |
31
|
|
|
|
|
|
|
{ |
32
|
|
|
|
|
|
|
unsigned long index; |
33
|
|
|
|
|
|
|
unsigned char isNonzero = _BitScanForward(&index, x); /* MSVC intrinsic */ |
34
|
|
|
|
|
|
|
return (isNonzero ? (unsigned)index : 0); |
35
|
|
|
|
|
|
|
} |
36
|
|
|
|
|
|
|
# else /* _MSC_VER >= 1300... */ |
37
|
|
|
|
|
|
|
|
38
|
|
|
|
|
|
|
/** |
39
|
|
|
|
|
|
|
* Returns index of the trailing bit of a 32-bit number. |
40
|
|
|
|
|
|
|
* This is a plain C equivalent for GCC __builtin_ctz() bit scan. |
41
|
|
|
|
|
|
|
* |
42
|
|
|
|
|
|
|
* @param x the number to process |
43
|
|
|
|
|
|
|
* @return zero-based index of the trailing bit |
44
|
|
|
|
|
|
|
*/ |
45
|
|
|
|
|
|
|
unsigned rhash_ctz(unsigned x) |
46
|
|
|
|
|
|
|
{ |
47
|
|
|
|
|
|
|
/* array for conversion to bit position */ |
48
|
|
|
|
|
|
|
static unsigned char bit_pos[32] = { |
49
|
|
|
|
|
|
|
0, 1, 28, 2, 29, 14, 24, 3, 30, 22, 20, 15, 25, 17, 4, 8, |
50
|
|
|
|
|
|
|
31, 27, 13, 23, 21, 19, 16, 7, 26, 12, 18, 6, 11, 5, 10, 9 |
51
|
|
|
|
|
|
|
}; |
52
|
|
|
|
|
|
|
|
53
|
|
|
|
|
|
|
/* The De Bruijn bit-scan was devised in 1997, according to Donald Knuth |
54
|
|
|
|
|
|
|
* by Martin Lauter. The constant 0x077CB531UL is a De Bruijn sequence, |
55
|
|
|
|
|
|
|
* which produces a unique pattern of bits into the high 5 bits for each |
56
|
|
|
|
|
|
|
* possible bit position that it is multiplied against. |
57
|
|
|
|
|
|
|
* See http://graphics.stanford.edu/~seander/bithacks.html |
58
|
|
|
|
|
|
|
* and http://chessprogramming.wikispaces.com/BitScan */ |
59
|
|
|
|
|
|
|
return (unsigned)bit_pos[((uint32_t)((x & -x) * 0x077CB531U)) >> 27]; |
60
|
|
|
|
|
|
|
} |
61
|
|
|
|
|
|
|
# endif /* _MSC_VER >= 1300... */ |
62
|
|
|
|
|
|
|
#endif /* rhash_ctz */ |
63
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
/** |
65
|
|
|
|
|
|
|
* Copy a memory block with simultaneous exchanging byte order. |
66
|
|
|
|
|
|
|
* The byte order is changed from little-endian 32-bit integers |
67
|
|
|
|
|
|
|
* to big-endian (or vice-versa). |
68
|
|
|
|
|
|
|
* |
69
|
|
|
|
|
|
|
* @param to the pointer where to copy memory block |
70
|
|
|
|
|
|
|
* @param index the index to start writing from |
71
|
|
|
|
|
|
|
* @param from the source block to copy |
72
|
|
|
|
|
|
|
* @param length length of the memory block |
73
|
|
|
|
|
|
|
*/ |
74
|
23
|
|
|
|
|
|
void rhash_swap_copy_str_to_u32(void* to, int index, const void* from, size_t length) |
75
|
|
|
|
|
|
|
{ |
76
|
|
|
|
|
|
|
/* if all pointers and length are 32-bits aligned */ |
77
|
23
|
50
|
|
|
|
|
if ( 0 == (( (int)((char*)to - (char*)0) | ((char*)from - (char*)0) | index | length ) & 3) ) { |
78
|
|
|
|
|
|
|
/* copy memory as 32-bit words */ |
79
|
23
|
|
|
|
|
|
const uint32_t* src = (const uint32_t*)from; |
80
|
23
|
|
|
|
|
|
const uint32_t* end = (const uint32_t*)((const char*)src + length); |
81
|
23
|
|
|
|
|
|
uint32_t* dst = (uint32_t*)((char*)to + index); |
82
|
147
|
100
|
|
|
|
|
for (; src < end; dst++, src++) |
83
|
124
|
|
|
|
|
|
*dst = bswap_32(*src); |
84
|
|
|
|
|
|
|
} else { |
85
|
0
|
|
|
|
|
|
const char* src = (const char*)from; |
86
|
0
|
0
|
|
|
|
|
for (length += index; (size_t)index < length; index++) |
87
|
0
|
|
|
|
|
|
((char*)to)[index ^ 3] = *(src++); |
88
|
|
|
|
|
|
|
} |
89
|
23
|
|
|
|
|
|
} |
90
|
|
|
|
|
|
|
|
91
|
|
|
|
|
|
|
/** |
92
|
|
|
|
|
|
|
* Copy a memory block with changed byte order. |
93
|
|
|
|
|
|
|
* The byte order is changed from little-endian 64-bit integers |
94
|
|
|
|
|
|
|
* to big-endian (or vice-versa). |
95
|
|
|
|
|
|
|
* |
96
|
|
|
|
|
|
|
* @param to the pointer where to copy memory block |
97
|
|
|
|
|
|
|
* @param index the index to start writing from |
98
|
|
|
|
|
|
|
* @param from the source block to copy |
99
|
|
|
|
|
|
|
* @param length length of the memory block |
100
|
|
|
|
|
|
|
*/ |
101
|
6
|
|
|
|
|
|
void rhash_swap_copy_str_to_u64(void* to, int index, const void* from, size_t length) |
102
|
|
|
|
|
|
|
{ |
103
|
|
|
|
|
|
|
/* if all pointers and length are 64-bits aligned */ |
104
|
6
|
50
|
|
|
|
|
if ( 0 == (( (int)((char*)to - (char*)0) | ((char*)from - (char*)0) | index | length ) & 7) ) { |
105
|
|
|
|
|
|
|
/* copy aligned memory block as 64-bit integers */ |
106
|
6
|
|
|
|
|
|
const uint64_t* src = (const uint64_t*)from; |
107
|
6
|
|
|
|
|
|
const uint64_t* end = (const uint64_t*)((const char*)src + length); |
108
|
6
|
|
|
|
|
|
uint64_t* dst = (uint64_t*)((char*)to + index); |
109
|
50
|
100
|
|
|
|
|
while (src < end) *(dst++) = bswap_64( *(src++) ); |
110
|
|
|
|
|
|
|
} else { |
111
|
0
|
|
|
|
|
|
const char* src = (const char*)from; |
112
|
0
|
0
|
|
|
|
|
for (length += index; (size_t)index < length; index++) ((char*)to)[index ^ 7] = *(src++); |
113
|
|
|
|
|
|
|
} |
114
|
6
|
|
|
|
|
|
} |
115
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
/** |
117
|
|
|
|
|
|
|
* Copy data from a sequence of 64-bit words to a binary string of given length, |
118
|
|
|
|
|
|
|
* while changing byte order. |
119
|
|
|
|
|
|
|
* |
120
|
|
|
|
|
|
|
* @param to the binary string to receive data |
121
|
|
|
|
|
|
|
* @param from the source sequence of 64-bit words |
122
|
|
|
|
|
|
|
* @param length the size in bytes of the data being copied |
123
|
|
|
|
|
|
|
*/ |
124
|
3
|
|
|
|
|
|
void rhash_swap_copy_u64_to_str(void* to, const void* from, size_t length) |
125
|
|
|
|
|
|
|
{ |
126
|
|
|
|
|
|
|
/* if all pointers and length are 64-bits aligned */ |
127
|
3
|
50
|
|
|
|
|
if ( 0 == (( (int)((char*)to - (char*)0) | ((char*)from - (char*)0) | length ) & 7) ) { |
128
|
|
|
|
|
|
|
/* copy aligned memory block as 64-bit integers */ |
129
|
3
|
|
|
|
|
|
const uint64_t* src = (const uint64_t*)from; |
130
|
3
|
|
|
|
|
|
const uint64_t* end = (const uint64_t*)((const char*)src + length); |
131
|
3
|
|
|
|
|
|
uint64_t* dst = (uint64_t*)to; |
132
|
25
|
100
|
|
|
|
|
while (src < end) *(dst++) = bswap_64( *(src++) ); |
133
|
|
|
|
|
|
|
} else { |
134
|
|
|
|
|
|
|
size_t index; |
135
|
0
|
|
|
|
|
|
char* dst = (char*)to; |
136
|
0
|
0
|
|
|
|
|
for (index = 0; index < length; index++) *(dst++) = ((char*)from)[index ^ 7]; |
137
|
|
|
|
|
|
|
} |
138
|
3
|
|
|
|
|
|
} |
139
|
|
|
|
|
|
|
|
140
|
|
|
|
|
|
|
/** |
141
|
|
|
|
|
|
|
* Exchange byte order in the given array of 32-bit integers. |
142
|
|
|
|
|
|
|
* |
143
|
|
|
|
|
|
|
* @param arr the array to process |
144
|
|
|
|
|
|
|
* @param length array length |
145
|
|
|
|
|
|
|
*/ |
146
|
2
|
|
|
|
|
|
void rhash_u32_mem_swap(unsigned *arr, int length) |
147
|
|
|
|
|
|
|
{ |
148
|
2
|
|
|
|
|
|
unsigned* end = arr + length; |
149
|
12
|
100
|
|
|
|
|
for (; arr < end; arr++) { |
150
|
10
|
|
|
|
|
|
*arr = bswap_32(*arr); |
151
|
|
|
|
|
|
|
} |
152
|
2
|
|
|
|
|
|
} |
153
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
#ifdef HAS_INTEL_CPUID |
155
|
|
|
|
|
|
|
#include |
156
|
|
|
|
|
|
|
|
157
|
2
|
|
|
|
|
|
static uint64_t get_cpuid_features(void) |
158
|
|
|
|
|
|
|
{ |
159
|
|
|
|
|
|
|
uint32_t tmp, edx, ecx; |
160
|
2
|
50
|
|
|
|
|
if (__get_cpuid(1, &tmp, &tmp, &ecx, &edx)) |
161
|
2
|
|
|
|
|
|
return ((((uint64_t)ecx) << 32) ^ edx); |
162
|
2
|
|
|
|
|
|
return 0; |
163
|
|
|
|
|
|
|
} |
164
|
|
|
|
|
|
|
|
165
|
2
|
|
|
|
|
|
int has_cpu_feature(unsigned feature_bit) |
166
|
|
|
|
|
|
|
{ |
167
|
|
|
|
|
|
|
static uint64_t features; |
168
|
2
|
|
|
|
|
|
const uint64_t feature = ((uint64_t)1) << feature_bit; |
169
|
2
|
50
|
|
|
|
|
if (!features) |
170
|
2
|
|
|
|
|
|
features = (get_cpuid_features() | 1); |
171
|
2
|
|
|
|
|
|
return !!(features & feature); |
172
|
|
|
|
|
|
|
} |
173
|
|
|
|
|
|
|
#endif |