/*
 * \brief  Test double-list implementation of the kernel
 * \author Martin Stein
 * \date   2014-09-30
 */

/*
 * Copyright (C) 2014 Genode Labs GmbH
 *
 * This file is part of the Genode OS framework, which is distributed
 * under the terms of the GNU General Public License version 2.
 */

/* base includes */
#include <base/component.h>
#include <base/log.h>

/* core includes */
#include <kernel/double_list.h>


/*
 * Utilities
 */

using Genode::size_t;
using Kernel::Double_list_typed;
using Kernel::Double_list_item;

void * operator new(__SIZE_TYPE__ s, void * p) { return p; }

struct Item_load { char volatile x, y, z; };

struct Item : Item_load, Double_list_item
{
	unsigned _id;

	Item(unsigned const id) : _id(id) { x = 1; y = 2; z = 3; }

	void iteration() { Genode::log(_id); }
};

struct Data
{
	static constexpr unsigned nr_of_items = 9;

	Double_list_typed<Item> list;
	char items[nr_of_items][sizeof(Item)];

	Data()
	{
		for (unsigned i = 0; i < nr_of_items; i++) {
			new (&items[i]) Item(i + 1); }
	}
};

Data * data()
{
	static Data d;
	return &d;
}

void done()
{
	Genode::log("done");
	while (1) ;
}

void check(unsigned i1, unsigned l)
{
	Item * const i2 = data()->list.head();
	if (i1 && i2) {
		if(i1 == i2->_id) { return; }
		Genode::log("head ", i2->_id, " in line ", l);
		done();
	} else if (i1 && !i2) {
		Genode::log("empty in line ", l);
		done();
	} else if (!i1 && i2){
		Genode::log("non-empty ", i2->_id, " in line ", l);
		done();
	}
}

void print_each()
{
	Genode::log("print each");
	data()->list.for_each([] (Item * const i) { i->iteration(); });
}

Item * item(unsigned const i) {
	return reinterpret_cast<Item *>(&data()->items[i - 1]); }


/*
 * Shortcuts for all basic operations that the test consists of
 */

#define C(i) check(i, __LINE__);
#define T(i) data()->list.insert_tail(item(i));
#define H(i) data()->list.insert_head(item(i));
#define R(i) data()->list.remove(item(i));
#define B(i) data()->list.to_tail(item(i));
#define P    print_each();
#define N    data()->list.head_to_tail();


/**
 * Main routine
 */
void Component::construct(Genode::Env &)
{
	/*
	 * Step-by-step testing
	 *
	 * Every line in this test is structured according to the scheme
	 * '<ops> C(i) <doc>' where the symbols are defined as follows:
	 *
	 * ops    Operations that affect the list structure. These are:
	 *
	 *        T(i)  insert the item with ID 'i' as tail
	 *        H(i)  insert the item with ID 'i' as head
	 *        R(i)  remove the item with ID 'i'
	 *        B(i)  move the item with ID 'i' to the tail
	 *        N     move the head to the tail
	 *        P     print IDs of the items in the list in their list order
	 *
	 * C(i)   check if the item with ID 'i' is head
	 *
	 * doc    Documents the expected list content for the point after the
	 *        operations in the corresponding line.
	 *
	 * If any check in a line fails, the test prematurely stops and prints out
	 * where and why it has stopped.
	 */

	          C(0) /* */
	        N C(0) /* */
	        P C(0) /* */
	     T(1) C(1) /* 1 */
	        N C(1) /* 1 */
	      P N C(1) /* 1 */
	     B(1) C(1) /* 1 */
	        N C(1) /* 1 */
	     R(1) C(0) /* */
	        N C(0) /* */
	        N C(0) /* */
	     H(2) C(2) /* 2 */
	        N C(2) /* 2 */
	        N C(2) /* 2 */
	     T(3) C(2) /* 2 3 */
	        N C(3) /* 3 2 */
	     B(2) C(3) /* 3 2 */
	        N C(2) /* 2 3 */
	     H(4) C(4) /* 4 2 3 */
	        N C(2) /* 2 3 4 */
	        N C(3) /* 3 4 2 */
	        N C(4) /* 4 2 3 */
	   R(4) N C(3) /* 3 2 */
	        N C(2) /* 2 3 */
	     T(1) C(2) /* 2 3 1 */
	        N C(3) /* 3 1 2 */
	        N C(1) /* 1 2 3 */
	        N C(2) /* 2 3 1 */
	        N C(3) /* 3 1 2 */
	     R(1) C(3) /* 3 2 */
	        N C(2) /* 2 3 */
	        N C(3) /* 3 2 */
	     B(3) C(2) /* 2 3 */
	T(4) T(1) C(2) /* 2 3 4 1 */
	      N N C(4) /* 4 1 2 3 */
	        N C(1) /* 1 2 3 4 */
	      N N C(3) /* 3 4 1 2 */
	     R(2) C(3) /* 3 4 1 */
	     R(3) C(4) /* 4 1 */
	        N C(1) /* 1 4 */
	      N N C(1) /* 1 4 */
	T(3) T(2) C(1) /* 1 4 3 2 */
	   T(5) N C(4) /* 4 3 2 5 1 */
	T(7) H(6) C(6) /* 6 4 3 2 5 1 7 */
	        N C(4) /* 4 3 2 5 1 7 6 */
	     B(4) C(3) /* 3 2 5 1 7 6 4 */
	 B(4) N N C(5) /* 5 1 7 6 4 3 2 */
	 N B(7) N C(6) /* 6 4 3 2 5 7 1*/
	 N N B(1) C(3) /* 3 2 5 7 6 4 1 */
	        P C(3) /* 3 2 5 7 6 4 1 */
	R(4) H(4) C(4) /* 4 3 2 5 7 6 1 */
	B(7) B(6) C(4) /* 4 3 2 5 1 7 6 */
	    N N N C(5) /* 5 1 7 6 4 3 2 */
	    N N N C(6) /* 6 4 3 2 5 1 7 */
	    N N N C(2) /* 2 5 1 7 6 4 3 */
	 T(9) N N C(1) /* 1 7 6 4 3 9 2 5 */
	  N N N N C(3) /* 3 9 2 5 1 7 6 4 */
	  N N N N C(1) /* 1 7 6 4 3 9 2 5 */
	    N N N C(4) /* 4 3 9 2 5 1 7 6 */
	      N N C(9) /* 9 2 5 1 7 6 4 3 */
	   H(8) P C(8) /* 8 9 2 5 1 7 6 4 3 */
	     R(8) C(9) /* 9 2 5 1 7 6 4 3 */
	     R(9) C(2) /* 2 5 1 7 6 4 3 */
	 R(1) N N C(7) /* 7 6 4 3 2 5 */
	 N R(6) N C(3) /* 3 2 5 7 4 */
	T(8) R(3) C(2) /* 2 5 7 4 8 */
	 N N R(5) C(7) /* 7 4 8 2 */
	R(2) R(4) C(7) /* 7 8 */
	        N C(8) /* 8 7 */
	      N P C(7) /* 7 8 */
	     R(7) C(8) /* 7 8 */
	     R(8) C(0) /* */
	          C(0) /* */

	done();
}
