1
// Code taken from Boost.Geometry
3
// Copyright Mateusz Loskot <mateusz@loskot.net> 2009
4
// Use, modification and distribution is subject to the Boost Software License,
5
// Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
6
// http://www.boost.org/LICENSE_1_0.txt)
8
// Load/Store values from/to stream of bytes across different endianness.
10
// Original design of unrolled_byte_loops templates based on
11
// endian utility library from Boost C++ Libraries,
12
// source: boost/spirit/home/support/detail/integer/endian.hpp
13
// Copyright Darin Adler 2000
14
// Copyright Beman Dawes 2006, 2009
15
// Distributed under the Boost Software License, Version 1.0.
17
#ifndef LIBLAS_DETAIL_BINARY_HPP_INCLUDED
18
#define LIBLAS_DETAIL_BINARY_HPP_INCLUDED
26
#include <boost/config.hpp>
27
#include <boost/cstdint.hpp>
28
#include <boost/static_assert.hpp>
29
#include <boost/detail/endian.hpp>
30
#include <boost/type_traits/is_signed.hpp>
33
#error Platforms with CHAR_BIT != 8 are not supported
36
// TODO: mloskot - add static asserts to validate compile-time pre-conditions
40
namespace detail { namespace binary {
42
// Endianness tag used to indicate load/store directoin
44
struct big_endian_tag {};
45
struct little_endian_tag {};
47
#ifdef BOOST_BIG_ENDIAN
48
typedef big_endian_tag native_endian_tag;
50
typedef little_endian_tag native_endian_tag;
53
// Unrolled loops for loading and storing streams of bytes.
55
template <typename T, std::size_t N, bool Sign = boost::is_signed<T>::value>
56
struct unrolled_byte_loops
58
typedef unrolled_byte_loops<T, N - 1, Sign> next;
60
template <typename Iterator>
61
static T load_forward(Iterator& bytes)
63
T const value = *bytes;
65
return value | (next::load_forward(bytes) << 8);
68
template <typename Iterator>
69
static T load_backward(Iterator& bytes)
71
T const value = *(bytes - 1);
73
return value | (next::load_backward(bytes) << 8);
76
template <typename Iterator>
77
static void store_forward(Iterator& bytes, T value)
79
*bytes = static_cast<char>(value);
80
next::store_forward(++bytes, value >> 8);
83
template <typename Iterator>
84
static void store_backward(Iterator& bytes, T value)
86
*(bytes - 1) = static_cast<char>(value);
87
next::store_backward(--bytes, value >> 8);
92
struct unrolled_byte_loops<T, 1, false>
94
template <typename Iterator>
95
static T load_forward(Iterator& bytes)
100
template <typename Iterator>
101
static T load_backward(Iterator& bytes)
106
template <typename Iterator>
107
static void store_forward(Iterator& bytes, T value)
109
// typename Iterator::value_type
110
*bytes = static_cast<char>(value);
113
template <typename Iterator>
114
static void store_backward(Iterator& bytes, T value)
116
*(bytes - 1) = static_cast<char>(value);
120
template <typename T>
121
struct unrolled_byte_loops<T, 1, true>
123
template <typename Iterator>
124
static T load_forward(Iterator& bytes)
126
return *reinterpret_cast<const signed char*>(&*bytes);
129
template <typename Iterator>
130
static T load_backward(Iterator& bytes)
132
return *reinterpret_cast<const signed char*>(&*(bytes - 1));
135
template <typename Iterator>
136
static void store_forward(Iterator& bytes, T value)
138
*bytes = static_cast<char>(value);
141
template <typename Iterator>
142
static void store_backward(Iterator& bytes, T value)
144
*(bytes - 1) = static_cast<char>(value);
148
// load/store operation dispatch
149
// E, E - source and target endianness is the same
150
// E1, E2 - source and target endianness is different (big-endian <-> little-endian)
152
template <typename T, std::size_t N, typename Iterator, typename E>
153
T load_dispatch(Iterator& bytes, E, E)
155
return unrolled_byte_loops<T, N>::load_forward(bytes);
158
template <typename T, std::size_t N, typename Iterator, typename E1, typename E2>
159
T load_dispatch(Iterator& bytes, E1, E2)
161
std::advance(bytes, N);
162
return unrolled_byte_loops<T, N>::load_backward(bytes);
165
template <typename T, std::size_t N, typename Iterator, typename E>
166
void store_dispatch(Iterator& bytes, T value, E, E)
168
return unrolled_byte_loops<T, N>::store_forward(bytes, value);
171
template <typename T, std::size_t N, typename Iterator, typename E1, typename E2>
172
void store_dispatch(Iterator& bytes, T value, E1, E2)
174
std::advance(bytes, N);
175
return unrolled_byte_loops<T, N>::store_backward(bytes, value);
178
// numeric value holder for load/store operation
180
template <typename T>
181
struct endian_value_base
183
typedef T value_type;
184
typedef native_endian_tag endian_type;
186
endian_value_base() : value(T()) {}
187
explicit endian_value_base(T value) : value(value) {}
198
template <typename T, std::size_t N = sizeof(T)>
199
struct endian_value : public endian_value_base<T>
201
typedef endian_value_base<T> base;
204
explicit endian_value(T value) : base(value) {}
206
template <typename E, typename Iterator>
207
void load(Iterator bytes)
209
base::value = load_dispatch<T, N>(bytes, typename base::endian_type(), E());
212
template <typename E, typename Iterator>
213
void store(Iterator bytes)
215
store_dispatch<T, N>(bytes, base::value, typename base::endian_type(), E());
220
struct endian_value<double, 8> : public endian_value_base<double>
222
typedef endian_value_base<double> base;
225
explicit endian_value(double value) : base(value) {}
227
template <typename E, typename Iterator>
228
void load(Iterator bytes)
230
endian_value<boost::uint64_t, 8> raw;
233
double& target_value = base::value;
234
std::memcpy(&target_value, &raw, sizeof(double));
237
template <typename E, typename Iterator>
238
void store(Iterator bytes)
241
double const& source_value = base::value;
242
std::memcpy(&raw, &source_value, sizeof(boost::uint64_t));
247
sizeof(boost::uint64_t)
248
>(bytes, raw, typename base::endian_type(), E());
252
}} // namespace detail::binary
253
} // namespace liblas
255
#endif // LIBLAS_DETAIL_BINARY_HPP_INCLUDED