Short live q20::to_address!
An implementation of C++20 std::to_address, a prerequesite for QSpan<>. The test cases are inspired by libstdc++'s test suite, just to avoid missing some cases, but the to_address implementation is white-room. Fixes: QTBUG-108430 Change-Id: I4c092fdd7a56c0b279068e341bbf91a725ca3b1f Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
This commit is contained in:
parent
a1dd9a9f77
commit
e2b2bb7ff1
@ -1,4 +1,5 @@
|
||||
// Copyright (C) 2023 The Qt Company Ltd.
|
||||
// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
|
||||
|
||||
#ifndef Q20MEMORY_H
|
||||
@ -7,9 +8,9 @@
|
||||
#include <QtCore/qtconfigmacros.h>
|
||||
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
//
|
||||
// W A R N I N G
|
||||
@ -45,6 +46,48 @@ T *construct_at(T *ptr, Args && ... args)
|
||||
#endif // __cpp_lib_constexpr_dynamic_alloc
|
||||
} // namespace q20
|
||||
|
||||
|
||||
namespace q20 {
|
||||
// like std::to_address
|
||||
#ifdef __cpp_lib_to_address
|
||||
using std::to_address;
|
||||
#else
|
||||
// http://eel.is/c++draft/pointer.conversion
|
||||
template <typename T>
|
||||
constexpr T *to_address(T *p) noexcept {
|
||||
// http://eel.is/c++draft/pointer.conversion#1:
|
||||
// Mandates: T is not a function type.
|
||||
static_assert(!std::is_function_v<T>, "to_address must not be used on function types");
|
||||
return p;
|
||||
}
|
||||
|
||||
template <typename Ptr, typename std::enable_if_t<!std::is_pointer_v<Ptr>, bool> = true>
|
||||
constexpr auto to_address(const Ptr &ptr) noexcept; // fwd declared
|
||||
|
||||
namespace detail {
|
||||
// http://eel.is/c++draft/pointer.conversion#3
|
||||
template <typename Ptr, typename = void>
|
||||
struct to_address_helper {
|
||||
static auto get(const Ptr &ptr) noexcept
|
||||
{ return q20::to_address(ptr.operator->()); }
|
||||
};
|
||||
template <typename Ptr>
|
||||
struct to_address_helper<Ptr, std::void_t<
|
||||
decltype(std::pointer_traits<Ptr>::to_address(std::declval<const Ptr&>()))
|
||||
>>
|
||||
{
|
||||
static auto get(const Ptr &ptr) noexcept
|
||||
{ return std::pointer_traits<Ptr>::to_address(ptr); }
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
template <typename Ptr, typename std::enable_if_t<!std::is_pointer_v<Ptr>, bool>>
|
||||
constexpr auto to_address(const Ptr &ptr) noexcept
|
||||
{ return detail::to_address_helper<Ptr>::get(ptr); }
|
||||
|
||||
#endif // __cpp_lib_to_address
|
||||
} // namespace q20
|
||||
|
||||
QT_END_NAMESPACE
|
||||
|
||||
#endif /* Q20MEMORY_H */
|
||||
|
@ -21,3 +21,4 @@ add_subdirectory(qglobalstatic)
|
||||
add_subdirectory(qhooks)
|
||||
add_subdirectory(qoperatingsystemversion)
|
||||
add_subdirectory(qxp)
|
||||
add_subdirectory(q20)
|
||||
|
1
tests/auto/corelib/global/q20/CMakeLists.txt
Normal file
1
tests/auto/corelib/global/q20/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
||||
add_subdirectory(memory)
|
10
tests/auto/corelib/global/q20/memory/CMakeLists.txt
Normal file
10
tests/auto/corelib/global/q20/memory/CMakeLists.txt
Normal file
@ -0,0 +1,10 @@
|
||||
# Copyright (C) 2022 The Qt Company Ltd.
|
||||
# SPDX-License-Identifier: BSD-3-Clause
|
||||
|
||||
qt_internal_add_test(tst_q20_memory
|
||||
EXCEPTIONS
|
||||
SOURCES
|
||||
tst_q20_memory.cpp
|
||||
LIBRARIES
|
||||
Qt::Core
|
||||
)
|
161
tests/auto/corelib/global/q20/memory/tst_q20_memory.cpp
Normal file
161
tests/auto/corelib/global/q20/memory/tst_q20_memory.cpp
Normal file
@ -0,0 +1,161 @@
|
||||
// Copyright (C) 2020 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
|
||||
// Copyright (C) 2022 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
|
||||
#include <q20memory.h>
|
||||
#include <QtCore/q20memory.h>
|
||||
|
||||
#include <QTest>
|
||||
#include <QObject>
|
||||
#include <QExplicitlySharedDataPointer>
|
||||
#include <QSharedDataPointer>
|
||||
|
||||
struct Private : QSharedData {};
|
||||
|
||||
class tst_q20_memory : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private Q_SLOTS:
|
||||
void raw();
|
||||
void smart();
|
||||
void recursion();
|
||||
void usesPointerTraits();
|
||||
void prefersPointerTraits();
|
||||
|
||||
private Q_SLOTS:
|
||||
void to_address_broken_const_propagation_QExplicitlySharedDataPointer()
|
||||
{ to_address_broken_const_propagation<QExplicitlySharedDataPointer<Private>>(); }
|
||||
void to_address_broken_const_propagation_QSharedDataPointer()
|
||||
{ to_address_broken_const_propagation<QSharedDataPointer<Private>>(); }
|
||||
void to_address_broken_const_propagation_shared_ptr()
|
||||
{ to_address_broken_const_propagation<std::shared_ptr<Private>>(); }
|
||||
void to_address_broken_const_propagation_unique_ptr()
|
||||
{ to_address_broken_const_propagation<std::unique_ptr<Private>>(); }
|
||||
|
||||
private:
|
||||
template <typename Pointer>
|
||||
void to_address_broken_const_propagation();
|
||||
};
|
||||
|
||||
void tst_q20_memory::raw()
|
||||
{
|
||||
auto i = 0;
|
||||
auto p = &i;
|
||||
QVERIFY(q20::to_address(p) == &i);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class MinimalPtr {
|
||||
public:
|
||||
using element_type = T;
|
||||
|
||||
explicit MinimalPtr(T *d) : d(d) {}
|
||||
|
||||
T *operator->() const noexcept { return d; }
|
||||
|
||||
private:
|
||||
T *d;
|
||||
};
|
||||
|
||||
void tst_q20_memory::smart()
|
||||
{
|
||||
int i;
|
||||
MinimalPtr ptr(&i);
|
||||
QCOMPARE_EQ(q20::to_address(ptr), &i);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class RecursivePtr {
|
||||
public:
|
||||
using element_type = T;
|
||||
|
||||
explicit RecursivePtr(T *d) : d(d) {}
|
||||
|
||||
MinimalPtr<T> operator->() const noexcept { return d; }
|
||||
|
||||
private:
|
||||
MinimalPtr<T> d;
|
||||
};
|
||||
|
||||
void tst_q20_memory::recursion()
|
||||
{
|
||||
int i;
|
||||
RecursivePtr ptr(&i);
|
||||
QCOMPARE_EQ(q20::to_address(ptr), &i);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class NoDerefOperatorPtr {
|
||||
public:
|
||||
using element_type = T;
|
||||
|
||||
explicit NoDerefOperatorPtr(T *d) : d(d) {}
|
||||
|
||||
T *get() const noexcept { return d; }
|
||||
|
||||
private:
|
||||
T *d;
|
||||
};
|
||||
|
||||
namespace std {
|
||||
template <typename T>
|
||||
struct pointer_traits<NoDerefOperatorPtr<T>>
|
||||
{
|
||||
static T *to_address(const NoDerefOperatorPtr<T> &ptr) noexcept { return ptr.get(); }
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
void tst_q20_memory::usesPointerTraits()
|
||||
{
|
||||
int i;
|
||||
NoDerefOperatorPtr ptr(&i);
|
||||
QCOMPARE_EQ(q20::to_address(ptr), &i);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
class PrefersPointerTraitsPtr
|
||||
{
|
||||
public:
|
||||
using element_type = T;
|
||||
|
||||
explicit PrefersPointerTraitsPtr(T *d) : d(d) {}
|
||||
|
||||
T *operator->() const noexcept { return nullptr; }
|
||||
|
||||
T *get() const noexcept { return d; }
|
||||
|
||||
private:
|
||||
T *d;
|
||||
};
|
||||
|
||||
namespace std {
|
||||
template <typename T>
|
||||
struct pointer_traits<PrefersPointerTraitsPtr<T>>
|
||||
{
|
||||
static T *to_address(const PrefersPointerTraitsPtr<T> &p) noexcept { return p.get(); }
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
void tst_q20_memory::prefersPointerTraits()
|
||||
{
|
||||
int i;
|
||||
PrefersPointerTraitsPtr ptr(&i);
|
||||
QCOMPARE_EQ(q20::to_address(ptr), &i);
|
||||
}
|
||||
|
||||
template <typename Pointer>
|
||||
void tst_q20_memory::to_address_broken_const_propagation()
|
||||
{
|
||||
Pointer p(nullptr);
|
||||
QCOMPARE_EQ(q20::to_address(p), nullptr);
|
||||
p = Pointer{new Private()};
|
||||
QCOMPARE_EQ(q20::to_address(p), p.operator->());
|
||||
static_assert(std::is_same_v<decltype(q20::to_address(p)),
|
||||
decltype(std::as_const(p).operator->())>);
|
||||
}
|
||||
|
||||
QTEST_GUILESS_MAIN(tst_q20_memory)
|
||||
#include "tst_q20_memory.moc"
|
||||
|
Loading…
x
Reference in New Issue
Block a user