diff --git a/README.md b/README.md
index 0417c9b..e7275c5 100644
--- a/README.md
+++ b/README.md
@@ -1,17 +1,12 @@
# cpp-xor-list [](https://travis-ci.org/NikitkoCent/cpp-xor-list) [](https://codecov.io/gh/NikitkoCent/cpp-xor-list) [](https://github.com/NikitkoCent/cpp-xor-list/blob/master/LICENSE)
C++11-compatible implementation of [XOR linked list](https://en.wikipedia.org/wiki/XOR_linked_list)
-with STL-like interface. Most of C++14 `std::list` methods are supported.
+with STL-like interface. Most of C++14 `std::list` methods are also supported.
Notes
### Not supported methods:
-* `std::list::emplace` (but `std::list::emplace_` are supported) - may be added later
-* comparison operators (`operator==`, `operator<=` etc) - may be added later
-* `std::list::max_size` - may be added later
-* `std::list::get_allocator` - may be added later
-* `std::list::remove_if` - may be added later
-* `std::erase_if` - may be added later
+* `std::erase_if` - will be added after C++20 release
## Example
diff --git a/include/xor_list/xor_list.h b/include/xor_list/xor_list.h
index 12dba6a..82a2109 100644
--- a/include/xor_list/xor_list.h
+++ b/include/xor_list/xor_list.h
@@ -9,12 +9,13 @@
#include // ::std::conditional, ::std::enable_if, ::std::is_base_of
#include // ::std::uint*_t
#include // ::std::ptrdiff_t
-#include // ::std::swap
+#include // ::std::swap, ::std::equal, ::std::lexicographical_compare
#include // ::std::tie
#include // ::std::array
+#include // ::std::numeric_limits
-template >
+template>
class xor_list
{
private:
@@ -134,7 +135,7 @@ class xor_list
}
}
- virtual ~xor_list()
+ ~xor_list()
{
clear();
}
@@ -157,6 +158,11 @@ class xor_list
return *this;
}
+ allocator_type get_allocator() const
+ {
+ return allocator_type(allocator);
+ }
+
void swap(xor_list &other)
{
swapImpl(other);
@@ -182,16 +188,16 @@ class xor_list
emplace_front(::std::move(data));
}
- template
+ template
void emplace_back(Args&&... args)
{
- (void)insertNodeToThisBefore(cend(), createNode(::std::forward(args)...));
+ (void)emplace(cend(), ::std::forward(args)...);
}
- template
+ template
void emplace_front(Args&&... args)
{
- (void)insertNodeToThisBefore(cbegin(), createNode(::std::forward(args)...));
+ (void)emplace(cbegin(), ::std::forward(args)...);
}
void pop_front()
@@ -209,6 +215,11 @@ class xor_list
return length;
}
+ size_type max_size() const noexcept
+ {
+ return ::std::numeric_limits::max() / sizeof(NodeWithValue);
+ }
+
bool empty() const noexcept
{
return (size() == 0);
@@ -219,22 +230,22 @@ class xor_list
destroySequence(cbegin(), cend(), size());
}
- T& back() noexcept
+ T& back()
{
return *(--end());
}
- const T& back() const noexcept
+ const T& back() const
{
return *(--cend());
}
- T& front() noexcept
+ T& front()
{
return *begin();
}
- const T& front() const noexcept
+ const T& front() const
{
return *cbegin();
}
@@ -270,13 +281,13 @@ class xor_list
return { reinterpret_cast(afterTail.xorPtr), &afterTail };
}
- void sort() noexcept
+ void sort()
{
sort(::std::less{});
}
- template
- void sort(Compare isLess) noexcept
+ template
+ void sort(Compare isLess)
{
using Range = ::std::pair;
struct NullableRange
@@ -347,13 +358,12 @@ class xor_list
// strong exception-safe guarantee
iterator insert(const_iterator position, const_reference val)
{
- //insertNodeToThisBefore noexcept!
- return insertNodeToThisBefore(position, createNode(val)).first;
+ return emplace(position, val);
}
// WARNING! Iterators equal to position will become invalid
// strong exception-safe guarantee
- template
+ template
iterator insert(const_iterator position, InputIterator first, InputIterator last)
{
if (first == last)
@@ -381,7 +391,17 @@ class xor_list
return result;
}
+ // WARNING! Iterators equal to position will become invalid
+ // strong exception-safe guarantee
+ template
+ iterator emplace(const_iterator position, Args&&... args)
+ {
+ //insertNodeToThisBefore noexcept!
+ return insertNodeToThisBefore(position, createNode(::std::forward(args)...)).first;
+ }
+
// WARNING! All iterators will become invalid
+ // Complexity: O(1)
void reverse() noexcept
{
if (empty())
@@ -418,6 +438,32 @@ class xor_list
return { first.prev, last.current };
}
+ size_type remove(const T &value)
+ {
+ return remove_if([&value](const T &elem) { return (elem == value); });
+ }
+
+ template
+ size_type remove_if(UnaryPredicate p)
+ {
+ size_type result = 0;
+
+ for (const_iterator iter = cbegin(); iter != cend();)
+ {
+ if (p(*iter))
+ {
+ iter = erase(iter);
+ ++result;
+ }
+ else
+ {
+ ++iter;
+ }
+ }
+
+ return result;
+ }
+
void resize(size_type count)
{
resizeImpl(count);
@@ -428,7 +474,7 @@ class xor_list
resizeImpl(count, val);
}
- template
+ template
typename ::std::enable_if<::std::is_base_of<::std::input_iterator_tag,
typename ::std::iterator_traits::iterator_category>::value>::type
assign(InputIterator first, InputIterator last)
@@ -478,7 +524,7 @@ class xor_list
}
- void splice(const_iterator position, xor_list &x) noexcept
+ void splice(const_iterator position, xor_list &x)
{
if ((this == ::std::addressof(x)) || (x.empty()))
{
@@ -491,7 +537,7 @@ class xor_list
(void)insertSequenceToThisBefore(position, range.first, range.second, distance);
}
- void splice(const_iterator position, xor_list &x, const_iterator i) noexcept
+ void splice(const_iterator position, xor_list &x, const_iterator i)
{
if ((this == ::std::addressof(x)) && ((position == i) || (position.prev == i.current)))
{
@@ -502,7 +548,7 @@ class xor_list
(void)insertNodeToThisBefore(position, static_cast(range.first.current));
}
- void splice(const_iterator position, xor_list &x, const_iterator first, const_iterator last) noexcept
+ void splice(const_iterator position, xor_list &x, const_iterator first, const_iterator last)
{
if (first == last)
{
@@ -522,7 +568,7 @@ class xor_list
}
// All iterators will become invalid
- template
+ template
void unique(BinaryPredicate isEqual)
{
if (size() < 2)
@@ -545,14 +591,14 @@ class xor_list
}
// All iterators from *this and x will become invalid
- void merge(xor_list &x) noexcept
+ void merge(xor_list &x)
{
merge(x, ::std::less{});
}
// All iterators from *this and x will become invalid
- template
- void merge(xor_list &x, Compare isLess) noexcept
+ template
+ void merge(xor_list &x, Compare isLess)
{
if (!x.empty())
{
@@ -595,14 +641,14 @@ class xor_list
Node(const Node&) noexcept = default;
Node(Node &&) noexcept = default;
-
+
virtual ~Node() = default;
Node& operator=(const Node&) noexcept = default;
Node& operator=(Node &&) noexcept = default;
};
- struct NodeWithValue : Node
+ struct NodeWithValue final : Node
{
T value;
@@ -723,7 +769,7 @@ class xor_list
};
- struct CutResult
+ struct CutResult final
{
::std::pair cutted;
iterator end;
@@ -788,10 +834,8 @@ class xor_list
return insertNodeBefore(position, node);
}
- /*
- * All iterators equal to will become invalid
- * Returns valid range [inserted, position]
- */
+ // All iterators equal to will become invalid
+ // Returns valid range [inserted, position]
static ::std::pair
insertNodeBefore(const_iterator position, NodeWithValue *const node) noexcept
{
@@ -819,11 +863,10 @@ class xor_list
return insertSequenceBefore(position, begin, end);
}
- /*
- * All iterators equal to , will become invalid
- * Iterators equal to end still remains valid (--end == result.second)
- * Returns valid range [begin, position]
- */
+
+ // All iterators equal to , will become invalid
+ // Iterators equal to end still remains valid (--end == result.second)
+ // Returns valid range [begin, position]
static ::std::pair
insertSequenceBefore(const_iterator position, const_iterator begin,
const_iterator end) noexcept
@@ -852,14 +895,12 @@ class xor_list
return cutSequence(first, last);
}
- /*
- * Returns iterators to the first cutted and following the last cutted elements
- * Decrement result.first or increment result.second is UB
- * Dereference result.second is UB
- * Increment and dereference result.first are still valid
- * Decrement result.second returns is an iterator to the last cutted element
- * Iterators equal to begin, end will become invalid
- */
+ // Returns iterators to the first cutted and following the last cutted elements
+ // Decrement result.first or increment result.second is UB
+ // Dereference result.second is UB
+ // Increment and dereference result.first are still valid
+ // Decrement result.second returns is an iterator to the last cutted element
+ // Iterators equal to begin, end will become invalid
static CutResult
cutSequence(const_iterator begin, const_iterator end) noexcept
{
@@ -1026,10 +1067,8 @@ class xor_list
return mergeSequences(beginTo, endTo, beginFrom, endFrom, ::std::forward(isLess));
}
- /*
- * All iterators will become invalid
- * Return new range [first, second)
- */
+ // All iterators will become invalid
+ // Return new range [first, second)
template
static ::std::pair
mergeSequences(const_iterator beginTo, const_iterator endTo,
@@ -1080,4 +1119,43 @@ class xor_list
}
};
+
+// Comparison operators
+
+template
+bool operator==(const xor_list &lhs, const xor_list &rhs)
+{
+ return ((lhs.size() == rhs.size()) && (::std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin())));
+}
+
+template
+bool operator!=(const xor_list &lhs, const xor_list &rhs)
+{
+ return (!(lhs == rhs));
+}
+
+template
+bool operator<(const xor_list &lhs, const xor_list &rhs)
+{
+ return ::std::lexicographical_compare(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend());
+}
+
+template
+bool operator>(const xor_list &lhs, const xor_list &rhs)
+{
+ return (rhs < lhs);
+}
+
+template
+bool operator<=(const xor_list &lhs, const xor_list &rhs)
+{
+ return (!(rhs < lhs));
+}
+
+template
+bool operator>=(const xor_list &lhs, const xor_list &rhs)
+{
+ return (!(lhs < rhs));
+}
+
#endif //XORLIST_XOR_LIST_H
diff --git a/tests/list.cpp b/tests/list.cpp
index b713c0f..3fd5a1b 100644
--- a/tests/list.cpp
+++ b/tests/list.cpp
@@ -5,6 +5,7 @@
#include
#include
#include
+#include
template
@@ -1089,6 +1090,22 @@ TEST(LIST, EMPLACE2)
ASSERT_THAT(list, ::testing::ElementsAre(2, 1, 0, -1));
}
+TEST(LIST, EMPLACE3)
+{
+ xor_list> list{2, 1, 0, -1};
+
+ auto emplacedIter1 = list.emplace(++++list.cbegin(), 10);
+ auto emplacedIter2 = list.emplace(std::next(emplacedIter1), 20);
+
+ ASSERT_EQ(list.size(), 6U);
+ ASSERT_THAT(list, ::testing::ElementsAre(2, 1, 10, 20, 0, -1));
+
+ ASSERT_EQ(*emplacedIter1, 10);
+ ASSERT_EQ(*emplacedIter2, 20);
+
+ ASSERT_EQ(++emplacedIter1, emplacedIter2);
+}
+
TEST(LIST, EMPLACE_EXCEPTION1)
{
xor_list> list;
@@ -2293,3 +2310,178 @@ TEST(LIST, INSERT_RANGE_EXCEPTION2)
ASSERT_EQ(list.size(), 4U);
ASSERT_THAT(list, ::testing::ElementsAre(100, 200, 300, 400));
}
+
+TEST(LIST, REMOVE_EMPTY)
+{
+ xor_list> list;
+
+ ASSERT_EQ(list.remove(1), 0U);
+
+ ASSERT_TRUE(list.empty());
+}
+
+TEST(LIST, REMOVE_SINGLE)
+{
+ xor_list> list{1};
+
+ ASSERT_EQ(list.remove(1), 1U);
+
+ ASSERT_TRUE(list.empty());
+}
+
+TEST(LIST, REMOVE_ALL)
+{
+ xor_list> list{1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
+
+ ASSERT_EQ(list.remove(1), 10U);
+
+ ASSERT_TRUE(list.empty());
+}
+
+TEST(LIST, REMOVE_MIDDLE)
+{
+ xor_list> list{0, 0, 0, 1, 1, 1, 0, 1, 0, 0};
+
+ ASSERT_EQ(list.remove(1), 4U);
+
+ ASSERT_EQ(list.size(), 6U);
+ ASSERT_THAT(list, ::testing::ElementsAre(0, 0, 0, 0, 0, 0));
+}
+
+TEST(LIST, REMOVE_IF_EMPTY)
+{
+ xor_list> list;
+
+ ASSERT_EQ(list.remove_if([](const Value &val) { return val > 0; }), 0U);
+
+ ASSERT_TRUE(list.empty());
+}
+
+TEST(LIST, REMOVE_IF_SINGLE)
+{
+ xor_list> list{1};
+
+ ASSERT_EQ(list.remove_if([](const Value &val) { return val > 0; }), 1U);
+
+ ASSERT_TRUE(list.empty());
+}
+
+TEST(LIST, REMOVE_IF_ALL)
+{
+ xor_list> list{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+
+ ASSERT_EQ(list.remove_if([](const Value &) { return true; }), 10U);
+
+ ASSERT_TRUE(list.empty());
+}
+
+TEST(LIST, REMOVE_IF_MIDDLE)
+{
+ xor_list> list{1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+
+ ASSERT_EQ(list.remove_if([](const Value &val) { return ((val > 3) && (val < 8)); }), 4U);
+
+ ASSERT_EQ(list.size(), 6U);
+ ASSERT_THAT(list, ::testing::ElementsAre(1, 2, 3, 8, 9, 10));
+}
+
+TEST(LIST, MAX_SIZE_INVOKE)
+{
+ xor_list> list;
+ (void)list.max_size();
+}
+
+TEST(LIST, COMPARISON_EMPTY_EMPTY)
+{
+ xor_list> list, list2;
+
+ ASSERT_TRUE(list == list2);
+ ASSERT_FALSE(list != list2);
+ ASSERT_FALSE(list < list2);
+ ASSERT_TRUE(list <= list2);
+ ASSERT_FALSE(list > list2);
+ ASSERT_TRUE(list >= list2);
+
+ ASSERT_TRUE(list2 == list);
+ ASSERT_FALSE(list2 != list);
+ ASSERT_FALSE(list2 < list);
+ ASSERT_TRUE(list2 <= list);
+ ASSERT_FALSE(list2 > list);
+ ASSERT_TRUE(list2 >= list);
+}
+
+TEST(LIST, COMPARISON_EMPTY_SINGLE)
+{
+ xor_list> list, list2{1};
+
+ ASSERT_FALSE(list == list2);
+ ASSERT_TRUE(list != list2);
+ ASSERT_TRUE(list < list2);
+ ASSERT_TRUE(list <= list2);
+ ASSERT_FALSE(list > list2);
+ ASSERT_FALSE(list >= list2);
+
+ ASSERT_FALSE(list2 == list);
+ ASSERT_TRUE(list2 != list);
+ ASSERT_FALSE(list2 < list);
+ ASSERT_FALSE(list2 <= list);
+ ASSERT_TRUE(list2 > list);
+ ASSERT_TRUE(list2 >= list);
+}
+
+TEST(LIST, COMPARISON_SINGLE_SINGLE)
+{
+ xor_list> list{1}, list2{2};
+
+ ASSERT_FALSE(list == list2);
+ ASSERT_TRUE(list != list2);
+ ASSERT_TRUE(list < list2);
+ ASSERT_TRUE(list <= list2);
+ ASSERT_FALSE(list > list2);
+ ASSERT_FALSE(list >= list2);
+
+ ASSERT_FALSE(list2 == list);
+ ASSERT_TRUE(list2 != list);
+ ASSERT_FALSE(list2 < list);
+ ASSERT_FALSE(list2 <= list);
+ ASSERT_TRUE(list2 > list);
+ ASSERT_TRUE(list2 >= list);
+}
+
+TEST(LIST, COMPARISON_GENERIC1)
+{
+ xor_list> list{1, 2, 3, 4, 5}, list2{1, 2, 3};
+
+ ASSERT_FALSE(list == list2);
+ ASSERT_TRUE(list != list2);
+ ASSERT_FALSE(list < list2);
+ ASSERT_FALSE(list <= list2);
+ ASSERT_TRUE(list > list2);
+ ASSERT_TRUE(list >= list2);
+
+ ASSERT_FALSE(list2 == list);
+ ASSERT_TRUE(list2 != list);
+ ASSERT_TRUE(list2 < list);
+ ASSERT_TRUE(list2 <= list);
+ ASSERT_FALSE(list2 > list);
+ ASSERT_FALSE(list2 >= list);
+}
+
+TEST(LIST, COMPARISON_GENERIC2)
+{
+ xor_list> list{1, 2, 3, 4, 5}, list2{10, 9, 8, 7, 6};
+
+ ASSERT_FALSE(list == list2);
+ ASSERT_TRUE(list != list2);
+ ASSERT_TRUE(list < list2);
+ ASSERT_TRUE(list <= list2);
+ ASSERT_FALSE(list > list2);
+ ASSERT_FALSE(list >= list2);
+
+ ASSERT_FALSE(list2 == list);
+ ASSERT_TRUE(list2 != list);
+ ASSERT_FALSE(list2 < list);
+ ASSERT_FALSE(list2 <= list);
+ ASSERT_TRUE(list2 > list);
+ ASSERT_TRUE(list2 >= list);
+}