├── .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().data())>::value && 515 | std::is_convertible< 516 | std::remove_pointer_t().data())> (*)[], 517 | element_type (*)[]>::value, 518 | int> = 0> 519 | constexpr span(Container& cont) noexcept : span(cont.data(), cont.size()) 520 | {} 521 | 522 | template < 523 | std::size_t MyExtent = Extent, class Container, 524 | std::enable_if_t< 525 | MyExtent != dynamic_extent && std::is_const::value && 526 | !details::is_span::value && !details::is_std_array::value && 527 | std::is_pointer().data())>::value && 528 | std::is_convertible< 529 | std::remove_pointer_t().data())> (*)[], 530 | element_type (*)[]>::value, 531 | int> = 0> 532 | constexpr explicit span(const Container& cont) noexcept : span(cont.data(), cont.size()) 533 | {} 534 | 535 | template < 536 | std::size_t MyExtent = Extent, class Container, 537 | std::enable_if_t< 538 | MyExtent == dynamic_extent && std::is_const::value && 539 | !details::is_span::value && !details::is_std_array::value && 540 | std::is_pointer().data())>::value && 541 | std::is_convertible< 542 | std::remove_pointer_t().data())> (*)[], 543 | element_type (*)[]>::value, 544 | int> = 0> 545 | constexpr span(const Container& cont) noexcept : span(cont.data(), cont.size()) 546 | {} 547 | 548 | constexpr span(const span& other) noexcept = default; 549 | 550 | template ::value, 554 | int> = 0> 555 | constexpr span(const span& other) noexcept 556 | : storage_(other.data(), details::extent_type(other.size())) 557 | {} 558 | 559 | template ::value, 563 | int> = 0> 564 | constexpr explicit span(const span& other) noexcept 565 | : storage_(other.data(), details::extent_type(other.size())) 566 | {} 567 | 568 | ~span() noexcept = default; 569 | constexpr span& operator=(const span& other) noexcept = default; 570 | 571 | // [span.sub], span subviews 572 | template 573 | constexpr span first() const noexcept 574 | { 575 | Expects(Count <= size()); 576 | return span{data(), Count}; 577 | } 578 | 579 | template 580 | // clang-format off 581 | GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute 582 | // clang-format on 583 | constexpr span last() const noexcept 584 | { 585 | Expects(Count <= size()); 586 | return span{data() + (size() - Count), Count}; 587 | } 588 | 589 | template 590 | // clang-format off 591 | GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute 592 | // clang-format on 593 | constexpr auto subspan() const noexcept -> 594 | typename details::calculate_subspan_type::type 595 | { 596 | Expects((size() >= Offset) && (Count == dynamic_extent || (Count <= size() - Offset))); 597 | using type = 598 | typename details::calculate_subspan_type::type; 599 | return type{data() + Offset, Count == dynamic_extent ? size() - Offset : Count}; 600 | } 601 | 602 | constexpr span first(size_type count) const noexcept 603 | { 604 | Expects(count <= size()); 605 | return {data(), count}; 606 | } 607 | 608 | constexpr span last(size_type count) const noexcept 609 | { 610 | Expects(count <= size()); 611 | return make_subspan(size() - count, dynamic_extent, subspan_selector{}); 612 | } 613 | 614 | constexpr span 615 | subspan(size_type offset, size_type count = dynamic_extent) const noexcept 616 | { 617 | return make_subspan(offset, count, subspan_selector{}); 618 | } 619 | 620 | // [span.obs], span observers 621 | constexpr size_type size() const noexcept { return storage_.size(); } 622 | 623 | constexpr size_type size_bytes() const noexcept 624 | { 625 | Expects(size() < dynamic_extent / sizeof(element_type)); 626 | return size() * sizeof(element_type); 627 | } 628 | 629 | constexpr bool empty() const noexcept { return size() == 0; } 630 | 631 | // [span.elem], span element access 632 | // clang-format off 633 | GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute 634 | // clang-format on 635 | constexpr reference operator[](size_type idx) const noexcept 636 | { 637 | Expects(idx < size()); 638 | return data()[idx]; 639 | } 640 | 641 | constexpr reference front() const noexcept 642 | { 643 | Expects(size() > 0); 644 | return data()[0]; 645 | } 646 | 647 | constexpr reference back() const noexcept 648 | { 649 | Expects(size() > 0); 650 | return data()[size() - 1]; 651 | } 652 | 653 | constexpr pointer data() const noexcept { return storage_.data(); } 654 | 655 | // [span.iter], span iterator support 656 | constexpr iterator begin() const noexcept 657 | { 658 | const auto data = storage_.data(); 659 | // clang-format off 660 | GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute 661 | // clang-format on 662 | return {data, data + size(), data}; 663 | } 664 | 665 | constexpr iterator end() const noexcept 666 | { 667 | const auto data = storage_.data(); 668 | // clang-format off 669 | GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute 670 | // clang-format on 671 | const auto endData = data + storage_.size(); 672 | return {data, endData, endData}; 673 | } 674 | 675 | constexpr reverse_iterator rbegin() const noexcept { return reverse_iterator{end()}; } 676 | constexpr reverse_iterator rend() const noexcept { return reverse_iterator{begin()}; } 677 | 678 | #ifdef _MSC_VER 679 | // Tell MSVC how to unwrap spans in range-based-for 680 | constexpr pointer _Unchecked_begin() const noexcept { return data(); } 681 | constexpr pointer _Unchecked_end() const noexcept 682 | { 683 | // clang-format off 684 | GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute 685 | // clang-format on 686 | return data() + size(); 687 | } 688 | #endif // _MSC_VER 689 | 690 | private: 691 | // Needed to remove unnecessary null check in subspans 692 | struct KnownNotNull 693 | { 694 | pointer p; 695 | }; 696 | 697 | // this implementation detail class lets us take advantage of the 698 | // empty base class optimization to pay for only storage of a single 699 | // pointer in the case of fixed-size spans 700 | template 701 | class storage_type : public ExtentType 702 | { 703 | public: 704 | // KnownNotNull parameter is needed to remove unnecessary null check 705 | // in subspans and constructors from arrays 706 | template 707 | constexpr storage_type(KnownNotNull data, OtherExtentType ext) 708 | : ExtentType(ext), data_(data.p) 709 | {} 710 | 711 | template 712 | constexpr storage_type(pointer data, OtherExtentType ext) : ExtentType(ext), data_(data) 713 | { 714 | Expects(data || ExtentType::size() == 0); 715 | } 716 | 717 | constexpr pointer data() const noexcept { return data_; } 718 | 719 | private: 720 | pointer data_; 721 | }; 722 | 723 | storage_type> storage_; 724 | 725 | // The rest is needed to remove unnecessary null check 726 | // in subspans and constructors from arrays 727 | constexpr span(KnownNotNull ptr, size_type count) noexcept : storage_(ptr, count) {} 728 | 729 | template 730 | class subspan_selector 731 | { 732 | }; 733 | 734 | template 735 | constexpr span 736 | make_subspan(size_type offset, size_type count, subspan_selector) const noexcept 737 | { 738 | const span tmp(*this); 739 | return tmp.subspan(offset, count); 740 | } 741 | 742 | // clang-format off 743 | GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute 744 | // clang-format on 745 | constexpr span 746 | make_subspan(size_type offset, size_type count, subspan_selector) const noexcept 747 | { 748 | Expects(size() >= offset); 749 | 750 | if (count == dynamic_extent) { return {KnownNotNull{data() + offset}, size() - offset}; } 751 | 752 | Expects(size() - offset >= count); 753 | return {KnownNotNull{data() + offset}, count}; 754 | } 755 | }; 756 | 757 | #if (defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L)) 758 | 759 | // Deduction Guides 760 | template 761 | span(Type (&)[Extent]) -> span; 762 | 763 | template 764 | span(std::array&) -> span; 765 | 766 | template 767 | span(const std::array&) -> span; 768 | 769 | template ().data())>> 771 | span(Container&) -> span; 772 | 773 | template ().data())>> 775 | span(const Container&) -> span; 776 | 777 | #endif // ( defined(__cpp_deduction_guides) && (__cpp_deduction_guides >= 201611L) ) 778 | 779 | #if defined(GSL_USE_STATIC_CONSTEXPR_WORKAROUND) 780 | template 781 | constexpr const typename span::size_type span::extent; 782 | #endif 783 | 784 | namespace details 785 | { 786 | // if we only supported compilers with good constexpr support then 787 | // this pair of classes could collapse down to a constexpr function 788 | 789 | // we should use a narrow_cast<> to go to std::size_t, but older compilers may not see it as 790 | // constexpr 791 | // and so will fail compilation of the template 792 | template 793 | struct calculate_byte_size : std::integral_constant 794 | { 795 | static_assert(Extent < dynamic_extent / sizeof(ElementType), "Size is too big."); 796 | }; 797 | 798 | template 799 | struct calculate_byte_size 800 | : std::integral_constant 801 | { 802 | }; 803 | } // namespace details 804 | 805 | // [span.objectrep], views of object representation 806 | template 807 | span::value> 808 | as_bytes(span s) noexcept 809 | { 810 | using type = span::value>; 811 | 812 | // clang-format off 813 | GSL_SUPPRESS(type.1) // NO-FORMAT: attribute 814 | // clang-format on 815 | return type{reinterpret_cast(s.data()), s.size_bytes()}; 816 | } 817 | 818 | template ::value, int> = 0> 820 | span::value> 821 | as_writable_bytes(span s) noexcept 822 | { 823 | using type = span::value>; 824 | 825 | // clang-format off 826 | GSL_SUPPRESS(type.1) // NO-FORMAT: attribute 827 | // clang-format on 828 | return type{reinterpret_cast(s.data()), s.size_bytes()}; 829 | } 830 | 831 | } // namespace gsl 832 | 833 | #if defined(_MSC_VER) && !defined(__clang__) 834 | 835 | #pragma warning(pop) 836 | #endif // _MSC_VER 837 | 838 | #if defined(__GNUC__) && __GNUC__ > 6 839 | #pragma GCC diagnostic pop 840 | #endif // __GNUC__ > 6 841 | 842 | #endif // GSL_SPAN_H 843 | -------------------------------------------------------------------------------- /gsl/span_ext: -------------------------------------------------------------------------------- 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_EXT_H 18 | #define GSL_SPAN_EXT_H 19 | 20 | /////////////////////////////////////////////////////////////////////////////// 21 | // 22 | // File: span_ext 23 | // Purpose: continue offering features that have been cut from the official 24 | // implementation of span. 25 | // While modernizing gsl::span a number of features needed to be removed to 26 | // be compliant with the design of std::span 27 | // 28 | /////////////////////////////////////////////////////////////////////////////// 29 | 30 | #include "assert" // GSL_KERNEL_MODE 31 | #include "util" // for narrow_cast, narrow 32 | 33 | #include // for ptrdiff_t, size_t 34 | #include 35 | 36 | #ifndef GSL_KERNEL_MODE 37 | #include // for lexicographical_compare 38 | #endif // GSL_KERNEL_MODE 39 | 40 | namespace gsl 41 | { 42 | 43 | // [span.views.constants], constants 44 | constexpr const std::size_t dynamic_extent = narrow_cast(-1); 45 | 46 | template 47 | class span; 48 | 49 | // std::equal and std::lexicographical_compare are not /kernel compatible 50 | // so all comparison operators must be removed for kernel mode. 51 | #ifndef GSL_KERNEL_MODE 52 | 53 | // [span.comparison], span comparison operators 54 | template 55 | constexpr bool operator==(span l, span r) 56 | { 57 | return std::equal(l.begin(), l.end(), r.begin(), r.end()); 58 | } 59 | 60 | template 61 | constexpr bool operator!=(span l, span r) 62 | { 63 | return !(l == r); 64 | } 65 | 66 | template 67 | constexpr bool operator<(span l, span r) 68 | { 69 | return std::lexicographical_compare(l.begin(), l.end(), r.begin(), r.end()); 70 | } 71 | 72 | template 73 | constexpr bool operator<=(span l, span r) 74 | { 75 | return !(l > r); 76 | } 77 | 78 | template 79 | constexpr bool operator>(span l, span r) 80 | { 81 | return r < l; 82 | } 83 | 84 | template 85 | constexpr bool operator>=(span l, span r) 86 | { 87 | return !(l < r); 88 | } 89 | 90 | #endif // GSL_KERNEL_MODE 91 | 92 | // 93 | // make_span() - Utility functions for creating spans 94 | // 95 | template 96 | constexpr span make_span(ElementType* ptr, typename span::size_type count) 97 | { 98 | return span(ptr, count); 99 | } 100 | 101 | template 102 | constexpr span make_span(ElementType* firstElem, ElementType* lastElem) 103 | { 104 | return span(firstElem, lastElem); 105 | } 106 | 107 | template 108 | constexpr span make_span(ElementType (&arr)[N]) noexcept 109 | { 110 | return span(arr); 111 | } 112 | 113 | template 114 | constexpr span make_span(Container& cont) 115 | { 116 | return span(cont); 117 | } 118 | 119 | template 120 | constexpr span make_span(const Container& cont) 121 | { 122 | return span(cont); 123 | } 124 | 125 | template 126 | constexpr span make_span(Ptr& cont, std::size_t count) 127 | { 128 | return span(cont, count); 129 | } 130 | 131 | template 132 | constexpr span make_span(Ptr& cont) 133 | { 134 | return span(cont); 135 | } 136 | 137 | // Specialization of gsl::at for span 138 | template 139 | constexpr ElementType& at(span s, index i) 140 | { 141 | // No bounds checking here because it is done in span::operator[] called below 142 | Ensures(i >= 0); 143 | return s[narrow_cast(i)]; 144 | } 145 | 146 | // [span.obs] Free observer functions 147 | template 148 | constexpr std::ptrdiff_t ssize(const span& s) noexcept 149 | { 150 | return static_cast(s.size()); 151 | } 152 | 153 | // [span.iter] Free functions for begin/end functions 154 | template 155 | constexpr typename span::iterator 156 | begin(const span& s) noexcept 157 | { 158 | return s.begin(); 159 | } 160 | 161 | template 162 | constexpr typename span::iterator 163 | end(const span& s) noexcept 164 | { 165 | return s.end(); 166 | } 167 | 168 | template 169 | constexpr typename span::reverse_iterator 170 | rbegin(const span& s) noexcept 171 | { 172 | return s.rbegin(); 173 | } 174 | 175 | template 176 | constexpr typename span::reverse_iterator 177 | rend(const span& s) noexcept 178 | { 179 | return s.rend(); 180 | } 181 | 182 | template 183 | constexpr typename span::iterator 184 | cbegin(const span& s) noexcept 185 | { 186 | return s.begin(); 187 | } 188 | 189 | template 190 | constexpr typename span::iterator 191 | cend(const span& s) noexcept 192 | { 193 | return s.end(); 194 | } 195 | 196 | template 197 | constexpr typename span::reverse_iterator 198 | crbegin(const span& s) noexcept 199 | { 200 | return s.rbegin(); 201 | } 202 | 203 | template 204 | constexpr typename span::reverse_iterator 205 | crend(const span& s) noexcept 206 | { 207 | return s.rend(); 208 | } 209 | 210 | } // namespace gsl 211 | 212 | #endif // GSL_SPAN_EXT_H 213 | -------------------------------------------------------------------------------- /gsl/string_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_STRING_SPAN_H 18 | #define GSL_STRING_SPAN_H 19 | 20 | #include "assert" // for Ensures, Expects 21 | #include "span_ext" // for operator!=, operator==, dynamic_extent 22 | #include "util" // for narrow_cast 23 | 24 | #include // for equal, lexicographical_compare 25 | #include // for array 26 | #include // for size_t, nullptr_t 27 | #include // for PTRDIFF_MAX 28 | #include 29 | #include // for basic_string, allocator, char_traits 30 | #include // for declval, is_convertible, enable_if_t, add_... 31 | 32 | #if defined(_MSC_VER) && !defined(__clang__) 33 | #pragma warning(push) 34 | 35 | // Turn MSVC /analyze rules that generate too much noise. TODO: fix in the tool. 36 | #pragma warning(disable : 26446) // TODO: bug in parser - attributes and templates 37 | #pragma warning(disable : 26481) // TODO: suppress does not work inside templates sometimes 38 | #pragma warning(disable : 4996) // use of functions & classes marked [[deprecated]] 39 | #endif // _MSC_VER 40 | 41 | #if defined(__GNUC__) || defined(__clang__) 42 | #pragma GCC diagnostic push 43 | #pragma GCC diagnostic ignored "-Wdeprecated-declarations" 44 | #endif 45 | 46 | namespace gsl 47 | { 48 | // 49 | // czstring and wzstring 50 | // 51 | // These are "tag" typedefs for C-style strings (i.e. null-terminated character arrays) 52 | // that allow static analysis to help find bugs. 53 | // 54 | // There are no additional features/semantics that we can find a way to add inside the 55 | // type system for these types that will not either incur significant runtime costs or 56 | // (sometimes needlessly) break existing programs when introduced. 57 | // 58 | 59 | template 60 | using basic_zstring = CharT*; 61 | 62 | using czstring = basic_zstring; 63 | 64 | using cwzstring = basic_zstring; 65 | 66 | using cu16zstring = basic_zstring; 67 | 68 | using cu32zstring = basic_zstring; 69 | 70 | using zstring = basic_zstring; 71 | 72 | using wzstring = basic_zstring; 73 | 74 | using u16zstring = basic_zstring; 75 | 76 | using u32zstring = basic_zstring; 77 | 78 | namespace details 79 | { 80 | template 81 | [[deprecated("string_span was removed from the C++ Core Guidelines. For more information, see " 82 | "isocpp/CppCoreGuidelines PR#1680")]] constexpr std::size_t 83 | string_length(const CharT* str, std::size_t n) 84 | { 85 | if (str == nullptr || n == dynamic_extent) return 0; 86 | 87 | const span str_span{str, n}; 88 | 89 | std::size_t len = 0; 90 | while (len < n && str_span[len]) len++; 91 | 92 | return len; 93 | } 94 | } // namespace details 95 | 96 | // 97 | // ensure_sentinel() 98 | // 99 | // Provides a way to obtain an span from a contiguous sequence 100 | // that ends with a (non-inclusive) sentinel value. 101 | // 102 | // Will fail-fast if sentinel cannot be found before max elements are examined. 103 | // 104 | template 105 | [[deprecated("string_span was removed from the C++ Core Guidelines. For more information, see " 106 | "isocpp/CppCoreGuidelines PR#1680")]] constexpr span 107 | ensure_sentinel(T* seq, std::size_t max = static_cast(-1)) 108 | { 109 | Ensures(seq != nullptr); 110 | 111 | // clang-format off 112 | GSL_SUPPRESS(f.23) // TODO: false positive // TODO: suppress does not work 113 | // clang-format on 114 | auto cur = seq; 115 | Ensures(cur != nullptr); // workaround for removing the warning 116 | 117 | // clang-format off 118 | GSL_SUPPRESS(bounds.1) // TODO: suppress does not work 119 | // clang-format on 120 | while (static_cast(cur - seq) < max && *cur != Sentinel) ++cur; 121 | Ensures(*cur == Sentinel); 122 | return {seq, static_cast(cur - seq)}; 123 | } 124 | 125 | // 126 | // ensure_z - creates a span for a zero terminated strings. The span will not contain the zero 127 | // termination. Will fail fast if a null-terminator cannot be found before the limit of size_type. 128 | // 129 | template 130 | [[deprecated("string_span was removed from the C++ Core Guidelines. For more information, see " 131 | "isocpp/CppCoreGuidelines PR#1680")]] constexpr span 132 | ensure_z(CharT* const& sz, std::size_t max = static_cast(-1)) 133 | { 134 | return ensure_sentinel(sz, max); 135 | } 136 | 137 | template 138 | constexpr span ensure_z(CharT (&sz)[N]) 139 | { 140 | return ensure_z(&sz[0], N); 141 | } 142 | 143 | template 144 | [[deprecated( 145 | "string_span was removed from the C++ Core Guidelines. For more information, see " 146 | "isocpp/CppCoreGuidelines PR#1680")]] constexpr span::type, 149 | dynamic_extent> 150 | ensure_z(Cont& cont) 151 | { 152 | return ensure_z(cont.data(), cont.size()); 153 | } 154 | 155 | template 156 | class [[deprecated("string_span was removed from the C++ Core Guidelines. For more information, " 157 | "see isocpp/CppCoreGuidelines PR#1680")]] basic_string_span; 158 | 159 | namespace details 160 | { 161 | template 162 | struct [[deprecated( 163 | "string_span was removed from the C++ Core Guidelines. For more information, " 164 | "see isocpp/CppCoreGuidelines PR#1680")]] is_basic_string_span_oracle : std::false_type{}; 165 | 166 | template 167 | struct [[deprecated( 168 | "string_span was removed from the C++ Core Guidelines. For more information, see " 169 | "isocpp/CppCoreGuidelines PR#1680")]] is_basic_string_span_oracle> 171 | : std::true_type{}; 172 | 173 | template 174 | struct [[deprecated("string_span was removed from the C++ Core Guidelines. For more " 175 | "information, see isocpp/CppCoreGuidelines PR#1680")]] is_basic_string_span 176 | : is_basic_string_span_oracle>{}; 177 | } // namespace details 178 | 179 | // 180 | // string_span and relatives 181 | // 182 | template 183 | class [[deprecated("string_span was removed from the C++ Core Guidelines. For more information, " 184 | "see isocpp/CppCoreGuidelines PR#1680")]] basic_string_span 185 | { 186 | public: 187 | using element_type = CharT; 188 | using value_type = std::remove_cv_t; 189 | using pointer = std::add_pointer_t; 190 | using reference = std::add_lvalue_reference_t; 191 | using const_reference = std::add_lvalue_reference_t>; 192 | using impl_type = span; 193 | 194 | using size_type = typename impl_type::size_type; 195 | using iterator = typename impl_type::iterator; 196 | using reverse_iterator = typename impl_type::reverse_iterator; 197 | 198 | // default (empty) 199 | constexpr basic_string_span() noexcept = default; 200 | 201 | // copy 202 | constexpr basic_string_span(const basic_string_span& other) noexcept = default; 203 | 204 | // assign 205 | constexpr basic_string_span& operator=(const basic_string_span& other) noexcept = default; 206 | 207 | constexpr basic_string_span(pointer ptr, size_type length) : span_(ptr, length) {} 208 | constexpr basic_string_span(pointer firstElem, pointer lastElem) : span_(firstElem, lastElem) {} 209 | 210 | // From static arrays - if 0-terminated, remove 0 from the view 211 | // All other containers allow 0s within the length, so we do not remove them 212 | template 213 | constexpr basic_string_span(element_type(&arr)[N]) : span_(remove_z(arr)) 214 | {} 215 | 216 | template > 217 | constexpr basic_string_span(std::array & arr) noexcept : span_(arr) 218 | {} 219 | 220 | template > 221 | constexpr basic_string_span(const std::array& arr) noexcept : span_(arr) 222 | {} 223 | 224 | // Container signature should work for basic_string after C++17 version exists 225 | template 226 | // GSL_SUPPRESS(bounds.4) // TODO: parser bug 227 | constexpr basic_string_span(std::basic_string & str) 228 | : span_(&str[0], str.length()) 229 | {} 230 | 231 | template 232 | constexpr basic_string_span(const std::basic_string& str) 233 | : span_(&str[0], str.length()) 234 | {} 235 | 236 | // from containers. Containers must have a pointer type and data() function signatures 237 | template ::value && 240 | std::is_convertible::value && 241 | std::is_convertible().data())>::value>> 243 | constexpr basic_string_span(Container & cont) : span_(cont) 244 | {} 245 | 246 | template ::value && 249 | std::is_convertible::value && 250 | std::is_convertible().data())>::value>> 252 | constexpr basic_string_span(const Container& cont) : span_(cont) 253 | {} 254 | 255 | // from string_span 256 | template < 257 | class OtherValueType, std::size_t OtherExtent, 258 | class = std::enable_if_t::impl_type, impl_type>::value>> 260 | constexpr basic_string_span(basic_string_span other) 261 | : span_(other.data(), other.length()) 262 | {} 263 | 264 | template 265 | constexpr basic_string_span first() const 266 | { 267 | return {span_.template first()}; 268 | } 269 | 270 | constexpr basic_string_span first(size_type count) const 271 | { 272 | return {span_.first(count)}; 273 | } 274 | 275 | template 276 | constexpr basic_string_span last() const 277 | { 278 | return {span_.template last()}; 279 | } 280 | 281 | constexpr basic_string_span last(size_type count) const 282 | { 283 | return {span_.last(count)}; 284 | } 285 | 286 | template 287 | constexpr basic_string_span subspan() const 288 | { 289 | return {span_.template subspan()}; 290 | } 291 | 292 | constexpr basic_string_span subspan( 293 | size_type offset, size_type count = dynamic_extent) const 294 | { 295 | return {span_.subspan(offset, count)}; 296 | } 297 | 298 | constexpr reference operator[](size_type idx) const { return span_[idx]; } 299 | constexpr reference operator()(size_type idx) const { return span_[idx]; } 300 | 301 | constexpr pointer data() const { return span_.data(); } 302 | 303 | constexpr size_type length() const noexcept { return span_.size(); } 304 | constexpr size_type size() const noexcept { return span_.size(); } 305 | constexpr size_type size_bytes() const noexcept { return span_.size_bytes(); } 306 | constexpr size_type length_bytes() const noexcept { return span_.length_bytes(); } 307 | constexpr bool empty() const noexcept { return size() == 0; } 308 | 309 | constexpr iterator begin() const noexcept { return span_.begin(); } 310 | constexpr iterator end() const noexcept { return span_.end(); } 311 | 312 | constexpr reverse_iterator rbegin() const noexcept { return span_.rbegin(); } 313 | constexpr reverse_iterator rend() const noexcept { return span_.rend(); } 314 | 315 | private: 316 | static constexpr impl_type remove_z(pointer const& sz, std::size_t max) 317 | { 318 | return impl_type(sz, details::string_length(sz, max)); 319 | } 320 | 321 | template 322 | static constexpr impl_type remove_z(element_type(&sz)[N]) 323 | { 324 | return remove_z(&sz[0], N); 325 | } 326 | 327 | impl_type span_; 328 | }; 329 | 330 | template 331 | using string_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more " 332 | "information, see isocpp/CppCoreGuidelines PR#1680")]] = 333 | basic_string_span; 334 | 335 | template 336 | using cstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more " 337 | "information, see isocpp/CppCoreGuidelines PR#1680")]] = 338 | basic_string_span; 339 | 340 | template 341 | using wstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more " 342 | "information, see isocpp/CppCoreGuidelines PR#1680")]] = 343 | basic_string_span; 344 | 345 | template 346 | using cwstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more " 347 | "information, see isocpp/CppCoreGuidelines PR#1680")]] = 348 | basic_string_span; 349 | 350 | template 351 | using u16string_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more " 352 | "information, see isocpp/CppCoreGuidelines PR#1680")]] = 353 | basic_string_span; 354 | 355 | template 356 | using cu16string_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more " 357 | "information, see isocpp/CppCoreGuidelines PR#1680")]] = 358 | basic_string_span; 359 | 360 | template 361 | using u32string_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more " 362 | "information, see isocpp/CppCoreGuidelines PR#1680")]] = 363 | basic_string_span; 364 | 365 | template 366 | using cu32string_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more " 367 | "information, see isocpp/CppCoreGuidelines PR#1680")]] = 368 | basic_string_span; 369 | 370 | // 371 | // to_string() allow (explicit) conversions from string_span to string 372 | // 373 | 374 | template 375 | constexpr std::basic_string::type> 376 | to_string(basic_string_span view) 377 | { 378 | return {view.data(), narrow_cast(view.length())}; 379 | } 380 | 381 | template , 382 | typename Allocator = std::allocator, typename gCharT, std::size_t Extent> 383 | constexpr std::basic_string 384 | to_basic_string(basic_string_span view) 385 | { 386 | return {view.data(), narrow_cast(view.length())}; 387 | } 388 | 389 | template 390 | constexpr basic_string_span::value> 391 | as_bytes(basic_string_span s) noexcept 392 | { 393 | // clang-format off 394 | GSL_SUPPRESS(type.1) 395 | // clang-format on 396 | return {reinterpret_cast(s.data()), s.size_bytes()}; 397 | } 398 | 399 | template ::value>> 401 | constexpr basic_string_span::value> 402 | as_writable_bytes(basic_string_span s) noexcept 403 | { 404 | // clang-format off 405 | GSL_SUPPRESS(type.1) 406 | // clang-format on 407 | return {reinterpret_cast(s.data()), s.size_bytes()}; 408 | } 409 | 410 | // zero-terminated string span, used to convert 411 | // zero-terminated spans to legacy strings 412 | template 413 | class [[deprecated("string_span was removed from the C++ Core Guidelines. For more information, " 414 | "see isocpp/CppCoreGuidelines PR#1680")]] basic_zstring_span 415 | { 416 | public: 417 | using value_type = CharT; 418 | using const_value_type = std::add_const_t; 419 | 420 | using pointer = std::add_pointer_t; 421 | using const_pointer = std::add_pointer_t; 422 | 423 | using zstring_type = basic_zstring; 424 | using const_zstring_type = basic_zstring; 425 | 426 | using impl_type = span; 427 | using string_span_type = basic_string_span; 428 | 429 | constexpr basic_zstring_span(impl_type s) : span_(s) 430 | { 431 | // expects a zero-terminated span 432 | Expects(s.size() > 0); 433 | Expects(s[s.size() - 1] == value_type{}); 434 | } 435 | 436 | // copy 437 | constexpr basic_zstring_span(const basic_zstring_span& other) = default; 438 | 439 | // move 440 | constexpr basic_zstring_span(basic_zstring_span && other) = default; 441 | 442 | // assign 443 | constexpr basic_zstring_span& operator=(const basic_zstring_span& other) = default; 444 | 445 | // move assign 446 | constexpr basic_zstring_span& operator=(basic_zstring_span&& other) = default; 447 | 448 | constexpr bool empty() const noexcept { return false; } 449 | 450 | constexpr string_span_type as_string_span() const noexcept 451 | { 452 | return {span_.data(), span_.size() - 1}; 453 | } 454 | constexpr string_span_type ensure_z() const { return gsl::ensure_z(span_); } 455 | 456 | constexpr const_zstring_type assume_z() const noexcept { return span_.data(); } 457 | 458 | private: 459 | impl_type span_; 460 | }; 461 | 462 | template 463 | using zstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more " 464 | "information, see isocpp/CppCoreGuidelines PR#1680")]] = 465 | basic_zstring_span; 466 | 467 | template 468 | using wzstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more " 469 | "information, see isocpp/CppCoreGuidelines PR#1680")]] = 470 | basic_zstring_span; 471 | 472 | template 473 | using u16zstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more " 474 | "information, see isocpp/CppCoreGuidelines PR#1680")]] = 475 | basic_zstring_span; 476 | 477 | template 478 | using u32zstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more " 479 | "information, see isocpp/CppCoreGuidelines PR#1680")]] = 480 | basic_zstring_span; 481 | 482 | template 483 | using czstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more " 484 | "information, see isocpp/CppCoreGuidelines PR#1680")]] = 485 | basic_zstring_span; 486 | 487 | template 488 | using cwzstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For more " 489 | "information, see isocpp/CppCoreGuidelines PR#1680")]] = 490 | basic_zstring_span; 491 | 492 | template 493 | using cu16zstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For " 494 | "more information, see isocpp/CppCoreGuidelines PR#1680")]] = 495 | basic_zstring_span; 496 | 497 | template 498 | using cu32zstring_span [[deprecated("string_span was removed from the C++ Core Guidelines. For " 499 | "more information, see isocpp/CppCoreGuidelines PR#1680")]] = 500 | basic_zstring_span; 501 | 502 | // operator == 503 | template ::value || 506 | std::is_convertible>>::value>> 507 | bool operator==(const gsl::basic_string_span& one, const T& other) 508 | { 509 | const gsl::basic_string_span> tmp(other); 510 | return std::equal(one.begin(), one.end(), tmp.begin(), tmp.end()); 511 | } 512 | 513 | template ::value && 516 | std::is_convertible>>::value>> 517 | bool operator==(const T& one, const gsl::basic_string_span& other) 518 | { 519 | const gsl::basic_string_span> tmp(one); 520 | return std::equal(tmp.begin(), tmp.end(), other.begin(), other.end()); 521 | } 522 | 523 | // operator != 524 | template , Extent>>::value>> 527 | bool operator!=(gsl::basic_string_span one, const T& other) 528 | { 529 | return !(one == other); 530 | } 531 | 532 | template < 533 | typename CharT, std::size_t Extent = dynamic_extent, typename T, 534 | typename = std::enable_if_t< 535 | std::is_convertible, Extent>>::value && 536 | !gsl::details::is_basic_string_span::value>> 537 | bool operator!=(const T& one, gsl::basic_string_span other) 538 | { 539 | return !(one == other); 540 | } 541 | 542 | // operator< 543 | template , Extent>>::value>> 546 | bool operator<(gsl::basic_string_span one, const T& other) 547 | { 548 | const gsl::basic_string_span, Extent> tmp(other); 549 | return std::lexicographical_compare(one.begin(), one.end(), tmp.begin(), tmp.end()); 550 | } 551 | 552 | template < 553 | typename CharT, std::size_t Extent = dynamic_extent, typename T, 554 | typename = std::enable_if_t< 555 | std::is_convertible, Extent>>::value && 556 | !gsl::details::is_basic_string_span::value>> 557 | bool operator<(const T& one, gsl::basic_string_span other) 558 | { 559 | gsl::basic_string_span, Extent> tmp(one); 560 | return std::lexicographical_compare(tmp.begin(), tmp.end(), other.begin(), other.end()); 561 | } 562 | 563 | #ifndef _MSC_VER 564 | 565 | // VS treats temp and const containers as convertible to basic_string_span, 566 | // so the cases below are already covered by the previous operators 567 | 568 | template < 569 | typename CharT, std::size_t Extent = dynamic_extent, typename T, 570 | typename DataType = typename T::value_type, 571 | typename = std::enable_if_t< 572 | !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && 573 | std::is_convertible::value && 574 | std::is_same().size(), *std::declval().data())>, 575 | DataType>::value>> 576 | bool operator<(gsl::basic_string_span one, const T& other) 577 | { 578 | gsl::basic_string_span, Extent> tmp(other); 579 | return std::lexicographical_compare(one.begin(), one.end(), tmp.begin(), tmp.end()); 580 | } 581 | 582 | template < 583 | typename CharT, std::size_t Extent = dynamic_extent, typename T, 584 | typename DataType = typename T::value_type, 585 | typename = std::enable_if_t< 586 | !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && 587 | std::is_convertible::value && 588 | std::is_same().size(), *std::declval().data())>, 589 | DataType>::value>> 590 | bool operator<(const T& one, gsl::basic_string_span other) 591 | { 592 | gsl::basic_string_span, Extent> tmp(one); 593 | return std::lexicographical_compare(tmp.begin(), tmp.end(), other.begin(), other.end()); 594 | } 595 | #endif 596 | 597 | // operator <= 598 | template , Extent>>::value>> 601 | bool operator<=(gsl::basic_string_span one, const T& other) 602 | { 603 | return !(other < one); 604 | } 605 | 606 | template < 607 | typename CharT, std::size_t Extent = dynamic_extent, typename T, 608 | typename = std::enable_if_t< 609 | std::is_convertible, Extent>>::value && 610 | !gsl::details::is_basic_string_span::value>> 611 | bool operator<=(const T& one, gsl::basic_string_span other) 612 | { 613 | return !(other < one); 614 | } 615 | 616 | #ifndef _MSC_VER 617 | 618 | // VS treats temp and const containers as convertible to basic_string_span, 619 | // so the cases below are already covered by the previous operators 620 | 621 | template < 622 | typename CharT, std::size_t Extent = dynamic_extent, typename T, 623 | typename DataType = typename T::value_type, 624 | typename = std::enable_if_t< 625 | !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && 626 | std::is_convertible::value && 627 | std::is_same().size(), *std::declval().data())>, 628 | DataType>::value>> 629 | bool operator<=(gsl::basic_string_span one, const T& other) 630 | { 631 | return !(other < one); 632 | } 633 | 634 | template < 635 | typename CharT, std::size_t Extent = dynamic_extent, typename T, 636 | typename DataType = typename T::value_type, 637 | typename = std::enable_if_t< 638 | !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && 639 | std::is_convertible::value && 640 | std::is_same().size(), *std::declval().data())>, 641 | DataType>::value>> 642 | bool operator<=(const T& one, gsl::basic_string_span other) 643 | { 644 | return !(other < one); 645 | } 646 | #endif 647 | 648 | // operator> 649 | template , Extent>>::value>> 652 | bool operator>(gsl::basic_string_span one, const T& other) 653 | { 654 | return other < one; 655 | } 656 | 657 | template < 658 | typename CharT, std::size_t Extent = dynamic_extent, typename T, 659 | typename = std::enable_if_t< 660 | std::is_convertible, Extent>>::value && 661 | !gsl::details::is_basic_string_span::value>> 662 | bool operator>(const T& one, gsl::basic_string_span other) 663 | { 664 | return other < one; 665 | } 666 | 667 | #ifndef _MSC_VER 668 | 669 | // VS treats temp and const containers as convertible to basic_string_span, 670 | // so the cases below are already covered by the previous operators 671 | 672 | template < 673 | typename CharT, std::size_t Extent = dynamic_extent, typename T, 674 | typename DataType = typename T::value_type, 675 | typename = std::enable_if_t< 676 | !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && 677 | std::is_convertible::value && 678 | std::is_same().size(), *std::declval().data())>, 679 | DataType>::value>> 680 | bool operator>(gsl::basic_string_span one, const T& other) 681 | { 682 | return other < one; 683 | } 684 | 685 | template < 686 | typename CharT, std::size_t Extent = dynamic_extent, typename T, 687 | typename DataType = typename T::value_type, 688 | typename = std::enable_if_t< 689 | !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && 690 | std::is_convertible::value && 691 | std::is_same().size(), *std::declval().data())>, 692 | DataType>::value>> 693 | bool operator>(const T& one, gsl::basic_string_span other) 694 | { 695 | return other < one; 696 | } 697 | #endif 698 | 699 | // operator >= 700 | template , Extent>>::value>> 703 | bool operator>=(gsl::basic_string_span one, const T& other) 704 | { 705 | return !(one < other); 706 | } 707 | 708 | template < 709 | typename CharT, std::size_t Extent = dynamic_extent, typename T, 710 | typename = std::enable_if_t< 711 | std::is_convertible, Extent>>::value && 712 | !gsl::details::is_basic_string_span::value>> 713 | bool operator>=(const T& one, gsl::basic_string_span other) 714 | { 715 | return !(one < other); 716 | } 717 | 718 | #ifndef _MSC_VER 719 | 720 | // VS treats temp and const containers as convertible to basic_string_span, 721 | // so the cases below are already covered by the previous operators 722 | 723 | template < 724 | typename CharT, std::size_t Extent = dynamic_extent, typename T, 725 | typename DataType = typename T::value_type, 726 | typename = std::enable_if_t< 727 | !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && 728 | std::is_convertible::value && 729 | std::is_same().size(), *std::declval().data())>, 730 | DataType>::value>> 731 | bool operator>=(gsl::basic_string_span one, const T& other) 732 | { 733 | return !(one < other); 734 | } 735 | 736 | template < 737 | typename CharT, std::size_t Extent = dynamic_extent, typename T, 738 | typename DataType = typename T::value_type, 739 | typename = std::enable_if_t< 740 | !gsl::details::is_span::value && !gsl::details::is_basic_string_span::value && 741 | std::is_convertible::value && 742 | std::is_same().size(), *std::declval().data())>, 743 | DataType>::value>> 744 | bool operator>=(const T& one, gsl::basic_string_span other) 745 | { 746 | return !(one < other); 747 | } 748 | #endif 749 | } // namespace gsl 750 | 751 | #if defined(_MSC_VER) && !defined(__clang__) 752 | #pragma warning(pop) 753 | 754 | #endif // _MSC_VER 755 | 756 | #if defined(__GNUC__) || defined(__clang__) 757 | #pragma GCC diagnostic pop 758 | #endif 759 | #endif // GSL_STRING_SPAN_H 760 | -------------------------------------------------------------------------------- /gsl/util: -------------------------------------------------------------------------------- 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_UTIL_H 18 | #define GSL_UTIL_H 19 | 20 | #include "assert" // for Expects 21 | 22 | #include 23 | #include // for ptrdiff_t, size_t 24 | #include // for initializer_list 25 | #include // for is_signed, integral_constant 26 | #include // for exchange, forward 27 | 28 | #if defined(__has_include) && __has_include() 29 | #include 30 | #if defined(__cpp_lib_span) && __cpp_lib_span >= 202002L 31 | #include 32 | #endif // __cpp_lib_span >= 202002L 33 | #endif //__has_include() 34 | 35 | #if defined(_MSC_VER) && !defined(__clang__) 36 | 37 | #pragma warning(push) 38 | #pragma warning(disable : 4127) // conditional expression is constant 39 | 40 | #endif // _MSC_VER 41 | 42 | #if defined(__cplusplus) && (__cplusplus >= 201703L) 43 | #define GSL_NODISCARD [[nodiscard]] 44 | #else 45 | #define GSL_NODISCARD 46 | #endif // defined(__cplusplus) && (__cplusplus >= 201703L) 47 | 48 | namespace gsl 49 | { 50 | // 51 | // GSL.util: utilities 52 | // 53 | 54 | // index type for all container indexes/subscripts/sizes 55 | using index = std::ptrdiff_t; 56 | 57 | // final_action allows you to ensure something gets run at the end of a scope 58 | template 59 | class final_action 60 | { 61 | public: 62 | static_assert(!std::is_reference::value && !std::is_const::value && 63 | !std::is_volatile::value, 64 | "Final_action should store its callable by value"); 65 | 66 | explicit final_action(F f) noexcept : f_(std::move(f)) {} 67 | 68 | final_action(final_action&& other) noexcept 69 | : f_(std::move(other.f_)), invoke_(std::exchange(other.invoke_, false)) 70 | {} 71 | 72 | final_action(const final_action&) = delete; 73 | final_action& operator=(const final_action&) = delete; 74 | final_action& operator=(final_action&&) = delete; 75 | 76 | // clang-format off 77 | GSL_SUPPRESS(f.6) // NO-FORMAT: attribute // terminate if throws 78 | // clang-format on 79 | ~final_action() noexcept 80 | { 81 | if (invoke_) f_(); 82 | } 83 | 84 | private: 85 | F f_; 86 | bool invoke_{true}; 87 | }; 88 | 89 | // finally() - convenience function to generate a final_action 90 | template 91 | GSL_NODISCARD final_action::type>::type> 92 | finally(F&& f) noexcept 93 | { 94 | return final_action::type>::type>( 95 | std::forward(f)); 96 | } 97 | 98 | // narrow_cast(): a searchable way to do narrowing casts of values 99 | template 100 | // clang-format off 101 | GSL_SUPPRESS(type.1) // NO-FORMAT: attribute 102 | // clang-format on 103 | constexpr T narrow_cast(U&& u) noexcept 104 | { 105 | return static_cast(std::forward(u)); 106 | } 107 | 108 | // 109 | // at() - Bounds-checked way of accessing builtin arrays, std::array, std::vector 110 | // 111 | template 112 | // clang-format off 113 | GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute 114 | GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute 115 | // clang-format on 116 | constexpr T& at(T (&arr)[N], const index i) 117 | { 118 | Expects(i >= 0 && i < narrow_cast(N)); 119 | return arr[narrow_cast(i)]; 120 | } 121 | 122 | template 123 | // clang-format off 124 | GSL_SUPPRESS(bounds.4) // NO-FORMAT: attribute 125 | GSL_SUPPRESS(bounds.2) // NO-FORMAT: attribute 126 | // clang-format on 127 | constexpr auto at(Cont& cont, const index i) -> decltype(cont[cont.size()]) 128 | { 129 | Expects(i >= 0 && i < narrow_cast(cont.size())); 130 | using size_type = decltype(cont.size()); 131 | return cont[narrow_cast(i)]; 132 | } 133 | 134 | template 135 | // clang-format off 136 | GSL_SUPPRESS(bounds.1) // NO-FORMAT: attribute 137 | // clang-format on 138 | constexpr T at(const std::initializer_list cont, const index i) 139 | { 140 | Expects(i >= 0 && i < narrow_cast(cont.size())); 141 | return *(cont.begin() + i); 142 | } 143 | 144 | #if defined(__cpp_lib_span) && __cpp_lib_span >= 202002L 145 | template 146 | constexpr auto at(std::span sp, const index i) -> decltype(sp[sp.size()]) 147 | { 148 | Expects(i >= 0 && i < narrow_cast(sp.size())); 149 | return sp[gsl::narrow_cast(i)]; 150 | } 151 | #endif // __cpp_lib_span >= 202002L 152 | } // namespace gsl 153 | 154 | #if defined(_MSC_VER) && !defined(__clang__) 155 | 156 | #pragma warning(pop) 157 | 158 | #endif // _MSC_VER 159 | 160 | #endif // GSL_UTIL_H 161 | -------------------------------------------------------------------------------- /hook/SymHook.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | using RVA = unsigned int; 4 | // public: class gsl::span,-1> 5 | // __cdecl BlockSource::fetchEntities(enum ActorType,class AABB const & 6 | // __ptr64,class Actor const * __ptr64) __ptr64 7 | constexpr RVA MSSYM_MD5_21a49b5175e9c00856ce77825b121141 = 0x00A18070; 8 | 9 | namespace SymHook { 10 | 11 | // [ԭ��] public: virtual class Vec3 const & __ptr64 __cdecl 12 | // Actor::getPos(void)const __ptr64 [����] ?getPos@Actor@@UEBAAEBVVec3@@XZ 13 | constexpr RVA MSSYM_B1QA6getPosB1AA5ActorB2AAE12UEBAAEBVVec3B2AAA2XZ = 14 | 0x00554A80; 15 | } // namespace SymHook 16 | -------------------------------------------------------------------------------- /lib/detours.h: -------------------------------------------------------------------------------- 1 | ///////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Core Detours Functionality (detours.h of detours.lib) 4 | // 5 | // Microsoft Research Detours Package, Version 4.0.1 6 | // 7 | // Copyright (c) Microsoft Corporation. All rights reserved. 8 | // 9 | 10 | #pragma once 11 | #ifndef _DETOURS_H_ 12 | #define _DETOURS_H_ 13 | 14 | #define DETOURS_VERSION 0x4c0c1 // 0xMAJORcMINORcPATCH 15 | 16 | ////////////////////////////////////////////////////////////////////////////// 17 | // 18 | 19 | #undef DETOURS_X64 20 | #undef DETOURS_X86 21 | #undef DETOURS_IA64 22 | #undef DETOURS_ARM 23 | #undef DETOURS_ARM64 24 | #undef DETOURS_BITS 25 | #undef DETOURS_32BIT 26 | #undef DETOURS_64BIT 27 | 28 | #if defined(_X86_) 29 | #define DETOURS_X86 30 | #define DETOURS_OPTION_BITS 64 31 | 32 | #elif defined(_AMD64_) 33 | #define DETOURS_X64 34 | #define DETOURS_OPTION_BITS 32 35 | 36 | #elif defined(_IA64_) 37 | #define DETOURS_IA64 38 | #define DETOURS_OPTION_BITS 32 39 | 40 | #elif defined(_ARM_) 41 | #define DETOURS_ARM 42 | 43 | #elif defined(_ARM64_) 44 | #define DETOURS_ARM64 45 | 46 | #else 47 | #error Unknown architecture (x86, amd64, ia64, arm, arm64) 48 | #endif 49 | 50 | #ifdef _WIN64 51 | #undef DETOURS_32BIT 52 | #define DETOURS_64BIT 1 53 | #define DETOURS_BITS 64 54 | // If all 64bit kernels can run one and only one 32bit architecture. 55 | //#define DETOURS_OPTION_BITS 32 56 | #else 57 | #define DETOURS_32BIT 1 58 | #undef DETOURS_64BIT 59 | #define DETOURS_BITS 32 60 | // If all 64bit kernels can run one and only one 32bit architecture. 61 | //#define DETOURS_OPTION_BITS 32 62 | #endif 63 | 64 | #define VER_DETOURS_BITS DETOUR_STRINGIFY(DETOURS_BITS) 65 | 66 | ////////////////////////////////////////////////////////////////////////////// 67 | // 68 | 69 | #if (_MSC_VER < 1299) 70 | typedef LONG LONG_PTR; 71 | typedef ULONG ULONG_PTR; 72 | #endif 73 | 74 | ///////////////////////////////////////////////// SAL 2.0 Annotations w/o SAL. 75 | // 76 | // These definitions are include so that Detours will build even if the 77 | // compiler doesn't have full SAL 2.0 support. 78 | // 79 | #ifndef DETOURS_DONT_REMOVE_SAL_20 80 | 81 | #ifdef DETOURS_TEST_REMOVE_SAL_20 82 | #undef _Analysis_assume_ 83 | #undef _Benign_race_begin_ 84 | #undef _Benign_race_end_ 85 | #undef _Field_range_ 86 | #undef _Field_size_ 87 | #undef _In_ 88 | #undef _In_bytecount_ 89 | #undef _In_count_ 90 | #undef _In_opt_ 91 | #undef _In_opt_bytecount_ 92 | #undef _In_opt_count_ 93 | #undef _In_opt_z_ 94 | #undef _In_range_ 95 | #undef _In_reads_ 96 | #undef _In_reads_bytes_ 97 | #undef _In_reads_opt_ 98 | #undef _In_reads_opt_bytes_ 99 | #undef _In_reads_or_z_ 100 | #undef _In_z_ 101 | #undef _Inout_ 102 | #undef _Inout_opt_ 103 | #undef _Inout_z_count_ 104 | #undef _Out_ 105 | #undef _Out_opt_ 106 | #undef _Out_writes_ 107 | #undef _Outptr_result_maybenull_ 108 | #undef _Readable_bytes_ 109 | #undef _Success_ 110 | #undef _Writable_bytes_ 111 | #undef _Pre_notnull_ 112 | #endif 113 | 114 | #if defined(_Deref_out_opt_z_) && !defined(_Outptr_result_maybenull_) 115 | #define _Outptr_result_maybenull_ _Deref_out_opt_z_ 116 | #endif 117 | 118 | #if defined(_In_count_) && !defined(_In_reads_) 119 | #define _In_reads_(x) _In_count_(x) 120 | #endif 121 | 122 | #if defined(_In_opt_count_) && !defined(_In_reads_opt_) 123 | #define _In_reads_opt_(x) _In_opt_count_(x) 124 | #endif 125 | 126 | #if defined(_In_opt_bytecount_) && !defined(_In_reads_opt_bytes_) 127 | #define _In_reads_opt_bytes_(x) _In_opt_bytecount_(x) 128 | #endif 129 | 130 | #if defined(_In_bytecount_) && !defined(_In_reads_bytes_) 131 | #define _In_reads_bytes_(x) _In_bytecount_(x) 132 | #endif 133 | 134 | #ifndef _In_ 135 | #define _In_ 136 | #endif 137 | 138 | #ifndef _In_bytecount_ 139 | #define _In_bytecount_(x) 140 | #endif 141 | 142 | #ifndef _In_count_ 143 | #define _In_count_(x) 144 | #endif 145 | 146 | #ifndef _In_opt_ 147 | #define _In_opt_ 148 | #endif 149 | 150 | #ifndef _In_opt_bytecount_ 151 | #define _In_opt_bytecount_(x) 152 | #endif 153 | 154 | #ifndef _In_opt_count_ 155 | #define _In_opt_count_(x) 156 | #endif 157 | 158 | #ifndef _In_opt_z_ 159 | #define _In_opt_z_ 160 | #endif 161 | 162 | #ifndef _In_range_ 163 | #define _In_range_(x,y) 164 | #endif 165 | 166 | #ifndef _In_reads_ 167 | #define _In_reads_(x) 168 | #endif 169 | 170 | #ifndef _In_reads_bytes_ 171 | #define _In_reads_bytes_(x) 172 | #endif 173 | 174 | #ifndef _In_reads_opt_ 175 | #define _In_reads_opt_(x) 176 | #endif 177 | 178 | #ifndef _In_reads_opt_bytes_ 179 | #define _In_reads_opt_bytes_(x) 180 | #endif 181 | 182 | #ifndef _In_reads_or_z_ 183 | #define _In_reads_or_z_ 184 | #endif 185 | 186 | #ifndef _In_z_ 187 | #define _In_z_ 188 | #endif 189 | 190 | #ifndef _Inout_ 191 | #define _Inout_ 192 | #endif 193 | 194 | #ifndef _Inout_opt_ 195 | #define _Inout_opt_ 196 | #endif 197 | 198 | #ifndef _Inout_z_count_ 199 | #define _Inout_z_count_(x) 200 | #endif 201 | 202 | #ifndef _Out_ 203 | #define _Out_ 204 | #endif 205 | 206 | #ifndef _Out_opt_ 207 | #define _Out_opt_ 208 | #endif 209 | 210 | #ifndef _Out_writes_ 211 | #define _Out_writes_(x) 212 | #endif 213 | 214 | #ifndef _Outptr_result_maybenull_ 215 | #define _Outptr_result_maybenull_ 216 | #endif 217 | 218 | #ifndef _Writable_bytes_ 219 | #define _Writable_bytes_(x) 220 | #endif 221 | 222 | #ifndef _Readable_bytes_ 223 | #define _Readable_bytes_(x) 224 | #endif 225 | 226 | #ifndef _Success_ 227 | #define _Success_(x) 228 | #endif 229 | 230 | #ifndef _Pre_notnull_ 231 | #define _Pre_notnull_ 232 | #endif 233 | 234 | #ifdef DETOURS_INTERNAL 235 | 236 | #pragma warning(disable:4615) // unknown warning type (suppress with older compilers) 237 | 238 | #ifndef _Benign_race_begin_ 239 | #define _Benign_race_begin_ 240 | #endif 241 | 242 | #ifndef _Benign_race_end_ 243 | #define _Benign_race_end_ 244 | #endif 245 | 246 | #ifndef _Field_size_ 247 | #define _Field_size_(x) 248 | #endif 249 | 250 | #ifndef _Field_range_ 251 | #define _Field_range_(x,y) 252 | #endif 253 | 254 | #ifndef _Analysis_assume_ 255 | #define _Analysis_assume_(x) 256 | #endif 257 | 258 | #endif // DETOURS_INTERNAL 259 | #endif // DETOURS_DONT_REMOVE_SAL_20 260 | 261 | ////////////////////////////////////////////////////////////////////////////// 262 | // 263 | #ifndef GUID_DEFINED 264 | #define GUID_DEFINED 265 | typedef struct _GUID 266 | { 267 | DWORD Data1; 268 | WORD Data2; 269 | WORD Data3; 270 | BYTE Data4[ 8 ]; 271 | } GUID; 272 | 273 | #ifdef INITGUID 274 | #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ 275 | const GUID name \ 276 | = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } } 277 | #else 278 | #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \ 279 | const GUID name 280 | #endif // INITGUID 281 | #endif // !GUID_DEFINED 282 | 283 | #if defined(__cplusplus) 284 | #ifndef _REFGUID_DEFINED 285 | #define _REFGUID_DEFINED 286 | #define REFGUID const GUID & 287 | #endif // !_REFGUID_DEFINED 288 | #else // !__cplusplus 289 | #ifndef _REFGUID_DEFINED 290 | #define _REFGUID_DEFINED 291 | #define REFGUID const GUID * const 292 | #endif // !_REFGUID_DEFINED 293 | #endif // !__cplusplus 294 | 295 | #ifndef ARRAYSIZE 296 | #define ARRAYSIZE(x) (sizeof(x)/sizeof(x[0])) 297 | #endif 298 | 299 | // 300 | ////////////////////////////////////////////////////////////////////////////// 301 | 302 | #ifdef __cplusplus 303 | extern "C" { 304 | #endif // __cplusplus 305 | 306 | /////////////////////////////////////////////////// Instruction Target Macros. 307 | // 308 | #define DETOUR_INSTRUCTION_TARGET_NONE ((PVOID)0) 309 | #define DETOUR_INSTRUCTION_TARGET_DYNAMIC ((PVOID)(LONG_PTR)-1) 310 | #define DETOUR_SECTION_HEADER_SIGNATURE 0x00727444 // "Dtr\0" 311 | 312 | extern const GUID DETOUR_EXE_RESTORE_GUID; 313 | extern const GUID DETOUR_EXE_HELPER_GUID; 314 | 315 | #define DETOUR_TRAMPOLINE_SIGNATURE 0x21727444 // Dtr! 316 | typedef struct _DETOUR_TRAMPOLINE DETOUR_TRAMPOLINE, *PDETOUR_TRAMPOLINE; 317 | 318 | /////////////////////////////////////////////////////////// Binary Structures. 319 | // 320 | #pragma pack(push, 8) 321 | typedef struct _DETOUR_SECTION_HEADER 322 | { 323 | DWORD cbHeaderSize; 324 | DWORD nSignature; 325 | DWORD nDataOffset; 326 | DWORD cbDataSize; 327 | 328 | DWORD nOriginalImportVirtualAddress; 329 | DWORD nOriginalImportSize; 330 | DWORD nOriginalBoundImportVirtualAddress; 331 | DWORD nOriginalBoundImportSize; 332 | 333 | DWORD nOriginalIatVirtualAddress; 334 | DWORD nOriginalIatSize; 335 | DWORD nOriginalSizeOfImage; 336 | DWORD cbPrePE; 337 | 338 | DWORD nOriginalClrFlags; 339 | DWORD reserved1; 340 | DWORD reserved2; 341 | DWORD reserved3; 342 | 343 | // Followed by cbPrePE bytes of data. 344 | } DETOUR_SECTION_HEADER, *PDETOUR_SECTION_HEADER; 345 | 346 | typedef struct _DETOUR_SECTION_RECORD 347 | { 348 | DWORD cbBytes; 349 | DWORD nReserved; 350 | GUID guid; 351 | } DETOUR_SECTION_RECORD, *PDETOUR_SECTION_RECORD; 352 | 353 | typedef struct _DETOUR_CLR_HEADER 354 | { 355 | // Header versioning 356 | ULONG cb; 357 | USHORT MajorRuntimeVersion; 358 | USHORT MinorRuntimeVersion; 359 | 360 | // Symbol table and startup information 361 | IMAGE_DATA_DIRECTORY MetaData; 362 | ULONG Flags; 363 | 364 | // Followed by the rest of the IMAGE_COR20_HEADER 365 | } DETOUR_CLR_HEADER, *PDETOUR_CLR_HEADER; 366 | 367 | typedef struct _DETOUR_EXE_RESTORE 368 | { 369 | DWORD cb; 370 | DWORD cbidh; 371 | DWORD cbinh; 372 | DWORD cbclr; 373 | 374 | PBYTE pidh; 375 | PBYTE pinh; 376 | PBYTE pclr; 377 | 378 | IMAGE_DOS_HEADER idh; 379 | union { 380 | IMAGE_NT_HEADERS inh; // all environments have this 381 | #ifdef IMAGE_NT_OPTIONAL_HDR32_MAGIC // some environments do not have this 382 | IMAGE_NT_HEADERS32 inh32; 383 | #endif 384 | #ifdef IMAGE_NT_OPTIONAL_HDR64_MAGIC // some environments do not have this 385 | IMAGE_NT_HEADERS64 inh64; 386 | #endif 387 | #ifdef IMAGE_NT_OPTIONAL_HDR64_MAGIC // some environments do not have this 388 | BYTE raw[sizeof(IMAGE_NT_HEADERS64) + 389 | sizeof(IMAGE_SECTION_HEADER) * 32]; 390 | #else 391 | BYTE raw[0x108 + sizeof(IMAGE_SECTION_HEADER) * 32]; 392 | #endif 393 | }; 394 | DETOUR_CLR_HEADER clr; 395 | 396 | } DETOUR_EXE_RESTORE, *PDETOUR_EXE_RESTORE; 397 | 398 | #ifdef IMAGE_NT_OPTIONAL_HDR64_MAGIC 399 | C_ASSERT(sizeof(IMAGE_NT_HEADERS64) == 0x108); 400 | #endif 401 | 402 | // The size can change, but assert for clarity due to the muddying #ifdefs. 403 | #ifdef _WIN64 404 | C_ASSERT(sizeof(DETOUR_EXE_RESTORE) == 0x688); 405 | #else 406 | C_ASSERT(sizeof(DETOUR_EXE_RESTORE) == 0x678); 407 | #endif 408 | 409 | typedef struct _DETOUR_EXE_HELPER 410 | { 411 | DWORD cb; 412 | DWORD pid; 413 | DWORD nDlls; 414 | CHAR rDlls[4]; 415 | } DETOUR_EXE_HELPER, *PDETOUR_EXE_HELPER; 416 | 417 | #pragma pack(pop) 418 | 419 | #define DETOUR_SECTION_HEADER_DECLARE(cbSectionSize) \ 420 | { \ 421 | sizeof(DETOUR_SECTION_HEADER),\ 422 | DETOUR_SECTION_HEADER_SIGNATURE,\ 423 | sizeof(DETOUR_SECTION_HEADER),\ 424 | (cbSectionSize),\ 425 | \ 426 | 0,\ 427 | 0,\ 428 | 0,\ 429 | 0,\ 430 | \ 431 | 0,\ 432 | 0,\ 433 | 0,\ 434 | 0,\ 435 | } 436 | 437 | /////////////////////////////////////////////////////////////// Helper Macros. 438 | // 439 | #define DETOURS_STRINGIFY(x) DETOURS_STRINGIFY_(x) 440 | #define DETOURS_STRINGIFY_(x) #x 441 | 442 | ///////////////////////////////////////////////////////////// Binary Typedefs. 443 | // 444 | typedef BOOL (CALLBACK *PF_DETOUR_BINARY_BYWAY_CALLBACK)( 445 | _In_opt_ PVOID pContext, 446 | _In_opt_ LPCSTR pszFile, 447 | _Outptr_result_maybenull_ LPCSTR *ppszOutFile); 448 | 449 | typedef BOOL (CALLBACK *PF_DETOUR_BINARY_FILE_CALLBACK)( 450 | _In_opt_ PVOID pContext, 451 | _In_ LPCSTR pszOrigFile, 452 | _In_ LPCSTR pszFile, 453 | _Outptr_result_maybenull_ LPCSTR *ppszOutFile); 454 | 455 | typedef BOOL (CALLBACK *PF_DETOUR_BINARY_SYMBOL_CALLBACK)( 456 | _In_opt_ PVOID pContext, 457 | _In_ ULONG nOrigOrdinal, 458 | _In_ ULONG nOrdinal, 459 | _Out_ ULONG *pnOutOrdinal, 460 | _In_opt_ LPCSTR pszOrigSymbol, 461 | _In_opt_ LPCSTR pszSymbol, 462 | _Outptr_result_maybenull_ LPCSTR *ppszOutSymbol); 463 | 464 | typedef BOOL (CALLBACK *PF_DETOUR_BINARY_COMMIT_CALLBACK)( 465 | _In_opt_ PVOID pContext); 466 | 467 | typedef BOOL (CALLBACK *PF_DETOUR_ENUMERATE_EXPORT_CALLBACK)(_In_opt_ PVOID pContext, 468 | _In_ ULONG nOrdinal, 469 | _In_opt_ LPCSTR pszName, 470 | _In_opt_ PVOID pCode); 471 | 472 | typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FILE_CALLBACK)(_In_opt_ PVOID pContext, 473 | _In_opt_ HMODULE hModule, 474 | _In_opt_ LPCSTR pszFile); 475 | 476 | typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FUNC_CALLBACK)(_In_opt_ PVOID pContext, 477 | _In_ DWORD nOrdinal, 478 | _In_opt_ LPCSTR pszFunc, 479 | _In_opt_ PVOID pvFunc); 480 | 481 | // Same as PF_DETOUR_IMPORT_FUNC_CALLBACK but extra indirection on last parameter. 482 | typedef BOOL (CALLBACK *PF_DETOUR_IMPORT_FUNC_CALLBACK_EX)(_In_opt_ PVOID pContext, 483 | _In_ DWORD nOrdinal, 484 | _In_opt_ LPCSTR pszFunc, 485 | _In_opt_ PVOID* ppvFunc); 486 | 487 | typedef VOID * PDETOUR_BINARY; 488 | typedef VOID * PDETOUR_LOADED_BINARY; 489 | 490 | //////////////////////////////////////////////////////////// Transaction APIs. 491 | // 492 | LONG WINAPI DetourTransactionBegin(VOID); 493 | LONG WINAPI DetourTransactionAbort(VOID); 494 | LONG WINAPI DetourTransactionCommit(VOID); 495 | LONG WINAPI DetourTransactionCommitEx(_Out_opt_ PVOID **pppFailedPointer); 496 | 497 | LONG WINAPI DetourUpdateThread(_In_ HANDLE hThread); 498 | 499 | LONG WINAPI DetourAttach(_Inout_ PVOID *ppPointer, 500 | _In_ PVOID pDetour); 501 | 502 | LONG WINAPI DetourAttachEx(_Inout_ PVOID *ppPointer, 503 | _In_ PVOID pDetour, 504 | _Out_opt_ PDETOUR_TRAMPOLINE *ppRealTrampoline, 505 | _Out_opt_ PVOID *ppRealTarget, 506 | _Out_opt_ PVOID *ppRealDetour); 507 | 508 | LONG WINAPI DetourDetach(_Inout_ PVOID *ppPointer, 509 | _In_ PVOID pDetour); 510 | 511 | BOOL WINAPI DetourSetIgnoreTooSmall(_In_ BOOL fIgnore); 512 | BOOL WINAPI DetourSetRetainRegions(_In_ BOOL fRetain); 513 | PVOID WINAPI DetourSetSystemRegionLowerBound(_In_ PVOID pSystemRegionLowerBound); 514 | PVOID WINAPI DetourSetSystemRegionUpperBound(_In_ PVOID pSystemRegionUpperBound); 515 | 516 | ////////////////////////////////////////////////////////////// Code Functions. 517 | // 518 | PVOID WINAPI DetourFindFunction(_In_ LPCSTR pszModule, 519 | _In_ LPCSTR pszFunction); 520 | PVOID WINAPI DetourCodeFromPointer(_In_ PVOID pPointer, 521 | _Out_opt_ PVOID *ppGlobals); 522 | PVOID WINAPI DetourCopyInstruction(_In_opt_ PVOID pDst, 523 | _Inout_opt_ PVOID *ppDstPool, 524 | _In_ PVOID pSrc, 525 | _Out_opt_ PVOID *ppTarget, 526 | _Out_opt_ LONG *plExtra); 527 | BOOL WINAPI DetourSetCodeModule(_In_ HMODULE hModule, 528 | _In_ BOOL fLimitReferencesToModule); 529 | PVOID WINAPI DetourAllocateRegionWithinJumpBounds(_In_ LPCVOID pbTarget, 530 | _Out_ PDWORD pcbAllocatedSize); 531 | 532 | ///////////////////////////////////////////////////// Loaded Binary Functions. 533 | // 534 | HMODULE WINAPI DetourGetContainingModule(_In_ PVOID pvAddr); 535 | HMODULE WINAPI DetourEnumerateModules(_In_opt_ HMODULE hModuleLast); 536 | PVOID WINAPI DetourGetEntryPoint(_In_opt_ HMODULE hModule); 537 | ULONG WINAPI DetourGetModuleSize(_In_opt_ HMODULE hModule); 538 | BOOL WINAPI DetourEnumerateExports(_In_ HMODULE hModule, 539 | _In_opt_ PVOID pContext, 540 | _In_ PF_DETOUR_ENUMERATE_EXPORT_CALLBACK pfExport); 541 | BOOL WINAPI DetourEnumerateImports(_In_opt_ HMODULE hModule, 542 | _In_opt_ PVOID pContext, 543 | _In_opt_ PF_DETOUR_IMPORT_FILE_CALLBACK pfImportFile, 544 | _In_opt_ PF_DETOUR_IMPORT_FUNC_CALLBACK pfImportFunc); 545 | 546 | BOOL WINAPI DetourEnumerateImportsEx(_In_opt_ HMODULE hModule, 547 | _In_opt_ PVOID pContext, 548 | _In_opt_ PF_DETOUR_IMPORT_FILE_CALLBACK pfImportFile, 549 | _In_opt_ PF_DETOUR_IMPORT_FUNC_CALLBACK_EX pfImportFuncEx); 550 | 551 | _Writable_bytes_(*pcbData) 552 | _Readable_bytes_(*pcbData) 553 | _Success_(return != NULL) 554 | PVOID WINAPI DetourFindPayload(_In_opt_ HMODULE hModule, 555 | _In_ REFGUID rguid, 556 | _Out_ DWORD *pcbData); 557 | 558 | _Writable_bytes_(*pcbData) 559 | _Readable_bytes_(*pcbData) 560 | _Success_(return != NULL) 561 | PVOID WINAPI DetourFindPayloadEx(_In_ REFGUID rguid, 562 | _Out_ DWORD * pcbData); 563 | 564 | DWORD WINAPI DetourGetSizeOfPayloads(_In_opt_ HMODULE hModule); 565 | 566 | ///////////////////////////////////////////////// Persistent Binary Functions. 567 | // 568 | 569 | PDETOUR_BINARY WINAPI DetourBinaryOpen(_In_ HANDLE hFile); 570 | 571 | _Writable_bytes_(*pcbData) 572 | _Readable_bytes_(*pcbData) 573 | _Success_(return != NULL) 574 | PVOID WINAPI DetourBinaryEnumeratePayloads(_In_ PDETOUR_BINARY pBinary, 575 | _Out_opt_ GUID *pGuid, 576 | _Out_ DWORD *pcbData, 577 | _Inout_ DWORD *pnIterator); 578 | 579 | _Writable_bytes_(*pcbData) 580 | _Readable_bytes_(*pcbData) 581 | _Success_(return != NULL) 582 | PVOID WINAPI DetourBinaryFindPayload(_In_ PDETOUR_BINARY pBinary, 583 | _In_ REFGUID rguid, 584 | _Out_ DWORD *pcbData); 585 | 586 | PVOID WINAPI DetourBinarySetPayload(_In_ PDETOUR_BINARY pBinary, 587 | _In_ REFGUID rguid, 588 | _In_reads_opt_(cbData) PVOID pData, 589 | _In_ DWORD cbData); 590 | BOOL WINAPI DetourBinaryDeletePayload(_In_ PDETOUR_BINARY pBinary, _In_ REFGUID rguid); 591 | BOOL WINAPI DetourBinaryPurgePayloads(_In_ PDETOUR_BINARY pBinary); 592 | BOOL WINAPI DetourBinaryResetImports(_In_ PDETOUR_BINARY pBinary); 593 | BOOL WINAPI DetourBinaryEditImports(_In_ PDETOUR_BINARY pBinary, 594 | _In_opt_ PVOID pContext, 595 | _In_opt_ PF_DETOUR_BINARY_BYWAY_CALLBACK pfByway, 596 | _In_opt_ PF_DETOUR_BINARY_FILE_CALLBACK pfFile, 597 | _In_opt_ PF_DETOUR_BINARY_SYMBOL_CALLBACK pfSymbol, 598 | _In_opt_ PF_DETOUR_BINARY_COMMIT_CALLBACK pfCommit); 599 | BOOL WINAPI DetourBinaryWrite(_In_ PDETOUR_BINARY pBinary, _In_ HANDLE hFile); 600 | BOOL WINAPI DetourBinaryClose(_In_ PDETOUR_BINARY pBinary); 601 | 602 | /////////////////////////////////////////////////// Create Process & Load Dll. 603 | // 604 | typedef BOOL (WINAPI *PDETOUR_CREATE_PROCESS_ROUTINEA)( 605 | _In_opt_ LPCSTR lpApplicationName, 606 | _Inout_opt_ LPSTR lpCommandLine, 607 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 608 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 609 | _In_ BOOL bInheritHandles, 610 | _In_ DWORD dwCreationFlags, 611 | _In_opt_ LPVOID lpEnvironment, 612 | _In_opt_ LPCSTR lpCurrentDirectory, 613 | _In_ LPSTARTUPINFOA lpStartupInfo, 614 | _Out_ LPPROCESS_INFORMATION lpProcessInformation); 615 | 616 | typedef BOOL (WINAPI *PDETOUR_CREATE_PROCESS_ROUTINEW)( 617 | _In_opt_ LPCWSTR lpApplicationName, 618 | _Inout_opt_ LPWSTR lpCommandLine, 619 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 620 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 621 | _In_ BOOL bInheritHandles, 622 | _In_ DWORD dwCreationFlags, 623 | _In_opt_ LPVOID lpEnvironment, 624 | _In_opt_ LPCWSTR lpCurrentDirectory, 625 | _In_ LPSTARTUPINFOW lpStartupInfo, 626 | _Out_ LPPROCESS_INFORMATION lpProcessInformation); 627 | 628 | BOOL WINAPI DetourCreateProcessWithDllA(_In_opt_ LPCSTR lpApplicationName, 629 | _Inout_opt_ LPSTR lpCommandLine, 630 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 631 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 632 | _In_ BOOL bInheritHandles, 633 | _In_ DWORD dwCreationFlags, 634 | _In_opt_ LPVOID lpEnvironment, 635 | _In_opt_ LPCSTR lpCurrentDirectory, 636 | _In_ LPSTARTUPINFOA lpStartupInfo, 637 | _Out_ LPPROCESS_INFORMATION lpProcessInformation, 638 | _In_ LPCSTR lpDllName, 639 | _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); 640 | 641 | BOOL WINAPI DetourCreateProcessWithDllW(_In_opt_ LPCWSTR lpApplicationName, 642 | _Inout_opt_ LPWSTR lpCommandLine, 643 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 644 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 645 | _In_ BOOL bInheritHandles, 646 | _In_ DWORD dwCreationFlags, 647 | _In_opt_ LPVOID lpEnvironment, 648 | _In_opt_ LPCWSTR lpCurrentDirectory, 649 | _In_ LPSTARTUPINFOW lpStartupInfo, 650 | _Out_ LPPROCESS_INFORMATION lpProcessInformation, 651 | _In_ LPCSTR lpDllName, 652 | _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); 653 | 654 | #ifdef UNICODE 655 | #define DetourCreateProcessWithDll DetourCreateProcessWithDllW 656 | #define PDETOUR_CREATE_PROCESS_ROUTINE PDETOUR_CREATE_PROCESS_ROUTINEW 657 | #else 658 | #define DetourCreateProcessWithDll DetourCreateProcessWithDllA 659 | #define PDETOUR_CREATE_PROCESS_ROUTINE PDETOUR_CREATE_PROCESS_ROUTINEA 660 | #endif // !UNICODE 661 | 662 | BOOL WINAPI DetourCreateProcessWithDllExA(_In_opt_ LPCSTR lpApplicationName, 663 | _Inout_opt_ LPSTR lpCommandLine, 664 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 665 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 666 | _In_ BOOL bInheritHandles, 667 | _In_ DWORD dwCreationFlags, 668 | _In_opt_ LPVOID lpEnvironment, 669 | _In_opt_ LPCSTR lpCurrentDirectory, 670 | _In_ LPSTARTUPINFOA lpStartupInfo, 671 | _Out_ LPPROCESS_INFORMATION lpProcessInformation, 672 | _In_ LPCSTR lpDllName, 673 | _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); 674 | 675 | BOOL WINAPI DetourCreateProcessWithDllExW(_In_opt_ LPCWSTR lpApplicationName, 676 | _Inout_opt_ LPWSTR lpCommandLine, 677 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 678 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 679 | _In_ BOOL bInheritHandles, 680 | _In_ DWORD dwCreationFlags, 681 | _In_opt_ LPVOID lpEnvironment, 682 | _In_opt_ LPCWSTR lpCurrentDirectory, 683 | _In_ LPSTARTUPINFOW lpStartupInfo, 684 | _Out_ LPPROCESS_INFORMATION lpProcessInformation, 685 | _In_ LPCSTR lpDllName, 686 | _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); 687 | 688 | #ifdef UNICODE 689 | #define DetourCreateProcessWithDllEx DetourCreateProcessWithDllExW 690 | #else 691 | #define DetourCreateProcessWithDllEx DetourCreateProcessWithDllExA 692 | #endif // !UNICODE 693 | 694 | BOOL WINAPI DetourCreateProcessWithDllsA(_In_opt_ LPCSTR lpApplicationName, 695 | _Inout_opt_ LPSTR lpCommandLine, 696 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 697 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 698 | _In_ BOOL bInheritHandles, 699 | _In_ DWORD dwCreationFlags, 700 | _In_opt_ LPVOID lpEnvironment, 701 | _In_opt_ LPCSTR lpCurrentDirectory, 702 | _In_ LPSTARTUPINFOA lpStartupInfo, 703 | _Out_ LPPROCESS_INFORMATION lpProcessInformation, 704 | _In_ DWORD nDlls, 705 | _In_reads_(nDlls) LPCSTR *rlpDlls, 706 | _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); 707 | 708 | BOOL WINAPI DetourCreateProcessWithDllsW(_In_opt_ LPCWSTR lpApplicationName, 709 | _Inout_opt_ LPWSTR lpCommandLine, 710 | _In_opt_ LPSECURITY_ATTRIBUTES lpProcessAttributes, 711 | _In_opt_ LPSECURITY_ATTRIBUTES lpThreadAttributes, 712 | _In_ BOOL bInheritHandles, 713 | _In_ DWORD dwCreationFlags, 714 | _In_opt_ LPVOID lpEnvironment, 715 | _In_opt_ LPCWSTR lpCurrentDirectory, 716 | _In_ LPSTARTUPINFOW lpStartupInfo, 717 | _Out_ LPPROCESS_INFORMATION lpProcessInformation, 718 | _In_ DWORD nDlls, 719 | _In_reads_(nDlls) LPCSTR *rlpDlls, 720 | _In_opt_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); 721 | 722 | #ifdef UNICODE 723 | #define DetourCreateProcessWithDlls DetourCreateProcessWithDllsW 724 | #else 725 | #define DetourCreateProcessWithDlls DetourCreateProcessWithDllsA 726 | #endif // !UNICODE 727 | 728 | BOOL WINAPI DetourProcessViaHelperA(_In_ DWORD dwTargetPid, 729 | _In_ LPCSTR lpDllName, 730 | _In_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); 731 | 732 | BOOL WINAPI DetourProcessViaHelperW(_In_ DWORD dwTargetPid, 733 | _In_ LPCSTR lpDllName, 734 | _In_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); 735 | 736 | #ifdef UNICODE 737 | #define DetourProcessViaHelper DetourProcessViaHelperW 738 | #else 739 | #define DetourProcessViaHelper DetourProcessViaHelperA 740 | #endif // !UNICODE 741 | 742 | BOOL WINAPI DetourProcessViaHelperDllsA(_In_ DWORD dwTargetPid, 743 | _In_ DWORD nDlls, 744 | _In_reads_(nDlls) LPCSTR *rlpDlls, 745 | _In_ PDETOUR_CREATE_PROCESS_ROUTINEA pfCreateProcessA); 746 | 747 | BOOL WINAPI DetourProcessViaHelperDllsW(_In_ DWORD dwTargetPid, 748 | _In_ DWORD nDlls, 749 | _In_reads_(nDlls) LPCSTR *rlpDlls, 750 | _In_ PDETOUR_CREATE_PROCESS_ROUTINEW pfCreateProcessW); 751 | 752 | #ifdef UNICODE 753 | #define DetourProcessViaHelperDlls DetourProcessViaHelperDllsW 754 | #else 755 | #define DetourProcessViaHelperDlls DetourProcessViaHelperDllsA 756 | #endif // !UNICODE 757 | 758 | BOOL WINAPI DetourUpdateProcessWithDll(_In_ HANDLE hProcess, 759 | _In_reads_(nDlls) LPCSTR *rlpDlls, 760 | _In_ DWORD nDlls); 761 | 762 | BOOL WINAPI DetourUpdateProcessWithDllEx(_In_ HANDLE hProcess, 763 | _In_ HMODULE hImage, 764 | _In_ BOOL bIs32Bit, 765 | _In_reads_(nDlls) LPCSTR *rlpDlls, 766 | _In_ DWORD nDlls); 767 | 768 | BOOL WINAPI DetourCopyPayloadToProcess(_In_ HANDLE hProcess, 769 | _In_ REFGUID rguid, 770 | _In_reads_bytes_(cbData) PVOID pvData, 771 | _In_ DWORD cbData); 772 | BOOL WINAPI DetourRestoreAfterWith(VOID); 773 | BOOL WINAPI DetourRestoreAfterWithEx(_In_reads_bytes_(cbData) PVOID pvData, 774 | _In_ DWORD cbData); 775 | BOOL WINAPI DetourIsHelperProcess(VOID); 776 | VOID CALLBACK DetourFinishHelperProcess(_In_ HWND, 777 | _In_ HINSTANCE, 778 | _In_ LPSTR, 779 | _In_ INT); 780 | 781 | // 782 | ////////////////////////////////////////////////////////////////////////////// 783 | #ifdef __cplusplus 784 | } 785 | #endif // __cplusplus 786 | 787 | //////////////////////////////////////////////// Detours Internal Definitions. 788 | // 789 | #ifdef __cplusplus 790 | #ifdef DETOURS_INTERNAL 791 | 792 | #define NOTHROW 793 | // #define NOTHROW (nothrow) 794 | 795 | ////////////////////////////////////////////////////////////////////////////// 796 | // 797 | #if (_MSC_VER < 1299) 798 | #include 799 | typedef IMAGEHLP_MODULE IMAGEHLP_MODULE64; 800 | typedef PIMAGEHLP_MODULE PIMAGEHLP_MODULE64; 801 | typedef IMAGEHLP_SYMBOL SYMBOL_INFO; 802 | typedef PIMAGEHLP_SYMBOL PSYMBOL_INFO; 803 | 804 | static inline 805 | LONG InterlockedCompareExchange(_Inout_ LONG *ptr, _In_ LONG nval, _In_ LONG oval) 806 | { 807 | return (LONG)::InterlockedCompareExchange((PVOID*)ptr, (PVOID)nval, (PVOID)oval); 808 | } 809 | #else 810 | #pragma warning(push) 811 | #pragma warning(disable:4091) // empty typedef 812 | #include 813 | #pragma warning(pop) 814 | #endif 815 | 816 | #ifdef IMAGEAPI // defined by DBGHELP.H 817 | typedef LPAPI_VERSION (NTAPI *PF_ImagehlpApiVersionEx)(_In_ LPAPI_VERSION AppVersion); 818 | 819 | typedef BOOL (NTAPI *PF_SymInitialize)(_In_ HANDLE hProcess, 820 | _In_opt_ LPCSTR UserSearchPath, 821 | _In_ BOOL fInvadeProcess); 822 | typedef DWORD (NTAPI *PF_SymSetOptions)(_In_ DWORD SymOptions); 823 | typedef DWORD (NTAPI *PF_SymGetOptions)(VOID); 824 | typedef DWORD64 (NTAPI *PF_SymLoadModule64)(_In_ HANDLE hProcess, 825 | _In_opt_ HANDLE hFile, 826 | _In_ LPSTR ImageName, 827 | _In_opt_ LPSTR ModuleName, 828 | _In_ DWORD64 BaseOfDll, 829 | _In_opt_ DWORD SizeOfDll); 830 | typedef BOOL (NTAPI *PF_SymGetModuleInfo64)(_In_ HANDLE hProcess, 831 | _In_ DWORD64 qwAddr, 832 | _Out_ PIMAGEHLP_MODULE64 ModuleInfo); 833 | typedef BOOL (NTAPI *PF_SymFromName)(_In_ HANDLE hProcess, 834 | _In_ LPSTR Name, 835 | _Out_ PSYMBOL_INFO Symbol); 836 | 837 | typedef struct _DETOUR_SYM_INFO 838 | { 839 | HANDLE hProcess; 840 | HMODULE hDbgHelp; 841 | PF_ImagehlpApiVersionEx pfImagehlpApiVersionEx; 842 | PF_SymInitialize pfSymInitialize; 843 | PF_SymSetOptions pfSymSetOptions; 844 | PF_SymGetOptions pfSymGetOptions; 845 | PF_SymLoadModule64 pfSymLoadModule64; 846 | PF_SymGetModuleInfo64 pfSymGetModuleInfo64; 847 | PF_SymFromName pfSymFromName; 848 | } DETOUR_SYM_INFO, *PDETOUR_SYM_INFO; 849 | 850 | PDETOUR_SYM_INFO DetourLoadImageHlp(VOID); 851 | 852 | #endif // IMAGEAPI 853 | 854 | #if defined(_INC_STDIO) && !defined(_CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS) 855 | #error detours.h must be included before stdio.h (or at least define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS earlier) 856 | #endif 857 | #define _CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS 1 858 | 859 | #ifndef DETOUR_TRACE 860 | #if DETOUR_DEBUG 861 | #define DETOUR_TRACE(x) printf x 862 | #define DETOUR_BREAK() __debugbreak() 863 | #include 864 | #include 865 | #else 866 | #define DETOUR_TRACE(x) 867 | #define DETOUR_BREAK() 868 | #endif 869 | #endif 870 | 871 | #if 1 || defined(DETOURS_IA64) 872 | 873 | // 874 | // IA64 instructions are 41 bits, 3 per bundle, plus 5 bit bundle template => 128 bits per bundle. 875 | // 876 | 877 | #define DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE (3) 878 | 879 | #define DETOUR_IA64_TEMPLATE_OFFSET (0) 880 | #define DETOUR_IA64_TEMPLATE_SIZE (5) 881 | 882 | #define DETOUR_IA64_INSTRUCTION_SIZE (41) 883 | #define DETOUR_IA64_INSTRUCTION0_OFFSET (DETOUR_IA64_TEMPLATE_SIZE) 884 | #define DETOUR_IA64_INSTRUCTION1_OFFSET (DETOUR_IA64_TEMPLATE_SIZE + DETOUR_IA64_INSTRUCTION_SIZE) 885 | #define DETOUR_IA64_INSTRUCTION2_OFFSET (DETOUR_IA64_TEMPLATE_SIZE + DETOUR_IA64_INSTRUCTION_SIZE + DETOUR_IA64_INSTRUCTION_SIZE) 886 | 887 | C_ASSERT(DETOUR_IA64_TEMPLATE_SIZE + DETOUR_IA64_INSTRUCTIONS_PER_BUNDLE * DETOUR_IA64_INSTRUCTION_SIZE == 128); 888 | 889 | __declspec(align(16)) struct DETOUR_IA64_BUNDLE 890 | { 891 | public: 892 | union 893 | { 894 | BYTE data[16]; 895 | UINT64 wide[2]; 896 | }; 897 | 898 | enum { 899 | A_UNIT = 1u, 900 | I_UNIT = 2u, 901 | M_UNIT = 3u, 902 | B_UNIT = 4u, 903 | F_UNIT = 5u, 904 | L_UNIT = 6u, 905 | X_UNIT = 7u, 906 | }; 907 | struct DETOUR_IA64_METADATA 908 | { 909 | ULONG nTemplate : 8; // Instruction template. 910 | ULONG nUnit0 : 4; // Unit for slot 0 911 | ULONG nUnit1 : 4; // Unit for slot 1 912 | ULONG nUnit2 : 4; // Unit for slot 2 913 | }; 914 | 915 | protected: 916 | static const DETOUR_IA64_METADATA s_rceCopyTable[33]; 917 | 918 | UINT RelocateBundle(_Inout_ DETOUR_IA64_BUNDLE* pDst, _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra) const; 919 | 920 | bool RelocateInstruction(_Inout_ DETOUR_IA64_BUNDLE* pDst, 921 | _In_ BYTE slot, 922 | _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra) const; 923 | 924 | // 120 112 104 96 88 80 72 64 56 48 40 32 24 16 8 0 925 | // f. e. d. c. b. a. 9. 8. 7. 6. 5. 4. 3. 2. 1. 0. 926 | 927 | // 00 928 | // f.error. d.c. b.a. 9.8. 7.6. 5.4. 3.2. 1.0. 929 | // 0000 0000 0000 0000 0000 0000 0000 001f : Template [4..0] 930 | // 0000 0000 0000 0000 0000 03ff ffff ffe0 : Zero [ 41.. 5] 931 | // 0000 0000 0000 0000 0000 3c00 0000 0000 : Zero [ 45.. 42] 932 | // 0000 0000 0007 ffff ffff c000 0000 0000 : One [ 82.. 46] 933 | // 0000 0000 0078 0000 0000 0000 0000 0000 : One [ 86.. 83] 934 | // 0fff ffff ff80 0000 0000 0000 0000 0000 : Two [123.. 87] 935 | // f000 0000 0000 0000 0000 0000 0000 0000 : Two [127..124] 936 | BYTE GetTemplate() const; 937 | // Get 4 bit opcodes. 938 | BYTE GetInst0() const; 939 | BYTE GetInst1() const; 940 | BYTE GetInst2() const; 941 | BYTE GetUnit(BYTE slot) const; 942 | BYTE GetUnit0() const; 943 | BYTE GetUnit1() const; 944 | BYTE GetUnit2() const; 945 | // Get 37 bit data. 946 | UINT64 GetData0() const; 947 | UINT64 GetData1() const; 948 | UINT64 GetData2() const; 949 | 950 | // Get/set the full 41 bit instructions. 951 | UINT64 GetInstruction(BYTE slot) const; 952 | UINT64 GetInstruction0() const; 953 | UINT64 GetInstruction1() const; 954 | UINT64 GetInstruction2() const; 955 | void SetInstruction(BYTE slot, UINT64 instruction); 956 | void SetInstruction0(UINT64 instruction); 957 | void SetInstruction1(UINT64 instruction); 958 | void SetInstruction2(UINT64 instruction); 959 | 960 | // Get/set bitfields. 961 | static UINT64 GetBits(UINT64 Value, UINT64 Offset, UINT64 Count); 962 | static UINT64 SetBits(UINT64 Value, UINT64 Offset, UINT64 Count, UINT64 Field); 963 | 964 | // Get specific read-only fields. 965 | static UINT64 GetOpcode(UINT64 instruction); // 4bit opcode 966 | static UINT64 GetX(UINT64 instruction); // 1bit opcode extension 967 | static UINT64 GetX3(UINT64 instruction); // 3bit opcode extension 968 | static UINT64 GetX6(UINT64 instruction); // 6bit opcode extension 969 | 970 | // Get/set specific fields. 971 | static UINT64 GetImm7a(UINT64 instruction); 972 | static UINT64 SetImm7a(UINT64 instruction, UINT64 imm7a); 973 | static UINT64 GetImm13c(UINT64 instruction); 974 | static UINT64 SetImm13c(UINT64 instruction, UINT64 imm13c); 975 | static UINT64 GetSignBit(UINT64 instruction); 976 | static UINT64 SetSignBit(UINT64 instruction, UINT64 signBit); 977 | static UINT64 GetImm20a(UINT64 instruction); 978 | static UINT64 SetImm20a(UINT64 instruction, UINT64 imm20a); 979 | static UINT64 GetImm20b(UINT64 instruction); 980 | static UINT64 SetImm20b(UINT64 instruction, UINT64 imm20b); 981 | 982 | static UINT64 SignExtend(UINT64 Value, UINT64 Offset); 983 | 984 | BOOL IsMovlGp() const; 985 | 986 | VOID SetInst(BYTE Slot, BYTE nInst); 987 | VOID SetInst0(BYTE nInst); 988 | VOID SetInst1(BYTE nInst); 989 | VOID SetInst2(BYTE nInst); 990 | VOID SetData(BYTE Slot, UINT64 nData); 991 | VOID SetData0(UINT64 nData); 992 | VOID SetData1(UINT64 nData); 993 | VOID SetData2(UINT64 nData); 994 | BOOL SetNop(BYTE Slot); 995 | BOOL SetNop0(); 996 | BOOL SetNop1(); 997 | BOOL SetNop2(); 998 | 999 | public: 1000 | BOOL IsBrl() const; 1001 | VOID SetBrl(); 1002 | VOID SetBrl(UINT64 target); 1003 | UINT64 GetBrlTarget() const; 1004 | VOID SetBrlTarget(UINT64 target); 1005 | VOID SetBrlImm(UINT64 imm); 1006 | UINT64 GetBrlImm() const; 1007 | 1008 | UINT64 GetMovlGp() const; 1009 | VOID SetMovlGp(UINT64 gp); 1010 | 1011 | VOID SetStop(); 1012 | 1013 | UINT Copy(_Out_ DETOUR_IA64_BUNDLE *pDst, _Inout_opt_ DETOUR_IA64_BUNDLE* pBundleExtra = NULL) const; 1014 | }; 1015 | #endif // DETOURS_IA64 1016 | 1017 | #ifdef DETOURS_ARM 1018 | 1019 | #define DETOURS_PFUNC_TO_PBYTE(p) ((PBYTE)(((ULONG_PTR)(p)) & ~(ULONG_PTR)1)) 1020 | #define DETOURS_PBYTE_TO_PFUNC(p) ((PBYTE)(((ULONG_PTR)(p)) | (ULONG_PTR)1)) 1021 | 1022 | #endif // DETOURS_ARM 1023 | 1024 | ////////////////////////////////////////////////////////////////////////////// 1025 | 1026 | #ifdef __cplusplus 1027 | extern "C" { 1028 | #endif // __cplusplus 1029 | 1030 | #define DETOUR_OFFLINE_LIBRARY(x) \ 1031 | PVOID WINAPI DetourCopyInstruction##x(_In_opt_ PVOID pDst, \ 1032 | _Inout_opt_ PVOID *ppDstPool, \ 1033 | _In_ PVOID pSrc, \ 1034 | _Out_opt_ PVOID *ppTarget, \ 1035 | _Out_opt_ LONG *plExtra); \ 1036 | \ 1037 | BOOL WINAPI DetourSetCodeModule##x(_In_ HMODULE hModule, \ 1038 | _In_ BOOL fLimitReferencesToModule); \ 1039 | 1040 | DETOUR_OFFLINE_LIBRARY(X86) 1041 | DETOUR_OFFLINE_LIBRARY(X64) 1042 | DETOUR_OFFLINE_LIBRARY(ARM) 1043 | DETOUR_OFFLINE_LIBRARY(ARM64) 1044 | DETOUR_OFFLINE_LIBRARY(IA64) 1045 | 1046 | #undef DETOUR_OFFLINE_LIBRARY 1047 | 1048 | ////////////////////////////////////////////////////////////////////////////// 1049 | // 1050 | // Helpers for manipulating page protection. 1051 | // 1052 | 1053 | _Success_(return != FALSE) 1054 | BOOL WINAPI DetourVirtualProtectSameExecuteEx(_In_ HANDLE hProcess, 1055 | _In_ PVOID pAddress, 1056 | _In_ SIZE_T nSize, 1057 | _In_ DWORD dwNewProtect, 1058 | _Out_ PDWORD pdwOldProtect); 1059 | 1060 | _Success_(return != FALSE) 1061 | BOOL WINAPI DetourVirtualProtectSameExecute(_In_ PVOID pAddress, 1062 | _In_ SIZE_T nSize, 1063 | _In_ DWORD dwNewProtect, 1064 | _Out_ PDWORD pdwOldProtect); 1065 | #ifdef __cplusplus 1066 | } 1067 | #endif // __cplusplus 1068 | 1069 | ////////////////////////////////////////////////////////////////////////////// 1070 | 1071 | #define MM_ALLOCATION_GRANULARITY 0x10000 1072 | 1073 | ////////////////////////////////////////////////////////////////////////////// 1074 | 1075 | #endif // DETOURS_INTERNAL 1076 | #endif // __cplusplus 1077 | 1078 | #endif // _DETOURS_H_ 1079 | // 1080 | //////////////////////////////////////////////////////////////// End of File. 1081 | -------------------------------------------------------------------------------- /lib/detours.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bedrock-dev/MCBE-hopper-fix/16c356c2d326926b401753332e084c921ff2c81c/lib/detours.lib -------------------------------------------------------------------------------- /lib/detver.h: -------------------------------------------------------------------------------- 1 | ////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // Common version parameters. 4 | // 5 | // Microsoft Research Detours Package, Version 4.0.1 6 | // 7 | // Copyright (c) Microsoft Corporation. All rights reserved. 8 | // 9 | 10 | #define _USING_V110_SDK71_ 1 11 | 12 | #include "winver.h" 13 | #if 0 14 | #include 15 | #include 16 | #else 17 | #ifndef DETOURS_STRINGIFY 18 | #define DETOURS_STRINGIFY(x) DETOURS_STRINGIFY_(x) 19 | #define DETOURS_STRINGIFY_(x) #x 20 | #endif 21 | 22 | #define VER_FILEFLAGSMASK 0x3fL 23 | #define VER_FILEFLAGS 0x0L 24 | #define VER_FILEOS 0x00040004L 25 | #define VER_FILETYPE 0x00000002L 26 | #define VER_FILESUBTYPE 0x00000000L 27 | #endif 28 | #define VER_DETOURS_BITS DETOUR_STRINGIFY(DETOURS_BITS) 29 | -------------------------------------------------------------------------------- /lib/mod.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "Windows.h" 4 | #include "detours.h" 5 | #include "detver.h" 6 | #include 7 | 8 | using VA = unsigned __int64; 9 | 10 | #include 11 | 12 | #define _EXPORTED _declspec(dllexport) 13 | 14 | inline const char *Hook_wrap(void **pOriginal, void *f) { 15 | int error = DetourTransactionBegin(); 16 | if (error != NO_ERROR) { 17 | return "Hook: DetourTransactionBegin Error"; 18 | } 19 | error = DetourUpdateThread(GetCurrentThread()); 20 | if (error != NO_ERROR) { 21 | return "Hook: DetourUpdateThread Error"; 22 | } 23 | error = DetourAttach( 24 | pOriginal, (void *) 25 | f); 26 | if (error != NO_ERROR) { 27 | return "Hook: DetourAttach Error"; 28 | } 29 | error = DetourTransactionCommit(); 30 | if (error != NO_ERROR) { 31 | return "Hook: DetourTransactionCommit Error"; 32 | } 33 | return nullptr; 34 | } 35 | 36 | inline void Hook(void **pOriginal, void *f, const char *prefix) { 37 | auto ret = Hook_wrap(pOriginal, f); 38 | if (ret) { 39 | fprintf(stderr, "[!] Hook error at %s : %s\n", ret, prefix); 40 | } 41 | } 42 | 43 | inline VA GetVA(RVA off) { 44 | return (VA) GetModuleHandle(NULL) + (VA) off; 45 | } 46 | 47 | #define TD_CONCAT3_I(a, b, c) a##b##c 48 | #define TD_CONCAT3(a, b, c) TD_CONCAT3_I(a,b,c) 49 | #define THook(ret, iname, ...) struct TD_CONCAT3(TDHook_, __LINE__,iname) { static ret(*original)(__VA_ARGS__); _EXPORTED static ret p(__VA_ARGS__); TD_CONCAT3(TDHook_, __LINE__,iname) () { original = (decltype(original))GetVA(iname); Hook((void **)&original, (void *)&p, #iname); } }; static TD_CONCAT3(TDHook_, __LINE__,iname) tdh##iname; ret(*TD_CONCAT3(TDHook_, __LINE__,iname)::original)(__VA_ARGS__); ret TD_CONCAT3(TDHook_, __LINE__,iname)::p(__VA_ARGS__) 50 | #define FNTYPE_DEF(...) VA (*)(__VA_ARGS__) 51 | #define FNTYPE_DEF_0 FNTYPE_DEF() 52 | #define FNTYPE_DEF_1 FNTYPE_DEF(VA) 53 | #define FNTYPE_DEF_2 FNTYPE_DEF(VA,VA) 54 | #define FNTYPE_DEF_3 FNTYPE_DEF(VA,VA,VA) 55 | #define FNTYPE_DEF_4 FNTYPE_DEF(VA,VA,VA,VA) 56 | #define FNTYPE_DEF_5 FNTYPE_DEF(VA,VA,VA,VA,VA) 57 | #define FNTYPE_DEF_6 FNTYPE_DEF(VA,VA,VA,VA,VA,VA) 58 | #define FNTYPE_DEF_7 FNTYPE_DEF(VA,VA,VA,VA,VA,VA,VA) 59 | #define FNTYPE_DEF_8 FNTYPE_DEF(VA,VA,VA,VA,VA,VA,VA,VA) 60 | #define FNTYPE_DEF_9 FNTYPE_DEF(VA,VA,VA,VA,VA,VA,VA,VA,VA) 61 | #define FNTYPE_DEF_10 FNTYPE_DEF(VA,VA,VA,VA,VA,VA,VA,VA,VA,VA) 62 | #define FNTYPE_DEF_11 FNTYPE_DEF(VA,VA,VA,VA,VA,VA,VA,VA,VA,VA,VA) 63 | #define FNTYPE_DEF_12 FNTYPE_DEF(VA,VA,VA,VA,VA,VA,VA,VA,VA,VA,VA,VA) 64 | #define FNTYPE_DEF_13 FNTYPE_DEF(VA,VA,VA,VA,VA,VA,VA,VA,VA,VA,VA,VA,VA) 65 | #define FNTYPE_DEF_14 FNTYPE_DEF(VA,VA,VA,VA,VA,VA,VA,VA,VA,VA,VA,VA,VA,VA) 66 | #define FNTYPE_DEF_15 FNTYPE_DEF(VA,VA,VA,VA,VA,VA,VA,VA,VA,VA,VA,VA,VA,VA,VA) 67 | 68 | #define SYM_PTR(TYPE, SYM_RVA) reinterpret_cast(reinterpret_cast(GetModuleHandle(NULL))+SYM_RVA) 69 | #define SYM_CALL(TYPE, SYM_RVA, ...) SYM_PTR(TYPE, SYM_RVA)(__VA_ARGS__) 70 | 71 | #define SYM_CALL_0(SYM_RVA, ...) SYM_CALL(FNTYPE_DEF_0, SYM_RVA, __VA_ARGS__) 72 | #define SYM_CALL_1(SYM_RVA, ...) SYM_CALL(FNTYPE_DEF_1, SYM_RVA, __VA_ARGS__) 73 | #define SYM_CALL_2(SYM_RVA, ...) SYM_CALL(FNTYPE_DEF_2, SYM_RVA, __VA_ARGS__) 74 | #define SYM_CALL_3(SYM_RVA, ...) SYM_CALL(FNTYPE_DEF_3, SYM_RVA, __VA_ARGS__) 75 | #define SYM_CALL_4(SYM_RVA, ...) SYM_CALL(FNTYPE_DEF_4, SYM_RVA, __VA_ARGS__) 76 | #define SYM_CALL_5(SYM_RVA, ...) SYM_CALL(FNTYPE_DEF_5, SYM_RVA, __VA_ARGS__) 77 | #define SYM_CALL_6(SYM_RVA, ...) SYM_CALL(FNTYPE_DEF_6, SYM_RVA, __VA_ARGS__) 78 | #define SYM_CALL_7(SYM_RVA, ...) SYM_CALL(FNTYPE_DEF_7, SYM_RVA, __VA_ARGS__) 79 | #define SYM_CALL_8(SYM_RVA, ...) SYM_CALL(FNTYPE_DEF_8, SYM_RVA, __VA_ARGS__) 80 | #define SYM_CALL_9(SYM_RVA, ...) SYM_CALL(FNTYPE_DEF_9, SYM_RVA, __VA_ARGS__) 81 | #define SYM_CALL_10(SYM_RVA, ...) SYM_CALL(FNTYPE_DEF_10, SYM_RVA, __VA_ARGS__) 82 | #define SYM_CALL_11(SYM_RVA, ...) SYM_CALL(FNTYPE_DEF_11, SYM_RVA, __VA_ARGS__) 83 | #define SYM_CALL_12(SYM_RVA, ...) SYM_CALL(FNTYPE_DEF_12, SYM_RVA, __VA_ARGS__) 84 | #define SYM_CALL_13(SYM_RVA, ...) SYM_CALL(FNTYPE_DEF_13, SYM_RVA, __VA_ARGS__) 85 | #define SYM_CALL_14(SYM_RVA, ...) SYM_CALL(FNTYPE_DEF_14, SYM_RVA, __VA_ARGS__) 86 | #define SYM_CALL_15(SYM_RVA, ...) SYM_CALL(FNTYPE_DEF_15, SYM_RVA, __VA_ARGS__) 87 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | ## MCBE Hopper Fix 2 | 3 | **This is more vanilla than MOJANG** 4 | 5 | When a hopper tries to collect item entities on top of it, it will fetch all the item entities in a specific AABB, and it will only try to pull the first item stack, which causes the hopper bug. 6 | 7 | This fix modifies the code of collecting item entities, and selects a random item entity instead of the first one. 8 | 9 | ## How to use 10 | This a dll mod, you need to inject it into BDS 11 | -------------------------------------------------------------------------------- /src/HopperFix.cpp: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2020/11/27. 3 | // 4 | 5 | #include "../hook/SymHook.h" 6 | #include "../lib/mod.h" 7 | #include "../api/graphics/AABB.h" 8 | #include "../api/entity/Actor.h" 9 | #include "gsl" 10 | 11 | typedef trapdoor::Actor Actor; 12 | 13 | namespace { 14 | constexpr uint64_t ITEM_ENTITY = 64u; 15 | int getRand(int size) { return rand() % size; } 16 | float frac(float x) { return x - floor(x); } 17 | } // namespace 18 | 19 | // THook( 20 | // void*, 21 | // MSSYM_B2QUA9getItemAtB1AA6HopperB2AAE17IEAAPEAVItemActorB2AAE15AEAVBlockSourceB2AAA8AEBVVec3B3AAAA1Z, 22 | // void *hopper, void *blockSource, void * position 23 | //) { 24 | // hopperWorking = true; 25 | // auto *item = original(hopper, blockSource, position); 26 | // hopperWorking = false; 27 | // return item; 28 | // } 29 | 30 | // fix hopper 31 | THook(gsl::span>*, 32 | MSSYM_MD5_21a49b5175e9c00856ce77825b121141, 33 | void* blockSource, 34 | void* a2, 35 | uint64_t type, 36 | AABB* aABB) { 37 | auto volume = 38 | abs((aABB->max.x - aABB->min.x) * (aABB->max.y - aABB->min.y) * 39 | (aABB->max.z - aABB->min.z)); 40 | if (type != ITEM_ENTITY || volume < 0.99f || 41 | volume > 1.01f) // isn't hopper or hopper_minecart 42 | return original(blockSource, a2, type, aABB); 43 | 44 | if (abs(frac(aABB->min.y) - 0.625f) < 0.001f && 45 | abs(frac((aABB->max.x + aABB->min.x) / 2.0f) - 0.5f) < 0.001f && 46 | abs(frac((aABB->max.z + aABB->min.z) / 2.0f) - 0.5f) < 0.001f) { 47 | // is hopper 48 | aABB->max.y += 0.375f; 49 | } 50 | aABB->min.x = aABB->min.x - 0.125f; 51 | aABB->min.z = aABB->min.z - 0.125f; 52 | aABB->max.x = aABB->max.x + 0.125f; 53 | aABB->max.z = aABB->max.z + 0.125f; 54 | auto list = original(blockSource, a2, type, aABB); 55 | // std::cout << list->size(); 56 | if (list->size() > 0 && list->size() != static_cast(-1)) { 57 | std::vector suckList; 58 | for (int i = 0; i < list->size(); i++) { 59 | auto item = list->operator[](i); 60 | auto pos = item->getPos(); 61 | // std::cout << pos->x << ',' << pos->y << ',' << pos->z << 62 | // std::endl; 63 | if (pos->x > aABB->min.x && pos->z > aABB->min.z && 64 | pos->x < aABB->max.x && pos->z < aABB->max.z) { 65 | // std::cout << "true" << std::endl; 66 | suckList.push_back(list->operator[](i)); 67 | } 68 | } 69 | 70 | if (suckList.size() > 1) { 71 | auto random = getRand(suckList.size()); 72 | std::swap(suckList[0], suckList[random]); 73 | } 74 | 75 | auto mEntityList = (int64_t*)((char*)blockSource + 152); 76 | 77 | *((int64_t*)blockSource + 20) = 78 | *((int64_t*)blockSource + 19); // clear list 79 | 80 | for (auto* i : suckList) { 81 | float** end = (float**)mEntityList[1]; 82 | // int64_t v52; 83 | // *(int64_t*)&v52 = (int64_t)i; 84 | *end = (float*)i; 85 | mEntityList[1] += 8i64; 86 | } 87 | auto begin = (int64_t*)*mEntityList; 88 | auto end = (int64_t*)mEntityList[1]; 89 | auto __x = (int64_t*)*mEntityList; 90 | int64_t* result; 91 | result = (int64_t*)a2; 92 | if ((int64_t*)*mEntityList == end) { 93 | RES: 94 | auto l = end - begin; 95 | *result = l; 96 | } else { 97 | while (*__x) { 98 | if (++__x == end) 99 | goto RES; 100 | } 101 | } 102 | // std::cout << "hooked" << std::endl; 103 | return (gsl::span>*)result; 104 | } 105 | 106 | return list; 107 | } 108 | -------------------------------------------------------------------------------- /src/HopperFix.h: -------------------------------------------------------------------------------- 1 | // 2 | // Created by xhy on 2020/11/27. 3 | // 4 | 5 | #ifndef BDS_MOD_SAMPLE_HOPPERFIX_H 6 | #define BDS_MOD_SAMPLE_HOPPERFIX_H 7 | 8 | 9 | #endif //BDS_MOD_SAMPLE_HOPPERFIX_H 10 | -------------------------------------------------------------------------------- /symbol.txt: -------------------------------------------------------------------------------- 1 | #获取漏斗上方物品 2 | ?_getItemAt@Hopper@@IEAAPEAVItemActor@@AEAVBlockSource@@AEBVVec3@@@Z 3 | #获取实体 4 | ?fetchEntities@BlockSource@@QEAA?AV?$span@V?$not_null@PEAVActor@@@gsl@@$0?0@gsl@@W4ActorType@@AEBVAABB@@PEBVActor@@@Z --------------------------------------------------------------------------------