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#pragma once
18
19#ifndef GSL_BYTE_H
20#define GSL_BYTE_H
21
22#include <type_traits>
23
24#ifdef _MSC_VER
25
26#pragma warning(push)
27
28// don't warn about function style casts in byte related operators
29#pragma warning(disable : 26493)
30
31#ifndef GSL_USE_STD_BYTE
32// this tests if we are under MSVC and the standard lib has std::byte and it is enabled
33#if _MSC_VER >= 1911 && (!defined(_HAS_STD_BYTE) || _HAS_STD_BYTE)
34
35#define GSL_USE_STD_BYTE 1
36
37#else // _MSC_VER >= 1911 && (!defined(_HAS_STD_BYTE) || _HAS_STD_BYTE)
38
39#define GSL_USE_STD_BYTE 0
40
41#endif // _MSC_VER >= 1911 && (!defined(_HAS_STD_BYTE) || _HAS_STD_BYTE)
42#endif // GSL_USE_STD_BYTE
43
44#else // _MSC_VER
45
46#ifndef GSL_USE_STD_BYTE
47// this tests if we are under GCC or Clang with enough -std:c++1z power to get us std::byte
48#if defined(__cplusplus) && (__cplusplus >= 201703L)
49
50#define GSL_USE_STD_BYTE 1
51#include <cstddef>
52
53#else // defined(__cplusplus) && (__cplusplus >= 201703L)
54
55#define GSL_USE_STD_BYTE 0
56
57#endif //defined(__cplusplus) && (__cplusplus >= 201703L)
58#endif // GSL_USE_STD_BYTE
59
60#endif           // _MSC_VER
61
62namespace gsl
63{
64#if GSL_USE_STD_BYTE
65
66
67using std::byte;
68using std::to_integer;
69
70#else // GSL_USE_STD_BYTE
71
72// This is a simple definition for now that allows
73// use of byte within span<> to be standards-compliant
74enum class byte : unsigned char
75{
76};
77
78template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
79inline constexpr byte& operator<<=(byte& b, IntegerType shift) noexcept
80{
81    return b = byte(static_cast<unsigned char>(b) << shift);
82}
83
84template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
85inline constexpr byte operator<<(byte b, IntegerType shift) noexcept
86{
87    return byte(static_cast<unsigned char>(b) << shift);
88}
89
90template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
91inline constexpr byte& operator>>=(byte& b, IntegerType shift) noexcept
92{
93    return b = byte(static_cast<unsigned char>(b) >> shift);
94}
95
96template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
97inline constexpr byte operator>>(byte b, IntegerType shift) noexcept
98{
99    return byte(static_cast<unsigned char>(b) >> shift);
100}
101
102inline constexpr byte& operator|=(byte& l, byte r) noexcept
103{
104    return l = byte(static_cast<unsigned char>(l) | static_cast<unsigned char>(r));
105}
106
107inline constexpr byte operator|(byte l, byte r) noexcept
108{
109    return byte(static_cast<unsigned char>(l) | static_cast<unsigned char>(r));
110}
111
112inline constexpr byte& operator&=(byte& l, byte r) noexcept
113{
114    return l = byte(static_cast<unsigned char>(l) & static_cast<unsigned char>(r));
115}
116
117inline constexpr byte operator&(byte l, byte r) noexcept
118{
119    return byte(static_cast<unsigned char>(l) & static_cast<unsigned char>(r));
120}
121
122inline constexpr byte& operator^=(byte& l, byte r) noexcept
123{
124    return l = byte(static_cast<unsigned char>(l) ^ static_cast<unsigned char>(r));
125}
126
127inline constexpr byte operator^(byte l, byte r) noexcept
128{
129    return byte(static_cast<unsigned char>(l) ^ static_cast<unsigned char>(r));
130}
131
132inline constexpr byte operator~(byte b) noexcept { return byte(~static_cast<unsigned char>(b)); }
133
134template <class IntegerType, class = std::enable_if_t<std::is_integral<IntegerType>::value>>
135inline constexpr IntegerType to_integer(byte b) noexcept
136{
137    return static_cast<IntegerType>(b);
138}
139
140#endif // GSL_USE_STD_BYTE
141
142template <bool E, typename T>
143inline constexpr byte to_byte_impl(T t) noexcept
144{
145    static_assert(
146        E, "gsl::to_byte(t) must be provided an unsigned char, otherwise data loss may occur. "
147           "If you are calling to_byte with an integer contant use: gsl::to_byte<t>() version.");
148    return static_cast<byte>(t);
149}
150template <>
151inline constexpr byte to_byte_impl<true, unsigned char>(unsigned char t) noexcept
152{
153    return byte(t);
154}
155
156template <typename T>
157inline constexpr byte to_byte(T t) noexcept
158{
159    return to_byte_impl<std::is_same<T, unsigned char>::value, T>(t);
160}
161
162template <int I>
163inline constexpr byte to_byte() noexcept
164{
165    static_assert(I >= 0 && I <= 255,
166                  "gsl::byte only has 8 bits of storage, values must be in range 0-255");
167    return static_cast<byte>(I);
168}
169
170} // namespace gsl
171
172#ifdef _MSC_VER
173#pragma warning(pop)
174#endif // _MSC_VER
175
176#endif // GSL_BYTE_H
177