Skip to content

Commit

Permalink
feat: linked list
Browse files Browse the repository at this point in the history
  • Loading branch information
6lr61 committed May 7, 2024
1 parent 865a752 commit 9563137
Show file tree
Hide file tree
Showing 3 changed files with 191 additions and 11 deletions.
15 changes: 4 additions & 11 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,17 +1,10 @@
VPATH = src
DIST = dist
CPPFLAGS =
CXXFLAGS = -Wall -Wextra -Werror -Wpedantic -std=c++23
CXX = g++

all: $(DIST)/test dist
all: tests

dist:
mkdir dist
tests:
cd test && $(MAKE)

$(DIST)/test: linked-list/test.cpp
$(CXX) $(CPPFLAGS) $(CXXFLAGS) -o $@ $^

PHONY clean:
clean:
-rm dist/*
cd test && $(MAKE) clean
117 changes: 117 additions & 0 deletions src/linked_list.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#ifndef LINKED_LIST_HPP
#define LINKED_LIST_HPP

#include <algorithm>
#include <utility>

template <typename T> class LinkedList {
private:
struct Node {
Node *next = nullptr;
T value;

Node(T v) : value(std::move(v)){};

~Node() = default;
};

Node *head = nullptr;

class Iterator {
public:
using iterator_category = std::forward_iterator_tag;
using difference_type = std::ptrdiff_t;
using element_type = T;
using value_type = T;
using pointer = Node *;
using reference = T &;

private:
Node *node = nullptr;
Node *sentinel = nullptr;
static_assert(std::sentinel_for<decltype(sentinel), decltype(node)>);

public:
Iterator() {}

Iterator(pointer n) : node(n) {}

reference operator*() const { return node->value; }

pointer operator->() const { return node; }

Iterator &operator++() {
if (node != sentinel) {
node = node->next;
}

return *this;
}

Iterator operator++(int) {
auto old = *this;
++(*this);
return old;
}

friend bool operator==(const Iterator &a, const Iterator &b) {
return a.node == b.node;
};
};

static_assert(std::forward_iterator<Iterator>);

public:
LinkedList() = default;

~LinkedList() { clear(); }

void clear() {
Node *current = head;

while (current) {
Node *previous = current;
current = current->next;
delete previous;
}

head = nullptr;
}

Iterator begin() const { return Iterator{head}; }

Iterator end() const { return Iterator{nullptr}; }

bool empty() { return head == nullptr; }

T &front() { return head->value; }

void push_front(T value) {
Node *node = new Node(std::move(value));

if (empty()) {
head = node;
} else {
node->next = head;
head = node;
}
}

template <class... Args> T &emplace_front(Args &&...args) {
T value(std::forward<Args>(args)...);

push_front(std::move(value));

return front();
}

void pop_front() noexcept {
if (!empty()) {
Node *next = head->next;
delete head;
head = next;
}
}
};

#endif
70 changes: 70 additions & 0 deletions test/linked_list.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#include <algorithm>
#include <catch2/catch_test_macros.hpp>
#include <iostream>
#include <string>
#include <vector>

#include "../src/linked_list.hpp"

TEST_CASE("Initialize a new list") {
LinkedList<int> list;

REQUIRE(list.empty());
}

TEST_CASE("Add element to list") {
LinkedList<int> list;
list.push_front(123);

REQUIRE(list.front() == 123);
}

TEST_CASE("Move element to list") {
LinkedList<std::string> list;
std::string string{"Hello, Twitch!"};
list.push_front(std::move(string));

REQUIRE(list.front() == "Hello, Twitch!");
REQUIRE(string == "");
}

TEST_CASE("Clear list") {
LinkedList<int> list;
list.push_front(123);
list.push_front(234);
list.push_front(345);
list.clear();

REQUIRE(list.empty());
}

TEST_CASE("Create value and push to list") {
LinkedList<std::string> list;
std::string string = list.emplace_front("Hello, Twitch!");

REQUIRE(string == "Hello, Twitch!");
REQUIRE(list.front() == "Hello, Twitch!");
}

TEST_CASE("Pop a single element") {
LinkedList<int> list;
list.push_front(123);

REQUIRE(!list.empty());

list.pop_front();

REQUIRE(list.empty());
}

TEST_CASE("Print content") {
LinkedList<int> list;
list.push_front(123);
list.push_front(234);
list.push_front(345);

std::vector<int> vector;
vector.assign(list.begin(), list.end());

REQUIRE(vector == std::vector{345, 234, 123});
}

0 comments on commit 9563137

Please sign in to comment.