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,
62         typename CharT>
63inline value_type readNext(const CharT *&memory) {
64  value_type ret = read<value_type, endian, alignment>(memory);
65  memory += sizeof(value_type);
66  return ret;
67}
68
69/// Write a value to memory with a particular endianness.
70template<typename value_type,
71         endianness endian,
72         std::size_t alignment>
73inline void write(void *memory, value_type value) {
74  value = byte_swap<value_type, endian>(value);
75  memcpy(LLVM_ASSUME_ALIGNED(memory,
76           (detail::PickAlignment<value_type, alignment>::value)),
77         &value,
78         sizeof(value_type));
79}
80} // end namespace endian
81
82namespace detail {
83template<typename value_type,
84         endianness endian,
85         std::size_t alignment>
86struct packed_endian_specific_integral {
87  operator value_type() const {
88    return endian::read<value_type, endian, alignment>(
89      (const void*)Value.buffer);
90  }
91
92  void operator=(value_type newValue) {
93    endian::write<value_type, endian, alignment>(
94      (void*)Value.buffer, newValue);
95  }
96
97  packed_endian_specific_integral &operator+=(value_type newValue) {
98    *this = *this + newValue;
99    return *this;
100  }
101
102  packed_endian_specific_integral &operator-=(value_type newValue) {
103    *this = *this - newValue;
104    return *this;
105  }
106
107private:
108  AlignedCharArray<PickAlignment<value_type, alignment>::value,
109                   sizeof(value_type)> Value;
110
111public:
112  struct ref {
113    explicit ref(void *Ptr) : Ptr(Ptr) {}
114
115    operator value_type() const {
116      return endian::read<value_type, endian, alignment>(Ptr);
117    }
118
119    void operator=(value_type NewValue) {
120      endian::write<value_type, endian, alignment>(Ptr, NewValue);
121    }
122
123  private:
124    void *Ptr;
125  };
126};
127
128} // end namespace detail
129
130typedef detail::packed_endian_specific_integral
131                  <uint16_t, little, unaligned> ulittle16_t;
132typedef detail::packed_endian_specific_integral
133                  <uint32_t, little, unaligned> ulittle32_t;
134typedef detail::packed_endian_specific_integral
135                  <uint64_t, little, unaligned> ulittle64_t;
136
137typedef detail::packed_endian_specific_integral
138                   <int16_t, little, unaligned> little16_t;
139typedef detail::packed_endian_specific_integral
140                   <int32_t, little, unaligned> little32_t;
141typedef detail::packed_endian_specific_integral
142                   <int64_t, little, unaligned> little64_t;
143
144typedef detail::packed_endian_specific_integral
145                    <uint16_t, little, aligned> aligned_ulittle16_t;
146typedef detail::packed_endian_specific_integral
147                    <uint32_t, little, aligned> aligned_ulittle32_t;
148typedef detail::packed_endian_specific_integral
149                    <uint64_t, little, aligned> aligned_ulittle64_t;
150
151typedef detail::packed_endian_specific_integral
152                     <int16_t, little, aligned> aligned_little16_t;
153typedef detail::packed_endian_specific_integral
154                     <int32_t, little, aligned> aligned_little32_t;
155typedef detail::packed_endian_specific_integral
156                     <int64_t, little, aligned> aligned_little64_t;
157
158typedef detail::packed_endian_specific_integral
159                  <uint16_t, big, unaligned>    ubig16_t;
160typedef detail::packed_endian_specific_integral
161                  <uint32_t, big, unaligned>    ubig32_t;
162typedef detail::packed_endian_specific_integral
163                  <uint64_t, big, unaligned>    ubig64_t;
164
165typedef detail::packed_endian_specific_integral
166                   <int16_t, big, unaligned>    big16_t;
167typedef detail::packed_endian_specific_integral
168                   <int32_t, big, unaligned>    big32_t;
169typedef detail::packed_endian_specific_integral
170                   <int64_t, big, unaligned>    big64_t;
171
172typedef detail::packed_endian_specific_integral
173                    <uint16_t, big, aligned>    aligned_ubig16_t;
174typedef detail::packed_endian_specific_integral
175                    <uint32_t, big, aligned>    aligned_ubig32_t;
176typedef detail::packed_endian_specific_integral
177                    <uint64_t, big, aligned>    aligned_ubig64_t;
178
179typedef detail::packed_endian_specific_integral
180                     <int16_t, big, aligned>    aligned_big16_t;
181typedef detail::packed_endian_specific_integral
182                     <int32_t, big, aligned>    aligned_big32_t;
183typedef detail::packed_endian_specific_integral
184                     <int64_t, big, aligned>    aligned_big64_t;
185
186typedef detail::packed_endian_specific_integral
187                  <uint16_t, native, unaligned> unaligned_uint16_t;
188typedef detail::packed_endian_specific_integral
189                  <uint32_t, native, unaligned> unaligned_uint32_t;
190typedef detail::packed_endian_specific_integral
191                  <uint64_t, native, unaligned> unaligned_uint64_t;
192
193typedef detail::packed_endian_specific_integral
194                   <int16_t, native, unaligned> unaligned_int16_t;
195typedef detail::packed_endian_specific_integral
196                   <int32_t, native, unaligned> unaligned_int32_t;
197typedef detail::packed_endian_specific_integral
198                   <int64_t, native, unaligned> unaligned_int64_t;
199
200namespace endian {
201inline uint16_t read16le(const void *p) { return *(const ulittle16_t *)p; }
202inline uint32_t read32le(const void *p) { return *(const ulittle32_t *)p; }
203inline uint64_t read64le(const void *p) { return *(const ulittle64_t *)p; }
204inline uint16_t read16be(const void *p) { return *(const ubig16_t *)p; }
205inline uint32_t read32be(const void *p) { return *(const ubig32_t *)p; }
206inline uint64_t read64be(const void *p) { return *(const ubig64_t *)p; }
207
208inline void write16le(void *p, uint16_t v) { *(ulittle16_t *)p = v; }
209inline void write32le(void *p, uint32_t v) { *(ulittle32_t *)p = v; }
210inline void write64le(void *p, uint64_t v) { *(ulittle64_t *)p = v; }
211inline void write16be(void *p, uint16_t v) { *(ubig16_t *)p = v; }
212inline void write32be(void *p, uint32_t v) { *(ubig32_t *)p = v; }
213inline void write64be(void *p, uint64_t v) { *(ubig64_t *)p = v; }
214} // end namespace endian
215} // end namespace support
216} // end namespace llvm
217
218#endif
219