1218885Sdim//===- Endian.h - Utilities for IO with endian specific data ----*- C++ -*-===//
2218885Sdim//
3218885Sdim//                     The LLVM Compiler Infrastructure
4218885Sdim//
5218885Sdim// This file is distributed under the University of Illinois Open Source
6218885Sdim// License. See LICENSE.TXT for details.
7218885Sdim//
8218885Sdim//===----------------------------------------------------------------------===//
9218885Sdim//
10218885Sdim// This file declares generic functions to read and write endian specific data.
11218885Sdim//
12218885Sdim//===----------------------------------------------------------------------===//
13218885Sdim
14218885Sdim#ifndef LLVM_SUPPORT_ENDIAN_H
15218885Sdim#define LLVM_SUPPORT_ENDIAN_H
16218885Sdim
17249423Sdim#include "llvm/Support/AlignOf.h"
18218885Sdim#include "llvm/Support/Host.h"
19218885Sdim#include "llvm/Support/SwapByteOrder.h"
20218885Sdim#include "llvm/Support/type_traits.h"
21218885Sdim
22218885Sdimnamespace llvm {
23218885Sdimnamespace support {
24249423Sdimenum endianness {big, little, native};
25218885Sdim
26249423Sdim// These are named values for common alignments.
27249423Sdimenum {aligned = 0, unaligned = 1};
28218885Sdim
29218885Sdimnamespace detail {
30249423Sdim  /// \brief ::value is either alignment, or alignof(T) if alignment is 0.
31249423Sdim  template<class T, int alignment>
32249423Sdim  struct PickAlignment {
33249423Sdim    enum {value = alignment == 0 ? AlignOf<T>::Alignment : alignment};
34249423Sdim  };
35218885Sdim} // end namespace detail
36218885Sdim
37218885Sdimnamespace endian {
38249423Sdimtemplate<typename value_type, endianness endian>
39249423Sdiminline value_type byte_swap(value_type value) {
40251662Sdim  if (endian != native && sys::IsBigEndianHost != (endian == big))
41249423Sdim    return sys::SwapByteOrder(value);
42249423Sdim  return value;
43249423Sdim}
44218885Sdim
45249423Sdimtemplate<typename value_type,
46249423Sdim         endianness endian,
47249423Sdim         std::size_t alignment>
48249423Sdiminline value_type read(const void *memory) {
49249423Sdim  value_type ret;
50218885Sdim
51249423Sdim  memcpy(&ret,
52249423Sdim         LLVM_ASSUME_ALIGNED(memory,
53249423Sdim           (detail::PickAlignment<value_type, alignment>::value)),
54249423Sdim         sizeof(value_type));
55249423Sdim  return byte_swap<value_type, endian>(ret);
56249423Sdim}
57218885Sdim
58249423Sdimtemplate<typename value_type,
59249423Sdim         endianness endian,
60249423Sdim         std::size_t alignment>
61249423Sdiminline void write(void *memory, value_type value) {
62249423Sdim  value = byte_swap<value_type, endian>(value);
63249423Sdim  memcpy(LLVM_ASSUME_ALIGNED(memory,
64249423Sdim           (detail::PickAlignment<value_type, alignment>::value)),
65249423Sdim         &value,
66249423Sdim         sizeof(value_type));
67218885Sdim}
68249423Sdim} // end namespace endian
69218885Sdim
70218885Sdimnamespace detail {
71218885Sdimtemplate<typename value_type,
72218885Sdim         endianness endian,
73249423Sdim         std::size_t alignment>
74249423Sdimstruct packed_endian_specific_integral {
75218885Sdim  operator value_type() const {
76249423Sdim    return endian::read<value_type, endian, alignment>(
77249423Sdim      (const void*)Value.buffer);
78218885Sdim  }
79218885Sdim
80234353Sdim  void operator=(value_type newValue) {
81249423Sdim    endian::write<value_type, endian, alignment>(
82249423Sdim      (void*)Value.buffer, newValue);
83234353Sdim  }
84218885Sdim
85218885Sdimprivate:
86249423Sdim  AlignedCharArray<PickAlignment<value_type, alignment>::value,
87249423Sdim                   sizeof(value_type)> Value;
88218885Sdim};
89218885Sdim} // end namespace detail
90218885Sdim
91218885Sdimtypedef detail::packed_endian_specific_integral
92218885Sdim                  <uint8_t, little, unaligned>  ulittle8_t;
93218885Sdimtypedef detail::packed_endian_specific_integral
94218885Sdim                  <uint16_t, little, unaligned> ulittle16_t;
95218885Sdimtypedef detail::packed_endian_specific_integral
96218885Sdim                  <uint32_t, little, unaligned> ulittle32_t;
97218885Sdimtypedef detail::packed_endian_specific_integral
98218885Sdim                  <uint64_t, little, unaligned> ulittle64_t;
99218885Sdim
100218885Sdimtypedef detail::packed_endian_specific_integral
101218885Sdim                   <int8_t, little, unaligned>  little8_t;
102218885Sdimtypedef detail::packed_endian_specific_integral
103218885Sdim                   <int16_t, little, unaligned> little16_t;
104218885Sdimtypedef detail::packed_endian_specific_integral
105218885Sdim                   <int32_t, little, unaligned> little32_t;
106218885Sdimtypedef detail::packed_endian_specific_integral
107218885Sdim                   <int64_t, little, unaligned> little64_t;
108218885Sdim
109218885Sdimtypedef detail::packed_endian_specific_integral
110218885Sdim                    <uint8_t, little, aligned>  aligned_ulittle8_t;
111218885Sdimtypedef detail::packed_endian_specific_integral
112218885Sdim                    <uint16_t, little, aligned> aligned_ulittle16_t;
113218885Sdimtypedef detail::packed_endian_specific_integral
114218885Sdim                    <uint32_t, little, aligned> aligned_ulittle32_t;
115218885Sdimtypedef detail::packed_endian_specific_integral
116218885Sdim                    <uint64_t, little, aligned> aligned_ulittle64_t;
117218885Sdim
118218885Sdimtypedef detail::packed_endian_specific_integral
119218885Sdim                     <int8_t, little, aligned>  aligned_little8_t;
120218885Sdimtypedef detail::packed_endian_specific_integral
121218885Sdim                     <int16_t, little, aligned> aligned_little16_t;
122218885Sdimtypedef detail::packed_endian_specific_integral
123218885Sdim                     <int32_t, little, aligned> aligned_little32_t;
124218885Sdimtypedef detail::packed_endian_specific_integral
125218885Sdim                     <int64_t, little, aligned> aligned_little64_t;
126218885Sdim
127218885Sdimtypedef detail::packed_endian_specific_integral
128218885Sdim                  <uint8_t, big, unaligned>     ubig8_t;
129218885Sdimtypedef detail::packed_endian_specific_integral
130218885Sdim                  <uint16_t, big, unaligned>    ubig16_t;
131218885Sdimtypedef detail::packed_endian_specific_integral
132218885Sdim                  <uint32_t, big, unaligned>    ubig32_t;
133218885Sdimtypedef detail::packed_endian_specific_integral
134218885Sdim                  <uint64_t, big, unaligned>    ubig64_t;
135218885Sdim
136218885Sdimtypedef detail::packed_endian_specific_integral
137218885Sdim                   <int8_t, big, unaligned>     big8_t;
138218885Sdimtypedef detail::packed_endian_specific_integral
139218885Sdim                   <int16_t, big, unaligned>    big16_t;
140218885Sdimtypedef detail::packed_endian_specific_integral
141218885Sdim                   <int32_t, big, unaligned>    big32_t;
142218885Sdimtypedef detail::packed_endian_specific_integral
143218885Sdim                   <int64_t, big, unaligned>    big64_t;
144218885Sdim
145218885Sdimtypedef detail::packed_endian_specific_integral
146218885Sdim                    <uint8_t, big, aligned>     aligned_ubig8_t;
147218885Sdimtypedef detail::packed_endian_specific_integral
148218885Sdim                    <uint16_t, big, aligned>    aligned_ubig16_t;
149218885Sdimtypedef detail::packed_endian_specific_integral
150218885Sdim                    <uint32_t, big, aligned>    aligned_ubig32_t;
151218885Sdimtypedef detail::packed_endian_specific_integral
152218885Sdim                    <uint64_t, big, aligned>    aligned_ubig64_t;
153218885Sdim
154218885Sdimtypedef detail::packed_endian_specific_integral
155218885Sdim                     <int8_t, big, aligned>     aligned_big8_t;
156218885Sdimtypedef detail::packed_endian_specific_integral
157218885Sdim                     <int16_t, big, aligned>    aligned_big16_t;
158218885Sdimtypedef detail::packed_endian_specific_integral
159218885Sdim                     <int32_t, big, aligned>    aligned_big32_t;
160218885Sdimtypedef detail::packed_endian_specific_integral
161218885Sdim                     <int64_t, big, aligned>    aligned_big64_t;
162218885Sdim
163249423Sdimtypedef detail::packed_endian_specific_integral
164249423Sdim                  <uint16_t, native, unaligned> unaligned_uint16_t;
165249423Sdimtypedef detail::packed_endian_specific_integral
166249423Sdim                  <uint32_t, native, unaligned> unaligned_uint32_t;
167249423Sdimtypedef detail::packed_endian_specific_integral
168249423Sdim                  <uint64_t, native, unaligned> unaligned_uint64_t;
169249423Sdim
170249423Sdimtypedef detail::packed_endian_specific_integral
171249423Sdim                   <int16_t, native, unaligned> unaligned_int16_t;
172249423Sdimtypedef detail::packed_endian_specific_integral
173249423Sdim                   <int32_t, native, unaligned> unaligned_int32_t;
174249423Sdimtypedef detail::packed_endian_specific_integral
175249423Sdim                   <int64_t, native, unaligned> unaligned_int64_t;
176218885Sdim} // end namespace llvm
177218885Sdim} // end namespace support
178218885Sdim
179218885Sdim#endif
180