[libc][NFC] Move aligned access implementations to separate header
[llvm-project.git] / libc / src / __support / endian.h
blobcc4eaa29ff3476d7d4a2d752fb2d8fb379e070ec
1 //===-- Endianness support --------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_LIBC_SRC_SUPPORT_ENDIAN_H
10 #define LLVM_LIBC_SRC_SUPPORT_ENDIAN_H
12 #include "common.h"
14 #include <stdint.h>
16 namespace __llvm_libc {
18 // We rely on compiler preprocessor defines to allow for cross compilation.
19 #if !defined(__BYTE_ORDER__) || !defined(__ORDER_LITTLE_ENDIAN__) || \
20 !defined(__ORDER_BIG_ENDIAN__)
21 #error "Missing preprocessor definitions for endianness detection."
22 #endif
24 namespace internal {
26 // Converts uint8_t, uint16_t, uint32_t, uint64_t to its big or little endian
27 // counterpart.
28 // We use explicit template specialization:
29 // - to prevent accidental integer promotion.
30 // - to prevent fallback in (unlikely) case of middle-endianness.
32 template <unsigned ORDER> struct Endian {
33 static constexpr const bool IS_LITTLE = ORDER == __ORDER_LITTLE_ENDIAN__;
34 static constexpr const bool IS_BIG = ORDER == __ORDER_BIG_ENDIAN__;
35 template <typename T> LIBC_INLINE static T to_big_endian(T value);
36 template <typename T> LIBC_INLINE static T to_little_endian(T value);
39 // Little Endian specializations
40 template <>
41 template <>
42 LIBC_INLINE uint8_t
43 Endian<__ORDER_LITTLE_ENDIAN__>::to_big_endian<uint8_t>(uint8_t v) {
44 return v;
46 template <>
47 template <>
48 LIBC_INLINE uint8_t
49 Endian<__ORDER_LITTLE_ENDIAN__>::to_little_endian<uint8_t>(uint8_t v) {
50 return v;
52 template <>
53 template <>
54 LIBC_INLINE uint16_t
55 Endian<__ORDER_LITTLE_ENDIAN__>::to_big_endian<uint16_t>(uint16_t v) {
56 return __builtin_bswap16(v);
58 template <>
59 template <>
60 LIBC_INLINE uint16_t
61 Endian<__ORDER_LITTLE_ENDIAN__>::to_little_endian<uint16_t>(uint16_t v) {
62 return v;
64 template <>
65 template <>
66 LIBC_INLINE uint32_t
67 Endian<__ORDER_LITTLE_ENDIAN__>::to_big_endian<uint32_t>(uint32_t v) {
68 return __builtin_bswap32(v);
70 template <>
71 template <>
72 LIBC_INLINE uint32_t
73 Endian<__ORDER_LITTLE_ENDIAN__>::to_little_endian<uint32_t>(uint32_t v) {
74 return v;
76 template <>
77 template <>
78 LIBC_INLINE uint64_t
79 Endian<__ORDER_LITTLE_ENDIAN__>::to_big_endian<uint64_t>(uint64_t v) {
80 return __builtin_bswap64(v);
82 template <>
83 template <>
84 LIBC_INLINE uint64_t
85 Endian<__ORDER_LITTLE_ENDIAN__>::to_little_endian<uint64_t>(uint64_t v) {
86 return v;
89 // Big Endian specializations
90 template <>
91 template <>
92 LIBC_INLINE uint8_t
93 Endian<__ORDER_BIG_ENDIAN__>::to_big_endian<uint8_t>(uint8_t v) {
94 return v;
96 template <>
97 template <>
98 LIBC_INLINE uint8_t
99 Endian<__ORDER_BIG_ENDIAN__>::to_little_endian<uint8_t>(uint8_t v) {
100 return v;
102 template <>
103 template <>
104 LIBC_INLINE uint16_t
105 Endian<__ORDER_BIG_ENDIAN__>::to_big_endian<uint16_t>(uint16_t v) {
106 return v;
108 template <>
109 template <>
110 LIBC_INLINE uint16_t
111 Endian<__ORDER_BIG_ENDIAN__>::to_little_endian<uint16_t>(uint16_t v) {
112 return __builtin_bswap16(v);
114 template <>
115 template <>
116 LIBC_INLINE uint32_t
117 Endian<__ORDER_BIG_ENDIAN__>::to_big_endian<uint32_t>(uint32_t v) {
118 return v;
120 template <>
121 template <>
122 LIBC_INLINE uint32_t
123 Endian<__ORDER_BIG_ENDIAN__>::to_little_endian<uint32_t>(uint32_t v) {
124 return __builtin_bswap32(v);
126 template <>
127 template <>
128 LIBC_INLINE uint64_t
129 Endian<__ORDER_BIG_ENDIAN__>::to_big_endian<uint64_t>(uint64_t v) {
130 return v;
132 template <>
133 template <>
134 LIBC_INLINE uint64_t
135 Endian<__ORDER_BIG_ENDIAN__>::to_little_endian<uint64_t>(uint64_t v) {
136 return __builtin_bswap64(v);
139 } // namespace internal
141 using Endian = internal::Endian<__BYTE_ORDER__>;
143 } // namespace __llvm_libc
145 #endif // LLVM_LIBC_SRC_SUPPORT_ENDIAN_H