GSL/include/gsl.h
Florian Weber b0de100978 replace keyword-redefining macros with cleaner ones
Redefining keywords is undefined behavior and should therefore not be
presented as something acceptable. Furthermore the code is now easier to
read.
2016-02-12 16:37:55 +01:00

164 lines
4.5 KiB
C++

///////////////////////////////////////////////////////////////////////////////
//
// 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.
//
///////////////////////////////////////////////////////////////////////////////
#pragma once
#ifndef GSL_GSL_H
#define GSL_GSL_H
#include "gsl_assert.h" // GSL_ENSURES/GSL_EXPECTS
#include "gsl_util.h" // finally()/narrow()/narrow_cast()...
#include "span.h" // span, strided_span...
#include "string_span.h" // zstring, string_span, zstring_builder...
#include <memory>
#define GSL_IMPL_CONSTEXPR constexpr
#define GSL_IMPL_NOEXCEPT noexcept
#ifdef _MSC_VER
// No MSVC does constexpr fully yet
#undef GSL_IMPL_CONSTEXPR
#define GSL_IMPL_CONSTEXPR
// MSVC 2013 workarounds
#if _MSC_VER <= 1800
// noexcept is not understood
#undef GSL_IMPL_NOEXCEPT
#define GSL_IMPL_NOEXCEPT
// turn off some misguided warnings
#pragma warning(push)
#pragma warning(disable: 4351) // warns about newly introduced aggregate initializer behavior
#endif // _MSC_VER <= 1800
#endif // _MSC_VER
namespace gsl
{
//
// GSL.owner: ownership pointers
//
using std::unique_ptr;
using std::shared_ptr;
template <class T>
using owner = T;
//
// not_null
//
// Restricts a pointer or smart pointer to only hold non-null values.
//
// Has zero size overhead over T.
//
// If T is a pointer (i.e. T == U*) then
// - allow construction from U* or U&
// - disallow construction from nullptr_t
// - disallow default construction
// - ensure construction from U* fails with nullptr
// - allow implicit conversion to U*
//
template<class T>
class not_null
{
static_assert(std::is_assignable<T&, std::nullptr_t>::value, "T cannot be assigned nullptr.");
public:
not_null(T t) : ptr_(t) { ensure_invariant(); }
not_null& operator=(const T& t) { ptr_ = t; ensure_invariant(); return *this; }
not_null(const not_null &other) = default;
not_null& operator=(const not_null &other) = default;
template <typename U, typename Dummy = std::enable_if_t<std::is_convertible<U, T>::value>>
not_null(const not_null<U> &other)
{
*this = other;
}
template <typename U, typename Dummy = std::enable_if_t<std::is_convertible<U, T>::value>>
not_null& operator=(const not_null<U> &other)
{
ptr_ = other.get();
return *this;
}
// prevents compilation when someone attempts to assign a nullptr
not_null(std::nullptr_t) = delete;
not_null(int) = delete;
not_null<T>& operator=(std::nullptr_t) = delete;
not_null<T>& operator=(int) = delete;
T get() const {
#ifdef _MSC_VER
__assume(ptr_ != nullptr);
#endif
return ptr_;
} // the assume() should help the optimizer
operator T() const { return get(); }
T operator->() const { return get(); }
bool operator==(const T& rhs) const { return ptr_ == rhs; }
bool operator!=(const T& rhs) const { return !(*this == rhs); }
private:
T ptr_;
// we assume that the compiler can hoist/prove away most of the checks inlined from this function
// if not, we could make them optional via conditional compilation
void ensure_invariant() const { GSL_EXPECTS(ptr_ != nullptr); }
// 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
namespace std
{
template<class T>
struct hash<gsl::not_null<T>>
{
size_t operator()(const gsl::not_null<T> & value) const
{
return hash<T>{}(value);
}
};
} // namespace std
#undef GSL_IMPL_CONSTEXPR
#undef GSL_IMPL_NOEXCEPT
#if defined(_MSC_VER) and (_MSC_VER <= 1800)
#pragma warning(pop)
#endif // _MSC_VER <= 1800
#endif // GSL_GSL_H