
#ifndef PLS_LOCKING_DEQUE_IMPL_H_
#define PLS_LOCKING_DEQUE_IMPL_H_

namespace pls {
namespace internal {
namespace data_structures {

template<typename Item>
template<typename T, typename ...ARGS>
T *locking_deque<Item>::push_tail(ARGS &&... args) {
  return push_tail_cb<T>([](T *) {}, std::forward<ARGS>(args)...);
}

template<typename Item>
template<typename T, typename Function, typename ...ARGS>
T *locking_deque<Item>::push_tail_cb(const Function &after_creation, ARGS &&...args) {
  static_assert(std::is_same<Item, T>::value || std::is_base_of<Item, T>::value,
                "Must only push types of <Item> onto work_stealing_deque<Item>");

  std::lock_guard<base::spin_lock> lock{lock_};
  auto deque_item = stack_->push<locking_deque_container<Item, T>>(std::forward<ARGS>(args)...);
  deque_item->item_ = &deque_item->content_;
  after_creation(&deque_item->content_);

  if (tail_ != nullptr) {
    tail_->next_ = deque_item;
  } else {
    head_ = deque_item;
  }
  deque_item->prev_ = tail_;
  deque_item->next_ = nullptr;
  tail_ = deque_item;

  return &deque_item->content_;
}

template<typename Item>
Item *locking_deque<Item>::pop_tail() {
  std::lock_guard<base::spin_lock> lock{lock_};

  if (tail_ == nullptr) {
    return nullptr;
  }

  auto result = tail_;
  tail_ = tail_->prev_;
  if (tail_ == nullptr) {
    head_ = nullptr;
  } else {
    tail_->next_ = nullptr;
  }

  return result->item_;
}

template<typename Item>
Item *locking_deque<Item>::pop_head() {
  std::lock_guard<base::spin_lock> lock{lock_};

  if (head_ == nullptr) {
    return nullptr;
  }

  auto result = head_;
  head_ = head_->next_;
  if (head_ == nullptr) {
    tail_ = nullptr;
  } else {
    head_->prev_ = nullptr;
  }

  return result->item_;
}

template<typename Item>
void locking_deque<Item>::release_memory_until(state state) {
  stack_->reset_state(state);
}
template<typename Item>
typename locking_deque<Item>::state locking_deque<Item>::save_state() {
  return stack_->save_state();
}

}
}
}

#endif //PLS_LOCKING_DEQUE_IMPL_H_
