1//===- Endian.h - Utilities for IO with endian specific data ----*- C++ -*-===//
2//
3//                     The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file declares generic functions to read and write endian specific data.
11//
12//===----------------------------------------------------------------------===//
13
14#ifndef LLVM_SUPPORT_ENDIAN_H
15#define LLVM_SUPPORT_ENDIAN_H
16
17#include "llvm/Support/AlignOf.h"
18#include "llvm/Support/Host.h"
19#include "llvm/Support/SwapByteOrder.h"
20
21namespace llvm {
22namespace support {
23enum endianness {big, little, native};
24
25// These are named values for common alignments.
26enum {aligned = 0, unaligned = 1};
27
28namespace detail {
29  /// \brief ::value is either alignment, or alignof(T) if alignment is 0.
30  template<class T, int alignment>
31  struct PickAlignment {
32    enum {value = alignment == 0 ? AlignOf<T>::Alignment : alignment};
33  };
34} // end namespace detail
35
36namespace endian {
37/// Swap the bytes of value to match the given endianness.
38template<typename value_type, endianness endian>
39inline value_type byte_swap(value_type value) {
40  if (endian != native && sys::IsBigEndianHost != (endian == big))
41    sys::swapByteOrder(value);
42  return value;
43}
44
45/// Read a value of a particular endianness from memory.
46template<typename value_type,
47         endianness endian,
48         std::size_t alignment>
49inline value_type read(const void *memory) {
50  value_type ret;
51
52  memcpy(&ret,
53         LLVM_ASSUME_ALIGNED(memory,
54           (detail::PickAlignment<value_type, alignment>::value)),
55         sizeof(value_type));
56  return byte_swap<value_type, endian>(ret);
57}
58
59/// Read a value of a particular endianness from a buffer, and increment the
60/// buffer past that value.
61template<typename value_type, endianness endian, std::size_t alignment>
62inline value_type readNext(const unsigned char *&memory) {
63  value_type ret = read<value_type, endian, alignment>(memory);
64  memory += sizeof(value_type);
65  return ret;
66}
67
68/// Write a value to memory with a particular endianness.
69template<typename value_type,
70         endianness endian,
71         std::size_t alignment>
72inline void write(void *memory, value_type value) {
73  value = byte_swap<value_type, endian>(value);
74  memcpy(LLVM_ASSUME_ALIGNED(memory,
75           (detail::PickAlignment<value_type, alignment>::value)),
76         &value,
77         sizeof(value_type));
78}
79} // end namespace endian
80
81namespace detail {
82template<typename value_type,
83         endianness endian,
84         std::size_t alignment>
85struct packed_endian_specific_integral {
86  operator value_type() const {
87    return endian::read<value_type, endian, alignment>(
88      (const void*)Value.buffer);
89  }
90
91  void operator=(value_type newValue) {
92    endian::write<value_type, endian, alignment>(
93      (void*)Value.buffer, newValue);
94  }
95
96private:
97  AlignedCharArray<PickAlignment<value_type, alignment>::value,
98                   sizeof(value_type)> Value;
99};
100} // end namespace detail
101
102typedef detail::packed_endian_specific_integral
103                  <uint8_t, little, unaligned>  ulittle8_t;
104typedef detail::packed_endian_specific_integral
105                  <uint16_t, little, unaligned> ulittle16_t;
106typedef detail::packed_endian_specific_integral
107                  <uint32_t, little, unaligned> ulittle32_t;
108typedef detail::packed_endian_specific_integral
109                  <uint64_t, little, unaligned> ulittle64_t;
110
111typedef detail::packed_endian_specific_integral
112                   <int8_t, little, unaligned>  little8_t;
113typedef detail::packed_endian_specific_integral
114                   <int16_t, little, unaligned> little16_t;
115typedef detail::packed_endian_specific_integral
116                   <int32_t, little, unaligned> little32_t;
117typedef detail::packed_endian_specific_integral
118                   <int64_t, little, unaligned> little64_t;
119
120typedef detail::packed_endian_specific_integral
121                    <uint8_t, little, aligned>  aligned_ulittle8_t;
122typedef detail::packed_endian_specific_integral
123                    <uint16_t, little, aligned> aligned_ulittle16_t;
124typedef detail::packed_endian_specific_integral
125                    <uint32_t, little, aligned> aligned_ulittle32_t;
126typedef detail::packed_endian_specific_integral
127                    <uint64_t, little, aligned> aligned_ulittle64_t;
128
129typedef detail::packed_endian_specific_integral
130                     <int8_t, little, aligned>  aligned_little8_t;
131typedef detail::packed_endian_specific_integral
132                     <int16_t, little, aligned> aligned_little16_t;
133typedef detail::packed_endian_specific_integral
134                     <int32_t, little, aligned> aligned_little32_t;
135typedef detail::packed_endian_specific_integral
136                     <int64_t, little, aligned> aligned_little64_t;
137
138typedef detail::packed_endian_specific_integral
139                  <uint8_t, big, unaligned>     ubig8_t;
140typedef detail::packed_endian_specific_integral
141                  <uint16_t, big, unaligned>    ubig16_t;
142typedef detail::packed_endian_specific_integral
143                  <uint32_t, big, unaligned>    ubig32_t;
144typedef detail::packed_endian_specific_integral
145                  <uint64_t, big, unaligned>    ubig64_t;
146
147typedef detail::packed_endian_specific_integral
148                   <int8_t, big, unaligned>     big8_t;
149typedef detail::packed_endian_specific_integral
150                   <int16_t, big, unaligned>    big16_t;
151typedef detail::packed_endian_specific_integral
152                   <int32_t, big, unaligned>    big32_t;
153typedef detail::packed_endian_specific_integral
154                   <int64_t, big, unaligned>    big64_t;
155
156typedef detail::packed_endian_specific_integral
157                    <uint8_t, big, aligned>     aligned_ubig8_t;
158typedef detail::packed_endian_specific_integral
159                    <uint16_t, big, aligned>    aligned_ubig16_t;
160typedef detail::packed_endian_specific_integral
161                    <uint32_t, big, aligned>    aligned_ubig32_t;
162typedef detail::packed_endian_specific_integral
163                    <uint64_t, big, aligned>    aligned_ubig64_t;
164
165typedef detail::packed_endian_specific_integral
166                     <int8_t, big, aligned>     aligned_big8_t;
167typedef detail::packed_endian_specific_integral
168                     <int16_t, big, aligned>    aligned_big16_t;
169typedef detail::packed_endian_specific_integral
170                     <int32_t, big, aligned>    aligned_big32_t;
171typedef detail::packed_endian_specific_integral
172                     <int64_t, big, aligned>    aligned_big64_t;
173
174typedef detail::packed_endian_specific_integral
175                  <uint16_t, native, unaligned> unaligned_uint16_t;
176typedef detail::packed_endian_specific_integral
177                  <uint32_t, native, unaligned> unaligned_uint32_t;
178typedef detail::packed_endian_specific_integral
179                  <uint64_t, native, unaligned> unaligned_uint64_t;
180
181typedef detail::packed_endian_specific_integral
182                   <int16_t, native, unaligned> unaligned_int16_t;
183typedef detail::packed_endian_specific_integral
184                   <int32_t, native, unaligned> unaligned_int32_t;
185typedef detail::packed_endian_specific_integral
186                   <int64_t, native, unaligned> unaligned_int64_t;
187} // end namespace llvm
188} // end namespace support
189
190#endif
191