Fix for x86_64 build fail
[platform/upstream/connectedhomeip.git] / third_party / pigweed / repo / pw_bytes / public / pw_bytes / array.h
1 // Copyright 2020 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14
15 // Utilities for building std::byte arrays from strings or integer values at
16 // compile time.
17 #pragma once
18
19 #include <array>
20 #include <cstddef>
21 #include <iterator>
22
23 namespace pw::bytes {
24 namespace internal {
25
26 template <typename T>
27 constexpr bool UseBytesDirectly = std::is_integral_v<T> || std::is_enum_v<T>;
28
29 // Internal implementation functions. CopyBytes copies bytes from an array of
30 // byte-sized elements or the underlying bytes of an integer (as little-endian).
31 // std::memcpy cannot be used since it is not constexpr.
32 template <typename B, typename T, typename... Args>
33 consteval void CopyBytes(B* array, T value, Args... args) {
34   static_assert(sizeof(B) == sizeof(std::byte));
35
36   if constexpr (UseBytesDirectly<T>) {
37     if constexpr (sizeof(T) == 1u) {
38       *array++ = static_cast<B>(value);
39     } else {
40       for (size_t i = 0; i < sizeof(T); ++i) {
41         *array++ = static_cast<B>(value & 0xFF);
42         value >>= 8;
43       }
44     }
45   } else {
46     static_assert(sizeof(value[0]) == sizeof(B));
47     for (auto b : value) {
48       *array++ = static_cast<B>(b);
49     }
50   }
51
52   if constexpr (sizeof...(args) > 0u) {
53     CopyBytes(array, args...);
54   }
55 }
56
57 // Evaluates to the size in bytes of an integer or byte array.
58 template <typename T>
59 consteval size_t SizeOfBytes(const T& arg) {
60   if constexpr (UseBytesDirectly<T>) {
61     return sizeof(arg);
62   } else {
63     static_assert(sizeof(arg[0]) == sizeof(std::byte));
64     return std::size(arg);
65   }
66 }
67
68 template <typename B, typename T, size_t... kIndex>
69 consteval auto String(const T& array, std::index_sequence<kIndex...>) {
70   return std::array{static_cast<B>(array[kIndex])...};
71 }
72
73 template <typename T, typename U>
74 consteval bool CanBeRepresentedAsByteType(const U& value) {
75   return static_cast<U>(static_cast<T>(value)) == value;
76 }
77
78 }  // namespace internal
79
80 // Concatenates arrays or integers as a byte array at compile time. Integer
81 // values are copied little-endian. Spans are copied byte-for-byte.
82 template <typename B = std::byte, typename... Args>
83 consteval auto Concat(Args... args) {
84   std::array<B, (internal::SizeOfBytes(args) + ...)> bytes{};
85   internal::CopyBytes(bytes.begin(), args...);
86   return bytes;
87 }
88
89 // Converts a string literal to an array of bytes, without the trailing '\0'.
90 template <typename B = std::byte,
91           size_t size,
92           typename Indices = std::make_index_sequence<size - 1>>
93 consteval auto String(const char (&str)[size]) {
94   return internal::String<B>(str, Indices{});
95 }
96
97 // String overload for the empty string "".
98 template <typename B = std::byte>
99 consteval auto String(const char (&)[1]) {
100   return std::array<B, 0>{};
101 }
102
103 // Creates an array of bytes from values passed as template parameters. The
104 // values are guaranteed to be representable in the destination byte type.
105 template <typename B, auto... values>
106 consteval auto Array() {
107   static_assert((internal::CanBeRepresentedAsByteType<B>(values) && ...));
108   return std::array<B, sizeof...(values)>{static_cast<B>(values)...};
109 }
110
111 // Array() defaults to using std::byte.
112 template <auto... values>
113 consteval auto Array() {
114   return Array<std::byte, values...>();
115 }
116
117 // Creates an initialized array of bytes. Initializes the array to a value or
118 // the return values from a function that accepts the index as a parameter.
119 template <typename B, size_t size, typename T>
120 constexpr auto Initialized(const T& value_or_function) {
121   std::array<B, size> array{};
122
123   for (size_t i = 0; i < size; ++i) {
124     if constexpr (std::is_integral_v<T>) {
125       array[i] = static_cast<B>(value_or_function);
126     } else {
127       array[i] = static_cast<B>(value_or_function(i));
128     }
129   }
130   return array;
131 }
132
133 // Initialized(value_or_function) defaults to using std::byte.
134 template <size_t size, typename T>
135 constexpr auto Initialized(const T& value_or_function) {
136   return Initialized<std::byte, size>(value_or_function);
137 }
138
139 // Creates an array of bytes from a series of function arguments. Unlike
140 // Array(), MakeArray() cannot check if the values fit in the destination type.
141 // MakeArray() should only be used when Array() is not suitable.
142 template <typename B = std::byte, typename... Args>
143 constexpr auto MakeArray(const Args&... args) {
144   return std::array<B, sizeof...(args)>{static_cast<B>(args)...};
145 }
146
147 }  // namespace pw::bytes