1///////////////////////////////////////////////////////////////////////////////
2//
3// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
4//
5// This code is licensed under the MIT License (MIT).
6//
7// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
8// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
9// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
10// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
11// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
12// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
13// THE SOFTWARE.
14//
15///////////////////////////////////////////////////////////////////////////////
16
17#ifndef GSL_BYTE_H
18#define GSL_BYTE_H
19
20//
21// make suppress attributes work for some compilers
22// Hopefully temporary until suppression standardization occurs
23//
24#if defined(__clang__)
25#define GSL_SUPPRESS(x) [[gsl::suppress("x")]]
26#else
27#if defined(_MSC_VER)
28#define GSL_SUPPRESS(x) [[gsl::suppress(x)]]
29#else
30#define GSL_SUPPRESS(x)
31#endif // _MSC_VER
32#endif // __clang__
33
34#include <type_traits>
35
36// VS2017 15.8 added support for the __cpp_lib_byte definition
37// To do: drop _HAS_STD_BYTE when support for pre 15.8 expires
38#ifdef _MSC_VER
39
40#pragma warning(push)
41
42// Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool.
43#pragma warning(disable : 26493) // don't use c-style casts // TODO: MSVC suppression in templates does not always work
44
45#ifndef GSL_USE_STD_BYTE
46// this tests if we are under MSVC and the standard lib has std::byte and it is enabled
47#if (defined(_HAS_STD_BYTE) && _HAS_STD_BYTE) || (defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603)
48
49#define GSL_USE_STD_BYTE 1
50
51#else // (defined(_HAS_STD_BYTE) && _HAS_STD_BYTE) || (defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603)
52
53#define GSL_USE_STD_BYTE 0
54
55#endif // (defined(_HAS_STD_BYTE) && _HAS_STD_BYTE) || (defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603)
56#endif // GSL_USE_STD_BYTE
57
58#else // _MSC_VER
59
60#ifndef GSL_USE_STD_BYTE
61#include <cstddef> /* __cpp_lib_byte */
62// this tests if we are under GCC or Clang with enough -std:c++1z power to get us std::byte
63// also check if libc++ version is sufficient (> 5.0) or libstc++ actually contains std::byte
64#if defined(__cplusplus) && (__cplusplus >= 201703L) && \
65  (defined(__cpp_lib_byte) && (__cpp_lib_byte >= 201603)  || \
66   defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 5000))
67
68#define GSL_USE_STD_BYTE 1
69
70#else // defined(__cplusplus) && (__cplusplus >= 201703L) &&
71      //   (defined(__cpp_lib_byte) && (__cpp_lib_byte >= 201603)  ||
72      //    defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 5000))
73
74#define GSL_USE_STD_BYTE 0
75
76#endif //defined(__cplusplus) && (__cplusplus >= 201703L) &&
77       //   (defined(__cpp_lib_byte) && (__cpp_lib_byte >= 201603)  ||
78       //    defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 5000))
79#endif // GSL_USE_STD_BYTE
80
81#endif // _MSC_VER
82
83// Use __may_alias__ attribute on gcc and clang
84#if defined __clang__ || (defined(__GNUC__) && __GNUC__ > 5)
85#define byte_may_alias __attribute__((__may_alias__))
86#else // defined __clang__ || defined __GNUC__
87#define byte_may_alias
88#endif // defined __clang__ || defined __GNUC__
89
90#if GSL_USE_STD_BYTE
91#include <cstddef>
92#endif
93
94namespace gsl
95{
96#if GSL_USE_STD_BYTE
97
98using std::byte;
99using std::to_integer;
100
101#else // GSL_USE_STD_BYTE
102
103// This is a simple definition for now that allows
104// use of byte within span<> to be standards-compliant
105enum class byte_may_alias byte : unsigned char
106{
107};
108
109template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
110constexpr byte& operator<<=(byte& b, IntegerType shift) noexcept
111{
112    return b = byte(static_cast<unsigned char>(b) << shift);
113}
114
115template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
116constexpr byte operator<<(byte b, IntegerType shift) noexcept
117{
118    return byte(static_cast<unsigned char>(b) << shift);
119}
120
121template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
122constexpr byte& operator>>=(byte& b, IntegerType shift) noexcept
123{
124    return b = byte(static_cast<unsigned char>(b) >> shift);
125}
126
127template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
128constexpr byte operator>>(byte b, IntegerType shift) noexcept
129{
130    return byte(static_cast<unsigned char>(b) >> shift);
131}
132
133constexpr byte& operator|=(byte& l, byte r) noexcept
134{
135    return l = byte(static_cast<unsigned char>(l) | static_cast<unsigned char>(r));
136}
137
138constexpr byte operator|(byte l, byte r) noexcept
139{
140    return byte(static_cast<unsigned char>(l) | static_cast<unsigned char>(r));
141}
142
143constexpr byte& operator&=(byte& l, byte r) noexcept
144{
145    return l = byte(static_cast<unsigned char>(l) & static_cast<unsigned char>(r));
146}
147
148constexpr byte operator&(byte l, byte r) noexcept
149{
150    return byte(static_cast<unsigned char>(l) & static_cast<unsigned char>(r));
151}
152
153constexpr byte& operator^=(byte& l, byte r) noexcept
154{
155    return l = byte(static_cast<unsigned char>(l) ^ static_cast<unsigned char>(r));
156}
157
158constexpr byte operator^(byte l, byte r) noexcept
159{
160    return byte(static_cast<unsigned char>(l) ^ static_cast<unsigned char>(r));
161}
162
163constexpr byte operator~(byte b) noexcept { return byte(~static_cast<unsigned char>(b)); }
164
165template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
166constexpr IntegerType to_integer(byte b) noexcept
167{
168    return static_cast<IntegerType>(b);
169}
170
171#endif // GSL_USE_STD_BYTE
172
173template <bool E, typename T>
174constexpr byte to_byte_impl(T t) noexcept
175{
176    static_assert(
177        E, "gsl::to_byte(t) must be provided an unsigned char, otherwise data loss may occur. "
178           "If you are calling to_byte with an integer contant use: gsl::to_byte<t>() version.");
179    return static_cast<byte>(t);
180}
181template <>
182// NOTE: need suppression since c++14 does not allow "return {t}"
183// GSL_SUPPRESS(type.4) // NO-FORMAT: attribute // TODO: suppression does not work
184constexpr byte to_byte_impl<true, unsigned char>(unsigned char t) noexcept
185{
186    return byte(t);
187}
188
189template <typename T>
190constexpr byte to_byte(T t) noexcept
191{
192    return to_byte_impl<std::is_same<T, unsigned char>::value, T>(t);
193}
194
195template <int I>
196constexpr byte to_byte() noexcept
197{
198    static_assert(I >= 0 && I <= 255,
199                  "gsl::byte only has 8 bits of storage, values must be in range 0-255");
200    return static_cast<byte>(I);
201}
202
203} // namespace gsl
204
205#ifdef _MSC_VER
206#pragma warning(pop)
207#endif // _MSC_VER
208
209#endif // GSL_BYTE_H
210