Skip to content
Snippets Groups Projects
Commit edad4c40 authored by Daniel Agar's avatar Daniel Agar Committed by Beat Küng
Browse files

containers add IntrusiveQueue and testing

parent 23189329
No related branches found
No related tags found
No related merge requests found
......@@ -17,6 +17,7 @@ set(tests
hrt
hysteresis
int
IntrusiveQueue
List
mathlib
matrix
......
/****************************************************************************
*
* Copyright (C) 2019 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#pragma once
#include <stdlib.h>
template<class T>
class IntrusiveQueue
{
public:
bool empty() const { return _head == nullptr; }
T front() const { return _head; }
T back() const { return _tail; }
size_t size() const
{
size_t sz = 0;
for (auto node = front(); node != nullptr; node = node->next_intrusive_queue_node()) {
sz++;
}
return sz;
}
void push(T newNode)
{
// error, node already queued or already inserted
if ((newNode->next_intrusive_queue_node() != nullptr) || (newNode == _tail)) {
return;
}
if (_head == nullptr) {
_head = newNode;
}
if (_tail != nullptr) {
_tail->set_next_intrusive_queue_node(newNode);
}
_tail = newNode;
}
T pop()
{
T ret = _head;
if (!empty()) {
if (_head != _tail) {
_head = _head->next_intrusive_queue_node();
} else {
// only one item left
_head = nullptr;
_tail = nullptr;
}
// clear next in popped (in might be re-inserted later)
ret->set_next_intrusive_queue_node(nullptr);
}
return ret;
}
private:
T _head{nullptr};
T _tail{nullptr};
};
template<class T>
class IntrusiveQueueNode
{
private:
friend IntrusiveQueue<T>;
T next_intrusive_queue_node() const { return _next_intrusive_queue_node; }
void set_next_intrusive_queue_node(T new_next) { _next_intrusive_queue_node = new_next; }
T _next_intrusive_queue_node{nullptr};
};
......@@ -46,6 +46,7 @@ set(srcs
test_hrt.cpp
test_hysteresis.cpp
test_int.cpp
test_IntrusiveQueue.cpp
test_jig_voltages.c
test_led.c
test_List.cpp
......
/****************************************************************************
*
* Copyright (C) 2019 PX4 Development Team. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* 3. Neither the name PX4 nor the names of its contributors may be
* used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*
****************************************************************************/
#include <unit_test.h>
#include <containers/IntrusiveQueue.hpp>
#include <float.h>
#include <math.h>
class testContainer : public IntrusiveQueueNode<testContainer *>
{
public:
int i{0};
};
class IntrusiveQueueTest : public UnitTest
{
public:
virtual bool run_tests();
bool test_push();
bool test_pop();
bool test_push_duplicate();
};
bool IntrusiveQueueTest::run_tests()
{
ut_run_test(test_push);
ut_run_test(test_pop);
ut_run_test(test_push_duplicate);
return (_tests_failed == 0);
}
bool IntrusiveQueueTest::test_push()
{
IntrusiveQueue<testContainer *> q1;
// size should be 0 initially
ut_compare("size initially 0", q1.size(), 0);
ut_assert_true(q1.empty());
// insert 100
for (int i = 0; i < 100; i++) {
testContainer *t = new testContainer();
t->i = i;
ut_compare("size increasing with i", q1.size(), i);
q1.push(t);
ut_compare("size increasing with i", q1.size(), i + 1);
ut_assert_true(!q1.empty());
}
// verify full size (100)
ut_compare("size 100", q1.size(), 100);
// pop all elements
for (int i = 0; i < 100; i++) {
auto node = q1.front();
q1.pop();
delete node;
}
// verify list has been cleared
ut_compare("size 0", q1.size(), 0);
ut_assert_true(q1.empty());
return true;
}
bool IntrusiveQueueTest::test_pop()
{
IntrusiveQueue<testContainer *> q1;
// size should be 0 initially
ut_compare("size initially 0", q1.size(), 0);
ut_assert_true(q1.empty());
// insert 100
for (int i = 0; i < 100; i++) {
testContainer *t = new testContainer();
t->i = i;
q1.push(t);
}
// verify full size (100)
ut_assert_true(q1.size() == 100);
for (int i = 0; i < 100; i++) {
auto node = q1.front();
ut_compare("stored i", i, node->i);
ut_compare("size check", q1.size(), 100 - i);
q1.pop();
ut_compare("size check", q1.size(), 100 - i - 1);
delete node;
ut_compare("size check", q1.size(), 100 - i - 1);
}
// verify list has been cleared
ut_assert_true(q1.empty());
ut_compare("size check", q1.size(), 0);
// pop an empty queue
auto T = q1.pop();
ut_assert_true(T == nullptr);
ut_assert_true(q1.empty());
ut_compare("size check", q1.size(), 0);
return true;
}
bool IntrusiveQueueTest::test_push_duplicate()
{
IntrusiveQueue<testContainer *> q1;
// size should be 0 initially
ut_compare("size initially 0", q1.size(), 0);
ut_assert_true(q1.empty());
// insert 100
for (int i = 0; i < 100; i++) {
testContainer *t = new testContainer();
t->i = i;
ut_compare("size increasing with i", q1.size(), i);
q1.push(t);
ut_compare("size increasing with i", q1.size(), i + 1);
ut_assert_true(!q1.empty());
}
// verify full size (100)
ut_compare("size 100", q1.size(), 100);
// attempt to insert front again
const auto q1_front = q1.front();
const auto q1_front_i = q1_front->i; // copy i value
const auto q1_back = q1.back();
const auto q1_back_i = q1_back->i; // copy i value
// push front and back aagain
q1.push(q1_front);
q1.push(q1_back);
// verify no change
ut_compare("size 100", q1.size(), 100);
ut_compare("q front not reinserted", q1.front()->i, q1_front->i);
ut_compare("q back not reinserted", q1.back()->i, q1_back->i);
// pop the head
const auto q1_head = q1.pop();
// verfify size should now be 99
ut_compare("size 99", q1.size(), 99);
// push back on
q1.push(q1_head);
// verify size now 100 again
ut_compare("size 100", q1.size(), 100);
// pop all elements
for (int i = 0; i < 100; i++) {
auto node = q1.front();
q1.pop();
delete node;
}
// verify list has been cleared
ut_compare("size 0", q1.size(), 0);
ut_assert_true(q1.empty());
return true;
}
ut_declare_test_c(test_IntrusiveQueue, IntrusiveQueueTest)
......@@ -95,6 +95,7 @@ const struct {
{"hrt", test_hrt, OPT_NOJIGTEST | OPT_NOALLTEST},
{"hysteresis", test_hysteresis, 0},
{"int", test_int, 0},
{"IntrusiveQueue", test_IntrusiveQueue, 0},
{"jig_voltages", test_jig_voltages, OPT_NOALLTEST},
{"List", test_List, 0},
{"mathlib", test_mathlib, 0},
......
......@@ -57,6 +57,7 @@ extern int test_hott_telemetry(int argc, char *argv[]);
extern int test_hrt(int argc, char *argv[]);
extern int test_hysteresis(int argc, char *argv[]);
extern int test_int(int argc, char *argv[]);
extern int test_IntrusiveQueue(int argc, char *argv[]);
extern int test_jig_voltages(int argc, char *argv[]);
extern int test_led(int argc, char *argv[]);
extern int test_List(int argc, char *argv[]);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment