├── .gitignore
├── .idea
├── .gitignore
├── BDS_MOD_SAMPLE.iml
├── misc.xml
├── modules.xml
└── vcs.xml
├── CMakeLists.txt
├── api
├── entity
│ └── Actor.h
└── graphics
│ ├── AABB.h
│ ├── BlockPos.cpp
│ ├── BlockPos.h
│ ├── Vec3.cpp
│ └── Vec3.h
├── dllmain.cpp
├── gsl
├── algorithm
├── assert
├── byte
├── gsl
├── gsl_algorithm
├── gsl_assert
├── gsl_byte
├── gsl_narrow
├── gsl_util
├── narrow
├── pointers
├── span
├── span_ext
├── string_span
└── util
├── hook
└── SymHook.h
├── lib
├── detours.h
├── detours.lib
├── detver.h
└── mod.h
├── readme.md
├── src
├── HopperFix.cpp
└── HopperFix.h
└── symbol.txt
/.gitignore:
--------------------------------------------------------------------------------
1 | # Project exclude paths
2 | /cmake-build-debug/
3 | /cmake-build-release/
4 | .vscode
5 | build
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/.idea/BDS_MOD_SAMPLE.iml:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/CMakeLists.txt:
--------------------------------------------------------------------------------
1 | cmake_minimum_required(VERSION 3.17)
2 | project(MCBE-hopper-fix)
3 |
4 | set(CMAKE_CXX_STANDARD 17)
5 | if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
6 | add_compile_definitions(-O3 -Wall)
7 | elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
8 | add_compile_options(/wd4819 /EHsc)
9 | endif ()
10 |
11 | #上面不用管
12 | include_directories(${PROJECT_NAME} lib hook src gsl)
13 | add_library(${PROJECT_NAME} SHARED dllmain.cpp src/HopperFix.cpp) #这里是.cpp文件
14 | target_link_libraries(${PROJECT_NAME} ${PROJECT_SOURCE_DIR}/lib/detours.lib)
--------------------------------------------------------------------------------
/api/entity/Actor.h:
--------------------------------------------------------------------------------
1 |
2 |
3 | #ifndef TRAPDOOR_ACTOR_H
4 | #define TRAPDOOR_ACTOR_H
5 |
6 | #include
7 | #include
8 |
9 | //#include "commands/CommandNode.h"
10 | #include "../graphics/Vec3.h"
11 | #include "../../hook/SymHook.h"
12 | #include "../../lib/mod.h"
13 |
14 | namespace trapdoor {
15 | class Actor {
16 | public:
17 | class Actor& operator=(class Actor const&) = delete;
18 | Actor(class Actor const&) = delete;
19 | Actor() = delete;
20 | //获取头部坐标
21 | Vec3* getPos() {
22 | return SYM_CALL(
23 | Vec3 * (*)(void*),
24 | SymHook::MSSYM_B1QA6getPosB1AA5ActorB2AAE12UEBAAEBVVec3B2AAA2XZ,
25 | this);
26 | }
27 | };
28 | } // namespace trapdoor
29 | #endif
30 |
--------------------------------------------------------------------------------
/api/graphics/AABB.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by xhy on 2020/8/24.
3 | //
4 | #ifndef TRAPDOOR_AABB_H
5 | #define TRAPDOOR_AABB_H
6 |
7 | #include "BlockPos.h"
8 | #include "Vec3.h"
9 |
10 | namespace trapdoor {
11 |
12 | struct AABB {
13 | Vec3 min{};
14 | Vec3 max{};
15 |
16 | AABB(Vec3 _p1, Vec3 _p2) {
17 | min = _p1;
18 | max = _p2;
19 | }
20 |
21 | Vec3 getCenter() const { return (min + max) * 0.5; }
22 | float getVolume() const { return abs((min - max).volume()); }
23 | void grow(Vec3 a) {
24 | min = min - a;
25 | max = max + a;
26 | }
27 | };
28 |
29 | struct BoundingBox {
30 | BlockPos minPos;
31 | BlockPos maxPos;
32 |
33 | inline BlockPos getCenter() const {
34 | return {(minPos.x + maxPos.x) / 2, (minPos.y + maxPos.y) / 2,
35 | (minPos.z + maxPos.z) / 2};
36 | }
37 |
38 | AABB getSpawnArea() const {
39 | int x = (this->maxPos.x - this->minPos.x + 1) / 2 + this->minPos.x;
40 | int z =
41 | (this->maxPos.z - this->minPos.z + 1) / 2 + this->minPos.z + 1;
42 | Vec3 minPoint{x, minPos.y, z - 1};
43 | Vec3 maxPoint{x + 1, maxPos.y + 1, z};
44 | return {minPoint, maxPoint};
45 | }
46 |
47 | AABB toAABB() const {
48 | return {minPos.toVec3(), maxPos.toVec3() + Vec3(1, 1, 1)};
49 | }
50 |
51 | bool operator<(const BoundingBox& rhs) const {
52 | if (minPos < rhs.minPos)
53 | return true;
54 | if (rhs.minPos < minPos)
55 | return false;
56 | return maxPos < rhs.maxPos;
57 | }
58 | };
59 | } // namespace trapdoor
60 | typedef trapdoor::AABB AABB;
61 | typedef trapdoor::BoundingBox BoundingBox;
62 | #endif // TRAPDOOR_AABB_H
63 |
--------------------------------------------------------------------------------
/api/graphics/BlockPos.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by xhy on 2020/10/22.
3 | //
4 |
5 | #include "BlockPos.h"
6 |
7 | #include
8 | #include
9 |
10 | #include "Vec3.h"
11 |
12 | namespace trapdoor {
13 | bool BlockPos::operator==(const BlockPos &v) const {
14 | return x == v.x && y == v.y && z == v.z;
15 | }
16 |
17 | bool BlockPos::operator!=(const BlockPos &v) const {
18 | return x != v.x || y != v.y || z != v.z;
19 | }
20 |
21 | float BlockPos::distanceTo(const BlockPos &blockPos) const {
22 | return (float)sqrt((blockPos.x - x) * (blockPos.x - x) +
23 | (blockPos.y - y) * (blockPos.y - y) +
24 | (blockPos.z - z) * (blockPos.z - z));
25 | }
26 |
27 | std::ostream &operator<<(std::ostream &os, const BlockPos &vec3) {
28 | os << "[" << vec3.x << "," << vec3.y << "," << vec3.z << "]";
29 | return os;
30 | }
31 |
32 | Vec3 BlockPos::toVec3() const { return {x, y, z}; }
33 |
34 | std::string BlockPos::toString() const {
35 | return "[" + std::to_string(x) + "," + std::to_string(y) + "," +
36 | std::to_string(z) + "]";
37 | }
38 |
39 | std::vector BlockPos::getNeighbourPos() {
40 | return {{x + 1, y, z}, {x - 1, y, z}, {x, y + 1, z},
41 | {x, y - 1, z}, {x, y, z + 1}, {x, y, z - 1}};
42 | }
43 |
44 | std::vector BlockPos::getPlainNeighbourPos() {
45 | return {{x + 1, y, z}, {x - 1, y, z}, {x, y, z + 1}, {x, y, z - 1}};
46 | }
47 |
48 | BlockPos2 BlockPos::InChunkOffset() const {
49 | auto newX = x % 16;
50 | auto newZ = z % 16;
51 | if (newX < 0) newX += 16;
52 | if (newZ < 0) newZ += 16;
53 | return {newX, newZ};
54 | }
55 |
56 | BlockPos2 BlockPos::toChunkPos() const {
57 | auto cx = x < 0 ? x - 15 : x;
58 | auto cz = z < 0 ? z - 15 : z;
59 | return {cx / 16, cz / 16};
60 | }
61 |
62 | bool BlockPos::operator<(const BlockPos &rhs) const {
63 | if (x < rhs.x) return true;
64 | if (rhs.x < x) return false;
65 | if (y < rhs.y) return true;
66 | if (rhs.y < y) return false;
67 | return z < rhs.z;
68 | }
69 |
70 | int BlockPos::operator*(const BlockPos &pos) const {
71 | return this->x * pos.x + this->y * pos.y + this->z * pos.z;
72 | }
73 |
74 | BlockPos BlockPos::operator+(const BlockPos &pos) const {
75 | return {x + pos.x, y + pos.y, z + pos.z};
76 | }
77 |
78 | std::string BlockPos2::toString() const {
79 | return "[" + std::to_string(x) + "," + std::to_string(z) + "]";
80 | }
81 |
82 | bool BlockPos2::isSlimeChunk() const {
83 | auto seed = (x * 0x1f1f1f1fu) ^ (uint32_t)z;
84 | std::mt19937 mt(seed);
85 | return mt() % 10 == 0;
86 | }
87 |
88 | bool BlockPos2::operator<(const BlockPos2 &rhs) const {
89 | if (x < rhs.x) return true;
90 | if (rhs.x < x) return false;
91 | return z < rhs.z;
92 | }
93 |
94 | std::string facingToString(FACING facing) {
95 | switch (facing) {
96 | case FACING::POS_X:
97 | return "+x";
98 | case FACING::NEG_X:
99 | return "-x";
100 | case FACING::POS_Y:
101 | return "+y";
102 | case FACING::POS_Z:
103 | return "+z";
104 | case FACING::NEG_Y:
105 | return "-y";
106 | case FACING::NEG_Z:
107 | return "-z";
108 | default:
109 | return "unknown";
110 | }
111 | }
112 |
113 | std::string facingToDirString(FACING facing) {
114 | switch (facing) {
115 | case FACING::POS_X:
116 | return "west";
117 | case FACING::NEG_X:
118 | return "east";
119 | case FACING::POS_Y:
120 | return "up";
121 | case FACING::POS_Z:
122 | return "south";
123 | case FACING::NEG_Y:
124 | return "down";
125 | case FACING::NEG_Z:
126 | return "north";
127 | default:
128 | return "unknown";
129 | }
130 | }
131 |
132 | BlockPos facingToBlockPos(FACING facing) {
133 | switch (facing) {
134 | case FACING::NEG_Y:
135 | return {0, -1, 0};
136 | case FACING::POS_Y:
137 | return {0, 1, 0};
138 | case FACING::NEG_Z:
139 | return {0, 0, -1};
140 | case FACING::POS_Z:
141 | return {0, 0, 1};
142 | case FACING::NEG_X:
143 | return {-1, 0, 0};
144 | case FACING::POS_X:
145 | return {1, 0, 0};
146 | }
147 | return {0, 0, 0};
148 | }
149 |
150 | bool facingIsPos(FACING facing) {
151 | return facing == FACING::POS_X || facing == FACING::POS_Y ||
152 | facing == FACING::POS_Z;
153 | }
154 |
155 | bool facingIsNeg(FACING facing) {
156 | return facing == FACING::NEG_X || facing == FACING::NEG_Y ||
157 | facing == FACING::NEG_Z;
158 | }
159 |
160 | bool facingIsX(FACING facing) {
161 | return facing == FACING::POS_X || facing == FACING::NEG_X;
162 | }
163 |
164 | bool facingIsY(FACING facing) {
165 | return facing == FACING::POS_Y || facing == FACING::NEG_Y;
166 | }
167 |
168 | bool facingIsZ(FACING facing) {
169 | return facing == FACING::POS_Z || facing == FACING::NEG_Z;
170 | }
171 |
172 | FACING invFacing(FACING facing) {
173 | switch (facing) {
174 | case FACING::NEG_Y:
175 | return FACING::POS_Y;
176 | case FACING::POS_Y:
177 | return FACING::NEG_Y;
178 | case FACING::NEG_Z:
179 | return FACING::POS_Z;
180 | case FACING::POS_Z:
181 | return FACING::NEG_Z;
182 | case FACING::NEG_X:
183 | return FACING::POS_X;
184 | case FACING::POS_X:
185 | return FACING::NEG_X;
186 | default:
187 | return FACING::POS_X;
188 | }
189 | }
190 | } // namespace trapdoor
191 | typedef trapdoor::BlockPos BlockPos;
192 | typedef trapdoor::BlockPos2 BlockPos2;
193 |
--------------------------------------------------------------------------------
/api/graphics/BlockPos.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by xhy on 2020/10/22.
3 | //
4 |
5 | #ifndef LIBMCBEMOD_BLOCKPOS_H
6 | #define LIBMCBEMOD_BLOCKPOS_H
7 |
8 | #include
9 | #include
10 |
11 | namespace trapdoor {
12 | class BlockPos;
13 |
14 | class Vec3;
15 |
16 | enum FACING {
17 | NEG_Y = 0,
18 | POS_Y = 1,
19 | NEG_Z = 2,
20 | POS_Z = 3,
21 | NEG_X = 4,
22 | POS_X = 5,
23 | };
24 |
25 | bool facingIsPos(FACING facing);
26 |
27 | bool facingIsNeg(FACING facing);
28 |
29 | bool facingIsX(FACING facing);
30 |
31 | bool facingIsY(FACING facing);
32 |
33 | bool facingIsZ(FACING facing);
34 |
35 | FACING invFacing(FACING facing);
36 |
37 | std::string facingToString(FACING facing);
38 |
39 | std::string facingToDirString(FACING facing);
40 |
41 | BlockPos facingToBlockPos(FACING facing);
42 |
43 | struct BlockPos2 {
44 | int x = 0;
45 | int z = 0;
46 |
47 | BlockPos2(int _x, int _z) : x(_x), z(_z) {}
48 |
49 | std::string toString() const;
50 |
51 | bool isSlimeChunk() const;
52 |
53 | bool operator<(const BlockPos2 &rhs) const;
54 | };
55 |
56 | typedef BlockPos2 ChunkPos;
57 |
58 | class BlockPos {
59 | public:
60 | int x = 0;
61 | int y = 0;
62 | int z = 0;
63 |
64 | BlockPos() = default;
65 |
66 | BlockPos(int _x, int _y, int _z) : x(_x), y(_y), z(_z) {}
67 |
68 | explicit BlockPos(int x) : BlockPos(x, x, x) {}
69 |
70 | explicit BlockPos(float x) : BlockPos(x, x, x) {}
71 |
72 | BlockPos(float _x, float _y, float _z)
73 | : x((int)_x), y((int)_y), z((int)_z) {}
74 |
75 | bool operator==(const BlockPos &v) const;
76 |
77 | bool operator!=(const BlockPos &v) const;
78 |
79 | float distanceTo(const BlockPos &blockPos) const;
80 |
81 | friend std::ostream &operator<<(std::ostream &os, const BlockPos &vec3);
82 |
83 | Vec3 toVec3() const;
84 |
85 | std::string toString() const;
86 |
87 | std::vector getNeighbourPos();
88 |
89 | std::vector getPlainNeighbourPos();
90 |
91 | BlockPos2 toChunkPos() const;
92 |
93 | BlockPos2 InChunkOffset() const;
94 |
95 | int operator*(const BlockPos &pos) const;
96 |
97 | BlockPos operator+(const BlockPos &pos) const;
98 |
99 | bool operator<(const BlockPos &rhs) const;
100 | };
101 |
102 | } // namespace trapdoor
103 | #endif // LIBMCBEMOD_BLOCKPOS_H
104 |
--------------------------------------------------------------------------------
/api/graphics/Vec3.cpp:
--------------------------------------------------------------------------------
1 | //
2 | // Created by xhy on 2020/10/22.
3 | //
4 |
5 | #include "Vec3.h"
6 |
7 | #include "BlockPos.h"
8 |
9 | namespace trapdoor {
10 | Vec3::Vec3(int _x) : Vec3(_x, _x, _x) {}
11 |
12 | Vec3::Vec3(float _x) : Vec3(_x, _x, _x) {}
13 |
14 | float Vec3::distanceTo(const Vec3& vec3) const {
15 | return sqrt((vec3.x - x) * (vec3.x - x) + (vec3.y - y) * (vec3.y - y) +
16 | (vec3.z - z) * (vec3.z - z));
17 | }
18 |
19 | float Vec3::volume() const { return x * y * z; }
20 |
21 | std::string Vec3::toString() const {
22 | char buffer[64];
23 | sprintf(buffer, "[%.4f %.4f %.4f]", x, y, z);
24 | return std::string(buffer);
25 | }
26 |
27 | bool Vec3::operator!=(const Vec3& v) const {
28 | return x != v.x || y != v.y || z != v.z;
29 | }
30 |
31 | bool Vec3::operator==(const Vec3& v) const {
32 | return x == v.x && y == v.y && z == v.z;
33 | }
34 |
35 | BlockPos Vec3::toBlockPos() const {
36 | auto cx = x < 0 ? x - 1 : x;
37 | auto cy = y < 0 ? y - 1 : y;
38 | auto cz = z < 0 ? z - 1 : z;
39 | return {cx, cy, cz};
40 | }
41 |
42 | std::string Vec3::toDirString() const {
43 | FACING fx = this->x > 0 ? FACING::POS_X : FACING::NEG_X;
44 | FACING fz = this->x > 0 ? FACING::POS_Z : FACING::NEG_Z;
45 | std::string s;
46 | if (abs(this->x) >= abs(this->z)) {
47 | s = facingToDirString(fx);
48 | s += " (";
49 | s += facingToString(fx);
50 | s += ")";
51 | } else if (1.732 * abs(this->z) > abs(this->x)) {
52 | s = facingToDirString(fz);
53 | s += " (";
54 | s += facingToString(fz);
55 | s += ")";
56 | }
57 | return s;
58 | }
59 |
60 | bool Vec3::operator<(const Vec3& rhs) const {
61 | if (x < rhs.x)
62 | return true;
63 | if (rhs.x < x)
64 | return false;
65 | if (y < rhs.y)
66 | return true;
67 | if (rhs.y < y)
68 | return false;
69 | return z < rhs.z;
70 | }
71 |
72 | Vec3 Vec3::operator+(const Vec3& v) const {
73 | return {this->x + v.x, this->y + v.y, this->z + v.z};
74 | }
75 |
76 | Vec3 Vec3::operator-(const Vec3& v) const {
77 | return {this->x - v.x, this->y - v.y, this->z - v.z};
78 | }
79 |
80 | Vec3 Vec3::operator*(float times) const {
81 | return {x * times, y * times, z * times};
82 | }
83 | } // namespace trapdoor
--------------------------------------------------------------------------------
/api/graphics/Vec3.h:
--------------------------------------------------------------------------------
1 | //
2 | // Created by xhy on 2020/10/22.
3 | //
4 |
5 | #ifndef LIBMCBEMOD_VEC3_H
6 | #define LIBMCBEMOD_VEC3_H
7 |
8 | #include
9 |
10 | namespace trapdoor {
11 | struct BlockPos;
12 |
13 | struct Vec3 {
14 | float x;
15 | float y;
16 | float z;
17 |
18 | Vec3() = default;
19 |
20 | explicit Vec3(int _x);
21 |
22 | explicit Vec3(float _x);
23 |
24 | Vec3(int _x, int _y, int _z)
25 | : x((float)_x), y((float)_y), z((float)_z) {}
26 |
27 | Vec3(float _x, float _y, float _z) : x(_x), y(_y), z(_z) {}
28 |
29 | bool operator==(const Vec3 &v) const;
30 |
31 | bool operator!=(const Vec3 &v) const;
32 |
33 | bool operator<(const Vec3 &v) const;
34 |
35 | Vec3 operator+(const Vec3 &v) const;
36 |
37 | Vec3 operator-(const Vec3 &v) const;
38 |
39 | Vec3 operator*(float times) const;
40 |
41 | float distanceTo(const Vec3& vec3) const;
42 |
43 | float volume() const;
44 |
45 | std::string toString() const;
46 |
47 | BlockPos toBlockPos() const;
48 |
49 | std::string toDirString() const;
50 | };
51 | } // namespace trapdoor
52 |
53 | typedef trapdoor::Vec3 Vec3;
54 | #endif // LIBMCBEMOD_VEC3_H
55 |
--------------------------------------------------------------------------------
/dllmain.cpp:
--------------------------------------------------------------------------------
1 | // dllmain.cpp : 定义 DLL 应用程序的入口点。
2 | #include
3 |
4 | void mod_init() {
5 |
6 | }
7 |
8 | void mod_exit() {
9 |
10 |
11 | }
12 |
13 | BOOL APIENTRY DllMain(HMODULE hModule,
14 | DWORD ul_reason_for_call,
15 | LPVOID lpReserved
16 | ) {
17 | switch (ul_reason_for_call) {
18 | case DLL_PROCESS_ATTACH:
19 | mod_init();
20 | break;
21 | case DLL_THREAD_ATTACH:
22 | break;
23 | case DLL_THREAD_DETACH:
24 | break;
25 | case DLL_PROCESS_DETACH:
26 | mod_exit();
27 | break;
28 | }
29 | return TRUE;
30 | }
31 |
--------------------------------------------------------------------------------
/gsl/algorithm:
--------------------------------------------------------------------------------
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_ALGORITHM_H
18 | #define GSL_ALGORITHM_H
19 |
20 | #include "assert" // for Expects
21 | #include "span" // for dynamic_extent, span
22 |
23 | #include // for copy_n
24 | #include // for ptrdiff_t
25 | #include // for is_assignable
26 |
27 | #ifdef _MSC_VER
28 | #pragma warning(push)
29 |
30 | // turn off some warnings that are noisy about our Expects statements
31 | #pragma warning(disable : 4127) // conditional expression is constant
32 | #pragma warning(disable : 4996) // unsafe use of std::copy_n
33 |
34 | #endif // _MSC_VER
35 |
36 | namespace gsl
37 | {
38 | // Note: this will generate faster code than std::copy using span iterator in older msvc+stl
39 | // not necessary for msvc since VS2017 15.8 (_MSC_VER >= 1915)
40 | template
42 | void copy(span src, span dest)
43 | {
44 | static_assert(std::is_assignable::value,
45 | "Elements of source span can not be assigned to elements of destination span");
46 | static_assert(SrcExtent == dynamic_extent || DestExtent == dynamic_extent ||
47 | (SrcExtent <= DestExtent),
48 | "Source range is longer than target range");
49 |
50 | Expects(dest.size() >= src.size());
51 | // clang-format off
52 | GSL_SUPPRESS(stl.1) // NO-FORMAT: attribute
53 | // clang-format on
54 | std::copy_n(src.data(), src.size(), dest.data());
55 | }
56 |
57 | } // namespace gsl
58 |
59 | #ifdef _MSC_VER
60 | #pragma warning(pop)
61 | #endif // _MSC_VER
62 |
63 | #endif // GSL_ALGORITHM_H
64 |
--------------------------------------------------------------------------------
/gsl/assert:
--------------------------------------------------------------------------------
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_CONTRACTS_H
18 | #define GSL_CONTRACTS_H
19 |
20 | //
21 | // Temporary until MSVC STL supports no-exceptions mode.
22 | // Currently terminate is a no-op in this mode, so we add termination behavior back
23 | //
24 | #if defined(_MSC_VER) && (defined(_KERNEL_MODE) || (defined(_HAS_EXCEPTIONS) && !_HAS_EXCEPTIONS))
25 | #define GSL_KERNEL_MODE
26 |
27 | #define GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND
28 | #include
29 | #define RANGE_CHECKS_FAILURE 0
30 |
31 | #if defined(__clang__)
32 | #pragma clang diagnostic push
33 | #pragma clang diagnostic ignored "-Winvalid-noreturn"
34 | #endif // defined(__clang__)
35 |
36 | #else // defined(_MSC_VER) && (defined(_KERNEL_MODE) || (defined(_HAS_EXCEPTIONS) &&
37 | // !_HAS_EXCEPTIONS))
38 |
39 | #include
40 |
41 | #endif // defined(_MSC_VER) && (defined(_KERNEL_MODE) || (defined(_HAS_EXCEPTIONS) &&
42 | // !_HAS_EXCEPTIONS))
43 |
44 | //
45 | // make suppress attributes parse for some compilers
46 | // Hopefully temporary until suppression standardization occurs
47 | //
48 | #if defined(__clang__)
49 | #define GSL_SUPPRESS(x) [[gsl::suppress("x")]]
50 | #else
51 | #if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
52 | #define GSL_SUPPRESS(x) [[gsl::suppress(x)]]
53 | #else
54 | #define GSL_SUPPRESS(x)
55 | #endif // _MSC_VER
56 | #endif // __clang__
57 |
58 | #define GSL_STRINGIFY_DETAIL(x) #x
59 | #define GSL_STRINGIFY(x) GSL_STRINGIFY_DETAIL(x)
60 |
61 | #if defined(__clang__) || defined(__GNUC__)
62 | #define GSL_LIKELY(x) __builtin_expect(!!(x), 1)
63 | #define GSL_UNLIKELY(x) __builtin_expect(!!(x), 0)
64 |
65 | #else
66 |
67 | #define GSL_LIKELY(x) (!!(x))
68 | #define GSL_UNLIKELY(x) (!!(x))
69 | #endif // defined(__clang__) || defined(__GNUC__)
70 |
71 | //
72 | // GSL_ASSUME(cond)
73 | //
74 | // Tell the optimizer that the predicate cond must hold. It is unspecified
75 | // whether or not cond is actually evaluated.
76 | //
77 | #ifdef _MSC_VER
78 | #define GSL_ASSUME(cond) __assume(cond)
79 | #elif defined(__GNUC__)
80 | #define GSL_ASSUME(cond) ((cond) ? static_cast(0) : __builtin_unreachable())
81 | #else
82 | #define GSL_ASSUME(cond) static_cast((cond) ? 0 : 0)
83 | #endif
84 |
85 | //
86 | // GSL.assert: assertions
87 | //
88 |
89 | namespace gsl
90 | {
91 |
92 | namespace details
93 | {
94 | #if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND)
95 |
96 | typedef void(__cdecl* terminate_handler)();
97 |
98 | // clang-format off
99 | GSL_SUPPRESS(f.6) // NO-FORMAT: attribute
100 | // clang-format on
101 | [[noreturn]] inline void __cdecl default_terminate_handler()
102 | {
103 | __fastfail(RANGE_CHECKS_FAILURE);
104 | }
105 |
106 | inline gsl::details::terminate_handler& get_terminate_handler() noexcept
107 | {
108 | static terminate_handler handler = &default_terminate_handler;
109 | return handler;
110 | }
111 |
112 | #endif // defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND)
113 |
114 | [[noreturn]] inline void terminate() noexcept
115 | {
116 | #if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND)
117 | (*gsl::details::get_terminate_handler())();
118 | #else
119 | std::terminate();
120 | #endif // defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND)
121 | }
122 |
123 | } // namespace details
124 | } // namespace gsl
125 |
126 | #define GSL_CONTRACT_CHECK(type, cond) \
127 | (GSL_LIKELY(cond) ? static_cast(0) : gsl::details::terminate())
128 |
129 | #define Expects(cond) GSL_CONTRACT_CHECK("Precondition", cond)
130 | #define Ensures(cond) GSL_CONTRACT_CHECK("Postcondition", cond)
131 |
132 | #if defined(GSL_MSVC_USE_STL_NOEXCEPTION_WORKAROUND) && defined(__clang__)
133 | #pragma clang diagnostic pop
134 | #endif
135 |
136 | #endif // GSL_CONTRACTS_H
137 |
--------------------------------------------------------------------------------
/gsl/byte:
--------------------------------------------------------------------------------
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) && !defined(__INTEL_COMPILER)
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
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
44 | // does not always work
45 |
46 | #ifndef GSL_USE_STD_BYTE
47 | // this tests if we are under MSVC and the standard lib has std::byte and it is enabled
48 | #if (defined(_HAS_STD_BYTE) && _HAS_STD_BYTE) || \
49 | (defined(__cpp_lib_byte) && __cpp_lib_byte >= 201603)
50 |
51 | #define GSL_USE_STD_BYTE 1
52 |
53 | #else // (defined(_HAS_STD_BYTE) && _HAS_STD_BYTE) || (defined(__cpp_lib_byte) && __cpp_lib_byte >=
54 | // 201603)
55 |
56 | #define GSL_USE_STD_BYTE 0
57 |
58 | #endif // (defined(_HAS_STD_BYTE) && _HAS_STD_BYTE) || (defined(__cpp_lib_byte) && __cpp_lib_byte >=
59 | // 201603)
60 | #endif // GSL_USE_STD_BYTE
61 |
62 | #else // _MSC_VER
63 |
64 | #ifndef GSL_USE_STD_BYTE
65 | #include /* __cpp_lib_byte */
66 | // this tests if we are under GCC or Clang with enough -std=c++1z power to get us std::byte
67 | // also check if libc++ version is sufficient (> 5.0) or libstdc++ actually contains std::byte
68 | #if defined(__cplusplus) && (__cplusplus >= 201703L) && \
69 | (defined(__cpp_lib_byte) && (__cpp_lib_byte >= 201603) || \
70 | defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 5000))
71 |
72 | #define GSL_USE_STD_BYTE 1
73 |
74 | #else // defined(__cplusplus) && (__cplusplus >= 201703L) &&
75 | // (defined(__cpp_lib_byte) && (__cpp_lib_byte >= 201603) ||
76 | // defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 5000))
77 |
78 | #define GSL_USE_STD_BYTE 0
79 |
80 | #endif // defined(__cplusplus) && (__cplusplus >= 201703L) &&
81 | // (defined(__cpp_lib_byte) && (__cpp_lib_byte >= 201603) ||
82 | // defined(_LIBCPP_VERSION) && (_LIBCPP_VERSION >= 5000))
83 | #endif // GSL_USE_STD_BYTE
84 |
85 | #endif // _MSC_VER
86 |
87 | // Use __may_alias__ attribute on gcc and clang
88 | #if defined __clang__ || (defined(__GNUC__) && __GNUC__ > 5)
89 | #define byte_may_alias __attribute__((__may_alias__))
90 | #else // defined __clang__ || defined __GNUC__
91 | #define byte_may_alias
92 | #endif // defined __clang__ || defined __GNUC__
93 |
94 | #if GSL_USE_STD_BYTE
95 | #include
96 | #endif
97 |
98 | namespace gsl
99 | {
100 | #if GSL_USE_STD_BYTE
101 |
102 | using std::byte;
103 | using std::to_integer;
104 |
105 | #else // GSL_USE_STD_BYTE
106 |
107 | // This is a simple definition for now that allows
108 | // use of byte within span<> to be standards-compliant
109 | enum class byte_may_alias byte : unsigned char
110 | {
111 | };
112 |
113 | template ::value>>
114 | constexpr byte& operator<<=(byte& b, IntegerType shift) noexcept
115 | {
116 | return b = byte(static_cast(b) << shift);
117 | }
118 |
119 | template ::value>>
120 | constexpr byte operator<<(byte b, IntegerType shift) noexcept
121 | {
122 | return byte(static_cast(b) << shift);
123 | }
124 |
125 | template ::value>>
126 | constexpr byte& operator>>=(byte& b, IntegerType shift) noexcept
127 | {
128 | return b = byte(static_cast(b) >> shift);
129 | }
130 |
131 | template ::value>>
132 | constexpr byte operator>>(byte b, IntegerType shift) noexcept
133 | {
134 | return byte(static_cast(b) >> shift);
135 | }
136 |
137 | constexpr byte& operator|=(byte& l, byte r) noexcept
138 | {
139 | return l = byte(static_cast(l) | static_cast(r));
140 | }
141 |
142 | constexpr byte operator|(byte l, byte r) noexcept
143 | {
144 | return byte(static_cast(l) | static_cast(r));
145 | }
146 |
147 | constexpr byte& operator&=(byte& l, byte r) noexcept
148 | {
149 | return l = byte(static_cast(l) & static_cast(r));
150 | }
151 |
152 | constexpr byte operator&(byte l, byte r) noexcept
153 | {
154 | return byte(static_cast(l) & static_cast(r));
155 | }
156 |
157 | constexpr byte& operator^=(byte& l, byte r) noexcept
158 | {
159 | return l = byte(static_cast(l) ^ static_cast(r));
160 | }
161 |
162 | constexpr byte operator^(byte l, byte r) noexcept
163 | {
164 | return byte(static_cast(l) ^ static_cast(r));
165 | }
166 |
167 | constexpr byte operator~(byte b) noexcept { return byte(~static_cast(b)); }
168 |
169 | template ::value>>
170 | constexpr IntegerType to_integer(byte b) noexcept
171 | {
172 | return static_cast(b);
173 | }
174 |
175 | #endif // GSL_USE_STD_BYTE
176 |
177 | template
178 | constexpr byte to_byte_impl(T t) noexcept
179 | {
180 | static_assert(
181 | E, "gsl::to_byte(t) must be provided an unsigned char, otherwise data loss may occur. "
182 | "If you are calling to_byte with an integer contant use: gsl::to_byte() version.");
183 | return static_cast(t);
184 | }
185 | template <>
186 | // NOTE: need suppression since c++14 does not allow "return {t}"
187 | // GSL_SUPPRESS(type.4) // NO-FORMAT: attribute // TODO: suppression does not work
188 | constexpr byte to_byte_impl(unsigned char t) noexcept
189 | {
190 | return byte(t);
191 | }
192 |
193 | template
194 | constexpr byte to_byte(T t) noexcept
195 | {
196 | return to_byte_impl::value, T>(t);
197 | }
198 |
199 | template
200 | constexpr byte to_byte() noexcept
201 | {
202 | static_assert(I >= 0 && I <= 255,
203 | "gsl::byte only has 8 bits of storage, values must be in range 0-255");
204 | return static_cast(I);
205 | }
206 |
207 | } // namespace gsl
208 |
209 | #ifdef _MSC_VER
210 | #pragma warning(pop)
211 | #endif // _MSC_VER
212 |
213 | #endif // GSL_BYTE_H
214 |
--------------------------------------------------------------------------------
/gsl/gsl:
--------------------------------------------------------------------------------
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_GSL_H
18 | #define GSL_GSL_H
19 |
20 | #include "algorithm" // copy
21 | #include "assert" // Ensures/Expects
22 | #include "byte" // byte
23 | #include "pointers" // owner, not_null
24 | #include "span" // span
25 | #include "string_span" // zstring, string_span, zstring_builder...
26 | #include "util" // finally()/narrow_cast()...
27 |
28 | #ifdef __cpp_exceptions
29 | #include "narrow" // narrow()
30 | #endif
31 |
32 | #endif // GSL_GSL_H
33 |
--------------------------------------------------------------------------------
/gsl/gsl_algorithm:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #pragma message( \
3 | "This header will soon be removed. Use instead of ")
4 | #include "algorithm"
5 |
--------------------------------------------------------------------------------
/gsl/gsl_assert:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #pragma message("This header will soon be removed. Use instead of ")
3 | #include "assert"
4 |
--------------------------------------------------------------------------------
/gsl/gsl_byte:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #pragma message("This header will soon be removed. Use instead of ")
3 | #include "byte"
4 |
--------------------------------------------------------------------------------
/gsl/gsl_narrow:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #pragma message("This header will soon be removed. Use instead of ")
3 | #include "narrow"
4 |
--------------------------------------------------------------------------------
/gsl/gsl_util:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #pragma message("This header will soon be removed. Use instead of ")
3 | #include "util"
4 |
--------------------------------------------------------------------------------
/gsl/narrow:
--------------------------------------------------------------------------------
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_NARROW_H
18 | #define GSL_NARROW_H
19 | #include "assert" // for GSL_SUPPRESS
20 | #include "util" // for narrow_cast
21 | #include // for std::exception
22 | namespace gsl
23 | {
24 | struct narrowing_error : public std::exception
25 | {
26 | const char* what() const noexcept override { return "narrowing_error"; }
27 | };
28 |
29 | // narrow() : a checked version of narrow_cast() that throws if the cast changed the value
30 | template ::value>::type* = nullptr>
31 | // clang-format off
32 | GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
33 | GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // TODO: MSVC /analyze does not recognise noexcept(false)
34 | GSL_SUPPRESS(es.46) // NO-FORMAT: attribute // The warning suggests that a floating->unsigned conversion can occur
35 | // in the static_cast below, and that gsl::narrow should be used instead.
36 | // Suppress this warning, since gsl::narrow is defined in terms of
37 | // static_cast
38 | // clang-format on
39 | constexpr T narrow(U u) noexcept(false)
40 | {
41 | constexpr const bool is_different_signedness =
42 | (std::is_signed::value != std::is_signed::value);
43 |
44 | GSL_SUPPRESS(es.103) // NO-FORMAT: attribute // don't overflow
45 | GSL_SUPPRESS(es.104) // NO-FORMAT: attribute // don't underflow
46 | GSL_SUPPRESS(p.2) // NO-FORMAT: attribute // don't rely on undefined behavior
47 | const T t = narrow_cast(u); // While this is technically undefined behavior in some cases (i.e., if the source value is of floating-point type
48 | // and cannot fit into the destination integral type), the resultant behavior is benign on the platforms
49 | // that we target (i.e., no hardware trap representations are hit).
50 |
51 | #if defined(__clang__) || defined(__GNUC__)
52 | #pragma GCC diagnostic push
53 | #pragma GCC diagnostic ignored "-Wfloat-equal"
54 | #endif
55 | if (static_cast(t) != u || (is_different_signedness && ((t < T{}) != (u < U{}))))
56 | {
57 | throw narrowing_error{};
58 | }
59 | #if defined(__clang__) || defined(__GNUC__)
60 | #pragma GCC diagnostic pop
61 | #endif
62 |
63 | return t;
64 | }
65 |
66 | template ::value>::type* = nullptr>
67 | // clang-format off
68 | GSL_SUPPRESS(type.1) // NO-FORMAT: attribute
69 | GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // TODO: MSVC /analyze does not recognise noexcept(false)
70 | // clang-format on
71 | constexpr T narrow(U u) noexcept(false)
72 | {
73 | const T t = narrow_cast(u);
74 |
75 | if (static_cast(t) != u)
76 | {
77 | throw narrowing_error{};
78 | }
79 |
80 | return t;
81 | }
82 | } // namespace gsl
83 | #endif // GSL_NARROW_H
84 |
--------------------------------------------------------------------------------
/gsl/pointers:
--------------------------------------------------------------------------------
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_POINTERS_H
18 | #define GSL_POINTERS_H
19 |
20 | #include "assert" // for Ensures, Expects
21 |
22 | #include // for forward
23 | #include // for ptrdiff_t, nullptr_t, size_t
24 | #include // for shared_ptr, unique_ptr
25 | #include // for hash
26 | #include // for enable_if_t, is_convertible, is_assignable
27 |
28 | #if !defined(GSL_NO_IOSTREAMS)
29 | #include // for ostream
30 | #endif // !defined(GSL_NO_IOSTREAMS)
31 |
32 | namespace gsl
33 | {
34 |
35 | namespace details
36 | {
37 | template
38 | struct is_comparable_to_nullptr : std::false_type
39 | {
40 | };
41 |
42 | template
43 | struct is_comparable_to_nullptr<
44 | T,
45 | std::enable_if_t() != nullptr), bool>::value>>
46 | : std::true_type
47 | {
48 | };
49 | } // namespace details
50 |
51 | //
52 | // GSL.owner: ownership pointers
53 | //
54 | using std::shared_ptr;
55 | using std::unique_ptr;
56 |
57 | //
58 | // owner
59 | //
60 | // owner is designed as a bridge for code that must deal directly with owning pointers for some
61 | // reason
62 | //
63 | // T must be a pointer type
64 | // - disallow construction from any type other than pointer type
65 | //
66 | template ::value>>
67 | using owner = T;
68 |
69 | //
70 | // not_null
71 | //
72 | // Restricts a pointer or smart pointer to only hold non-null values.
73 | //
74 | // Has zero size overhead over T.
75 | //
76 | // If T is a pointer (i.e. T == U*) then
77 | // - allow construction from U*
78 | // - disallow construction from nullptr_t
79 | // - disallow default construction
80 | // - ensure construction from null U* fails
81 | // - allow implicit conversion to U*
82 | //
83 | template
84 | class not_null
85 | {
86 | public:
87 | static_assert(details::is_comparable_to_nullptr::value, "T cannot be compared to nullptr.");
88 |
89 | template ::value>>
90 | constexpr not_null(U&& u) : ptr_(std::forward(u))
91 | {
92 | Expects(ptr_ != nullptr);
93 | }
94 |
95 | template ::value>>
96 | constexpr not_null(T u) : ptr_(std::move(u))
97 | {
98 | Expects(ptr_ != nullptr);
99 | }
100 |
101 | template ::value>>
102 | constexpr not_null(const not_null& other) : not_null(other.get())
103 | {}
104 |
105 | not_null(const not_null& other) = default;
106 | not_null& operator=(const not_null& other) = default;
107 | constexpr std::conditional_t::value, T, const T&> get() const
108 | {
109 | Ensures(ptr_ != nullptr);
110 | return ptr_;
111 | }
112 |
113 | constexpr operator T() const { return get(); }
114 | constexpr decltype(auto) operator->() const { return get(); }
115 | constexpr decltype(auto) operator*() const { return *get(); }
116 |
117 | // prevents compilation when someone attempts to assign a null pointer constant
118 | not_null(std::nullptr_t) = delete;
119 | not_null& operator=(std::nullptr_t) = delete;
120 |
121 | // unwanted operators...pointers only point to single objects!
122 | not_null& operator++() = delete;
123 | not_null& operator--() = delete;
124 | not_null operator++(int) = delete;
125 | not_null operator--(int) = delete;
126 | not_null& operator+=(std::ptrdiff_t) = delete;
127 | not_null& operator-=(std::ptrdiff_t) = delete;
128 | void operator[](std::ptrdiff_t) const = delete;
129 |
130 | private:
131 | T ptr_;
132 | };
133 |
134 | template
135 | auto make_not_null(T&& t) noexcept
136 | {
137 | return not_null>>{std::forward(t)};
138 | }
139 |
140 | #if !defined(GSL_NO_IOSTREAMS)
141 | template
142 | std::ostream& operator<<(std::ostream& os, const not_null& val)
143 | {
144 | os << val.get();
145 | return os;
146 | }
147 | #endif // !defined(GSL_NO_IOSTREAMS)
148 |
149 | template
150 | auto operator==(const not_null& lhs,
151 | const not_null& rhs) noexcept(noexcept(lhs.get() == rhs.get()))
152 | -> decltype(lhs.get() == rhs.get())
153 | {
154 | return lhs.get() == rhs.get();
155 | }
156 |
157 | template
158 | auto operator!=(const not_null& lhs,
159 | const not_null& rhs) noexcept(noexcept(lhs.get() != rhs.get()))
160 | -> decltype(lhs.get() != rhs.get())
161 | {
162 | return lhs.get() != rhs.get();
163 | }
164 |
165 | template
166 | auto operator<(const not_null& lhs,
167 | const not_null& rhs) noexcept(noexcept(lhs.get() < rhs.get()))
168 | -> decltype(lhs.get() < rhs.get())
169 | {
170 | return lhs.get() < rhs.get();
171 | }
172 |
173 | template
174 | auto operator<=(const not_null& lhs,
175 | const not_null& rhs) noexcept(noexcept(lhs.get() <= rhs.get()))
176 | -> decltype(lhs.get() <= rhs.get())
177 | {
178 | return lhs.get() <= rhs.get();
179 | }
180 |
181 | template
182 | auto operator>(const not_null& lhs,
183 | const not_null& rhs) noexcept(noexcept(lhs.get() > rhs.get()))
184 | -> decltype(lhs.get() > rhs.get())
185 | {
186 | return lhs.get() > rhs.get();
187 | }
188 |
189 | template
190 | auto operator>=(const not_null& lhs,
191 | const not_null& rhs) noexcept(noexcept(lhs.get() >= rhs.get()))
192 | -> decltype(lhs.get() >= rhs.get())
193 | {
194 | return lhs.get() >= rhs.get();
195 | }
196 |
197 | // more unwanted operators
198 | template
199 | std::ptrdiff_t operator-(const not_null&, const not_null&) = delete;
200 | template
201 | not_null operator-(const not_null&, std::ptrdiff_t) = delete;
202 | template
203 | not_null operator+(const not_null&, std::ptrdiff_t) = delete;
204 | template
205 | not_null operator+(std::ptrdiff_t, const not_null&) = delete;
206 |
207 | } // namespace gsl
208 |
209 | namespace std
210 | {
211 | template
212 | struct hash>
213 | {
214 | std::size_t operator()(const gsl::not_null& value) const { return hash{}(value.get()); }
215 | };
216 |
217 | } // namespace std
218 |
219 | namespace gsl
220 | {
221 |
222 | //
223 | // strict_not_null
224 | //
225 | // Restricts a pointer or smart pointer to only hold non-null values,
226 | //
227 | // - provides a strict (i.e. explicit constructor from T) wrapper of not_null
228 | // - to be used for new code that wishes the design to be cleaner and make not_null
229 | // checks intentional, or in old code that would like to make the transition.
230 | //
231 | // To make the transition from not_null, incrementally replace not_null
232 | // by strict_not_null and fix compilation errors
233 | //
234 | // Expect to
235 | // - remove all unneeded conversions from raw pointer to not_null and back
236 | // - make API clear by specifying not_null in parameters where needed
237 | // - remove unnecessary asserts
238 | //
239 | template
240 | class strict_not_null : public not_null
241 | {
242 | public:
243 | template ::value>>
244 | constexpr explicit strict_not_null(U&& u) : not_null(std::forward(u))
245 | {}
246 |
247 | template ::value>>
248 | constexpr explicit strict_not_null(T u) : not_null(u)
249 | {}
250 |
251 | template ::value>>
252 | constexpr strict_not_null(const not_null& other) : not_null(other)
253 | {}
254 |
255 | template ::value>>
256 | constexpr strict_not_null(const strict_not_null& other) : not_null(other)
257 | {}
258 |
259 | strict_not_null(strict_not_null&& other) = default;
260 | strict_not_null(const strict_not_null& other) = default;
261 | strict_not_null& operator=(const strict_not_null& other) = default;
262 | strict_not_null& operator=(const not_null& other)
263 | {
264 | not_null::operator=(other);
265 | return *this;
266 | }
267 |
268 | // prevents compilation when someone attempts to assign a null pointer constant
269 | strict_not_null(std::nullptr_t) = delete;
270 | strict_not_null& operator=(std::nullptr_t) = delete;
271 |
272 | // unwanted operators...pointers only point to single objects!
273 | strict_not_null& operator++() = delete;
274 | strict_not_null& operator--() = delete;
275 | strict_not_null operator++(int) = delete;
276 | strict_not_null operator--(int) = delete;
277 | strict_not_null& operator+=(std::ptrdiff_t) = delete;
278 | strict_not_null& operator-=(std::ptrdiff_t) = delete;
279 | void operator[](std::ptrdiff_t) const = delete;
280 | };
281 |
282 | // more unwanted operators
283 | template
284 | std::ptrdiff_t operator-(const strict_not_null&, const strict_not_null&) = delete;
285 | template
286 | strict_not_null operator-(const strict_not_null&, std::ptrdiff_t) = delete;
287 | template
288 | strict_not_null operator+(const strict_not_null&, std::ptrdiff_t) = delete;
289 | template
290 | strict_not_null operator+(std::ptrdiff_t, const strict_not_null&) = delete;
291 |
292 | template
293 | auto make_strict_not_null(T&& t) noexcept
294 | {
295 | return strict_not_null>>{std::forward(t)};
296 | }
297 |
298 | #if (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L))
299 |
300 | // deduction guides to prevent the ctad-maybe-unsupported warning
301 | template
302 | not_null(T) -> not_null;
303 | template
304 | strict_not_null(T) -> strict_not_null;
305 |
306 | #endif // ( defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L) )
307 |
308 | } // namespace gsl
309 |
310 | namespace std
311 | {
312 | template
313 | struct hash>
314 | {
315 | std::size_t operator()(const gsl::strict_not_null& value) const
316 | {
317 | return hash{}(value.get());
318 | }
319 | };
320 |
321 | } // namespace std
322 |
323 | #endif // GSL_POINTERS_H
324 |
--------------------------------------------------------------------------------
/gsl/span:
--------------------------------------------------------------------------------
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_SPAN_H
18 | #define GSL_SPAN_H
19 |
20 | #include "assert" // for Expects
21 | #include "byte" // for byte
22 | #include "span_ext" // for span specialization of gsl::at and other span-related extensions
23 | #include "util" // for narrow_cast
24 |
25 | #include // for array
26 | #include // for ptrdiff_t, size_t, nullptr_t
27 | #include // for reverse_iterator, distance, random_access_...
28 | #include // for pointer_traits
29 | #include // for enable_if_t, declval, is_convertible, inte...
30 |
31 | #if defined(__has_include) && __has_include()
32 | #include
33 | #endif
34 |
35 | #if defined(_MSC_VER) && !defined(__clang__)
36 | #pragma warning(push)
37 |
38 | // turn off some warnings that are noisy about our Expects statements
39 | #pragma warning(disable : 4127) // conditional expression is constant
40 | #pragma warning( \
41 | disable : 4146) // unary minus operator applied to unsigned type, result still unsigned
42 | #pragma warning(disable : 4702) // unreachable code
43 |
44 | // Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool.
45 | #pragma warning(disable : 26495) // uninitalized member when constructor calls constructor
46 | #pragma warning(disable : 26446) // parser bug does not allow attributes on some templates
47 |
48 | #endif // _MSC_VER
49 |
50 | // See if we have enough C++17 power to use a static constexpr data member
51 | // without needing an out-of-line definition
52 | #if !(defined(__cplusplus) && (__cplusplus >= 201703L))
53 | #define GSL_USE_STATIC_CONSTEXPR_WORKAROUND
54 | #endif // !(defined(__cplusplus) && (__cplusplus >= 201703L))
55 |
56 | // GCC 7 does not like the signed unsigned missmatch (size_t ptrdiff_t)
57 | // While there is a conversion from signed to unsigned, it happens at
58 | // compiletime, so the compiler wouldn't have to warn indiscriminately, but
59 | // could check if the source value actually doesn't fit into the target type
60 | // and only warn in those cases.
61 | #if defined(__GNUC__) && __GNUC__ > 6
62 | #pragma GCC diagnostic push
63 | #pragma GCC diagnostic ignored "-Wsign-conversion"
64 | #endif
65 |
66 | namespace gsl
67 | {
68 |
69 | // implementation details
70 | namespace details
71 | {
72 | template
73 | struct is_span_oracle : std::false_type
74 | {
75 | };
76 |
77 | template
78 | struct is_span_oracle> : std::true_type
79 | {
80 | };
81 |
82 | template
83 | struct is_span : public is_span_oracle>
84 | {
85 | };
86 |
87 | template
88 | struct is_std_array_oracle : std::false_type
89 | {
90 | };
91 |
92 | template
93 | struct is_std_array_oracle> : std::true_type
94 | {
95 | };
96 |
97 | template
98 | struct is_std_array : is_std_array_oracle>
99 | {
100 | };
101 |
102 | template
103 | struct is_allowed_extent_conversion
104 | : std::integral_constant
105 | {
106 | };
107 |
108 | template
109 | struct is_allowed_element_type_conversion
110 | : std::integral_constant::value>
111 | {
112 | };
113 |
114 | template
115 | class span_iterator
116 | {
117 | public:
118 | #if defined(__cpp_lib_ranges) || (defined(_MSVC_STL_VERSION) && defined(__cpp_lib_concepts))
119 | using iterator_concept = std::contiguous_iterator_tag;
120 | #endif // __cpp_lib_ranges
121 | using iterator_category = std::random_access_iterator_tag;
122 | using value_type = std::remove_cv_t;
123 | using difference_type = std::ptrdiff_t;
124 | using pointer = Type*;
125 | using reference = Type&;
126 |
127 | #ifdef _MSC_VER
128 | using _Unchecked_type = pointer;
129 | #endif // _MSC_VER
130 | constexpr span_iterator() = default;
131 |
132 | constexpr span_iterator(pointer begin, pointer end, pointer current)
133 | : begin_(begin), end_(end), current_(current)
134 | {}
135 |
136 | constexpr operator span_iterator() const noexcept
137 | {
138 | return {begin_, end_, current_};
139 | }
140 |
141 | constexpr reference operator*() const noexcept
142 | {
143 | Expects(begin_ && end_);
144 | Expects(begin_ <= current_ && current_ < end_);
145 | return *current_;
146 | }
147 |
148 | constexpr pointer operator->() const noexcept
149 | {
150 | Expects(begin_ && end_);
151 | Expects(begin_ <= current_ && current_ < end_);
152 | return current_;
153 | }
154 | constexpr span_iterator& operator++() noexcept
155 | {
156 | Expects(begin_ && current_ && end_);
157 | Expects(current_ < end_);
158 | // clang-format off
159 | GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
160 | // clang-format on
161 | ++current_;
162 | return *this;
163 | }
164 |
165 | constexpr span_iterator operator++(int) noexcept
166 | {
167 | span_iterator ret = *this;
168 | ++*this;
169 | return ret;
170 | }
171 |
172 | constexpr span_iterator& operator--() noexcept
173 | {
174 | Expects(begin_ && end_);
175 | Expects(begin_ < current_);
176 | --current_;
177 | return *this;
178 | }
179 |
180 | constexpr span_iterator operator--(int) noexcept
181 | {
182 | span_iterator ret = *this;
183 | --*this;
184 | return ret;
185 | }
186 |
187 | constexpr span_iterator& operator+=(const difference_type n) noexcept
188 | {
189 | if (n != 0) Expects(begin_ && current_ && end_);
190 | if (n > 0) Expects(end_ - current_ >= n);
191 | if (n < 0) Expects(current_ - begin_ >= -n);
192 | // clang-format off
193 | GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
194 | // clang-format on
195 | current_ += n;
196 | return *this;
197 | }
198 |
199 | constexpr span_iterator operator+(const difference_type n) const noexcept
200 | {
201 | span_iterator ret = *this;
202 | ret += n;
203 | return ret;
204 | }
205 |
206 | friend constexpr span_iterator operator+(const difference_type n,
207 | const span_iterator& rhs) noexcept
208 | {
209 | return rhs + n;
210 | }
211 |
212 | constexpr span_iterator& operator-=(const difference_type n) noexcept
213 | {
214 | if (n != 0) Expects(begin_ && current_ && end_);
215 | if (n > 0) Expects(current_ - begin_ >= n);
216 | if (n < 0) Expects(end_ - current_ >= -n);
217 | current_ -= n;
218 | return *this;
219 | }
220 |
221 | constexpr span_iterator operator-(const difference_type n) const noexcept
222 | {
223 | span_iterator ret = *this;
224 | ret -= n;
225 | return ret;
226 | }
227 |
228 | template <
229 | class Type2,
230 | std::enable_if_t, value_type>::value, int> = 0>
231 | constexpr difference_type operator-(const span_iterator& rhs) const noexcept
232 | {
233 | Expects(begin_ == rhs.begin_ && end_ == rhs.end_);
234 | return current_ - rhs.current_;
235 | }
236 |
237 | constexpr reference operator[](const difference_type n) const noexcept
238 | {
239 | return *(*this + n);
240 | }
241 |
242 | template <
243 | class Type2,
244 | std::enable_if_t, value_type>::value, int> = 0>
245 | constexpr bool operator==(const span_iterator& rhs) const noexcept
246 | {
247 | Expects(begin_ == rhs.begin_ && end_ == rhs.end_);
248 | return current_ == rhs.current_;
249 | }
250 |
251 | template <
252 | class Type2,
253 | std::enable_if_t, value_type>::value, int> = 0>
254 | constexpr bool operator!=(const span_iterator& rhs) const noexcept
255 | {
256 | return !(*this == rhs);
257 | }
258 |
259 | template <
260 | class Type2,
261 | std::enable_if_t, value_type>::value, int> = 0>
262 | constexpr bool operator<(const span_iterator& rhs) const noexcept
263 | {
264 | Expects(begin_ == rhs.begin_ && end_ == rhs.end_);
265 | return current_ < rhs.current_;
266 | }
267 |
268 | template <
269 | class Type2,
270 | std::enable_if_t, value_type>::value, int> = 0>
271 | constexpr bool operator>(const span_iterator& rhs) const noexcept
272 | {
273 | return rhs < *this;
274 | }
275 |
276 | template <
277 | class Type2,
278 | std::enable_if_t, value_type>::value, int> = 0>
279 | constexpr bool operator<=(const span_iterator& rhs) const noexcept
280 | {
281 | return !(rhs < *this);
282 | }
283 |
284 | template <
285 | class Type2,
286 | std::enable_if_t, value_type>::value, int> = 0>
287 | constexpr bool operator>=(const span_iterator& rhs) const noexcept
288 | {
289 | return !(*this < rhs);
290 | }
291 |
292 | #ifdef _MSC_VER
293 | // MSVC++ iterator debugging support; allows STL algorithms in 15.8+
294 | // to unwrap span_iterator to a pointer type after a range check in STL
295 | // algorithm calls
296 | friend constexpr void _Verify_range(span_iterator lhs, span_iterator rhs) noexcept
297 | { // test that [lhs, rhs) forms a valid range inside an STL algorithm
298 | Expects(lhs.begin_ == rhs.begin_ // range spans have to match
299 | && lhs.end_ == rhs.end_ &&
300 | lhs.current_ <= rhs.current_); // range must not be transposed
301 | }
302 |
303 | constexpr void _Verify_offset(const difference_type n) const noexcept
304 | { // test that *this + n is within the range of this call
305 | if (n != 0) Expects(begin_ && current_ && end_);
306 | if (n > 0) Expects(end_ - current_ >= n);
307 | if (n < 0) Expects(current_ - begin_ >= -n);
308 | }
309 |
310 | // clang-format off
311 | GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute
312 | // clang-format on
313 | constexpr pointer _Unwrapped() const noexcept
314 | { // after seeking *this to a high water mark, or using one of the
315 | // _Verify_xxx functions above, unwrap this span_iterator to a raw
316 | // pointer
317 | return current_;
318 | }
319 |
320 | // Tell the STL that span_iterator should not be unwrapped if it can't
321 | // validate in advance, even in release / optimized builds:
322 | #if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
323 | static constexpr const bool _Unwrap_when_unverified = false;
324 | #else
325 | static constexpr bool _Unwrap_when_unverified = false;
326 | #endif
327 | // clang-format off
328 | GSL_SUPPRESS(con.3) // NO-FORMAT: attribute // TODO: false positive
329 | // clang-format on
330 | constexpr void _Seek_to(const pointer p) noexcept
331 | { // adjust the position of *this to previously verified location p
332 | // after _Unwrapped
333 | current_ = p;
334 | }
335 | #endif
336 |
337 | pointer begin_ = nullptr;
338 | pointer end_ = nullptr;
339 | pointer current_ = nullptr;
340 |
341 | template
342 | friend struct std::pointer_traits;
343 | };
344 | }} // namespace gsl::details
345 |
346 | template
347 | struct std::pointer_traits<::gsl::details::span_iterator> {
348 | using pointer = ::gsl::details::span_iterator;
349 | using element_type = Type;
350 | using difference_type = ptrdiff_t;
351 |
352 | static constexpr element_type* to_address(const pointer i) noexcept {
353 | return i.current_;
354 | }
355 | };
356 |
357 | namespace gsl { namespace details {
358 | template
359 | class extent_type
360 | {
361 | public:
362 | using size_type = std::size_t;
363 |
364 | constexpr extent_type() noexcept = default;
365 |
366 | constexpr explicit extent_type(extent_type);
367 |
368 | constexpr explicit extent_type(size_type size) { Expects(size == Ext); }
369 |
370 | constexpr size_type size() const noexcept { return Ext; }
371 |
372 | private:
373 | #if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
374 | static constexpr const size_type size_ = Ext; // static size equal to Ext
375 | #else
376 | static constexpr size_type size_ = Ext; // static size equal to Ext
377 | #endif
378 | };
379 |
380 | template <>
381 | class extent_type
382 | {
383 | public:
384 | using size_type = std::size_t;
385 |
386 | template
387 | constexpr explicit extent_type(extent_type ext) : size_(ext.size())
388 | {}
389 |
390 | constexpr explicit extent_type(size_type size) : size_(size)
391 | {
392 | Expects(size != dynamic_extent);
393 | }
394 |
395 | constexpr size_type size() const noexcept { return size_; }
396 |
397 | private:
398 | size_type size_;
399 | };
400 |
401 | template
402 | constexpr extent_type::extent_type(extent_type ext)
403 | {
404 | Expects(ext.size() == Ext);
405 | }
406 |
407 | template
408 | struct calculate_subspan_type
409 | {
410 | using type = span;
413 | };
414 | } // namespace details
415 |
416 | // [span], class template span
417 | template
418 | class span
419 | {
420 | public:
421 | // constants and types
422 | using element_type = ElementType;
423 | using value_type = std::remove_cv_t;
424 | using size_type = std::size_t;
425 | using pointer = element_type*;
426 | using const_pointer = const element_type*;
427 | using reference = element_type&;
428 | using const_reference = const element_type&;
429 | using difference_type = std::ptrdiff_t;
430 |
431 | using iterator = details::span_iterator;
432 | using reverse_iterator = std::reverse_iterator;
433 |
434 | #if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND)
435 | static constexpr const size_type extent{Extent};
436 | #else
437 | static constexpr size_type extent{Extent};
438 | #endif
439 |
440 | // [span.cons], span constructors, copy, assignment, and destructor
441 | template " SFINAE, since "std::enable_if_t" is ill-formed when Extent is greater than 0.
445 | class = std::enable_if_t<(Dependent ||
446 | details::is_allowed_extent_conversion<0, Extent>::value)>>
447 | constexpr span() noexcept : storage_(nullptr, details::extent_type<0>())
448 | {}
449 |
450 | template = 0>
451 | constexpr explicit span(pointer ptr, size_type count) noexcept : storage_(ptr, count)
452 | {
453 | Expects(count == Extent);
454 | }
455 |
456 | template = 0>
457 | constexpr span(pointer ptr, size_type count) noexcept : storage_(ptr, count)
458 | {}
459 |
460 | template = 0>
461 | constexpr explicit span(pointer firstElem, pointer lastElem) noexcept
462 | : storage_(firstElem, narrow_cast(lastElem - firstElem))
463 | {
464 | Expects(lastElem - firstElem == static_cast(Extent));
465 | }
466 |
467 | template = 0>
468 | constexpr span(pointer firstElem, pointer lastElem) noexcept
469 | : storage_(firstElem, narrow_cast(lastElem - firstElem))
470 | {}
471 |
472 | template ::value, int> = 0>
474 | constexpr span(element_type (&arr)[N]) noexcept
475 | : storage_(KnownNotNull{arr}, details::extent_type())
476 | {}
477 |
478 | template <
479 | class T, std::size_t N,
480 | std::enable_if_t<(details::is_allowed_extent_conversion::value &&
481 | details::is_allowed_element_type_conversion::value),
482 | int> = 0>
483 | constexpr span(std::array& arr) noexcept
484 | : storage_(KnownNotNull{arr.data()}, details::extent_type())
485 | {}
486 |
487 | template ::value &&
490 | details::is_allowed_element_type_conversion::value),
491 | int> = 0>
492 | constexpr span(const std::array& arr) noexcept
493 | : storage_(KnownNotNull{arr.data()}, details::extent_type())
494 | {}
495 |
496 | // NB: the SFINAE on these constructors uses .data() as an incomplete/imperfect proxy for the
497 | // requirement on Container to be a contiguous sequence container.
498 | template ::value &&
501 | !details::is_std_array::value &&
502 | std::is_pointer().data())>::value &&
503 | std::is_convertible<
504 | std::remove_pointer_t().data())> (*)[],
505 | element_type (*)[]>::value,
506 | int> = 0>
507 | constexpr explicit span(Container& cont) noexcept : span(cont.data(), cont.size())
508 | {}
509 |
510 | template ::value &&
513 | !details::is_std_array::value &&
514 | std::is_pointer