//
// Cforall Version 1.0.0 Copyright (C) 2016 University of Waterloo
//
// The contents of this file are covered under the licence agreement in the
// file "LICENCE" distributed with Cforall.
//
// bits/containers.h -- Intrusive generic containers.h
//
// Author           : Thierry Delisle
// Created On       : Tue Oct 31 16:38:50 2017
// Last Modified By : --
// Last Modified On : --
// Update Count     : 0

#pragma once

#include "bits/align.h"
#include "bits/defs.h"

//-----------------------------------------------------------------------------
// Array
//-----------------------------------------------------------------------------

#ifdef __cforall
	forall(dtype T)
#else
	#define T void
#endif
struct __small_array {
	T *           data;
	__lock_size_t size;
};
#undef T

#ifdef __cforall
	#define __small_array_t(T) __small_array(T)
#else
	#define __small_array_t(T) struct __small_array
#endif

#ifdef __cforall
	// forall(otype T | sized(T))
	// static inline void ?{}(__small_array(T) & this) {}

	forall(dtype T | sized(T))
	static inline T& ?[?]( __small_array(T) & this, __lock_size_t idx) {
		return ((typeof(this.data))this.data)[idx];
	}

	forall(dtype T | sized(T))
	static inline T& ?[?]( const __small_array(T) & this, __lock_size_t idx) {
		return ((typeof(this.data))this.data)[idx];
	}

	forall(dtype T | sized(T))
	static inline T* begin( const __small_array(T) & this ) {
		return ((typeof(this.data))this.data);
	}

	forall(dtype T | sized(T))
	static inline T* end( const __small_array(T) & this ) {
		return ((typeof(this.data))this.data) + this.size;
	}
#endif

//-----------------------------------------------------------------------------
// Node Base
//-----------------------------------------------------------------------------

#ifdef __cforall
	trait is_node(dtype T) {
		T*& get_next( T& );
	};
#endif

//-----------------------------------------------------------------------------
// Stack
//-----------------------------------------------------------------------------
#ifdef __cforall
	forall(dtype TYPE | is_node(TYPE))
	#define T TYPE
#else
	#define T void
#endif
struct __stack {
	T * top;
};
#undef T

#ifdef __cforall
#define __stack_t(T) __stack(T)
#else
#define __stack_t(T) struct __stack
#endif

#ifdef __cforall
	forall(dtype T | is_node(T))
	static inline void ?{}( __stack(T) & this ) {
		(this.top){ NULL };
	}

	forall(dtype T | is_node(T) | sized(T))
	static inline void push( __stack(T) & this, T * val ) {
		verify( !get_next( *val ) );
		get_next( *val ) = this.top;
		this.top = val;
	}

	forall(dtype T | is_node(T) | sized(T))
	static inline T * pop( __stack(T) & this ) {
		T * top = this.top;
		if( top ) {
			this.top = get_next( *top );
			get_next( *top ) = NULL;
		}
		return top;
	}
#endif

//-----------------------------------------------------------------------------
// Queue
//-----------------------------------------------------------------------------
#ifdef __cforall
	forall(dtype TYPE | is_node(TYPE))
	#define T TYPE
#else
	#define T void
#endif
struct __queue {
	T * head;
	T ** tail;
};
#undef T

#ifdef __cforall
#define __queue_t(T) __queue(T)
#else
#define __queue_t(T) struct __queue
#endif

#ifdef __cforall

	forall(dtype T | is_node(T))
	static inline void ?{}( __queue(T) & this ) with( this ) {
		head{ NULL };
		tail{ &head };
	}

	forall(dtype T | is_node(T) | sized(T))
	static inline void append( __queue(T) & this, T * val ) with( this ) {
		verify(tail != NULL);
		*tail = val;
		tail = &get_next( *val );
	}

	forall(dtype T | is_node(T) | sized(T))
	static inline T * pop_head( __queue(T) & this ) {
		T * head = this.head;
		if( head ) {
			this.head = get_next( *head );
			if( !get_next( *head ) ) {
				this.tail = &this.head;
			}
			get_next( *head ) = NULL;
		}
		return head;
	}

	forall(dtype T | is_node(T) | sized(T))
	static inline T * remove( __queue(T) & this, T ** it ) with( this ) {
		T * val = *it;
		verify( val );

		(*it) = get_next( *val );

		if( tail == &get_next( *val ) ) {
			tail = it;
		}

		get_next( *val ) = NULL;

		verify( (head == NULL) == (&head == tail) );
		verify( *tail == NULL );
		return val;
	}
#endif

//-----------------------------------------------------------------------------
// Tools
//-----------------------------------------------------------------------------
#ifdef __cforall

#endif