3737namespace mongo {
3838
3939template <typename T>
40- struct BigEndian {
41- BigEndian () {}
42- BigEndian (T t) : value(t) {}
43- T value;
44-
45- operator T () const {
46- return value;
47- }
48- };
49-
50- template <typename T>
51- BigEndian<T> tagBigEndian (T t) {
52- return t;
53- }
54-
55- template <typename T>
56- struct LittleEndian {
57- LittleEndian () {}
58- LittleEndian (T t) : value(t) {}
59- T value;
60-
61- operator T () const {
62- return value;
63- }
64- };
65-
66- template <typename T>
67- LittleEndian<T> tagLittleEndian (T t) {
68- return t;
69- }
70-
71- template <typename T>
72- struct DataType ::Handler<BigEndian<T>> {
73- static void unsafeLoad (BigEndian<T>* t, const char * ptr, size_t * advanced) {
74- if (t) {
75- DataType::unsafeLoad (&t->value , ptr, advanced);
76-
77- t->value = endian::bigToNative (t->value );
78- } else {
79- DataType::unsafeLoad (decltype (&t->value ){nullptr }, ptr, advanced);
80- }
81- }
82-
83- static Status load (BigEndian<T>* t,
84- const char * ptr,
85- size_t length,
86- size_t * advanced,
87- std::ptrdiff_t debug_offset) {
88- if (t) {
89- Status x = DataType::load (&t->value , ptr, length, advanced, debug_offset);
90-
91- if (x.isOK ()) {
92- t->value = endian::bigToNative (t->value );
93- }
94-
95- return x;
96- } else {
97- return DataType::load (
98- decltype (&t->value ){nullptr }, ptr, length, advanced, debug_offset);
99- }
100- }
101-
102- static void unsafeStore (const BigEndian<T>& t, char * ptr, size_t * advanced) {
103- DataType::unsafeStore (endian::nativeToBig (t.value ), ptr, advanced);
104- }
105-
106- static Status store (const BigEndian<T>& t,
107- char * ptr,
108- size_t length,
109- size_t * advanced,
110- std::ptrdiff_t debug_offset) {
111- return DataType::store (endian::nativeToBig (t.value ), ptr, length, advanced, debug_offset);
112- }
113-
114- static BigEndian<T> defaultConstruct () {
115- return DataType::defaultConstruct<T>();
116- }
117- };
40+ struct IsEndian : std::false_type {};
41+
42+ #define MAKE_ENDIAN (name, loadFunc, storeFunc ) \
43+ template <typename T> \
44+ struct name { \
45+ using value_type = T; \
46+ name () {} \
47+ name (T t) : value(t) {} \
48+ T value; \
49+ \
50+ operator T () const { \
51+ return value; \
52+ } \
53+ \
54+ static auto load (T t) -> decltype(loadFunc(t)) { \
55+ return loadFunc (t); \
56+ } \
57+ \
58+ static auto store (T t) -> decltype(storeFunc(t)) { \
59+ return storeFunc (t); \
60+ } \
61+ }; \
62+ \
63+ template <typename T> \
64+ name<T> tag##name(T t) { \
65+ return t; \
66+ } \
67+ \
68+ template <typename T> \
69+ struct IsEndian <name<T>> : std::true_type {};
70+
71+ /* *
72+ * BigEndian and LittleEndian offer support for using natively encoded types
73+ * and reading/writing them as big endian or little endian through char ptrs.
74+ *
75+ * The Reverse variants assume the pointed to bytes are natively encoded and
76+ * return big or little endian encoded types. I.e. you probably shouldn't use
77+ * them with floats and should be wary of using them with signed types.
78+ */
79+ MAKE_ENDIAN (BigEndian, endian::bigToNative, endian::nativeToBig)
80+ MAKE_ENDIAN (LittleEndian, endian::littleToNative, endian::nativeToLittle)
81+ MAKE_ENDIAN (ReverseBigEndian, endian::nativeToBig, endian::bigToNative)
82+ MAKE_ENDIAN (ReverseLittleEndian, endian::nativeToLittle, endian::littleToNative)
11883
11984template <typename T>
120- struct DataType ::Handler<LittleEndian<T> > {
121- static void unsafeLoad (LittleEndian<T> * t, const char * ptr, size_t * advanced) {
85+ struct DataType ::Handler<T, typename std::enable_if<IsEndian<T>::value>::type > {
86+ static void unsafeLoad (T * t, const char * ptr, size_t * advanced) {
12287 if (t) {
12388 DataType::unsafeLoad (&t->value , ptr, advanced);
12489
125- t->value = endian::littleToNative (t->value );
90+ t->value = T::load (t->value );
12691 } else {
12792 DataType::unsafeLoad (decltype (&t->value ){nullptr }, ptr, advanced);
12893 }
12994 }
13095
131- static Status load (LittleEndian<T>* t,
132- const char * ptr,
133- size_t length,
134- size_t * advanced,
135- std::ptrdiff_t debug_offset) {
96+ static Status load (
97+ T* t, const char * ptr, size_t length, size_t * advanced, std::ptrdiff_t debug_offset) {
13698 if (t) {
13799 Status x = DataType::load (&t->value , ptr, length, advanced, debug_offset);
138100
139101 if (x.isOK ()) {
140- t->value = endian::littleToNative (t->value );
102+ t->value = T::load (t->value );
141103 }
142104
143105 return x;
@@ -147,21 +109,17 @@ struct DataType::Handler<LittleEndian<T>> {
147109 }
148110 }
149111
150- static void unsafeStore (const LittleEndian<T> & t, char * ptr, size_t * advanced) {
151- DataType::unsafeStore (endian::nativeToLittle (t.value ), ptr, advanced);
112+ static void unsafeStore (const T & t, char * ptr, size_t * advanced) {
113+ DataType::unsafeStore (T::store (t.value ), ptr, advanced);
152114 }
153115
154- static Status store (const LittleEndian<T>& t,
155- char * ptr,
156- size_t length,
157- size_t * advanced,
158- std::ptrdiff_t debug_offset) {
159- return DataType::store (
160- endian::nativeToLittle (t.value ), ptr, length, advanced, debug_offset);
116+ static Status store (
117+ const T& t, char * ptr, size_t length, size_t * advanced, std::ptrdiff_t debug_offset) {
118+ return DataType::store (T::store (t.value ), ptr, length, advanced, debug_offset);
161119 }
162120
163- static LittleEndian<T> defaultConstruct () {
164- return DataType::defaultConstruct<T >();
121+ static typename T::value_type defaultConstruct () {
122+ return DataType::defaultConstruct<typename T::value_type >();
165123 }
166124};
167125
0 commit comments