util/IntrusiveList: add enum LinkMode
Compile-time code simplification.
This commit is contained in:
parent
3023816491
commit
fb5d77158a
@ -46,7 +46,7 @@ class RemoteTagCache final {
|
|||||||
|
|
||||||
struct Item final
|
struct Item final
|
||||||
: public boost::intrusive::unordered_set_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>>,
|
: public boost::intrusive::unordered_set_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>>,
|
||||||
public IntrusiveListHook,
|
public IntrusiveListHook<>,
|
||||||
RemoteTagHandler
|
RemoteTagHandler
|
||||||
{
|
{
|
||||||
RemoteTagCache &parent;
|
RemoteTagCache &parent;
|
||||||
|
@ -53,7 +53,7 @@ class Client final
|
|||||||
friend struct ClientPerPartitionListHook;
|
friend struct ClientPerPartitionListHook;
|
||||||
friend class ClientList;
|
friend class ClientList;
|
||||||
|
|
||||||
IntrusiveListHook list_siblings, partition_siblings;
|
IntrusiveListHook<> list_siblings, partition_siblings;
|
||||||
|
|
||||||
CoarseTimerEvent timeout_event;
|
CoarseTimerEvent timeout_event;
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ static constexpr unsigned DEVICE_PLAYLIST = -3;
|
|||||||
|
|
||||||
class SongFilter;
|
class SongFilter;
|
||||||
|
|
||||||
struct Directory : IntrusiveListHook {
|
struct Directory : IntrusiveListHook<> {
|
||||||
/* Note: the #IntrusiveListHook is protected with the global
|
/* Note: the #IntrusiveListHook is protected with the global
|
||||||
#db_mutex. Read access in the update thread does not need
|
#db_mutex. Read access in the update thread does not need
|
||||||
protection. */
|
protection. */
|
||||||
|
@ -39,7 +39,7 @@ class ArchiveFile;
|
|||||||
* A song file inside the configured music directory. Internal
|
* A song file inside the configured music directory. Internal
|
||||||
* #SimpleDatabase class.
|
* #SimpleDatabase class.
|
||||||
*/
|
*/
|
||||||
struct Song : IntrusiveListHook {
|
struct Song : IntrusiveListHook<> {
|
||||||
/* Note: the #IntrusiveListHook is protected with the global
|
/* Note: the #IntrusiveListHook is protected with the global
|
||||||
#db_mutex. Read access in the update thread does not need
|
#db_mutex. Read access in the update thread does not need
|
||||||
protection. */
|
protection. */
|
||||||
|
@ -40,7 +40,9 @@ class EventLoop;
|
|||||||
* thread that runs the #EventLoop, except where explicitly documented
|
* thread that runs the #EventLoop, except where explicitly documented
|
||||||
* as thread-safe.
|
* as thread-safe.
|
||||||
*/
|
*/
|
||||||
class SocketEvent final : IntrusiveListHook, public EventPollBackendEvents
|
class SocketEvent final
|
||||||
|
: IntrusiveListHook<IntrusiveHookMode::NORMAL>,
|
||||||
|
public EventPollBackendEvents
|
||||||
{
|
{
|
||||||
friend class EventLoop;
|
friend class EventLoop;
|
||||||
friend struct IntrusiveListBaseHookTraits<SocketEvent>;
|
friend struct IntrusiveListBaseHookTraits<SocketEvent>;
|
||||||
|
2
src/input/cache/Lease.hxx
vendored
2
src/input/cache/Lease.hxx
vendored
@ -29,7 +29,7 @@
|
|||||||
* A lease for an #InputCacheItem.
|
* A lease for an #InputCacheItem.
|
||||||
*/
|
*/
|
||||||
class InputCacheLease
|
class InputCacheLease
|
||||||
: public IntrusiveListHook
|
: public IntrusiveListHook<>
|
||||||
{
|
{
|
||||||
InputCacheItem *item = nullptr;
|
InputCacheItem *item = nullptr;
|
||||||
|
|
||||||
|
@ -40,7 +40,8 @@
|
|||||||
|
|
||||||
namespace Uring {
|
namespace Uring {
|
||||||
|
|
||||||
class CancellableOperation : public IntrusiveListHook
|
class CancellableOperation
|
||||||
|
: public IntrusiveListHook<IntrusiveHookMode::NORMAL>
|
||||||
{
|
{
|
||||||
Operation *operation;
|
Operation *operation;
|
||||||
|
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class CancellablePointer
|
class CancellablePointer
|
||||||
: public IntrusiveListHook
|
: public IntrusiveListHook<>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef T *pointer;
|
typedef T *pointer;
|
||||||
|
@ -79,7 +79,7 @@ class UPnPDeviceDirectory final : UpnpCallback {
|
|||||||
};
|
};
|
||||||
|
|
||||||
class Downloader final
|
class Downloader final
|
||||||
: public IntrusiveListHook, CurlResponseHandler
|
: public IntrusiveListHook<>, CurlResponseHandler
|
||||||
{
|
{
|
||||||
InjectEvent defer_start_event;
|
InjectEvent defer_start_event;
|
||||||
|
|
||||||
|
@ -34,7 +34,7 @@ class HttpdOutput;
|
|||||||
|
|
||||||
class HttpdClient final
|
class HttpdClient final
|
||||||
: BufferedSocket,
|
: BufferedSocket,
|
||||||
public IntrusiveListHook
|
public IntrusiveListHook<>
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* The httpd output object this client is connected to.
|
* The httpd output object this client is connected to.
|
||||||
|
@ -33,7 +33,7 @@ struct SnapcastTime;
|
|||||||
class SnapcastOutput;
|
class SnapcastOutput;
|
||||||
class UniqueSocketDescriptor;
|
class UniqueSocketDescriptor;
|
||||||
|
|
||||||
class SnapcastClient final : BufferedSocket, public IntrusiveListHook
|
class SnapcastClient final : BufferedSocket, public IntrusiveListHook<>
|
||||||
{
|
{
|
||||||
SnapcastOutput &output;
|
SnapcastOutput &output;
|
||||||
|
|
||||||
|
56
src/util/IntrusiveHookMode.hxx
Normal file
56
src/util/IntrusiveHookMode.hxx
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2022 Max Kellermann <max.kellermann@gmail.com>
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* - Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* - Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||||
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
|
||||||
|
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
|
||||||
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the mode in which a hook for intrusive containers
|
||||||
|
* operates. This is meant to be used as a template argument to the
|
||||||
|
* hook class (e.g. #IntrusiveListHook).
|
||||||
|
*/
|
||||||
|
enum class IntrusiveHookMode {
|
||||||
|
/**
|
||||||
|
* No implicit initialization.
|
||||||
|
*/
|
||||||
|
NORMAL,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keep track of whether the item is currently linked, allows
|
||||||
|
* using method is_linked(). This requires implicit
|
||||||
|
* initialization and requires iterating all items when
|
||||||
|
* deleting them which adds a considerable amount of overhead.
|
||||||
|
*/
|
||||||
|
TRACK,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Automatically unlinks the item in the destructor. This
|
||||||
|
* implies #TRACK and adds code to the destructor.
|
||||||
|
*/
|
||||||
|
AUTO_UNLINK,
|
||||||
|
};
|
@ -30,6 +30,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Cast.hxx"
|
#include "Cast.hxx"
|
||||||
|
#include "IntrusiveHookMode.hxx"
|
||||||
#include "MemberPointer.hxx"
|
#include "MemberPointer.hxx"
|
||||||
#include "OptionalCounter.hxx"
|
#include "OptionalCounter.hxx"
|
||||||
|
|
||||||
@ -47,6 +48,7 @@ struct IntrusiveListNode {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template<IntrusiveHookMode _mode=IntrusiveHookMode::NORMAL>
|
||||||
class IntrusiveListHook {
|
class IntrusiveListHook {
|
||||||
template<typename T> friend struct IntrusiveListBaseHookTraits;
|
template<typename T> friend struct IntrusiveListBaseHookTraits;
|
||||||
template<auto member> friend struct IntrusiveListMemberHookTraits;
|
template<auto member> friend struct IntrusiveListMemberHookTraits;
|
||||||
@ -56,13 +58,33 @@ protected:
|
|||||||
IntrusiveListNode siblings;
|
IntrusiveListNode siblings;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IntrusiveListHook() noexcept = default;
|
static constexpr IntrusiveHookMode mode = _mode;
|
||||||
|
|
||||||
|
IntrusiveListHook() noexcept {
|
||||||
|
if constexpr (mode >= IntrusiveHookMode::TRACK)
|
||||||
|
siblings.next = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
~IntrusiveListHook() noexcept {
|
||||||
|
if constexpr (mode >= IntrusiveHookMode::AUTO_UNLINK)
|
||||||
|
if (is_linked())
|
||||||
|
unlink();
|
||||||
|
}
|
||||||
|
|
||||||
IntrusiveListHook(const IntrusiveListHook &) = delete;
|
IntrusiveListHook(const IntrusiveListHook &) = delete;
|
||||||
IntrusiveListHook &operator=(const IntrusiveListHook &) = delete;
|
IntrusiveListHook &operator=(const IntrusiveListHook &) = delete;
|
||||||
|
|
||||||
void unlink() noexcept {
|
void unlink() noexcept {
|
||||||
IntrusiveListNode::Connect(*siblings.prev, *siblings.next);
|
IntrusiveListNode::Connect(*siblings.prev, *siblings.next);
|
||||||
|
|
||||||
|
if constexpr (mode >= IntrusiveHookMode::TRACK)
|
||||||
|
siblings.next = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_linked() const noexcept {
|
||||||
|
static_assert(mode >= IntrusiveHookMode::TRACK);
|
||||||
|
|
||||||
|
return siblings.next != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -75,52 +97,27 @@ private:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
using SafeLinkIntrusiveListHook =
|
||||||
* A variant of #IntrusiveListHook which keeps track of whether it is
|
IntrusiveListHook<IntrusiveHookMode::TRACK>;
|
||||||
* currently in a list.
|
using AutoUnlinkIntrusiveListHook =
|
||||||
*/
|
IntrusiveListHook<IntrusiveHookMode::AUTO_UNLINK>;
|
||||||
class SafeLinkIntrusiveListHook : public IntrusiveListHook {
|
|
||||||
public:
|
|
||||||
SafeLinkIntrusiveListHook() noexcept {
|
|
||||||
siblings.next = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void unlink() noexcept {
|
|
||||||
IntrusiveListHook::unlink();
|
|
||||||
siblings.next = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_linked() const noexcept {
|
|
||||||
return siblings.next != nullptr;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A variant of #IntrusiveListHook which auto-unlinks itself from the
|
* Detect the hook type which is embedded in the given type as a base
|
||||||
* list upon destruction. As a side effect, it has an is_linked()
|
* class. This is a template to postpone the type checks, to allow
|
||||||
* method.
|
|
||||||
*/
|
|
||||||
class AutoUnlinkIntrusiveListHook : public SafeLinkIntrusiveListHook {
|
|
||||||
public:
|
|
||||||
~AutoUnlinkIntrusiveListHook() noexcept {
|
|
||||||
if (is_linked())
|
|
||||||
unlink();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Detect the hook type; this is important because
|
|
||||||
* SafeLinkIntrusiveListHook::unlink() needs to clear the "next"
|
|
||||||
* pointer. This is a template to postpone the type checks, to allow
|
|
||||||
* forward-declared types.
|
* forward-declared types.
|
||||||
*/
|
*/
|
||||||
template<typename U>
|
template<typename U>
|
||||||
struct IntrusiveListHookDetection {
|
struct IntrusiveListHookDetection {
|
||||||
static_assert(std::is_base_of_v<IntrusiveListHook, U>);
|
/* TODO can this be simplified somehow, without checking for
|
||||||
|
all possible enum values? */
|
||||||
using type = std::conditional_t<std::is_base_of_v<SafeLinkIntrusiveListHook, U>,
|
using type = std::conditional_t<std::is_base_of_v<IntrusiveListHook<IntrusiveHookMode::NORMAL>, U>,
|
||||||
SafeLinkIntrusiveListHook,
|
IntrusiveListHook<IntrusiveHookMode::NORMAL>,
|
||||||
IntrusiveListHook>;
|
std::conditional_t<std::is_base_of_v<IntrusiveListHook<IntrusiveHookMode::TRACK>, U>,
|
||||||
|
IntrusiveListHook<IntrusiveHookMode::TRACK>,
|
||||||
|
std::conditional_t<std::is_base_of_v<IntrusiveListHook<IntrusiveHookMode::AUTO_UNLINK>, U>,
|
||||||
|
IntrusiveListHook<IntrusiveHookMode::AUTO_UNLINK>,
|
||||||
|
void>>>;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -131,10 +128,6 @@ struct IntrusiveListBaseHookTraits {
|
|||||||
template<typename U>
|
template<typename U>
|
||||||
using Hook = typename IntrusiveListHookDetection<U>::type;
|
using Hook = typename IntrusiveListHookDetection<U>::type;
|
||||||
|
|
||||||
static constexpr bool IsAutoUnlink() noexcept {
|
|
||||||
return std::is_base_of_v<AutoUnlinkIntrusiveListHook, T>;
|
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr T *Cast(IntrusiveListNode *node) noexcept {
|
static constexpr T *Cast(IntrusiveListNode *node) noexcept {
|
||||||
auto *hook = &Hook<T>::Cast(*node);
|
auto *hook = &Hook<T>::Cast(*node);
|
||||||
return static_cast<T *>(hook);
|
return static_cast<T *>(hook);
|
||||||
@ -152,14 +145,12 @@ template<auto member>
|
|||||||
struct IntrusiveListMemberHookTraits {
|
struct IntrusiveListMemberHookTraits {
|
||||||
using T = MemberPointerContainerType<decltype(member)>;
|
using T = MemberPointerContainerType<decltype(member)>;
|
||||||
using _Hook = MemberPointerType<decltype(member)>;
|
using _Hook = MemberPointerType<decltype(member)>;
|
||||||
using Hook = typename IntrusiveListHookDetection<_Hook>::type;
|
|
||||||
|
|
||||||
static constexpr bool IsAutoUnlink() noexcept {
|
template<typename Dummy>
|
||||||
return std::is_base_of_v<AutoUnlinkIntrusiveListHook, _Hook>;
|
using Hook = _Hook;
|
||||||
}
|
|
||||||
|
|
||||||
static constexpr T *Cast(IntrusiveListNode *node) noexcept {
|
static constexpr T *Cast(IntrusiveListNode *node) noexcept {
|
||||||
auto &hook = Hook::Cast(*node);
|
auto &hook = Hook<T>::Cast(*node);
|
||||||
return &ContainerCast(hook, member);
|
return &ContainerCast(hook, member);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,14 +167,15 @@ template<typename T,
|
|||||||
typename HookTraits=IntrusiveListBaseHookTraits<T>,
|
typename HookTraits=IntrusiveListBaseHookTraits<T>,
|
||||||
bool constant_time_size=false>
|
bool constant_time_size=false>
|
||||||
class IntrusiveList {
|
class IntrusiveList {
|
||||||
template<typename U>
|
|
||||||
using Hook = typename IntrusiveListHookDetection<U>::type;
|
|
||||||
|
|
||||||
IntrusiveListNode head{&head, &head};
|
IntrusiveListNode head{&head, &head};
|
||||||
|
|
||||||
[[no_unique_address]]
|
[[no_unique_address]]
|
||||||
OptionalCounter<constant_time_size> counter;
|
OptionalCounter<constant_time_size> counter;
|
||||||
|
|
||||||
|
static constexpr auto GetHookMode() noexcept {
|
||||||
|
return HookTraits::template Hook<T>::mode;
|
||||||
|
}
|
||||||
|
|
||||||
static constexpr T *Cast(IntrusiveListNode *node) noexcept {
|
static constexpr T *Cast(IntrusiveListNode *node) noexcept {
|
||||||
return HookTraits::Cast(node);
|
return HookTraits::Cast(node);
|
||||||
}
|
}
|
||||||
@ -234,7 +226,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
~IntrusiveList() noexcept {
|
~IntrusiveList() noexcept {
|
||||||
if constexpr (std::is_base_of_v<SafeLinkIntrusiveListHook, T>)
|
if constexpr (GetHookMode() >= IntrusiveHookMode::TRACK)
|
||||||
clear();
|
clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,7 +275,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void clear() noexcept {
|
void clear() noexcept {
|
||||||
if constexpr (std::is_base_of_v<SafeLinkIntrusiveListHook, T>) {
|
if constexpr (GetHookMode() >= IntrusiveHookMode::TRACK) {
|
||||||
/* for SafeLinkIntrusiveListHook, we need to
|
/* for SafeLinkIntrusiveListHook, we need to
|
||||||
remove each item manually, or else its
|
remove each item manually, or else its
|
||||||
is_linked() method will not work */
|
is_linked() method will not work */
|
||||||
@ -504,7 +496,7 @@ public:
|
|||||||
|
|
||||||
void insert(iterator p, reference t) noexcept {
|
void insert(iterator p, reference t) noexcept {
|
||||||
static_assert(!constant_time_size ||
|
static_assert(!constant_time_size ||
|
||||||
!HookTraits::IsAutoUnlink(),
|
GetHookMode() < IntrusiveHookMode::AUTO_UNLINK,
|
||||||
"Can't use auto-unlink hooks with constant_time_size");
|
"Can't use auto-unlink hooks with constant_time_size");
|
||||||
|
|
||||||
auto &existing_node = ToNode(*p);
|
auto &existing_node = ToNode(*p);
|
||||||
|
@ -36,17 +36,17 @@
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
template<typename Hook>
|
template<IntrusiveHookMode mode>
|
||||||
struct CharItem final : Hook {
|
struct CharItem final : IntrusiveListHook<mode> {
|
||||||
char ch;
|
char ch;
|
||||||
|
|
||||||
constexpr CharItem(char _ch) noexcept:ch(_ch) {}
|
constexpr CharItem(char _ch) noexcept:ch(_ch) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename Hook>
|
template<IntrusiveHookMode mode>
|
||||||
static std::string
|
static std::string
|
||||||
ToString(const IntrusiveList<CharItem<Hook>> &list,
|
ToString(const IntrusiveList<CharItem<mode>> &list,
|
||||||
typename IntrusiveList<CharItem<Hook>>::const_iterator it,
|
typename IntrusiveList<CharItem<mode>>::const_iterator it,
|
||||||
std::size_t n) noexcept
|
std::size_t n) noexcept
|
||||||
{
|
{
|
||||||
std::string result;
|
std::string result;
|
||||||
@ -55,10 +55,10 @@ ToString(const IntrusiveList<CharItem<Hook>> &list,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Hook>
|
template<IntrusiveHookMode mode>
|
||||||
static std::string
|
static std::string
|
||||||
ToStringReverse(const IntrusiveList<CharItem<Hook>> &list,
|
ToStringReverse(const IntrusiveList<CharItem<mode>> &list,
|
||||||
typename IntrusiveList<CharItem<Hook>>::const_iterator it,
|
typename IntrusiveList<CharItem<mode>>::const_iterator it,
|
||||||
std::size_t n) noexcept
|
std::size_t n) noexcept
|
||||||
{
|
{
|
||||||
std::string result;
|
std::string result;
|
||||||
@ -71,7 +71,7 @@ ToStringReverse(const IntrusiveList<CharItem<Hook>> &list,
|
|||||||
|
|
||||||
TEST(IntrusiveList, Basic)
|
TEST(IntrusiveList, Basic)
|
||||||
{
|
{
|
||||||
using Item = CharItem<IntrusiveListHook>;
|
using Item = CharItem<IntrusiveHookMode::NORMAL>;
|
||||||
|
|
||||||
Item items[]{'a', 'b', 'c'};
|
Item items[]{'a', 'b', 'c'};
|
||||||
|
|
||||||
@ -103,9 +103,9 @@ TEST(IntrusiveList, Basic)
|
|||||||
ASSERT_EQ(ToStringReverse(list, list.begin(), 6), "a_cfea");
|
ASSERT_EQ(ToStringReverse(list, list.begin(), 6), "a_cfea");
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST(IntrusiveList, SafeLink)
|
TEST(IntrusiveList, Track)
|
||||||
{
|
{
|
||||||
using Item = CharItem<SafeLinkIntrusiveListHook>;
|
using Item = CharItem<IntrusiveHookMode::TRACK>;
|
||||||
|
|
||||||
Item items[]{'a', 'b', 'c'};
|
Item items[]{'a', 'b', 'c'};
|
||||||
|
|
||||||
@ -162,7 +162,7 @@ TEST(IntrusiveList, SafeLink)
|
|||||||
|
|
||||||
TEST(IntrusiveList, AutoUnlink)
|
TEST(IntrusiveList, AutoUnlink)
|
||||||
{
|
{
|
||||||
using Item = CharItem<AutoUnlinkIntrusiveListHook>;
|
using Item = CharItem<IntrusiveHookMode::AUTO_UNLINK>;
|
||||||
|
|
||||||
Item a{'a'};
|
Item a{'a'};
|
||||||
ASSERT_FALSE(a.is_linked());
|
ASSERT_FALSE(a.is_linked());
|
||||||
@ -194,7 +194,7 @@ TEST(IntrusiveList, AutoUnlink)
|
|||||||
|
|
||||||
TEST(IntrusiveList, Merge)
|
TEST(IntrusiveList, Merge)
|
||||||
{
|
{
|
||||||
using Item = CharItem<IntrusiveListHook>;
|
using Item = CharItem<IntrusiveHookMode::NORMAL>;
|
||||||
|
|
||||||
const auto predicate = [](const Item &a, const Item &b){
|
const auto predicate = [](const Item &a, const Item &b){
|
||||||
return a.ch < b.ch;
|
return a.ch < b.ch;
|
||||||
@ -229,7 +229,7 @@ TEST(IntrusiveList, Merge)
|
|||||||
|
|
||||||
TEST(IntrusiveList, Sort)
|
TEST(IntrusiveList, Sort)
|
||||||
{
|
{
|
||||||
using Item = CharItem<IntrusiveListHook>;
|
using Item = CharItem<IntrusiveHookMode::NORMAL>;
|
||||||
|
|
||||||
const auto predicate = [](const Item &a, const Item &b){
|
const auto predicate = [](const Item &a, const Item &b){
|
||||||
return a.ch < b.ch;
|
return a.ch < b.ch;
|
||||||
|
Loading…
Reference in New Issue
Block a user