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 #include <catch/catch.hpp> 18 19 #include <gsl/gsl> 20 21 #include <memory> 22 #include <string> 23 #include <vector> 24 25 using namespace gsl; 26 27 struct MyBase 28 { 29 }; 30 struct MyDerived : public MyBase 31 { 32 }; 33 struct Unrelated 34 { 35 }; 36 37 // stand-in for a user-defined ref-counted class 38 template <typename T> 39 struct RefCounted 40 { 41 RefCounted(T* p) : p_(p) {} 42 operator T*() { return p_; } 43 T* p_; 44 }; 45 46 // user defined smart pointer with comparison operators returning non bool value 47 template <typename T> 48 struct CustomPtr 49 { 50 CustomPtr(T* p) : p_(p) {} 51 operator T*() { return p_; } 52 bool operator!=(std::nullptr_t) const { return p_ != nullptr; } 53 T* p_ = nullptr; 54 }; 55 56 template <typename T, typename U> 57 std::string operator==(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) 58 { 59 return reinterpret_cast<const void*>(lhs.p_) == reinterpret_cast<const void*>(rhs.p_) ? "true" 60 : "false"; 61 } 62 63 template <typename T, typename U> 64 std::string operator!=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) 65 { 66 return reinterpret_cast<const void*>(lhs.p_) != reinterpret_cast<const void*>(rhs.p_) ? "true" 67 : "false"; 68 } 69 70 template <typename T, typename U> 71 std::string operator<(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) 72 { 73 return reinterpret_cast<const void*>(lhs.p_) < reinterpret_cast<const void*>(rhs.p_) ? "true" 74 : "false"; 75 } 76 77 template <typename T, typename U> 78 std::string operator>(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) 79 { 80 return reinterpret_cast<const void*>(lhs.p_) > reinterpret_cast<const void*>(rhs.p_) ? "true" 81 : "false"; 82 } 83 84 template <typename T, typename U> 85 std::string operator<=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) 86 { 87 return reinterpret_cast<const void*>(lhs.p_) <= reinterpret_cast<const void*>(rhs.p_) ? "true" 88 : "false"; 89 } 90 91 template <typename T, typename U> 92 std::string operator>=(CustomPtr<T> const& lhs, CustomPtr<U> const& rhs) 93 { 94 return reinterpret_cast<const void*>(lhs.p_) >= reinterpret_cast<const void*>(rhs.p_) ? "true" 95 : "false"; 96 } 97 98 struct NonCopyableNonMovable 99 { 100 NonCopyableNonMovable() = default; 101 NonCopyableNonMovable(const NonCopyableNonMovable&) = delete; 102 NonCopyableNonMovable& operator=(const NonCopyableNonMovable&) = delete; 103 NonCopyableNonMovable(NonCopyableNonMovable&&) = delete; 104 NonCopyableNonMovable& operator=(NonCopyableNonMovable&&) = delete; 105 }; 106 107 bool helper(not_null<int*> p) { return *p == 12; } 108 109 TEST_CASE("TestNotNullConstructors") 110 { 111 #ifdef CONFIRM_COMPILATION_ERRORS 112 not_null<int*> p = nullptr; // yay...does not compile! 113 not_null<std::vector<char>*> p = 0; // yay...does not compile! 114 not_null<int*> p; // yay...does not compile! 115 std::unique_ptr<int> up = std::make_unique<int>(120); 116 not_null<int*> p = up; 117 118 // Forbid non-nullptr assignable types 119 not_null<std::vector<int>> f(std::vector<int>{1}); 120 not_null<int> z(10); 121 not_null<std::vector<int>> y({1, 2}); 122 #endif 123 int i = 12; 124 auto rp = RefCounted<int>(&i); 125 not_null<int*> p(rp); 126 CHECK(p.get() == &i); 127 128 not_null<std::shared_ptr<int>> x( 129 std::make_shared<int>(10)); // shared_ptr<int> is nullptr assignable 130 } 131 132 TEST_CASE("TestNotNullCasting") 133 { 134 MyBase base; 135 MyDerived derived; 136 Unrelated unrelated; 137 not_null<Unrelated*> u = &unrelated; 138 (void) u; 139 not_null<MyDerived*> p = &derived; 140 not_null<MyBase*> q = &base; 141 q = p; // allowed with heterogeneous copy ctor 142 CHECK(q == p); 143 144 #ifdef CONFIRM_COMPILATION_ERRORS 145 q = u; // no viable conversion possible between MyBase* and Unrelated* 146 p = q; // not possible to implicitly convert MyBase* to MyDerived* 147 148 not_null<Unrelated*> r = p; 149 not_null<Unrelated*> s = reinterpret_cast<Unrelated*>(p); 150 #endif 151 not_null<Unrelated*> t = reinterpret_cast<Unrelated*>(p.get()); 152 CHECK(reinterpret_cast<void*>(p.get()) == reinterpret_cast<void*>(t.get())); 153 } 154 155 TEST_CASE("TestNotNullAssignment") 156 { 157 int i = 12; 158 not_null<int*> p = &i; 159 CHECK(helper(p)); 160 161 int* q = nullptr; 162 CHECK_THROWS_AS(p = q, fail_fast); 163 } 164 165 TEST_CASE("TestNotNullRawPointerComparison") 166 { 167 int ints[2] = {42, 43}; 168 int* p1 = &ints[0]; 169 const int* p2 = &ints[1]; 170 171 using NotNull1 = not_null<decltype(p1)>; 172 using NotNull2 = not_null<decltype(p2)>; 173 174 CHECK((NotNull1(p1) == NotNull1(p1)) == true); 175 CHECK((NotNull1(p1) == NotNull2(p2)) == false); 176 177 CHECK((NotNull1(p1) != NotNull1(p1)) == false); 178 CHECK((NotNull1(p1) != NotNull2(p2)) == true); 179 180 CHECK((NotNull1(p1) < NotNull1(p1)) == false); 181 CHECK((NotNull1(p1) < NotNull2(p2)) == (p1 < p2)); 182 CHECK((NotNull2(p2) < NotNull1(p1)) == (p2 < p1)); 183 184 CHECK((NotNull1(p1) > NotNull1(p1)) == false); 185 CHECK((NotNull1(p1) > NotNull2(p2)) == (p1 > p2)); 186 CHECK((NotNull2(p2) > NotNull1(p1)) == (p2 > p1)); 187 188 CHECK((NotNull1(p1) <= NotNull1(p1)) == true); 189 CHECK((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2)); 190 CHECK((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1)); 191 192 } 193 194 TEST_CASE("TestNotNullDereferenceOperator") 195 { 196 { 197 auto sp1 = std::make_shared<NonCopyableNonMovable>(); 198 199 using NotNullSp1 = not_null<decltype(sp1)>; 200 CHECK(typeid(*sp1) == typeid(*NotNullSp1(sp1))); 201 CHECK(std::addressof(*NotNullSp1(sp1)) == std::addressof(*sp1)); 202 } 203 204 { 205 int ints[1] = { 42 }; 206 CustomPtr<int> p1(&ints[0]); 207 208 using NotNull1 = not_null<decltype(p1)>; 209 CHECK(typeid(*NotNull1(p1)) == typeid(*p1)); 210 CHECK(*NotNull1(p1) == 42); 211 *NotNull1(p1) = 43; 212 CHECK(ints[0] == 43); 213 } 214 215 { 216 int v = 42; 217 gsl::not_null<int*> p(&v); 218 CHECK(typeid(*p) == typeid(*(&v))); 219 *p = 43; 220 CHECK(v == 43); 221 } 222 } 223 224 TEST_CASE("TestNotNullSharedPtrComparison") 225 { 226 auto sp1 = std::make_shared<int>(42); 227 auto sp2 = std::make_shared<const int>(43); 228 229 using NotNullSp1 = not_null<decltype(sp1)>; 230 using NotNullSp2 = not_null<decltype(sp2)>; 231 232 CHECK((NotNullSp1(sp1) == NotNullSp1(sp1)) == true); 233 CHECK((NotNullSp1(sp1) == NotNullSp2(sp2)) == false); 234 235 CHECK((NotNullSp1(sp1) != NotNullSp1(sp1)) == false); 236 CHECK((NotNullSp1(sp1) != NotNullSp2(sp2)) == true); 237 238 CHECK((NotNullSp1(sp1) < NotNullSp1(sp1)) == false); 239 CHECK((NotNullSp1(sp1) < NotNullSp2(sp2)) == (sp1 < sp2)); 240 CHECK((NotNullSp2(sp2) < NotNullSp1(sp1)) == (sp2 < sp1)); 241 242 CHECK((NotNullSp1(sp1) > NotNullSp1(sp1)) == false); 243 CHECK((NotNullSp1(sp1) > NotNullSp2(sp2)) == (sp1 > sp2)); 244 CHECK((NotNullSp2(sp2) > NotNullSp1(sp1)) == (sp2 > sp1)); 245 246 CHECK((NotNullSp1(sp1) <= NotNullSp1(sp1)) == true); 247 CHECK((NotNullSp1(sp1) <= NotNullSp2(sp2)) == (sp1 <= sp2)); 248 CHECK((NotNullSp2(sp2) <= NotNullSp1(sp1)) == (sp2 <= sp1)); 249 250 CHECK((NotNullSp1(sp1) >= NotNullSp1(sp1)) == true); 251 CHECK((NotNullSp1(sp1) >= NotNullSp2(sp2)) == (sp1 >= sp2)); 252 CHECK((NotNullSp2(sp2) >= NotNullSp1(sp1)) == (sp2 >= sp1)); 253 } 254 255 TEST_CASE("TestNotNullCustomPtrComparison") 256 { 257 int ints[2] = {42, 43}; 258 CustomPtr<int> p1(&ints[0]); 259 CustomPtr<const int> p2(&ints[1]); 260 261 using NotNull1 = not_null<decltype(p1)>; 262 using NotNull2 = not_null<decltype(p2)>; 263 264 CHECK((NotNull1(p1) == NotNull1(p1)) == "true"); 265 CHECK((NotNull1(p1) == NotNull2(p2)) == "false"); 266 267 CHECK((NotNull1(p1) != NotNull1(p1)) == "false"); 268 CHECK((NotNull1(p1) != NotNull2(p2)) == "true"); 269 270 CHECK((NotNull1(p1) < NotNull1(p1)) == "false"); 271 CHECK((NotNull1(p1) < NotNull2(p2)) == (p1 < p2)); 272 CHECK((NotNull2(p2) < NotNull1(p1)) == (p2 < p1)); 273 274 CHECK((NotNull1(p1) > NotNull1(p1)) == "false"); 275 CHECK((NotNull1(p1) > NotNull2(p2)) == (p1 > p2)); 276 CHECK((NotNull2(p2) > NotNull1(p1)) == (p2 > p1)); 277 278 CHECK((NotNull1(p1) <= NotNull1(p1)) == "true"); 279 CHECK((NotNull1(p1) <= NotNull2(p2)) == (p1 <= p2)); 280 CHECK((NotNull2(p2) <= NotNull1(p1)) == (p2 <= p1)); 281 282 CHECK((NotNull1(p1) >= NotNull1(p1)) == "true"); 283 CHECK((NotNull1(p1) >= NotNull2(p2)) == (p1 >= p2)); 284 CHECK((NotNull2(p2) >= NotNull1(p1)) == (p2 >= p1)); 285 } 286