Skip to content

Commit

Permalink
[container] Implement LinkedList as std::list
Browse files Browse the repository at this point in the history
  • Loading branch information
chris-durand committed Jul 21, 2024
1 parent 55a003a commit 5fcd015
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 615 deletions.
41 changes: 38 additions & 3 deletions src/modm/container/doubly_linked_list.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ namespace modm
public:
using const_iterator = std::list<T>::const_iterator;
using iterator = std::list<T>::iterator;
using Size = std::size_t;

DoublyLinkedList(const Allocator& allocator = Allocator())
: data_(allocator)
Expand Down Expand Up @@ -63,10 +64,11 @@ namespace modm
}

/// Insert at the end of the list
void
bool
append(const T& value)
{
data_.push_back(value);
return true;
}

/// Remove the first entry
Expand All @@ -82,6 +84,12 @@ namespace modm
data_.pop_back();
}

T&
getFront()
{
return data_.front();
}

/**
* \return the first node in the list
*/
Expand All @@ -91,6 +99,12 @@ namespace modm
return data_.front();
}

T&
getBack()
{
return data_.back();
}

/**
* \return the last node in the list
*/
Expand All @@ -100,7 +114,6 @@ namespace modm
return data_.back();
}

public:
/**
* Returns a read/write iterator that points to the first element in the
* list. Iteration is done in ordinary element order.
Expand Down Expand Up @@ -153,7 +166,29 @@ namespace modm
iterator
erase(iterator position)
{
return data_.erase(position);
if (position != data_.end()) {
return data_.erase(position);
} else {
return data_.end();
}
}

/**
* Insert data after position iterator.
*
* This behavior is compatible with modm::LinkedList but different
* compared to std::list which inserts before the position iterator
* argument.
*/
bool
insert(iterator position, const T& value)
{
if (position == data_.end()) {
data_.push_back(value);
} else {
data_.insert(std::next(position), value);
}
return true;
}

private:
Expand Down
220 changes: 20 additions & 200 deletions src/modm/container/linked_list.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* Copyright (c) 2012, Niklas Hauser
* Copyright (c) 2013-2014, Sascha Schade
* Copyright (c) 2015, Kevin Läufer
* Copyright (c) 2023, Christopher Durand
*
* This file is part of the modm project.
*
Expand All @@ -16,9 +17,7 @@
#ifndef MODM_LINKED_LIST_HPP
#define MODM_LINKED_LIST_HPP

#include <stdint.h>
#include <iterator>
#include <modm/utils/allocator.hpp>
#include <modm/container/doubly_linked_list.hpp>

namespace modm
{
Expand All @@ -34,210 +33,31 @@ namespace modm
*
* \author Fabian Greif
* \ingroup modm_container
*
* \todo TODO: implementated as doubly-linked list
* std::forward_list does not save both front and back pointers.
* This would make operations in xpcc very inefficient.
*/
template <typename T, typename Allocator = allocator::Dynamic<T> >
class LinkedList
template <typename T, typename Allocator = std::allocator<T>>
class LinkedList : public DoublyLinkedList<T, Allocator>
{
public:
typedef std::size_t Size;

public:
LinkedList(const Allocator& allocator = Allocator());

~LinkedList();

/// check if there are any nodes in the list
inline bool
isEmpty() const;

/**
* \brief Get number of elements
*
* \warning This method is slow because it has to iterate through
* all elements.
*/
std::size_t
getSize() const;

/// Insert in front
bool
prepend(const T& value);

/// Insert at the end of the list
bool
append(const T& value);

/// Remove the first entry
void
removeFront();

/**
* \return the first node in the list
*/
inline const T&
getFront() const;

inline T&
getFront();
using DoublyLinkedList<T, Allocator>::DoublyLinkedList;
using iterator = DoublyLinkedList<T, Allocator>::iterator;

/**
* \return the last node in the list
*/
inline const T&
getBack() const;

inline T&
getBack();

/**
* \brief Remove all elements form the list
*/
void
removeAll();

protected:
struct Node
{
T value;
Node *next;
};

// The stored instance is not actually of type Allocator. Instead we
// rebind the type to Allocator<Node<T>>. Node<T> is not the same
// size as T (it's one pointer larger), and specializations on T may go
// unused because Node<T> is being bound instead.
typedef typename Allocator::template rebind< Node >::other NodeAllocator;

NodeAllocator nodeAllocator;

Node *front;
Node *back;

public:
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
/**
* \brief Forward iterator
*/
class iterator : public std::iterator<std::forward_iterator_tag, T>
iterator
remove(const iterator& position)
{
friend class LinkedList;
friend class const_iterator;

public:
/// Default constructor
iterator();
iterator(const iterator& other);
return this->erase(position);
}

iterator& operator = (const iterator& other);
iterator& operator ++ ();
bool operator == (const iterator& other) const;
bool operator != (const iterator& other) const;
T& operator * ();
T* operator -> ();

private:
iterator(Node* node);

Node* node;
};

/**
* \brief forward const iterator
*/
class const_iterator : public std::iterator<std::forward_iterator_tag, T>
void
removeAll()
{
friend class LinkedList;

public:
/// Default constructor
const_iterator();

/**
* \brief Copy construtor
*
* Used to convert a normal iterator to a const iterator.
* The other way is not possible.
*/
const_iterator(const iterator& other);

/**
* \brief Copy construtor
*/
const_iterator(const const_iterator& other);

const_iterator& operator = (const const_iterator& other);
const_iterator& operator ++ ();
bool operator == (const const_iterator& other) const;
bool operator != (const const_iterator& other) const;
const T& operator * () const;
const T* operator -> () const;

private:
const_iterator(Node* node);
// TODO: this should acutally be a node that points to a const
// value, but since all access is const, this does not really make
// a difference
Node* node;
};
#pragma GCC diagnostic pop

/**
* Returns a read/write iterator that points to the first element in the
* list. Iteration is done in ordinary element order.
*/
iterator
begin();

/**
* Returns a read-only (constant) iterator that points to the
* first element in the list. Iteration is done in ordinary
* element order.
*/
const_iterator
begin() const;

/**
* Returns a read/write iterator that points one past the last
* element in the list. Iteration is done in ordinary element
* order.
*/
iterator
end();

/**
* Returns a read-only (constant) iterator that points one past
* the last element in the list. Iteration is done in ordinary
* element order.
*/
const_iterator
end() const;

/**
* \brief Erase element
*
* Removes a single element from the list container.
* This effectively reduces the list size by one, calling the element's
* destructor before.
*/
iterator
remove(const iterator& position);

bool
insert(const_iterator pos, const T& value);

private:
friend class const_iterator;
friend class iterator;

LinkedList(const LinkedList& other);

LinkedList&
operator = (const LinkedList& other);
while (!this->isEmpty()) {
this->removeFront();
}
}
};
}

#include "linked_list_impl.hpp"
#include "linked_list_iterator_impl.hpp"

#endif // MODM_LINKED_LIST_HPP
Loading

0 comments on commit 5fcd015

Please sign in to comment.