GSL/include/gsl.h

173 lines
4.5 KiB
C
Raw Normal View History

2016-07-20 16:17:47 -04:00
///////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2015 Microsoft Corporation. All rights reserved.
//
// This code is licensed under the MIT License (MIT).
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
2015-08-20 21:09:14 -04:00
///////////////////////////////////////////////////////////////////////////////
#pragma once
2015-09-24 21:08:34 -04:00
#ifndef GSL_GSL_H
#define GSL_GSL_H
2016-07-20 16:17:47 -04:00
#include "gsl_assert.h" // Ensures/Expects
#include "gsl_util.h" // finally()/narrow()/narrow_cast()...
#include "multi_span.h" // multi_span, strided_span...
#include "span.h" // span
#include "string_span.h" // zstring, string_span, zstring_builder...
2015-08-20 21:09:14 -04:00
#include <memory>
#ifdef _MSC_VER
// No MSVC does constexpr fully yet
#pragma push_macro("constexpr")
2016-07-20 16:17:47 -04:00
#define constexpr
// MSVC 2013 workarounds
#if _MSC_VER <= 1800
2016-07-20 16:17:47 -04:00
// noexcept is not understood
#pragma push_macro("noexcept")
2016-07-20 16:17:47 -04:00
#define noexcept
// turn off some misguided warnings
#pragma warning(push)
2016-07-20 16:17:47 -04:00
#pragma warning(disable : 4351) // warns about newly introduced aggregate initializer behavior
#endif // _MSC_VER <= 1800
#endif // _MSC_VER
namespace gsl
2015-08-20 21:09:14 -04:00
{
//
2016-07-20 16:17:47 -04:00
// GSL.owner: ownership pointers
2015-08-20 21:09:14 -04:00
//
using std::unique_ptr;
using std::shared_ptr;
template <class T>
using owner = T;
2015-08-20 21:09:14 -04:00
//
// not_null
//
// Restricts a pointer or smart pointer to only hold non-null values.
2016-07-20 16:17:47 -04:00
//
2015-08-20 21:09:14 -04:00
// Has zero size overhead over T.
//
2016-07-20 16:17:47 -04:00
// If T is a pointer (i.e. T == U*) then
// - allow construction from U* or U&
2015-08-20 21:09:14 -04:00
// - disallow construction from nullptr_t
// - disallow default construction
// - ensure construction from U* fails with nullptr
// - allow implicit conversion to U*
//
2016-07-20 16:17:47 -04:00
template <class T>
2015-08-20 21:09:14 -04:00
class not_null
{
static_assert(std::is_assignable<T&, std::nullptr_t>::value, "T cannot be assigned nullptr.");
2016-07-20 16:17:47 -04:00
2015-08-20 21:09:14 -04:00
public:
not_null(T t) : ptr_(t) { ensure_invariant(); }
2016-07-20 16:17:47 -04:00
not_null& operator=(const T& t)
{
ptr_ = t;
ensure_invariant();
return *this;
}
2015-08-20 21:09:14 -04:00
2016-07-20 16:17:47 -04:00
not_null(const not_null& other) = default;
not_null& operator=(const not_null& other) = default;
2015-08-20 21:09:14 -04:00
template <typename U, typename Dummy = std::enable_if_t<std::is_convertible<U, T>::value>>
2016-07-20 16:17:47 -04:00
not_null(const not_null<U>& other)
2015-08-20 21:09:14 -04:00
{
*this = other;
2015-08-20 21:09:14 -04:00
}
template <typename U, typename Dummy = std::enable_if_t<std::is_convertible<U, T>::value>>
2016-07-20 16:17:47 -04:00
not_null& operator=(const not_null<U>& other)
{
ptr_ = other.get();
return *this;
}
2015-08-20 21:09:14 -04:00
2016-07-20 16:17:47 -04:00
// prevents compilation when someone attempts to assign a nullptr
not_null(std::nullptr_t) = delete;
not_null(int) = delete;
2015-08-20 21:09:14 -04:00
not_null<T>& operator=(std::nullptr_t) = delete;
2016-07-20 16:17:47 -04:00
not_null<T>& operator=(int) = delete;
T get() const
{
2015-08-20 21:09:14 -04:00
#ifdef _MSC_VER
__assume(ptr_ != nullptr);
#endif
return ptr_;
} // the assume() should help the optimizer
2016-07-20 16:17:47 -04:00
operator T() const { return get(); }
2015-08-20 21:09:14 -04:00
T operator->() const { return get(); }
2016-07-20 16:17:47 -04:00
bool operator==(const T& rhs) const { return ptr_ == rhs; }
bool operator!=(const T& rhs) const { return !(*this == rhs); }
2015-08-20 21:09:14 -04:00
private:
T ptr_;
2016-07-20 16:17:47 -04:00
// we assume that the compiler can hoist/prove away most of the checks inlined from this
// function
2015-08-20 21:09:14 -04:00
// if not, we could make them optional via conditional compilation
void ensure_invariant() const { Expects(ptr_ != nullptr); }
2015-08-20 21:09:14 -04:00
// unwanted operators...pointers only point to single objects!
// TODO ensure all arithmetic ops on this type are unavailable
not_null<T>& operator++() = delete;
not_null<T>& operator--() = delete;
not_null<T> operator++(int) = delete;
not_null<T> operator--(int) = delete;
not_null<T>& operator+(size_t) = delete;
not_null<T>& operator+=(size_t) = delete;
not_null<T>& operator-(size_t) = delete;
not_null<T>& operator-=(size_t) = delete;
};
} // namespace gsl
2015-09-24 21:08:34 -04:00
2015-10-17 02:53:58 -04:00
namespace std
{
2016-07-20 16:17:47 -04:00
template <class T>
struct hash<gsl::not_null<T>>
{
size_t operator()(const gsl::not_null<T>& value) const { return hash<T>{}(value); }
};
2015-10-17 02:53:58 -04:00
} // namespace std
#ifdef _MSC_VER
#undef constexpr
#pragma pop_macro("constexpr")
#if _MSC_VER <= 1800
#undef noexcept
#pragma pop_macro("noexcept")
2016-07-20 16:17:47 -04:00
#pragma warning(pop)
#endif // _MSC_VER <= 1800
#endif // _MSC_VER
2015-09-24 21:08:34 -04:00
#endif // GSL_GSL_H