This header first appeared in 4.4BSD and is provided by a number of C libraries including Newlib. Several of our embedded projects use this header and so to make LLVM libc a drop-in replacement, we need to provide it as well. For the initial commit, we only implement singly linked variants (SLIST and STAILQ). The doubly linked variants (LIST, TAILQ and CIRCLEQ) can be implemented in the future as needed.
169 lines
3.7 KiB
C++
169 lines
3.7 KiB
C++
//===-- Unittests for queue -----------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDSList-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "src/__support/CPP/string.h"
|
|
#include "src/__support/char_vector.h"
|
|
#include "test/UnitTest/Test.h"
|
|
|
|
#include "llvm-libc-macros/sys-queue-macros.h"
|
|
|
|
using LIBC_NAMESPACE::CharVector;
|
|
using LIBC_NAMESPACE::cpp::string;
|
|
|
|
namespace LIBC_NAMESPACE {
|
|
|
|
TEST(LlvmLibcQueueTest, SList) {
|
|
struct Entry {
|
|
char c;
|
|
SLIST_ENTRY(Entry) entries;
|
|
};
|
|
|
|
SLIST_HEAD(Head, Entry);
|
|
|
|
Head head = SLIST_HEAD_INITIALIZER(head);
|
|
|
|
struct Contains : public testing::Matcher<Head> {
|
|
string s;
|
|
Contains(string s) : s(s) {}
|
|
bool match(Head head) {
|
|
Entry *e;
|
|
CharVector v;
|
|
SLIST_FOREACH(e, &head, entries) { v.append(e->c); }
|
|
return s == v.c_str();
|
|
}
|
|
};
|
|
|
|
Entry e1 = {'a', {NULL}};
|
|
SLIST_INSERT_HEAD(&head, &e1, entries);
|
|
|
|
ASSERT_THAT(head, Contains("a"));
|
|
|
|
Entry e2 = {'b', {NULL}};
|
|
SLIST_INSERT_AFTER(&e1, &e2, entries);
|
|
|
|
ASSERT_THAT(head, Contains("ab"));
|
|
|
|
Head head2 = SLIST_HEAD_INITIALIZER(head);
|
|
|
|
Entry e3 = {'c', {NULL}};
|
|
SLIST_INSERT_HEAD(&head2, &e3, entries);
|
|
|
|
ASSERT_THAT(head2, Contains("c"));
|
|
|
|
SLIST_SWAP(&head, &head2, Entry);
|
|
|
|
ASSERT_THAT(head2, Contains("ab"));
|
|
|
|
SLIST_CONCAT(&head2, &head, Entry, entries);
|
|
|
|
ASSERT_THAT(head2, Contains("abc"));
|
|
|
|
SLIST_CONCAT(&head, &head2, Entry, entries);
|
|
|
|
ASSERT_THAT(head, Contains("abc"));
|
|
|
|
Entry *e = NULL, *tmp = NULL;
|
|
SLIST_FOREACH_SAFE(e, &head, entries, tmp) {
|
|
if (e == &e2) {
|
|
SLIST_REMOVE(&head, e, Entry, entries);
|
|
}
|
|
}
|
|
|
|
ASSERT_THAT(head, Contains("ac"));
|
|
|
|
while (!SLIST_EMPTY(&head)) {
|
|
e = SLIST_FIRST(&head);
|
|
SLIST_REMOVE_HEAD(&head, entries);
|
|
}
|
|
|
|
ASSERT_TRUE(SLIST_EMPTY(&head));
|
|
}
|
|
|
|
TEST(LlvmLibcQueueTest, STailQ) {
|
|
struct Entry {
|
|
char c;
|
|
STAILQ_ENTRY(Entry) entries;
|
|
};
|
|
|
|
STAILQ_HEAD(Head, Entry);
|
|
|
|
Head head = STAILQ_HEAD_INITIALIZER(head);
|
|
|
|
struct Contains : public testing::Matcher<Head> {
|
|
string s;
|
|
Contains(string s) : s(s) {}
|
|
bool match(Head head) {
|
|
Entry *e;
|
|
CharVector v;
|
|
STAILQ_FOREACH(e, &head, entries) { v.append(e->c); }
|
|
return s == v.c_str();
|
|
}
|
|
};
|
|
|
|
STAILQ_INIT(&head);
|
|
ASSERT_TRUE(STAILQ_EMPTY(&head));
|
|
|
|
Entry e1 = {'a', {NULL}};
|
|
STAILQ_INSERT_HEAD(&head, &e1, entries);
|
|
|
|
ASSERT_THAT(head, Contains("a"));
|
|
|
|
Entry e2 = {'b', {NULL}};
|
|
STAILQ_INSERT_TAIL(&head, &e2, entries);
|
|
|
|
ASSERT_THAT(head, Contains("ab"));
|
|
|
|
Entry e3 = {'c', {NULL}};
|
|
STAILQ_INSERT_AFTER(&head, &e2, &e3, entries);
|
|
|
|
ASSERT_THAT(head, Contains("abc"));
|
|
|
|
Head head2 = STAILQ_HEAD_INITIALIZER(head);
|
|
|
|
Entry e4 = {'d', {NULL}};
|
|
STAILQ_INSERT_HEAD(&head2, &e4, entries);
|
|
|
|
ASSERT_THAT(head2, Contains("d"));
|
|
|
|
STAILQ_SWAP(&head, &head2, Entry);
|
|
|
|
ASSERT_THAT(head2, Contains("abc"));
|
|
|
|
STAILQ_CONCAT(&head2, &head, Entry, entries);
|
|
|
|
ASSERT_EQ(STAILQ_FIRST(&head2), &e1);
|
|
ASSERT_EQ(STAILQ_LAST(&head2, Entry, entries), &e4);
|
|
|
|
ASSERT_THAT(head2, Contains("abcd"));
|
|
|
|
STAILQ_CONCAT(&head, &head2, Entry, entries);
|
|
|
|
ASSERT_EQ(STAILQ_FIRST(&head), &e1);
|
|
ASSERT_EQ(STAILQ_LAST(&head, Entry, entries), &e4);
|
|
|
|
ASSERT_THAT(head, Contains("abcd"));
|
|
|
|
Entry *e = NULL, *tmp = NULL;
|
|
STAILQ_FOREACH_SAFE(e, &head, entries, tmp) {
|
|
if (e == &e2) {
|
|
STAILQ_REMOVE(&head, e, Entry, entries);
|
|
}
|
|
}
|
|
|
|
ASSERT_THAT(head, Contains("acd"));
|
|
|
|
while (!STAILQ_EMPTY(&head)) {
|
|
e = STAILQ_FIRST(&head);
|
|
STAILQ_REMOVE_HEAD(&head, entries);
|
|
}
|
|
|
|
ASSERT_TRUE(STAILQ_EMPTY(&head));
|
|
}
|
|
|
|
} // namespace LIBC_NAMESPACE
|