#pragma once
#include<concepts>
#include<utility>
#include<vector>
#include<ranges>
#include<algorithm>#include"snippet/iterations.hpp"#include"internal/dev_env.hpp"namespaceuni{template<classFront,classBack=Front>structdeque_by_stack{static_assert(std::same_as<typenameFront::value_type,typenameBack::value_type>);static_assert(std::common_reference_with<typenameFront::size_type,typenameBack::size_type>);usingvalue_type=Front::value_type;usingsize_type=std::common_type_t<typenameFront::size_type,typenameBack::size_type>;protected:Front_front;Back_back;private:template<std::ptrdiff_tOFFSET>inlinevoid_distribute()noexcept(NO_EXCEPT){if(this->empty())return;std::vector<value_type>temp;temp.reserve(this->size());if(this->_front.empty()){while(!this->_back.empty()){temp.push_back(this->_back.top());this->_back.pop();}std::ranges::reverse(temp);}elseif(this->_back.empty()){while(!this->_front.empty()){temp.push_back(this->_front.top());this->_front.pop();}}else{return;}assert(this->empty());constautosize=std::ranges::ssize(temp);constautomid=(size+OFFSET)/2;REPD(i,mid)this->_front.push(temp[i]);REP(i,mid,size)this->_back.push(temp[i]);}public:deque_by_stack()noexcept=default;inlineboolempty()constnoexcept(NO_EXCEPT){returnthis->_front.empty()&&this->_back.empty();}inlineautosize()constnoexcept(NO_EXCEPT){returnthis->_front.size()+this->_back.size();}inlinedecltype(auto)front()constnoexcept(NO_EXCEPT){this->_distribute<1>();assert(!this->_front.empty());returnthis->_front.top();}inlinedecltype(auto)back()constnoexcept(NO_EXCEPT){this->_distribute<0>();assert(!this->_back.empty());returnthis->_back.top();}template<std::convertible_to<value_type>T=value_type>requiresstd::is_move_constructible_v<T>inlinedecltype(auto)front_or(T&&val)constnoexcept(NO_EXCEPT){if(this->empty())returnstatic_cast<value_type>(std::forward<T>(val));elsereturnthis->front();}template<std::convertible_to<value_type>T=value_type>requiresstd::is_move_constructible_v<T>inlinedecltype(auto)back_or(T&&val)constnoexcept(NO_EXCEPT){if(this->empty())returnstatic_cast<value_type>(std::forward<T>(val));elsereturnthis->back();}inlineauto&clear()noexcept(NO_EXCEPT){this->_front.clear(),this->_back.clear();return*this;}template<std::convertible_to<value_type>T=value_type>inlineauto&push_front(T&&val)noexcept(NO_EXCEPT){this->_front.push(std::forward<T>(val));return*this;}template<std::convertible_to<value_type>T=value_type>inlineauto&push_back(T&&val)noexcept(NO_EXCEPT){this->_back.push(std::forward<T>(val));return*this;}template<class...Args>inlinedecltype(auto)emplace_front(Args&&...args)noexcept(NO_EXCEPT){returnthis->_front.emplace(std::forward<Args>(args)...);}template<class...Args>inlinedecltype(auto)emplace_back(Args&&...args)noexcept(NO_EXCEPT){returnthis->_back.emplace(std::forward<Args>(args)...);}auto&pop_front()noexcept(NO_EXCEPT){this->_distribute<1>();assert(!this->_front.empty());this->_front.pop();return*this;}auto&pop_back()noexcept(NO_EXCEPT){this->_distribute<0>();assert(!this->_back.empty());this->_back.pop();return*this;}};}// namespace uni