ADT: Split out simple_ilist, a simple intrusive list
Split out a new, low-level intrusive list type with clear semantics.
Unlike iplist (and ilist), all operations on simple_ilist are intrusive,
and simple_ilist never takes ownership of its nodes. This enables an
intuitive API that has the right defaults for intrusive lists.
- insert() takes references (not pointers!) to nodes (in iplist/ilist,
passing a reference will cause the node to be copied).
- erase() takes only iterators (like std::list), and does not destroy
the nodes.
- remove() takes only references and has the same behaviour as erase().
- clear() does not destroy the nodes.
- The destructor does not destroy the nodes.
- New API {erase,remove,clear}AndDispose() take an extra Disposer
functor for callsites that want to call some disposal routine (e.g.,
std::default_delete).
This list is not currently configurable, and has no callbacks.
The initial motivation was to fix iplist<>::sort to work correctly (even
with callbacks in ilist_traits<>). iplist<> uses simple_ilist<>::sort
directly. The new test in unittests/IR/ModuleTest.cpp crashes without
this commit.
Fixing sort() via a low-level layer provided a good opportunity to:
- Unit test the low-level functionality thoroughly.
- Modernize the API, largely inspired by other intrusive list
implementations.
Here's a sketch of a longer-term plan:
- Create BumpPtrList<>, a non-intrusive list implemented using
simple_ilist<>, and use it for the Token list in
lib/Support/YAMLParser.cpp. This will factor out the only real use of
createNode().
- Evolve the iplist<> and ilist<> APIs in the direction of
simple_ilist<>, making allocation/deallocation explicit at call sites
(similar to simple_ilist<>::eraseAndDispose()).
- Factor out remaining calls to createNode() and deleteNode() and remove
the customization from ilist_traits<>.
- Transition uses of iplist<>/ilist<> that don't need callbacks over to
simple_ilist<>.
llvm-svn: 280107
2016-08-30 18:23:55 +02:00
|
|
|
//===- llvm/ADT/simple_ilist.h - Simple Intrusive List ----------*- C++ -*-===//
|
|
|
|
//
|
2019-01-19 09:50:56 +01:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
ADT: Split out simple_ilist, a simple intrusive list
Split out a new, low-level intrusive list type with clear semantics.
Unlike iplist (and ilist), all operations on simple_ilist are intrusive,
and simple_ilist never takes ownership of its nodes. This enables an
intuitive API that has the right defaults for intrusive lists.
- insert() takes references (not pointers!) to nodes (in iplist/ilist,
passing a reference will cause the node to be copied).
- erase() takes only iterators (like std::list), and does not destroy
the nodes.
- remove() takes only references and has the same behaviour as erase().
- clear() does not destroy the nodes.
- The destructor does not destroy the nodes.
- New API {erase,remove,clear}AndDispose() take an extra Disposer
functor for callsites that want to call some disposal routine (e.g.,
std::default_delete).
This list is not currently configurable, and has no callbacks.
The initial motivation was to fix iplist<>::sort to work correctly (even
with callbacks in ilist_traits<>). iplist<> uses simple_ilist<>::sort
directly. The new test in unittests/IR/ModuleTest.cpp crashes without
this commit.
Fixing sort() via a low-level layer provided a good opportunity to:
- Unit test the low-level functionality thoroughly.
- Modernize the API, largely inspired by other intrusive list
implementations.
Here's a sketch of a longer-term plan:
- Create BumpPtrList<>, a non-intrusive list implemented using
simple_ilist<>, and use it for the Token list in
lib/Support/YAMLParser.cpp. This will factor out the only real use of
createNode().
- Evolve the iplist<> and ilist<> APIs in the direction of
simple_ilist<>, making allocation/deallocation explicit at call sites
(similar to simple_ilist<>::eraseAndDispose()).
- Factor out remaining calls to createNode() and deleteNode() and remove
the customization from ilist_traits<>.
- Transition uses of iplist<>/ilist<> that don't need callbacks over to
simple_ilist<>.
llvm-svn: 280107
2016-08-30 18:23:55 +02:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#ifndef LLVM_ADT_SIMPLE_ILIST_H
|
|
|
|
#define LLVM_ADT_SIMPLE_ILIST_H
|
|
|
|
|
|
|
|
#include "llvm/ADT/ilist_base.h"
|
|
|
|
#include "llvm/ADT/ilist_iterator.h"
|
|
|
|
#include "llvm/ADT/ilist_node.h"
|
2017-06-14 23:42:24 +02:00
|
|
|
#include "llvm/ADT/ilist_node_options.h"
|
|
|
|
#include "llvm/Support/Compiler.h"
|
ADT: Split out simple_ilist, a simple intrusive list
Split out a new, low-level intrusive list type with clear semantics.
Unlike iplist (and ilist), all operations on simple_ilist are intrusive,
and simple_ilist never takes ownership of its nodes. This enables an
intuitive API that has the right defaults for intrusive lists.
- insert() takes references (not pointers!) to nodes (in iplist/ilist,
passing a reference will cause the node to be copied).
- erase() takes only iterators (like std::list), and does not destroy
the nodes.
- remove() takes only references and has the same behaviour as erase().
- clear() does not destroy the nodes.
- The destructor does not destroy the nodes.
- New API {erase,remove,clear}AndDispose() take an extra Disposer
functor for callsites that want to call some disposal routine (e.g.,
std::default_delete).
This list is not currently configurable, and has no callbacks.
The initial motivation was to fix iplist<>::sort to work correctly (even
with callbacks in ilist_traits<>). iplist<> uses simple_ilist<>::sort
directly. The new test in unittests/IR/ModuleTest.cpp crashes without
this commit.
Fixing sort() via a low-level layer provided a good opportunity to:
- Unit test the low-level functionality thoroughly.
- Modernize the API, largely inspired by other intrusive list
implementations.
Here's a sketch of a longer-term plan:
- Create BumpPtrList<>, a non-intrusive list implemented using
simple_ilist<>, and use it for the Token list in
lib/Support/YAMLParser.cpp. This will factor out the only real use of
createNode().
- Evolve the iplist<> and ilist<> APIs in the direction of
simple_ilist<>, making allocation/deallocation explicit at call sites
(similar to simple_ilist<>::eraseAndDispose()).
- Factor out remaining calls to createNode() and deleteNode() and remove
the customization from ilist_traits<>.
- Transition uses of iplist<>/ilist<> that don't need callbacks over to
simple_ilist<>.
llvm-svn: 280107
2016-08-30 18:23:55 +02:00
|
|
|
#include <algorithm>
|
|
|
|
#include <cassert>
|
|
|
|
#include <cstddef>
|
2017-06-14 23:42:24 +02:00
|
|
|
#include <functional>
|
|
|
|
#include <iterator>
|
|
|
|
#include <utility>
|
ADT: Split out simple_ilist, a simple intrusive list
Split out a new, low-level intrusive list type with clear semantics.
Unlike iplist (and ilist), all operations on simple_ilist are intrusive,
and simple_ilist never takes ownership of its nodes. This enables an
intuitive API that has the right defaults for intrusive lists.
- insert() takes references (not pointers!) to nodes (in iplist/ilist,
passing a reference will cause the node to be copied).
- erase() takes only iterators (like std::list), and does not destroy
the nodes.
- remove() takes only references and has the same behaviour as erase().
- clear() does not destroy the nodes.
- The destructor does not destroy the nodes.
- New API {erase,remove,clear}AndDispose() take an extra Disposer
functor for callsites that want to call some disposal routine (e.g.,
std::default_delete).
This list is not currently configurable, and has no callbacks.
The initial motivation was to fix iplist<>::sort to work correctly (even
with callbacks in ilist_traits<>). iplist<> uses simple_ilist<>::sort
directly. The new test in unittests/IR/ModuleTest.cpp crashes without
this commit.
Fixing sort() via a low-level layer provided a good opportunity to:
- Unit test the low-level functionality thoroughly.
- Modernize the API, largely inspired by other intrusive list
implementations.
Here's a sketch of a longer-term plan:
- Create BumpPtrList<>, a non-intrusive list implemented using
simple_ilist<>, and use it for the Token list in
lib/Support/YAMLParser.cpp. This will factor out the only real use of
createNode().
- Evolve the iplist<> and ilist<> APIs in the direction of
simple_ilist<>, making allocation/deallocation explicit at call sites
(similar to simple_ilist<>::eraseAndDispose()).
- Factor out remaining calls to createNode() and deleteNode() and remove
the customization from ilist_traits<>.
- Transition uses of iplist<>/ilist<> that don't need callbacks over to
simple_ilist<>.
llvm-svn: 280107
2016-08-30 18:23:55 +02:00
|
|
|
|
|
|
|
namespace llvm {
|
|
|
|
|
|
|
|
/// A simple intrusive list implementation.
|
|
|
|
///
|
|
|
|
/// This is a simple intrusive list for a \c T that inherits from \c
|
|
|
|
/// ilist_node<T>. The list never takes ownership of anything inserted in it.
|
|
|
|
///
|
2021-01-22 09:22:50 +01:00
|
|
|
/// Unlike \a iplist<T> and \a ilist<T>, \a simple_ilist<T> never deletes
|
|
|
|
/// values, and has no callback traits.
|
ADT: Split out simple_ilist, a simple intrusive list
Split out a new, low-level intrusive list type with clear semantics.
Unlike iplist (and ilist), all operations on simple_ilist are intrusive,
and simple_ilist never takes ownership of its nodes. This enables an
intuitive API that has the right defaults for intrusive lists.
- insert() takes references (not pointers!) to nodes (in iplist/ilist,
passing a reference will cause the node to be copied).
- erase() takes only iterators (like std::list), and does not destroy
the nodes.
- remove() takes only references and has the same behaviour as erase().
- clear() does not destroy the nodes.
- The destructor does not destroy the nodes.
- New API {erase,remove,clear}AndDispose() take an extra Disposer
functor for callsites that want to call some disposal routine (e.g.,
std::default_delete).
This list is not currently configurable, and has no callbacks.
The initial motivation was to fix iplist<>::sort to work correctly (even
with callbacks in ilist_traits<>). iplist<> uses simple_ilist<>::sort
directly. The new test in unittests/IR/ModuleTest.cpp crashes without
this commit.
Fixing sort() via a low-level layer provided a good opportunity to:
- Unit test the low-level functionality thoroughly.
- Modernize the API, largely inspired by other intrusive list
implementations.
Here's a sketch of a longer-term plan:
- Create BumpPtrList<>, a non-intrusive list implemented using
simple_ilist<>, and use it for the Token list in
lib/Support/YAMLParser.cpp. This will factor out the only real use of
createNode().
- Evolve the iplist<> and ilist<> APIs in the direction of
simple_ilist<>, making allocation/deallocation explicit at call sites
(similar to simple_ilist<>::eraseAndDispose()).
- Factor out remaining calls to createNode() and deleteNode() and remove
the customization from ilist_traits<>.
- Transition uses of iplist<>/ilist<> that don't need callbacks over to
simple_ilist<>.
llvm-svn: 280107
2016-08-30 18:23:55 +02:00
|
|
|
///
|
|
|
|
/// The API for adding nodes include \a push_front(), \a push_back(), and \a
|
|
|
|
/// insert(). These all take values by reference (not by pointer), except for
|
|
|
|
/// the range version of \a insert().
|
|
|
|
///
|
|
|
|
/// There are three sets of API for discarding nodes from the list: \a
|
|
|
|
/// remove(), which takes a reference to the node to remove, \a erase(), which
|
|
|
|
/// takes an iterator or iterator range and returns the next one, and \a
|
|
|
|
/// clear(), which empties out the container. All three are constant time
|
|
|
|
/// operations. None of these deletes any nodes; in particular, if there is a
|
|
|
|
/// single node in the list, then these have identical semantics:
|
|
|
|
/// \li \c L.remove(L.front());
|
|
|
|
/// \li \c L.erase(L.begin());
|
|
|
|
/// \li \c L.clear();
|
|
|
|
///
|
|
|
|
/// As a convenience for callers, there are parallel APIs that take a \c
|
|
|
|
/// Disposer (such as \c std::default_delete<T>): \a removeAndDispose(), \a
|
|
|
|
/// eraseAndDispose(), and \a clearAndDispose(). These have different names
|
|
|
|
/// because the extra semantic is otherwise non-obvious. They are equivalent
|
|
|
|
/// to calling \a std::for_each() on the range to be discarded.
|
2016-09-11 18:20:53 +02:00
|
|
|
///
|
|
|
|
/// The currently available \p Options customize the nodes in the list. The
|
2020-12-02 02:02:46 +01:00
|
|
|
/// same options must be specified in the \a ilist_node instantiation for
|
2016-09-11 18:20:53 +02:00
|
|
|
/// compatibility (although the order is irrelevant).
|
|
|
|
/// \li Use \a ilist_tag to designate which ilist_node for a given \p T this
|
|
|
|
/// list should use. This is useful if a type \p T is part of multiple,
|
|
|
|
/// independent lists simultaneously.
|
|
|
|
/// \li Use \a ilist_sentinel_tracking to always (or never) track whether a
|
|
|
|
/// node is a sentinel. Specifying \c true enables the \a
|
|
|
|
/// ilist_node::isSentinel() API. Unlike \a ilist_node::isKnownSentinel(),
|
|
|
|
/// which is only appropriate for assertions, \a ilist_node::isSentinel() is
|
|
|
|
/// appropriate for real logic.
|
|
|
|
///
|
|
|
|
/// Here are examples of \p Options usage:
|
|
|
|
/// \li \c simple_ilist<T> gives the defaults. \li \c
|
|
|
|
/// simple_ilist<T,ilist_sentinel_tracking<true>> enables the \a
|
|
|
|
/// ilist_node::isSentinel() API.
|
|
|
|
/// \li \c simple_ilist<T,ilist_tag<A>,ilist_sentinel_tracking<false>>
|
|
|
|
/// specifies a tag of A and that tracking should be off (even when
|
|
|
|
/// LLVM_ENABLE_ABI_BREAKING_CHECKS are enabled).
|
|
|
|
/// \li \c simple_ilist<T,ilist_sentinel_tracking<false>,ilist_tag<A>> is
|
|
|
|
/// equivalent to the last.
|
|
|
|
///
|
|
|
|
/// See \a is_valid_option for steps on adding a new option.
|
|
|
|
template <typename T, class... Options>
|
|
|
|
class simple_ilist
|
|
|
|
: ilist_detail::compute_node_options<T, Options...>::type::list_base_type,
|
|
|
|
ilist_detail::SpecificNodeAccess<
|
|
|
|
typename ilist_detail::compute_node_options<T, Options...>::type> {
|
|
|
|
static_assert(ilist_detail::check_options<Options...>::value,
|
|
|
|
"Unrecognized node option!");
|
2017-06-14 23:42:24 +02:00
|
|
|
using OptionsT =
|
|
|
|
typename ilist_detail::compute_node_options<T, Options...>::type;
|
|
|
|
using list_base_type = typename OptionsT::list_base_type;
|
2016-09-11 18:20:53 +02:00
|
|
|
ilist_sentinel<OptionsT> Sentinel;
|
ADT: Split out simple_ilist, a simple intrusive list
Split out a new, low-level intrusive list type with clear semantics.
Unlike iplist (and ilist), all operations on simple_ilist are intrusive,
and simple_ilist never takes ownership of its nodes. This enables an
intuitive API that has the right defaults for intrusive lists.
- insert() takes references (not pointers!) to nodes (in iplist/ilist,
passing a reference will cause the node to be copied).
- erase() takes only iterators (like std::list), and does not destroy
the nodes.
- remove() takes only references and has the same behaviour as erase().
- clear() does not destroy the nodes.
- The destructor does not destroy the nodes.
- New API {erase,remove,clear}AndDispose() take an extra Disposer
functor for callsites that want to call some disposal routine (e.g.,
std::default_delete).
This list is not currently configurable, and has no callbacks.
The initial motivation was to fix iplist<>::sort to work correctly (even
with callbacks in ilist_traits<>). iplist<> uses simple_ilist<>::sort
directly. The new test in unittests/IR/ModuleTest.cpp crashes without
this commit.
Fixing sort() via a low-level layer provided a good opportunity to:
- Unit test the low-level functionality thoroughly.
- Modernize the API, largely inspired by other intrusive list
implementations.
Here's a sketch of a longer-term plan:
- Create BumpPtrList<>, a non-intrusive list implemented using
simple_ilist<>, and use it for the Token list in
lib/Support/YAMLParser.cpp. This will factor out the only real use of
createNode().
- Evolve the iplist<> and ilist<> APIs in the direction of
simple_ilist<>, making allocation/deallocation explicit at call sites
(similar to simple_ilist<>::eraseAndDispose()).
- Factor out remaining calls to createNode() and deleteNode() and remove
the customization from ilist_traits<>.
- Transition uses of iplist<>/ilist<> that don't need callbacks over to
simple_ilist<>.
llvm-svn: 280107
2016-08-30 18:23:55 +02:00
|
|
|
|
|
|
|
public:
|
2017-06-14 23:42:24 +02:00
|
|
|
using value_type = typename OptionsT::value_type;
|
|
|
|
using pointer = typename OptionsT::pointer;
|
|
|
|
using reference = typename OptionsT::reference;
|
|
|
|
using const_pointer = typename OptionsT::const_pointer;
|
|
|
|
using const_reference = typename OptionsT::const_reference;
|
|
|
|
using iterator = ilist_iterator<OptionsT, false, false>;
|
|
|
|
using const_iterator = ilist_iterator<OptionsT, false, true>;
|
|
|
|
using reverse_iterator = ilist_iterator<OptionsT, true, false>;
|
|
|
|
using const_reverse_iterator = ilist_iterator<OptionsT, true, true>;
|
|
|
|
using size_type = size_t;
|
|
|
|
using difference_type = ptrdiff_t;
|
ADT: Split out simple_ilist, a simple intrusive list
Split out a new, low-level intrusive list type with clear semantics.
Unlike iplist (and ilist), all operations on simple_ilist are intrusive,
and simple_ilist never takes ownership of its nodes. This enables an
intuitive API that has the right defaults for intrusive lists.
- insert() takes references (not pointers!) to nodes (in iplist/ilist,
passing a reference will cause the node to be copied).
- erase() takes only iterators (like std::list), and does not destroy
the nodes.
- remove() takes only references and has the same behaviour as erase().
- clear() does not destroy the nodes.
- The destructor does not destroy the nodes.
- New API {erase,remove,clear}AndDispose() take an extra Disposer
functor for callsites that want to call some disposal routine (e.g.,
std::default_delete).
This list is not currently configurable, and has no callbacks.
The initial motivation was to fix iplist<>::sort to work correctly (even
with callbacks in ilist_traits<>). iplist<> uses simple_ilist<>::sort
directly. The new test in unittests/IR/ModuleTest.cpp crashes without
this commit.
Fixing sort() via a low-level layer provided a good opportunity to:
- Unit test the low-level functionality thoroughly.
- Modernize the API, largely inspired by other intrusive list
implementations.
Here's a sketch of a longer-term plan:
- Create BumpPtrList<>, a non-intrusive list implemented using
simple_ilist<>, and use it for the Token list in
lib/Support/YAMLParser.cpp. This will factor out the only real use of
createNode().
- Evolve the iplist<> and ilist<> APIs in the direction of
simple_ilist<>, making allocation/deallocation explicit at call sites
(similar to simple_ilist<>::eraseAndDispose()).
- Factor out remaining calls to createNode() and deleteNode() and remove
the customization from ilist_traits<>.
- Transition uses of iplist<>/ilist<> that don't need callbacks over to
simple_ilist<>.
llvm-svn: 280107
2016-08-30 18:23:55 +02:00
|
|
|
|
|
|
|
simple_ilist() = default;
|
|
|
|
~simple_ilist() = default;
|
|
|
|
|
|
|
|
// No copy constructors.
|
|
|
|
simple_ilist(const simple_ilist &) = delete;
|
|
|
|
simple_ilist &operator=(const simple_ilist &) = delete;
|
|
|
|
|
|
|
|
// Move constructors.
|
|
|
|
simple_ilist(simple_ilist &&X) { splice(end(), X); }
|
|
|
|
simple_ilist &operator=(simple_ilist &&X) {
|
|
|
|
clear();
|
|
|
|
splice(end(), X);
|
|
|
|
return *this;
|
|
|
|
}
|
|
|
|
|
|
|
|
iterator begin() { return ++iterator(Sentinel); }
|
|
|
|
const_iterator begin() const { return ++const_iterator(Sentinel); }
|
|
|
|
iterator end() { return iterator(Sentinel); }
|
|
|
|
const_iterator end() const { return const_iterator(Sentinel); }
|
|
|
|
reverse_iterator rbegin() { return ++reverse_iterator(Sentinel); }
|
|
|
|
const_reverse_iterator rbegin() const {
|
|
|
|
return ++const_reverse_iterator(Sentinel);
|
|
|
|
}
|
|
|
|
reverse_iterator rend() { return reverse_iterator(Sentinel); }
|
|
|
|
const_reverse_iterator rend() const {
|
|
|
|
return const_reverse_iterator(Sentinel);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Check if the list is empty in constant time.
|
2016-10-16 22:42:34 +02:00
|
|
|
LLVM_NODISCARD bool empty() const { return Sentinel.empty(); }
|
ADT: Split out simple_ilist, a simple intrusive list
Split out a new, low-level intrusive list type with clear semantics.
Unlike iplist (and ilist), all operations on simple_ilist are intrusive,
and simple_ilist never takes ownership of its nodes. This enables an
intuitive API that has the right defaults for intrusive lists.
- insert() takes references (not pointers!) to nodes (in iplist/ilist,
passing a reference will cause the node to be copied).
- erase() takes only iterators (like std::list), and does not destroy
the nodes.
- remove() takes only references and has the same behaviour as erase().
- clear() does not destroy the nodes.
- The destructor does not destroy the nodes.
- New API {erase,remove,clear}AndDispose() take an extra Disposer
functor for callsites that want to call some disposal routine (e.g.,
std::default_delete).
This list is not currently configurable, and has no callbacks.
The initial motivation was to fix iplist<>::sort to work correctly (even
with callbacks in ilist_traits<>). iplist<> uses simple_ilist<>::sort
directly. The new test in unittests/IR/ModuleTest.cpp crashes without
this commit.
Fixing sort() via a low-level layer provided a good opportunity to:
- Unit test the low-level functionality thoroughly.
- Modernize the API, largely inspired by other intrusive list
implementations.
Here's a sketch of a longer-term plan:
- Create BumpPtrList<>, a non-intrusive list implemented using
simple_ilist<>, and use it for the Token list in
lib/Support/YAMLParser.cpp. This will factor out the only real use of
createNode().
- Evolve the iplist<> and ilist<> APIs in the direction of
simple_ilist<>, making allocation/deallocation explicit at call sites
(similar to simple_ilist<>::eraseAndDispose()).
- Factor out remaining calls to createNode() and deleteNode() and remove
the customization from ilist_traits<>.
- Transition uses of iplist<>/ilist<> that don't need callbacks over to
simple_ilist<>.
llvm-svn: 280107
2016-08-30 18:23:55 +02:00
|
|
|
|
|
|
|
/// Calculate the size of the list in linear time.
|
2016-10-16 22:42:34 +02:00
|
|
|
LLVM_NODISCARD size_type size() const {
|
ADT: Split out simple_ilist, a simple intrusive list
Split out a new, low-level intrusive list type with clear semantics.
Unlike iplist (and ilist), all operations on simple_ilist are intrusive,
and simple_ilist never takes ownership of its nodes. This enables an
intuitive API that has the right defaults for intrusive lists.
- insert() takes references (not pointers!) to nodes (in iplist/ilist,
passing a reference will cause the node to be copied).
- erase() takes only iterators (like std::list), and does not destroy
the nodes.
- remove() takes only references and has the same behaviour as erase().
- clear() does not destroy the nodes.
- The destructor does not destroy the nodes.
- New API {erase,remove,clear}AndDispose() take an extra Disposer
functor for callsites that want to call some disposal routine (e.g.,
std::default_delete).
This list is not currently configurable, and has no callbacks.
The initial motivation was to fix iplist<>::sort to work correctly (even
with callbacks in ilist_traits<>). iplist<> uses simple_ilist<>::sort
directly. The new test in unittests/IR/ModuleTest.cpp crashes without
this commit.
Fixing sort() via a low-level layer provided a good opportunity to:
- Unit test the low-level functionality thoroughly.
- Modernize the API, largely inspired by other intrusive list
implementations.
Here's a sketch of a longer-term plan:
- Create BumpPtrList<>, a non-intrusive list implemented using
simple_ilist<>, and use it for the Token list in
lib/Support/YAMLParser.cpp. This will factor out the only real use of
createNode().
- Evolve the iplist<> and ilist<> APIs in the direction of
simple_ilist<>, making allocation/deallocation explicit at call sites
(similar to simple_ilist<>::eraseAndDispose()).
- Factor out remaining calls to createNode() and deleteNode() and remove
the customization from ilist_traits<>.
- Transition uses of iplist<>/ilist<> that don't need callbacks over to
simple_ilist<>.
llvm-svn: 280107
2016-08-30 18:23:55 +02:00
|
|
|
return std::distance(begin(), end());
|
|
|
|
}
|
|
|
|
|
|
|
|
reference front() { return *begin(); }
|
|
|
|
const_reference front() const { return *begin(); }
|
|
|
|
reference back() { return *rbegin(); }
|
|
|
|
const_reference back() const { return *rbegin(); }
|
|
|
|
|
|
|
|
/// Insert a node at the front; never copies.
|
|
|
|
void push_front(reference Node) { insert(begin(), Node); }
|
|
|
|
|
|
|
|
/// Insert a node at the back; never copies.
|
|
|
|
void push_back(reference Node) { insert(end(), Node); }
|
|
|
|
|
|
|
|
/// Remove the node at the front; never deletes.
|
|
|
|
void pop_front() { erase(begin()); }
|
|
|
|
|
|
|
|
/// Remove the node at the back; never deletes.
|
|
|
|
void pop_back() { erase(--end()); }
|
|
|
|
|
|
|
|
/// Swap with another list in place using std::swap.
|
|
|
|
void swap(simple_ilist &X) { std::swap(*this, X); }
|
|
|
|
|
|
|
|
/// Insert a node by reference; never copies.
|
|
|
|
iterator insert(iterator I, reference Node) {
|
2016-09-10 18:28:52 +02:00
|
|
|
list_base_type::insertBefore(*I.getNodePtr(), *this->getNodePtr(&Node));
|
ADT: Split out simple_ilist, a simple intrusive list
Split out a new, low-level intrusive list type with clear semantics.
Unlike iplist (and ilist), all operations on simple_ilist are intrusive,
and simple_ilist never takes ownership of its nodes. This enables an
intuitive API that has the right defaults for intrusive lists.
- insert() takes references (not pointers!) to nodes (in iplist/ilist,
passing a reference will cause the node to be copied).
- erase() takes only iterators (like std::list), and does not destroy
the nodes.
- remove() takes only references and has the same behaviour as erase().
- clear() does not destroy the nodes.
- The destructor does not destroy the nodes.
- New API {erase,remove,clear}AndDispose() take an extra Disposer
functor for callsites that want to call some disposal routine (e.g.,
std::default_delete).
This list is not currently configurable, and has no callbacks.
The initial motivation was to fix iplist<>::sort to work correctly (even
with callbacks in ilist_traits<>). iplist<> uses simple_ilist<>::sort
directly. The new test in unittests/IR/ModuleTest.cpp crashes without
this commit.
Fixing sort() via a low-level layer provided a good opportunity to:
- Unit test the low-level functionality thoroughly.
- Modernize the API, largely inspired by other intrusive list
implementations.
Here's a sketch of a longer-term plan:
- Create BumpPtrList<>, a non-intrusive list implemented using
simple_ilist<>, and use it for the Token list in
lib/Support/YAMLParser.cpp. This will factor out the only real use of
createNode().
- Evolve the iplist<> and ilist<> APIs in the direction of
simple_ilist<>, making allocation/deallocation explicit at call sites
(similar to simple_ilist<>::eraseAndDispose()).
- Factor out remaining calls to createNode() and deleteNode() and remove
the customization from ilist_traits<>.
- Transition uses of iplist<>/ilist<> that don't need callbacks over to
simple_ilist<>.
llvm-svn: 280107
2016-08-30 18:23:55 +02:00
|
|
|
return iterator(&Node);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Insert a range of nodes; never copies.
|
|
|
|
template <class Iterator>
|
|
|
|
void insert(iterator I, Iterator First, Iterator Last) {
|
|
|
|
for (; First != Last; ++First)
|
|
|
|
insert(I, *First);
|
|
|
|
}
|
|
|
|
|
ADT: Add AllocatorList, and use it for yaml::Token
- Add AllocatorList, a non-intrusive list that owns an LLVM-style
allocator and provides a std::list-like interface (trivially built on
top of simple_ilist),
- add a typedef (and unit tests) for BumpPtrList, and
- use BumpPtrList for the list of llvm::yaml::Token (i.e., TokenQueueT).
TokenQueueT has no need for the complexity of an intrusive list. The
only reason to inherit from ilist was to customize the allocator.
TokenQueueT was the only example in-tree of using ilist<> in a truly
non-intrusive way.
Moreover, this removes the final use of the non-intrusive
ilist_traits<>::createNode (after r280573, r281177, and r281181). I
have a WIP patch that removes this customization point (and the API that
relies on it) that I plan to commit soon.
Note: AllocatorList owns the allocator, which limits the viable API
(e.g., splicing must be on the same list). For now I've left out
any problematic API. It wouldn't be hard to split AllocatorList into
two layers: an Impl class that calls DerivedT::getAlloc (via CRTP), and
derived classes that handle Allocator ownership/reference/etc semantics;
and then implement splice with appropriate assertions; but TBH we should
probably just customize the std::list allocators at that point.
llvm-svn: 281182
2016-09-12 00:40:40 +02:00
|
|
|
/// Clone another list.
|
|
|
|
template <class Cloner, class Disposer>
|
|
|
|
void cloneFrom(const simple_ilist &L2, Cloner clone, Disposer dispose) {
|
|
|
|
clearAndDispose(dispose);
|
|
|
|
for (const_reference V : L2)
|
|
|
|
push_back(*clone(V));
|
|
|
|
}
|
|
|
|
|
ADT: Split out simple_ilist, a simple intrusive list
Split out a new, low-level intrusive list type with clear semantics.
Unlike iplist (and ilist), all operations on simple_ilist are intrusive,
and simple_ilist never takes ownership of its nodes. This enables an
intuitive API that has the right defaults for intrusive lists.
- insert() takes references (not pointers!) to nodes (in iplist/ilist,
passing a reference will cause the node to be copied).
- erase() takes only iterators (like std::list), and does not destroy
the nodes.
- remove() takes only references and has the same behaviour as erase().
- clear() does not destroy the nodes.
- The destructor does not destroy the nodes.
- New API {erase,remove,clear}AndDispose() take an extra Disposer
functor for callsites that want to call some disposal routine (e.g.,
std::default_delete).
This list is not currently configurable, and has no callbacks.
The initial motivation was to fix iplist<>::sort to work correctly (even
with callbacks in ilist_traits<>). iplist<> uses simple_ilist<>::sort
directly. The new test in unittests/IR/ModuleTest.cpp crashes without
this commit.
Fixing sort() via a low-level layer provided a good opportunity to:
- Unit test the low-level functionality thoroughly.
- Modernize the API, largely inspired by other intrusive list
implementations.
Here's a sketch of a longer-term plan:
- Create BumpPtrList<>, a non-intrusive list implemented using
simple_ilist<>, and use it for the Token list in
lib/Support/YAMLParser.cpp. This will factor out the only real use of
createNode().
- Evolve the iplist<> and ilist<> APIs in the direction of
simple_ilist<>, making allocation/deallocation explicit at call sites
(similar to simple_ilist<>::eraseAndDispose()).
- Factor out remaining calls to createNode() and deleteNode() and remove
the customization from ilist_traits<>.
- Transition uses of iplist<>/ilist<> that don't need callbacks over to
simple_ilist<>.
llvm-svn: 280107
2016-08-30 18:23:55 +02:00
|
|
|
/// Remove a node by reference; never deletes.
|
|
|
|
///
|
|
|
|
/// \see \a erase() for removing by iterator.
|
|
|
|
/// \see \a removeAndDispose() if the node should be deleted.
|
2016-09-10 18:28:52 +02:00
|
|
|
void remove(reference N) { list_base_type::remove(*this->getNodePtr(&N)); }
|
ADT: Split out simple_ilist, a simple intrusive list
Split out a new, low-level intrusive list type with clear semantics.
Unlike iplist (and ilist), all operations on simple_ilist are intrusive,
and simple_ilist never takes ownership of its nodes. This enables an
intuitive API that has the right defaults for intrusive lists.
- insert() takes references (not pointers!) to nodes (in iplist/ilist,
passing a reference will cause the node to be copied).
- erase() takes only iterators (like std::list), and does not destroy
the nodes.
- remove() takes only references and has the same behaviour as erase().
- clear() does not destroy the nodes.
- The destructor does not destroy the nodes.
- New API {erase,remove,clear}AndDispose() take an extra Disposer
functor for callsites that want to call some disposal routine (e.g.,
std::default_delete).
This list is not currently configurable, and has no callbacks.
The initial motivation was to fix iplist<>::sort to work correctly (even
with callbacks in ilist_traits<>). iplist<> uses simple_ilist<>::sort
directly. The new test in unittests/IR/ModuleTest.cpp crashes without
this commit.
Fixing sort() via a low-level layer provided a good opportunity to:
- Unit test the low-level functionality thoroughly.
- Modernize the API, largely inspired by other intrusive list
implementations.
Here's a sketch of a longer-term plan:
- Create BumpPtrList<>, a non-intrusive list implemented using
simple_ilist<>, and use it for the Token list in
lib/Support/YAMLParser.cpp. This will factor out the only real use of
createNode().
- Evolve the iplist<> and ilist<> APIs in the direction of
simple_ilist<>, making allocation/deallocation explicit at call sites
(similar to simple_ilist<>::eraseAndDispose()).
- Factor out remaining calls to createNode() and deleteNode() and remove
the customization from ilist_traits<>.
- Transition uses of iplist<>/ilist<> that don't need callbacks over to
simple_ilist<>.
llvm-svn: 280107
2016-08-30 18:23:55 +02:00
|
|
|
|
|
|
|
/// Remove a node by reference and dispose of it.
|
|
|
|
template <class Disposer>
|
|
|
|
void removeAndDispose(reference N, Disposer dispose) {
|
|
|
|
remove(N);
|
|
|
|
dispose(&N);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Remove a node by iterator; never deletes.
|
|
|
|
///
|
|
|
|
/// \see \a remove() for removing by reference.
|
|
|
|
/// \see \a eraseAndDispose() it the node should be deleted.
|
|
|
|
iterator erase(iterator I) {
|
|
|
|
assert(I != end() && "Cannot remove end of list!");
|
|
|
|
remove(*I++);
|
|
|
|
return I;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Remove a range of nodes; never deletes.
|
|
|
|
///
|
|
|
|
/// \see \a eraseAndDispose() if the nodes should be deleted.
|
|
|
|
iterator erase(iterator First, iterator Last) {
|
2016-09-10 18:28:52 +02:00
|
|
|
list_base_type::removeRange(*First.getNodePtr(), *Last.getNodePtr());
|
ADT: Split out simple_ilist, a simple intrusive list
Split out a new, low-level intrusive list type with clear semantics.
Unlike iplist (and ilist), all operations on simple_ilist are intrusive,
and simple_ilist never takes ownership of its nodes. This enables an
intuitive API that has the right defaults for intrusive lists.
- insert() takes references (not pointers!) to nodes (in iplist/ilist,
passing a reference will cause the node to be copied).
- erase() takes only iterators (like std::list), and does not destroy
the nodes.
- remove() takes only references and has the same behaviour as erase().
- clear() does not destroy the nodes.
- The destructor does not destroy the nodes.
- New API {erase,remove,clear}AndDispose() take an extra Disposer
functor for callsites that want to call some disposal routine (e.g.,
std::default_delete).
This list is not currently configurable, and has no callbacks.
The initial motivation was to fix iplist<>::sort to work correctly (even
with callbacks in ilist_traits<>). iplist<> uses simple_ilist<>::sort
directly. The new test in unittests/IR/ModuleTest.cpp crashes without
this commit.
Fixing sort() via a low-level layer provided a good opportunity to:
- Unit test the low-level functionality thoroughly.
- Modernize the API, largely inspired by other intrusive list
implementations.
Here's a sketch of a longer-term plan:
- Create BumpPtrList<>, a non-intrusive list implemented using
simple_ilist<>, and use it for the Token list in
lib/Support/YAMLParser.cpp. This will factor out the only real use of
createNode().
- Evolve the iplist<> and ilist<> APIs in the direction of
simple_ilist<>, making allocation/deallocation explicit at call sites
(similar to simple_ilist<>::eraseAndDispose()).
- Factor out remaining calls to createNode() and deleteNode() and remove
the customization from ilist_traits<>.
- Transition uses of iplist<>/ilist<> that don't need callbacks over to
simple_ilist<>.
llvm-svn: 280107
2016-08-30 18:23:55 +02:00
|
|
|
return Last;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Remove a node by iterator and dispose of it.
|
|
|
|
template <class Disposer>
|
|
|
|
iterator eraseAndDispose(iterator I, Disposer dispose) {
|
|
|
|
auto Next = std::next(I);
|
|
|
|
erase(I);
|
|
|
|
dispose(&*I);
|
|
|
|
return Next;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Remove a range of nodes and dispose of them.
|
|
|
|
template <class Disposer>
|
|
|
|
iterator eraseAndDispose(iterator First, iterator Last, Disposer dispose) {
|
|
|
|
while (First != Last)
|
|
|
|
First = eraseAndDispose(First, dispose);
|
|
|
|
return Last;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Clear the list; never deletes.
|
|
|
|
///
|
|
|
|
/// \see \a clearAndDispose() if the nodes should be deleted.
|
|
|
|
void clear() { Sentinel.reset(); }
|
|
|
|
|
|
|
|
/// Clear the list and dispose of the nodes.
|
|
|
|
template <class Disposer> void clearAndDispose(Disposer dispose) {
|
|
|
|
eraseAndDispose(begin(), end(), dispose);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Splice in another list.
|
|
|
|
void splice(iterator I, simple_ilist &L2) {
|
|
|
|
splice(I, L2, L2.begin(), L2.end());
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Splice in a node from another list.
|
|
|
|
void splice(iterator I, simple_ilist &L2, iterator Node) {
|
|
|
|
splice(I, L2, Node, std::next(Node));
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Splice in a range of nodes from another list.
|
|
|
|
void splice(iterator I, simple_ilist &, iterator First, iterator Last) {
|
2016-09-10 18:28:52 +02:00
|
|
|
list_base_type::transferBefore(*I.getNodePtr(), *First.getNodePtr(),
|
|
|
|
*Last.getNodePtr());
|
ADT: Split out simple_ilist, a simple intrusive list
Split out a new, low-level intrusive list type with clear semantics.
Unlike iplist (and ilist), all operations on simple_ilist are intrusive,
and simple_ilist never takes ownership of its nodes. This enables an
intuitive API that has the right defaults for intrusive lists.
- insert() takes references (not pointers!) to nodes (in iplist/ilist,
passing a reference will cause the node to be copied).
- erase() takes only iterators (like std::list), and does not destroy
the nodes.
- remove() takes only references and has the same behaviour as erase().
- clear() does not destroy the nodes.
- The destructor does not destroy the nodes.
- New API {erase,remove,clear}AndDispose() take an extra Disposer
functor for callsites that want to call some disposal routine (e.g.,
std::default_delete).
This list is not currently configurable, and has no callbacks.
The initial motivation was to fix iplist<>::sort to work correctly (even
with callbacks in ilist_traits<>). iplist<> uses simple_ilist<>::sort
directly. The new test in unittests/IR/ModuleTest.cpp crashes without
this commit.
Fixing sort() via a low-level layer provided a good opportunity to:
- Unit test the low-level functionality thoroughly.
- Modernize the API, largely inspired by other intrusive list
implementations.
Here's a sketch of a longer-term plan:
- Create BumpPtrList<>, a non-intrusive list implemented using
simple_ilist<>, and use it for the Token list in
lib/Support/YAMLParser.cpp. This will factor out the only real use of
createNode().
- Evolve the iplist<> and ilist<> APIs in the direction of
simple_ilist<>, making allocation/deallocation explicit at call sites
(similar to simple_ilist<>::eraseAndDispose()).
- Factor out remaining calls to createNode() and deleteNode() and remove
the customization from ilist_traits<>.
- Transition uses of iplist<>/ilist<> that don't need callbacks over to
simple_ilist<>.
llvm-svn: 280107
2016-08-30 18:23:55 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Merge in another list.
|
|
|
|
///
|
|
|
|
/// \pre \c this and \p RHS are sorted.
|
|
|
|
///@{
|
|
|
|
void merge(simple_ilist &RHS) { merge(RHS, std::less<T>()); }
|
|
|
|
template <class Compare> void merge(simple_ilist &RHS, Compare comp);
|
|
|
|
///@}
|
|
|
|
|
|
|
|
/// Sort the list.
|
|
|
|
///@{
|
|
|
|
void sort() { sort(std::less<T>()); }
|
|
|
|
template <class Compare> void sort(Compare comp);
|
|
|
|
///@}
|
|
|
|
};
|
|
|
|
|
2016-09-11 18:20:53 +02:00
|
|
|
template <class T, class... Options>
|
ADT: Split out simple_ilist, a simple intrusive list
Split out a new, low-level intrusive list type with clear semantics.
Unlike iplist (and ilist), all operations on simple_ilist are intrusive,
and simple_ilist never takes ownership of its nodes. This enables an
intuitive API that has the right defaults for intrusive lists.
- insert() takes references (not pointers!) to nodes (in iplist/ilist,
passing a reference will cause the node to be copied).
- erase() takes only iterators (like std::list), and does not destroy
the nodes.
- remove() takes only references and has the same behaviour as erase().
- clear() does not destroy the nodes.
- The destructor does not destroy the nodes.
- New API {erase,remove,clear}AndDispose() take an extra Disposer
functor for callsites that want to call some disposal routine (e.g.,
std::default_delete).
This list is not currently configurable, and has no callbacks.
The initial motivation was to fix iplist<>::sort to work correctly (even
with callbacks in ilist_traits<>). iplist<> uses simple_ilist<>::sort
directly. The new test in unittests/IR/ModuleTest.cpp crashes without
this commit.
Fixing sort() via a low-level layer provided a good opportunity to:
- Unit test the low-level functionality thoroughly.
- Modernize the API, largely inspired by other intrusive list
implementations.
Here's a sketch of a longer-term plan:
- Create BumpPtrList<>, a non-intrusive list implemented using
simple_ilist<>, and use it for the Token list in
lib/Support/YAMLParser.cpp. This will factor out the only real use of
createNode().
- Evolve the iplist<> and ilist<> APIs in the direction of
simple_ilist<>, making allocation/deallocation explicit at call sites
(similar to simple_ilist<>::eraseAndDispose()).
- Factor out remaining calls to createNode() and deleteNode() and remove
the customization from ilist_traits<>.
- Transition uses of iplist<>/ilist<> that don't need callbacks over to
simple_ilist<>.
llvm-svn: 280107
2016-08-30 18:23:55 +02:00
|
|
|
template <class Compare>
|
2016-09-11 18:20:53 +02:00
|
|
|
void simple_ilist<T, Options...>::merge(simple_ilist &RHS, Compare comp) {
|
ADT: Split out simple_ilist, a simple intrusive list
Split out a new, low-level intrusive list type with clear semantics.
Unlike iplist (and ilist), all operations on simple_ilist are intrusive,
and simple_ilist never takes ownership of its nodes. This enables an
intuitive API that has the right defaults for intrusive lists.
- insert() takes references (not pointers!) to nodes (in iplist/ilist,
passing a reference will cause the node to be copied).
- erase() takes only iterators (like std::list), and does not destroy
the nodes.
- remove() takes only references and has the same behaviour as erase().
- clear() does not destroy the nodes.
- The destructor does not destroy the nodes.
- New API {erase,remove,clear}AndDispose() take an extra Disposer
functor for callsites that want to call some disposal routine (e.g.,
std::default_delete).
This list is not currently configurable, and has no callbacks.
The initial motivation was to fix iplist<>::sort to work correctly (even
with callbacks in ilist_traits<>). iplist<> uses simple_ilist<>::sort
directly. The new test in unittests/IR/ModuleTest.cpp crashes without
this commit.
Fixing sort() via a low-level layer provided a good opportunity to:
- Unit test the low-level functionality thoroughly.
- Modernize the API, largely inspired by other intrusive list
implementations.
Here's a sketch of a longer-term plan:
- Create BumpPtrList<>, a non-intrusive list implemented using
simple_ilist<>, and use it for the Token list in
lib/Support/YAMLParser.cpp. This will factor out the only real use of
createNode().
- Evolve the iplist<> and ilist<> APIs in the direction of
simple_ilist<>, making allocation/deallocation explicit at call sites
(similar to simple_ilist<>::eraseAndDispose()).
- Factor out remaining calls to createNode() and deleteNode() and remove
the customization from ilist_traits<>.
- Transition uses of iplist<>/ilist<> that don't need callbacks over to
simple_ilist<>.
llvm-svn: 280107
2016-08-30 18:23:55 +02:00
|
|
|
if (this == &RHS || RHS.empty())
|
|
|
|
return;
|
|
|
|
iterator LI = begin(), LE = end();
|
|
|
|
iterator RI = RHS.begin(), RE = RHS.end();
|
|
|
|
while (LI != LE) {
|
|
|
|
if (comp(*RI, *LI)) {
|
|
|
|
// Transfer a run of at least size 1 from RHS to LHS.
|
|
|
|
iterator RunStart = RI++;
|
|
|
|
RI = std::find_if(RI, RE, [&](reference RV) { return !comp(RV, *LI); });
|
|
|
|
splice(LI, RHS, RunStart, RI);
|
|
|
|
if (RI == RE)
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
++LI;
|
|
|
|
}
|
|
|
|
// Transfer the remaining RHS nodes once LHS is finished.
|
|
|
|
splice(LE, RHS, RI, RE);
|
|
|
|
}
|
|
|
|
|
2016-09-11 18:20:53 +02:00
|
|
|
template <class T, class... Options>
|
ADT: Split out simple_ilist, a simple intrusive list
Split out a new, low-level intrusive list type with clear semantics.
Unlike iplist (and ilist), all operations on simple_ilist are intrusive,
and simple_ilist never takes ownership of its nodes. This enables an
intuitive API that has the right defaults for intrusive lists.
- insert() takes references (not pointers!) to nodes (in iplist/ilist,
passing a reference will cause the node to be copied).
- erase() takes only iterators (like std::list), and does not destroy
the nodes.
- remove() takes only references and has the same behaviour as erase().
- clear() does not destroy the nodes.
- The destructor does not destroy the nodes.
- New API {erase,remove,clear}AndDispose() take an extra Disposer
functor for callsites that want to call some disposal routine (e.g.,
std::default_delete).
This list is not currently configurable, and has no callbacks.
The initial motivation was to fix iplist<>::sort to work correctly (even
with callbacks in ilist_traits<>). iplist<> uses simple_ilist<>::sort
directly. The new test in unittests/IR/ModuleTest.cpp crashes without
this commit.
Fixing sort() via a low-level layer provided a good opportunity to:
- Unit test the low-level functionality thoroughly.
- Modernize the API, largely inspired by other intrusive list
implementations.
Here's a sketch of a longer-term plan:
- Create BumpPtrList<>, a non-intrusive list implemented using
simple_ilist<>, and use it for the Token list in
lib/Support/YAMLParser.cpp. This will factor out the only real use of
createNode().
- Evolve the iplist<> and ilist<> APIs in the direction of
simple_ilist<>, making allocation/deallocation explicit at call sites
(similar to simple_ilist<>::eraseAndDispose()).
- Factor out remaining calls to createNode() and deleteNode() and remove
the customization from ilist_traits<>.
- Transition uses of iplist<>/ilist<> that don't need callbacks over to
simple_ilist<>.
llvm-svn: 280107
2016-08-30 18:23:55 +02:00
|
|
|
template <class Compare>
|
2016-09-11 18:20:53 +02:00
|
|
|
void simple_ilist<T, Options...>::sort(Compare comp) {
|
ADT: Split out simple_ilist, a simple intrusive list
Split out a new, low-level intrusive list type with clear semantics.
Unlike iplist (and ilist), all operations on simple_ilist are intrusive,
and simple_ilist never takes ownership of its nodes. This enables an
intuitive API that has the right defaults for intrusive lists.
- insert() takes references (not pointers!) to nodes (in iplist/ilist,
passing a reference will cause the node to be copied).
- erase() takes only iterators (like std::list), and does not destroy
the nodes.
- remove() takes only references and has the same behaviour as erase().
- clear() does not destroy the nodes.
- The destructor does not destroy the nodes.
- New API {erase,remove,clear}AndDispose() take an extra Disposer
functor for callsites that want to call some disposal routine (e.g.,
std::default_delete).
This list is not currently configurable, and has no callbacks.
The initial motivation was to fix iplist<>::sort to work correctly (even
with callbacks in ilist_traits<>). iplist<> uses simple_ilist<>::sort
directly. The new test in unittests/IR/ModuleTest.cpp crashes without
this commit.
Fixing sort() via a low-level layer provided a good opportunity to:
- Unit test the low-level functionality thoroughly.
- Modernize the API, largely inspired by other intrusive list
implementations.
Here's a sketch of a longer-term plan:
- Create BumpPtrList<>, a non-intrusive list implemented using
simple_ilist<>, and use it for the Token list in
lib/Support/YAMLParser.cpp. This will factor out the only real use of
createNode().
- Evolve the iplist<> and ilist<> APIs in the direction of
simple_ilist<>, making allocation/deallocation explicit at call sites
(similar to simple_ilist<>::eraseAndDispose()).
- Factor out remaining calls to createNode() and deleteNode() and remove
the customization from ilist_traits<>.
- Transition uses of iplist<>/ilist<> that don't need callbacks over to
simple_ilist<>.
llvm-svn: 280107
2016-08-30 18:23:55 +02:00
|
|
|
// Vacuously sorted.
|
|
|
|
if (empty() || std::next(begin()) == end())
|
|
|
|
return;
|
|
|
|
|
|
|
|
// Split the list in the middle.
|
|
|
|
iterator Center = begin(), End = begin();
|
|
|
|
while (End != end() && ++End != end()) {
|
|
|
|
++Center;
|
|
|
|
++End;
|
|
|
|
}
|
2016-09-11 18:20:53 +02:00
|
|
|
simple_ilist RHS;
|
ADT: Split out simple_ilist, a simple intrusive list
Split out a new, low-level intrusive list type with clear semantics.
Unlike iplist (and ilist), all operations on simple_ilist are intrusive,
and simple_ilist never takes ownership of its nodes. This enables an
intuitive API that has the right defaults for intrusive lists.
- insert() takes references (not pointers!) to nodes (in iplist/ilist,
passing a reference will cause the node to be copied).
- erase() takes only iterators (like std::list), and does not destroy
the nodes.
- remove() takes only references and has the same behaviour as erase().
- clear() does not destroy the nodes.
- The destructor does not destroy the nodes.
- New API {erase,remove,clear}AndDispose() take an extra Disposer
functor for callsites that want to call some disposal routine (e.g.,
std::default_delete).
This list is not currently configurable, and has no callbacks.
The initial motivation was to fix iplist<>::sort to work correctly (even
with callbacks in ilist_traits<>). iplist<> uses simple_ilist<>::sort
directly. The new test in unittests/IR/ModuleTest.cpp crashes without
this commit.
Fixing sort() via a low-level layer provided a good opportunity to:
- Unit test the low-level functionality thoroughly.
- Modernize the API, largely inspired by other intrusive list
implementations.
Here's a sketch of a longer-term plan:
- Create BumpPtrList<>, a non-intrusive list implemented using
simple_ilist<>, and use it for the Token list in
lib/Support/YAMLParser.cpp. This will factor out the only real use of
createNode().
- Evolve the iplist<> and ilist<> APIs in the direction of
simple_ilist<>, making allocation/deallocation explicit at call sites
(similar to simple_ilist<>::eraseAndDispose()).
- Factor out remaining calls to createNode() and deleteNode() and remove
the customization from ilist_traits<>.
- Transition uses of iplist<>/ilist<> that don't need callbacks over to
simple_ilist<>.
llvm-svn: 280107
2016-08-30 18:23:55 +02:00
|
|
|
RHS.splice(RHS.end(), *this, Center, end());
|
|
|
|
|
|
|
|
// Sort the sublists and merge back together.
|
|
|
|
sort(comp);
|
|
|
|
RHS.sort(comp);
|
|
|
|
merge(RHS, comp);
|
|
|
|
}
|
|
|
|
|
|
|
|
} // end namespace llvm
|
|
|
|
|
|
|
|
#endif // LLVM_ADT_SIMPLE_ILIST_H
|