
#ifndef PLS_ALIGNED_STACK_IMPL_H
#define PLS_ALIGNED_STACK_IMPL_H

#include <utility>

namespace pls {
namespace internal {
namespace data_structures {

template<typename T, typename ...ARGS>
T *aligned_stack::push(ARGS &&... args) {
  return new(push_bytes<T>())T(std::forward<ARGS>(args)...);
}

template<typename T>
void *aligned_stack::push_bytes() {
  return push_bytes(sizeof(T));
}

template<typename T>
void aligned_stack::pop() {
  auto num_cache_lines = base::alignment::next_alignment(sizeof(T)) / base::system_details::CACHE_LINE_SIZE;
  current_offset_ -= num_cache_lines;

  auto result = *reinterpret_cast<T *>(memory_at_offset(current_offset_));
  ~result();
}

template<size_t SIZE>
static_aligned_stack<SIZE>::static_aligned_stack(): aligned_stack{memory_.data()} {};

heap_aligned_stack::heap_aligned_stack(size_t size) :
    aligned_stack{new char[base::alignment::next_alignment(size)], size, base::alignment::next_alignment(size)} {}

heap_aligned_stack::~heap_aligned_stack() {
  delete[] unaligned_memory_pointer_;
}

}
}
}

#endif //PLS_ALIGNED_STACK_IMPL_H
