
#ifndef PLS_DEQUE_H
#define PLS_DEQUE_H

#include "pls/internal/base/spin_lock.h"

namespace pls {
namespace internal {
namespace data_structures {

/**
 * Turns any object into deque item when inheriting from this.
 */
class locking_deque_item {
  friend class locking_deque_internal;

  locking_deque_item *prev_;
  locking_deque_item *next_;

};

class locking_deque_internal {
 protected:
  locking_deque_item *head_;
  locking_deque_item *tail_;

  base::spin_lock lock_;

  locking_deque_item *pop_head_internal();
  locking_deque_item *pop_tail_internal();
  void push_tail_internal(locking_deque_item *new_item);
};

/**
 * A double linked list based deque.
 * Storage is therefore only needed for the individual items.
 *
 * @tparam Item The type of items stored in this deque
 */
template<typename Item>
class locking_deque : locking_deque_internal {
 public:
  explicit locking_deque() : locking_deque_internal{} {}

  inline Item *pop_head() {
    return static_cast<Item *>(pop_head_internal());
  }

  inline Item *pop_tail() {
    return static_cast<Item *>(pop_tail_internal());
  }

  inline void push_tail(Item *new_item) {
    push_tail_internal(new_item);
  }
};

}
}
}

#endif //PLS_DEQUE_H
