Currently my class looks like this, by unit tests done, it works but my goal will be to implement as precise in question the lib Boost and especially the multi index container.
I tried to change the type of the items but it didn't work, like this:
typedef multi_index_container<items,indexed_by<sequenced<>,hashed_unique<identity<Item> >>> item_list;
I got a message: Invalid use of non-static data member '_items'. This kind of error I can understand it but i not specify it because it is the global implementation that worries me
If you find any other error apart from my precise question, I am also a taker.
template<typename Tkey, typename Tval>
class CacheWeb{
private:
unsigned int capacity;
std::list<std::pair<Tkey, Tval>> items;
std::unordered_map<key, typename std::list<std::pair<Tkey, Tval>>::iterator> lookup;
CacheWeb(const CacheWeb&) = delete;
CacheWeb& operator=(const CacheWeb&) = delete;
int capacityOut(){
if( capacity == 0 || lookup.size() < capacity ) {
return 0;
}
int cnt = 0;
while(lookup.size() > capacity) {
lookup.erase(items.back().first);
items.pop_back();
++cnt;
}
return cnt;
};
public:
CacheWeb(int icapacity) : capacity(icapacity){};
virtual ~CacheWeb() = default;
int size(){
return lookup.size();
};
bool empty(){
return lookup.empty();
};
void clear(){
lookup.clear();
items.clear();
};
bool contains(const Tkey& key){
return lookup.find(key) != lookup.end();
};
void remove(const Tkey& key){
auto it = lookup.find(key);
items.erase(it->second);
lookup.erase(it);
};
void put(const Tkey& key, const Tval& val){
auto it = lookup.find(key);
if( it != lookup.end() ) {
it->second->second = val;
items.splice(items.begin(), items, it->second);
return;
}
items.emplace_front(key, val);
lookup[key] = items.begin();
capacityOut();
};
std::list<std::pair<Tkey, Tval>>getItems(){
return items;
};
const VAL_T& get(const Tkey& key){
const auto it = lookup.find(key);
if( it == lookup.end() ) {
throw std::invalid_argument("Key does not exist");
}
items.splice(items.begin(), items, it->second);
return it->second->second;
};
};
}
Something like this can do:
Live Coliru Demo
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/key.hpp>
template<typename Tkey, typename Tval>
class CacheWeb{
private:
using value_type = std::pair<Tkey, Tval>;
unsigned int capacity;
boost::multi_index_container<
value_type,
boost::multi_index::indexed_by<
boost::multi_index::sequenced<>,
boost::multi_index::hashed_unique<boost::multi_index::key<&value_type::first>>
>
> container;
CacheWeb(const CacheWeb&) = delete;
CacheWeb& operator=(const CacheWeb&) = delete;
int capacityOut(){
if( capacity == 0 || container.size() < capacity ) {
return 0;
}
int cnt = 0;
while(container.size() > capacity) {
container.pop_back();
++cnt;
}
return cnt;
};
public:
CacheWeb(int icapacity) : capacity(icapacity){};
virtual ~CacheWeb() = default;
int size(){
return container.size();
};
bool empty(){
return container.empty();
};
void clear(){
container.clear();
};
bool contains(const Tkey& key){
const auto& lookup = container.template get<1>();
return lookup.find(key) != container.template get<1>().end();
};
void remove(const Tkey& key){
container.erase(key);
};
void put(const Tkey& key, const Tval& val){
auto& lookup = container.template get<1>();
auto it = lookup.find(key);
if( it != lookup.end() ) {
lookup.modify(it,[&](value_type& x){ x.second = val; });
}
else{
it=lookup.emplace(key, val).first;
}
container.relocate(container.begin(),container.template project<0>(it));
capacityOut();
};
std::list<std::pair<Tkey, Tval>>getItems(){
return {container.begin(), container.end()};
};
const Tval& get(const Tkey& key){
const auto& lookup = container.template get<1>();
const auto it = lookup.find(key);
if( it == lookup.end() ) {
throw std::invalid_argument("Key does not exist");
}
return it->second;
}
};
#include <iostream>
int main()
{
CacheWeb<int,int> c(10);
for(int i=0;i<11;++i)c.put(i,i);
for(const auto& x:c.getItems()){
std::cout<<"("<<x.first<<","<<x.second<<")";
}
std::cout<<"\n";
for(int i=1;i<11;++i){
std::cout<<i<<"->"<<c.get(i)<<" ";
}
std::cout<<"\n";
}
Output
(10,10)(9,9)(8,8)(7,7)(6,6)(5,5)(4,4)(3,3)(2,2)(1,1)
1->1 2->2 3->3 4->4 5->5 6->6 7->7 8->8 9->9 10->10
Related
Given the code below, how would I specify a non-type template parameter for Pathfinder in order to declare the size of the Pathfinder::Node member std::array<Node*, 8> neighbors array (hard-coded to 8 in this use) so that the neighbor can be of any size (realistically specialized to 4 for mazes, 6 for hex-tiles a la modern Civilization games, or 8 for tiles sets a la Rogue-likes.)?
#pragma once
#include "Engine/Math/IntVector2.hpp"
#include <algorithm>
#include <array>
#include <functional>
#include <limits>
#include <numeric>
#include <queue>
#include <vector>
class Pathfinder {
public:
constexpr static uint8_t PATHFINDING_SUCCESS = 0;
constexpr static uint8_t PATHFINDING_NO_PATH = 1;
constexpr static uint8_t PATHFINDING_GOAL_UNREACHABLE = 2;
constexpr static uint8_t PATHFINDING_INVALID_INITIAL_NODE = 3;
constexpr static uint8_t PATHFINDING_PATH_EMPTY_ERROR = 4;
constexpr static uint8_t PATHFINDING_UNKNOWN_ERROR = 5;
struct Node {
std::array<Node*, 8> neighbors{nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr};
Node* parent{nullptr};
float f = std::numeric_limits<float>::infinity();
float g = std::numeric_limits<float>::infinity();
IntVector2 coords = IntVector2::ZERO;
bool visited = false;
};
void Initialize(int width, int height) noexcept;
const std::vector<const Pathfinder::Node*> GetResult() const noexcept;
void ResetNavMap() noexcept;
template<typename Viability, typename Heuristic, typename DistanceFunc>
uint8_t AStar(const IntVector2& start, const IntVector2& goal, Viability&& viable, Heuristic&& h, DistanceFunc&& distance) {
auto* initial = GetNode(start);
if(!initial) {
return PATHFINDING_INVALID_INITIAL_NODE;
}
initial->g = 0.0f;
initial->f = static_cast<float>(std::invoke(h, start, goal));
const auto comp = [](const Node* a, const Node* b) { return a->f < b->f; };
std::priority_queue<Node*, std::vector<Node*>, decltype(comp)> openSet(comp);
std::vector<Node*> closedSet{};
const auto IsGoalInClosedSet = [&closedSet, goal]()->bool {
const auto found = std::find_if(std::cbegin(closedSet), std::cend(closedSet), [goal](const Node* a)->bool { return a->coords == goal; });
return found != std::cend(closedSet);
};
const auto IsNodeVisited = [](const Node* a)-> bool {
return a->visited;
};
const auto EveryNodeSearched = [this, &closedSet]()->bool {
return _navMap.size() == closedSet.size();
};
const auto IsGoalUnreachable = [&closedSet](const Node* current)->bool {
unsigned char visited_count = 0;
const auto is_in_closed_set = std::find(std::begin(closedSet), std::end(closedSet), current) != std::end(closedSet);
for(const Node* neighbor : current->neighbors) {
if(neighbor == nullptr) {
++visited_count;
continue;
}
if(is_in_closed_set) {
++visited_count;
}
}
return visited_count >= 8;
};
const auto IsNeighborValid = [&closedSet](const Node* current)->bool {
if(current != nullptr) {
const auto found = std::find(std::begin(closedSet), std::end(closedSet), current);
return found == std::end(closedSet);
}
return false;
};
const auto IsNeighborTraversable = [this](const Node* neighbor)->bool {
if(neighbor == nullptr) {
return false;
}
const auto n_idx = neighbor->coords.y * _dimensions.x + neighbor->coords.x; 0 > n_idx || n_idx >= _dimensions.x * _dimensions.y;
const auto is_inside_map = n_idx < _dimensions.x * _dimensions.y;
return is_inside_map;
};
openSet.push(initial);
while(true) {
if(openSet.empty()) {
return PATHFINDING_GOAL_UNREACHABLE;
}
Node* current = openSet.top();
openSet.pop();
closedSet.push_back(current);
current->visited = true;
if(current->coords == goal) {
break;
}
for(const auto neighbor : current->neighbors) {
if(!(IsNeighborValid(neighbor) && IsNeighborTraversable(neighbor))) {
continue;
}
if(!std::invoke(viable, neighbor->coords)) {
continue;
}
if(!IsNodeVisited(neighbor)) {
openSet.push(neighbor);
}
const float tenativeGScore = current->g + std::invoke(distance, current->coords, neighbor->coords);
if(tenativeGScore < neighbor->g) {
neighbor->parent = current;
neighbor->g = tenativeGScore;
neighbor->f = neighbor->g + std::invoke(h, neighbor->coords, goal);
}
}
}
if(!IsGoalInClosedSet() && !_path.empty()) {
return PATHFINDING_GOAL_UNREACHABLE;
}
if(!IsGoalInClosedSet() && _path.empty()) {
return PATHFINDING_NO_PATH;
}
if(IsGoalInClosedSet() && !_path.empty()) {
const Node* end = _path.front();
if(end) {
if(const Node* p = end) {
_path.clear();
while(p->parent) {
_path.push_back(p);
p = p->parent;
}
}
}
return PATHFINDING_SUCCESS;
}
if(IsGoalInClosedSet() && _path.empty()) {
if(const Node* end = closedSet.back()) {
if(const Node* p = end) {
_path.clear();
_path.push_back(p);
while(p->parent) {
_path.push_back(p);
p = p->parent;
}
return PATHFINDING_SUCCESS;
}
}
}
return PATHFINDING_UNKNOWN_ERROR;
}
template<typename Viability, typename DistanceFunc>
uint8_t Dijkstra(const IntVector2& start, const IntVector2& goal, Viability&& viable, DistanceFunc&& distance) {
return AStar(start, goal, viable, [](const IntVector2&, const IntVector2&)->int { return 0; }, distance);
}
protected:
private:
const Pathfinder::Node* GetNode(int x, int y) const noexcept;
Pathfinder::Node* GetNode(int x, int y) noexcept;
const Pathfinder::Node* GetNode(const IntVector2& pos) const noexcept;
Pathfinder::Node* GetNode(const IntVector2& pos) noexcept;
const std::array<const Pathfinder::Node*, 8> GetNeighbors(int x, int y) const noexcept;
void SetNeighbors(int x, int y) noexcept;
std::vector<const Node*> _path{};
std::vector<Node> _navMap{};
IntVector2 _dimensions{};
static inline bool already_initialized{false};
};
I'm very very new to vectors and templates. Can't seem to wrap my head around them just yet.
The code is as follows:
template <class T>
class m_vector
{
int m_iNextIndex;
int m_iMaxSize;
T* m_pArray;
public:
m_vector()
{
m_pArray = 0;
init();
}
m_vector(const m_vector<T>& other)
{
m_pArray = 0;
m_iNextIndex = 0;
m_iMaxSize = 0;
*this = other;
}
~m_vector()
{
if (m_pArray != 0)
delete [] m_pArray;
}
void init()
{
m_iMaxSize = VECT_INC_SIZE;
m_pArray = new T[m_iMaxSize];
m_iNextIndex = 0;
}
inline void push_back(const T& item)
{
if (m_iNextIndex >= m_iMaxSize)
{
resize(m_iNextIndex + VECT_INC_SIZE);
m_iNextIndex -= VECT_INC_SIZE;
}
m_pArray[m_iNextIndex] = item;
++m_iNextIndex;
}
void resize(int iNewSize)
{
if (iNewSize >= m_iMaxSize)
{
T* temp = new T[iNewSize];
for (int i = 0; i < m_iNextIndex; ++i)
{
temp[i] = m_pArray[i];
}
delete [] m_pArray;
m_pArray = temp;
m_iMaxSize = iNewSize;
}
m_iNextIndex = iNewSize;
}
};
The push_back is called with Vectors that are (x, y) and rectangles that are (x, y, width, height).
I thought that since the code had "m_pArray[m_iNextIndex] = item" that I could simply add a new function to check that the item is unique before adding it to the vector list. So I coded a routine as follows:
int inline exists(const &item)
{
for(int i = 0; i < m_iMaxSize; i++)
{
if(m_pArray[i] == item)
return 1;
}
return 0;
}
The compiler was non to happy. It reported the following error on the if statement:
“left operand must be a pointer or pointer to class member, or arithmetic”
I'm thinking that I probably need something like:
if (type == vector)
if( (m_pArray[i].x == item.x) ....)
else
if( (m_pArray[i].x == item.x) && (m_pArray[i].width == item.width) )
Am I on the right track?
If so, how do I check the type of item.
Thx, Bill.
The problem is that your Vector or Rectangle are missing a comparison operator e.g.
friend bool operator== (Vector const& lhs, Vector const& rhs){
return lhs.x == rhs.x && lhs.y == rhs.y;
}
But the rest of you code is not good and needs a rewrite. I've rewritten my code to old-old style:
NOTE: DON'T BLINDLY COPY THIS CODE. ITS JUST FOR REFERENCE. TEST BEFORE YOU USE
#define VECT_INC_SIZE 10
// replaced by iterator version
//template< class InputIt, class Size, class OutputIt>
//OutputIt copy_n(InputIt first, Size count, OutputIt result) {
// while (count-- > 0) {
// *result++ = *first++;
// }
// return result;
//}
template<class InputIt, class OutputIt>
OutputIt copy(InputIt first, InputIt last, OutputIt d_first) {
while (first != last) {
*d_first++ = *first++;
}
return d_first;
}
template<class T>
T exchange(T& obj, T new_value)
{
T old_value = obj;
obj = new_value;
return old_value;
}
template <class T>
class m_vector
{
private:
unsigned int size;
unsigned int capacity;
T* array;
public:
m_vector()
: size(0)
, capacity(VECT_INC_SIZE)
, array(new T[VECT_INC_SIZE])
{}
m_vector(m_vector<T> const& other)
: size(other.size)
, capacity(other.capacity)
, array(new T[other.capacity]) {
//copy_n(other.array, size, array);
copy(other.cbegin(), other.cend(), begin());
}
// rule of 3
m_vector& operator=(m_vector<T> const& other) {
if (&other != this) {
if (other.capacity != capacity){
delete [] exchange(array, new T[other.capacity]);
capacity = other.capacity;
}
size = other.size;
//copy_n(other.array, size, array);
copy(other.cbegin(), other.cend(), begin());
}
return *this;
}
~m_vector() {
if (array != 0) delete [] array;
}
void push_back(T const& item) {
if (size >= capacity) {
reserve(capacity + VECT_INC_SIZE);
}
array[size] = item;
++size;
}
void reserve(unsigned int newCapacity) {
if (size > capacity) {
T* const temp = new T[newCapacity];
//copy_n(array, size, temp);
copy(cbegin(), cend(), temp);
delete [] exchange(array, temp);
capacity = newCapacity;
}
}
bool exists(T const& item) const {
//for(unsigned int i = 0; i < size; ++i) {
// if(array[i] == item) return true;
//}
for(T const* it = cbegin(); it != cend(); ++it) {
if(*it == item) return true;
}
return false;
}
void erase(T const& item) {
T* it = begin();
T* const endIt = end();
while(it != endIt && *it != item) ++it;
if (it == endIt) return;
copy(it + 1, endIt, it);
--size;
}
// iterators
T* begin() { return array; }
T* end() { return array + size; }
T const* cbegin() const { return array; }
T const* cend() const { return array + size; }
};
class Vector {
private:
int x,y;
public:
Vector() : x(0), y(0) {}
Vector(int x, int y) : x(x), y(y) {}
friend bool operator== (Vector const& lhs, Vector const& rhs){
return lhs.x == rhs.x && lhs.y == rhs.y;
}
friend bool operator!= (Vector const& lhs, Vector const& rhs){
return !(lhs==rhs);
}
};
#include <cstdio>
void VectorInM_Vector(m_vector<Vector> const& vec, Vector const& item) {
if (vec.exists(item)) printf("Vector found in vector\n");
else printf("Vector not found in vector\n");
}
int main(){
m_vector<Vector> vec;
vec.push_back(Vector(1,1));
VectorInM_Vector(vec, Vector(1,1));
m_vector<Vector> vec2(vec);
vec.erase(Vector(1,1));
VectorInM_Vector(vec, Vector(1,1));
VectorInM_Vector(vec2, Vector(1,1));
vec2 = vec;
VectorInM_Vector(vec2, Vector(1,1));
}
on compiler explorer/godbolt
I start to play with std::ranges and want understand how views really work. So I try to write my own container and iterator type and want to use it in a view.
But something seems to be missing but the compiler only tells me that there is no begin() method inside the view but not why.
Example:
#include <iostream>
#include <array>
#include <ranges>
class MyFixedContainer;
class MyIterator
{
MyFixedContainer* ptr;
unsigned int offset;
public:
MyIterator( MyFixedContainer* ptr_, unsigned int offset_ ): ptr{ ptr_},offset{offset_}{}
bool operator==( MyIterator& other ) const
{
return ( ptr == other.ptr )&& ( offset == other.offset );
}
bool operator!=( MyIterator& other ) const
{
return !(*this == other);
}
MyIterator operator++()
{
offset++;
return *this;
}
MyIterator operator++(int)
{
MyIterator tmp = *this;
offset++;
return tmp;
}
int operator*() const;
};
class MyFixedContainer
{
std::array<int,4> arr={5,6,7,8};
public:
auto begin() { return MyIterator{ this, 0 }; }
auto end() { return MyIterator{ this, 4}; }
int Get( int offset ) const
{
return arr[ offset ];
}
};
int MyIterator::operator*() const
{
return ptr->Get( offset );
}
int main()
{
MyFixedContainer c;
// Container type itself works:
for ( int i: c )
{
std::cout << i << std::endl;
}
// Try to use with std::ranges
auto even = [] (int i) { return 0 == i % 2; };
auto y = std::views::filter(c, even);
auto b = y.begin(); // << error message
}
Compiles with
main.cpp:90:16: error: 'struct std::ranges::views::__adaptor::_RangeAdaptorClosurestd::ranges::views::__adaptor::_RangeAdaptor<_Callable::operator()<{MyFixedContainer&, main()::<lambda(int)>&}>::<lambda(_Range&&)> >' has no member named 'begin'
90 | auto b = y.begin();
https://godbolt.org/z/doW76j
MyIterator does not model std::input_or_output_iterator because:
It needs to be default constructible.
std::iter_difference_t<MyIterator> must be valid, and
the pre-increment operator must return a reference.
MyIterator is not a std::sentinel_for<MyIterator, MyIterator> because its operators == and != take references instead of const references.
MyIterator does not satisfy std::input_iterator, which requires std::iter_value_t to be valid.
Fixing all of the above:
#include <iostream>
#include <array>
#include <ranges>
class MyFixedContainer;
class MyIterator
{
MyFixedContainer* ptr;
unsigned int offset;
public:
using difference_type = int;
using value_type = int;
MyIterator() = default;
MyIterator( MyFixedContainer* ptr_, unsigned int offset_ ): ptr{ ptr_},offset{offset_}{}
bool operator==( MyIterator const & other ) const
{
return ( ptr == other.ptr )&& ( offset == other.offset );
}
bool operator!=( MyIterator const & other ) const
{
return !(*this == other);
}
MyIterator &operator++()
{
offset++;
return *this;
}
MyIterator operator++(int)
{
MyIterator tmp = *this;
offset++;
return tmp;
}
int operator*() const;
};
class MyFixedContainer
{
std::array<int,4> arr={5,6,7,8};
public:
auto begin() { return MyIterator{ this, 0 }; }
auto end() { return MyIterator{ this, 4}; }
int Get( int offset ) const
{
return arr[ offset ];
}
};
int MyIterator::operator*() const
{
return ptr->Get( offset );
}
int main()
{
MyFixedContainer c;
// Container type itself works:
for ( int i: c )
{
std::cout << i << std::endl;
}
// Try to use with std::ranges
auto even = [] (int i) { return 0 == i % 2; };
static_assert(std::input_or_output_iterator<MyIterator>);
static_assert(std::ranges::input_range<MyFixedContainer>);
auto y = c | std::views::filter(even);
auto b = y.begin(); // << OK
}
The error messages are much clearer if you static_assert every concept that your container/iterator has to model.
I would like to dump the content inside the object tmp_np which is a UllmanSet which if you know a key then you know the position and if you know the position , you know the key. Is there a standard C++ container that's similar to the Ullmanset. Ullmanset 's index starts at 0 and Ullmanset1's index start at 1.
and also dump the content of frontierq which is a PriorityQ class.
UllmanSet tmp_np;
template<unsigned B>
class BasedUllmanSet
{
size_t n;
std::vector<int> key;
BasedVector<unsigned, B> pos;
public:
BasedUllmanSet()
: n(0)
{}
BasedUllmanSet(size_t cap)
: n(0), key(cap), pos(cap)
{}
size_t capacity() const { return key.size(); }
size_t size() const { return n; }
bool empty() const { return n == 0; }
void clear() { n = 0; }
void resize(size_t cap)
{
key.resize(cap);
pos.resize(cap);
n = 0;
}
bool contains(int k) const
{
unsigned p = pos[k];
return (p < n
&& key[p] == k);
}
void insert(int k)
{
if (contains(k))
return;
unsigned p = n++;
key[p] = k;
pos[k] = p;
}
void extend(int k)
{
assert(!contains(k));
unsigned p = n++;
key[p] = k;
pos[k] = p;
}
void erase(int k)
{
if (!contains(k))
return;
unsigned p = pos[k];
--n;
if (p != n)
{
int ell = key[n];
pos[ell] = p;
key[p] = ell;
}
}
int ith(int i)
{
assert(i >= 0 && i < (int)n);
return key[i];
}
};
using UllmanSet = BasedUllmanSet<0>;
using UllmanSet1 = BasedUllmanSet<1>;
The priority queue is implemented as followed. I like to print out the values inside the queue using std::cout.
PriorityQ<std::pair<int, int>, Comp> frontierq;
class Comp
{
public:
Comp() {}
bool operator()(const std::pair<int, int> &lhs,
const std::pair<int, int> &rhs) const
{
return (lhs.second > rhs.second
|| (lhs.second == rhs.second
&& lhs.first > rhs.first));
}
};
class PriorityQ
{
public:
Comp comp;
std::vector<T> v;
unsigned n;
public:
PriorityQ() : n(0) {}
PriorityQ(Comp comp_) : comp(comp_), n(0) {}
size_t size() const { return n; }
void clear() { n = 0; }
bool empty() { return n == 0; }
void push(const T &x)
{
assert(v.size() >= n);
if (v.size() == n)
v.push_back(x);
else
v[n] = x;
++n;
std::push_heap(&v[0], &v[n], comp);
}
const T &pop()
{
assert(n > 0);
std::pop_heap(&v[0], &v[n], comp);
--n;
return v[n];
}
const T &top()
{
assert(n > 0);
return v[0];
}
};
C++ standard containers do get this esoteric. If you have another question about the priority queue you should make another post.
I am implementing a container class that ensures uniqueness among the elements and restricts insertion and deletion to only the end only. Somewhat like a stack of unique elements or an ordered set with functions like push and pop. And it must also have a fixed maximum size.
template <class T, int max_size>
class FixedSizedUniqueStack
{
std::vector<T> m_vec;
std::unordered_set<T> m_uset;
public:
FixedSizedUniqueStack():m_vec(max_size),m_uset(){}
bool push(T x)
{
bool success = true;
if( m_uset.insert(x).second ) m_vec.push_back(x);
else success = false;
return success;
}
void pop()
{
if(m_vec.size() > 0)
{
m_uset.erase(m_vec.back());
m_vec.pop_back();
}
}
T back()
{
return m_vec.back();
}
};
#include <vector>
#include <unordered_set>
#include <initializer_list>
template <class T, int max_size>
class FixedSizedUniqueStack: public std::initializer_list<T>
{
protected:
std::vector<T> m_vec;
std::unordered_set<T> m_uset;
public:
FixedSizedUniqueStack():m_vec(),m_uset(){}
FixedSizedUniqueStack( const FixedSizedUniqueStack &x)
{
m_vec = x.m_vec;
m_uset = x.m_uset;
}
FixedSizedUniqueStack& operator= ( const FixedSizedUniqueStack &x)
{
if (this != &x)
{
m_vec = x.m_vec;
m_uset = x.m_uset;
}
return *this;
}
auto size() const -> decltype(m_vec.size())
{
return m_vec.size();
}
int push(const std::initializer_list<T>& il)
{
int errors = 0;
for (auto x: il)
{
if( push(x) )
{
errors++;
}
}
return errors;
}
int push(const T& x)
{
int error =0;
if(m_vec.size() < max_size)
{
if( x < start)
{
error = 1;
}
else if( x > stop)
{
error = 2;
}
else
{
if( m_uset.insert(x).second ) m_vec.push_back(x);
else error = 3;
}
}
else
{
error = 4;
}
return error;
}
void pop()
{
if(!m_vec.empty())
{
m_uset.erase(m_vec.back());
m_vec.pop_back();
}
}
T back()
{
return m_vec.back();
}
auto cbegin() const -> decltype(m_vec.cbegin())
{
return m_vec.cbegin();
}
auto cend() const -> decltype(m_vec.cend())
{
return m_vec.cend();
}
auto begin() const -> decltype(m_vec.begin())
{
return m_vec.begin();
}
auto end() const -> decltype(m_vec.end())
{
return m_vec.end();
}
auto empty() ->decltype(m_vec.empty())
{
return m_vec.empty();
}