TuringSim
C++ framework to simulate abstract computing models
stack.h
1 #pragma once
2 
3 #include <utils/messageException.h>
4 #include <memory/memoryStructure.h>
5 
6 #include <vector>
7 
11 namespace TuringSim::Memory::Stack {
12  template <typename T> class StackObserver;
13  template <typename T> class StackModifier;
14 
19  public:
24 
35  StackTooSmallException(std::string message, size_t allocated, size_t freeSpace, size_t requestedElementsNumber) :
37  {}
38 
42  size_t getAllocated() const noexcept {
43  return allocated;
44  }
45 
49  size_t getFreeSpace() const noexcept {
50  return freeSpace;
51  }
52 
53  protected:
54  virtual std::string makeFullMessage() const override {
55  std::ostringstream ss;
56  ss << this->msg << std::endl;
57  ss << " Allocated size: " << allocated << std::endl;
58  ss << " Free space: " << freeSpace << std::endl;
59  ss << " Requested elements number: " << requestedElementsNumber << std::endl;
60  return ss.str();
61  }
62 
63  size_t allocated;
64  size_t freeSpace;
66  };
67 
75  template<typename T>
76  class Stack : public MemoryStructure<T, Stack<T>, StackObserver<T>, StackModifier<T>>
77  {
81  friend class StackObserver<T>;
82 
86  friend class StackModifier<T>;
87 
88  public:
93  static constexpr size_t MinAllocatedStackSize = 10;
94 
98  constexpr Stack();
99 
103  constexpr Stack(const Stack<T>& other);
104 
108  constexpr Stack(Stack<T>&& other);
109 
114  constexpr Stack<T>& operator=(const Stack<T>& other);
115 
120  constexpr Stack<T>& operator=(Stack<T>&& other);
121 
125  ~Stack() = default;
126 
130  constexpr void push(const T& symbol);
131 
135  constexpr void push(T&& symbol);
136 
140  constexpr void pushs(const std::vector<T>& symbol);
141 
145  constexpr void pushs(std::vector<T>&& symbol);
146 
154  [[nodiscard]] const T& top() const;
155 
161  [[nodiscard]] std::optional<T> top_opt() const;
162 
168  [[nodiscard]] std::vector<T> tops(size_t nb) const;
169 
174  [[nodiscard]] std::optional<std::vector<T>> tops_opt(size_t nb) const;
175 
179  void pop();
180 
185  void pops(size_t nb);
186 
190  [[nodiscard]] constexpr bool empty() const noexcept;
191 
195  void assertNonEmpty() const;
196 
197  private:
198  constexpr void allocate();
199  constexpr void allocate(size_t additionalSize);
200  constexpr void shrink();
201  constexpr void disableFree();
202  constexpr void enableFree();
203  void setSizeFactor(size_t newSizeFactor);
204  constexpr void free();
205 
206  size_t size = 0;
207  size_t freeSpace = MinAllocatedStackSize;
208  std::vector<T> stack = std::vector<T>(MinAllocatedStackSize);
209  bool enabledFree = true;
210  size_t sizeFactor = 2;
211  };
212 
213  template<typename T>
214  constexpr Stack<T>::Stack()
215  {}
216 
217  template<typename T>
218  constexpr Stack<T>::Stack(const Stack<T>& other) :
219  size(other.size),
220  freeSpace(other.freeSpace),
221  stack(other.stack),
222  enabledFree(other.enabledFree),
223  sizeFactor(other.sizeFactor)
224  {}
225 
226  template<typename T>
227  constexpr Stack<T>::Stack(Stack<T>&& other) :
228  size(std::move(other.size)),
229  freeSpace(std::move(other.freeSpace)),
230  stack(std::move(other.stack)),
231  enabledFree(std::move(other.enabledFree)),
232  sizeFactor(std::move(other.sizeFactor))
233  {}
234 
235  template<typename T>
236  constexpr Stack<T> &Stack<T>::operator=(const Stack<T>& other) {
237  if(this != &other) {
238  size = other.size;
239  freeSpace = other.freeSpace;
240  stack = other.stack;
241  enabledFree = other.enabledFree;
242  sizeFactor = other.sizeFactor;
243  }
244  return *this;
245  }
246 
247  template<typename T>
248  constexpr Stack<T> &Stack<T>::operator=(Stack<T>&& other) {
249  if(this != &other) {
250  size = std::move(other.size);
251  freeSpace = std::move(other.freeSpace);
252  stack = std::move(other.stack);
253  enabledFree = std::move(other.enabledFree);
254  sizeFactor = std::move(other.sizeFactor);
255  }
256  return *this;
257  }
258 
259  template<typename T>
260  constexpr void Stack<T>::push(const T& symbol) {
261  if(!freeSpace) {
262  allocate();
263  }
264 
265  stack[size] = symbol;
266  size++;
267  freeSpace--;
268  }
269 
270  template<typename T>
271  constexpr void Stack<T>::push(T&& symbol) {
272  if(!freeSpace) {
273  allocate();
274  }
275 
276  stack[size] = std::move(symbol);
277  size++;
278  freeSpace--;
279  }
280 
281  template<typename T>
282  constexpr void Stack<T>::pushs(const std::vector<T>& symbols) {
283  while(freeSpace < symbols.size()) {
284  allocate();
285  }
286 
287  for(const T& symbol: symbols) {
288  stack[size] = symbol;
289  size++;
290  }
291 
292  freeSpace -= symbols.size();
293  }
294 
295  template<typename T>
296  constexpr void Stack<T>::pushs(std::vector<T>&& symbols) {
297  while(freeSpace < symbols.size()) {
298  allocate();
299  }
300 
301  for(T& symbol: symbols) {
302  stack[size] = std::move(symbol);
303  size++;
304  }
305 
306  freeSpace -= symbols.size();
307  }
308 
309  template<typename T>
310  constexpr void Stack<T>::allocate()
311  {
312  stack.resize(sizeFactor*stack.size());
313  freeSpace = stack.size() - size;
314  }
315 
316  template<typename T>
317  constexpr void Stack<T>::allocate(size_t additionalSize) {
318  stack.resize(stack.size() + additionalSize);
319  freeSpace = stack.size() - size;
320  }
321 
322  template <typename T>
323  const T& Stack<T>::top() const {
324  if(!size) {
325  throw StackTooSmallException("Empty stack in Stack<T>::top()", stack.size(), freeSpace, 1);
326  }
327  return stack[size-1];
328  }
329 
330  template <typename T>
331  std::optional<T> Stack<T>::top_opt() const {
332  if(!size) {
333  return {};
334  }
335  return {stack[size - 1]};
336  }
337 
338  template <typename T>
339  std::vector<T> Stack<T>::tops(size_t nb) const {
340  if(size < nb) {
341  throw StackTooSmallException("Empty stack in Stack<T>::tops()", stack.size(), freeSpace, nb);
342  }
343  return {stack.begin() + static_cast<long>(size) - static_cast<long>(nb), stack.begin() + static_cast<long>(size)};
344  }
345 
346  template <typename T>
347  std::optional<std::vector<T>> Stack<T>::tops_opt(size_t nb) const {
348  if(size < nb) {
349  return {};
350  }
351  return {std::vector<T>{stack.begin() + static_cast<long>(size) - static_cast<long>(nb), stack.begin() + static_cast<long>(size)}};
352  }
353 
354  template <typename T>
355  void Stack<T>::pop() {
356  if(!size) {
357  throw StackTooSmallException("Empty stack in Stack<T>::pop()", stack.size(), freeSpace, 1);
358  }
359  size--;
360  freeSpace++;
361 
362  if(enabledFree) {
363  free();
364  }
365  }
366 
367  template <typename T>
368  void Stack<T>::pops(size_t nb) {
369  if(size < nb) {
370  throw StackTooSmallException("Stack too small in Stack<T>::pops()", stack.size(), freeSpace, nb);
371  }
372  size -= nb;
373  freeSpace += nb;
374 
375  if(enabledFree) {
376  free();
377  }
378  }
379 
380  template <typename T>
381  constexpr bool Stack<T>::empty() const noexcept {
382  return size==0;
383  }
384 
385  template <typename T>
387  if (!size) {
388  throw StackTooSmallException("Empty stack in Stack<T>::assertNonEmpty()", stack.size(), freeSpace, 1);
389  }
390  }
391 
392  template <typename T>
393  constexpr void Stack<T>::free() {
394  if((sizeFactor*sizeFactor-1)*size < freeSpace) {
395  stack.resize(std::max(MinAllocatedStackSize, stack.size()/sizeFactor));
396  freeSpace = stack.size() - size;
397  }
398  }
399 
400  template <typename T>
401  constexpr void Stack<T>::shrink() {
402  stack.resize(std::max(size, MinAllocatedStackSize));
403  freeSpace = 0;
404  }
405 
406  template <typename T>
407  constexpr void Stack<T>::disableFree() {
408  enabledFree = false;
409  }
410 
411  template <typename T>
412  constexpr void Stack<T>::enableFree() {
413  enabledFree = true;
414  free();
415  }
416 
417  template <typename T>
418  void Stack<T>::setSizeFactor(size_t newSizeFactor) {
419  if(newSizeFactor < 2) {
420  throw InvalidFactorException("Size factor is too small in Stack<T>::setSizeFactor(size_t). Must be > 1.", newSizeFactor);
421  }
422  sizeFactor = newSizeFactor;
423  }
424 
428  template <typename T>
429  class StackObserver : public MemoryObserver<Stack<T>, StackObserver<T>>
430  {
431  public:
437  constexpr StackObserver(const Stack<T>& stack) : MemoryObserver<Stack<T>, StackObserver<T>>(&stack) {}
441  [[nodiscard]] constexpr size_t getSize() const { return this->memory->size; }
445  [[nodiscard]] constexpr size_t getFreeSpace() const { return this->memory->freeSpace; }
449  [[nodiscard]] constexpr size_t getAllocatedSize() const { return this->memory->stack.size(); }
453  [[nodiscard]] constexpr const std::vector<T>& getStack() const { return this->memory->stack; }
457  [[nodiscard]] constexpr bool getEnabledFree() const { return this->memory->enabledFree; }
461  [[nodiscard]] constexpr size_t getSizeFactor() const { return this->memory->sizeFactor; }
462  };
463 
467  template <typename T>
468  class StackModifier : public MemoryModifier<Stack<T>, StackModifier<T>>
469  {
470  public:
476  constexpr StackModifier(Stack<T>& stack) : MemoryModifier<Stack<T>, StackModifier<T>>(&stack) {}
481  constexpr void allocate() const { this->memory->allocate(); }
485  constexpr void allocate(size_t additionalSize) const { this->memory->allocate(additionalSize); }
489  constexpr void shrink() const { this->memory->shrink(); }
490 
493  constexpr void disableFree() const { this->memory->disableFree(); }
494 
497  constexpr void enableFree() const { this->memory->enableFree(); }
498 
503  constexpr void setSizeFactor(size_t newSizeFactor) { this->memory->setSizeFactor(newSizeFactor); }
504  };
505 }
TuringSim::Utils::MessageException::MessageException
MessageException()=delete
a message exception must have an explicative message.
TuringSim::Memory::Stack::StackModifier::shrink
constexpr void shrink() const
Deallocate all unused space.
Definition: stack.h:489
TuringSim::Memory::Stack::StackTooSmallException::makeFullMessage
virtual std::string makeFullMessage() const override
Build the full error message. It should be overridden by derived class that adds data to the exceptio...
Definition: stack.h:54
TuringSim::Memory::Stack::StackTooSmallException::getAllocated
size_t getAllocated() const noexcept
Get the allocated size on the empty stack.
Definition: stack.h:42
TuringSim::Memory::Stack::StackModifier::enableFree
constexpr void enableFree() const
Enable the deallocating.
Definition: stack.h:497
TuringSim::Memory::Stack::StackTooSmallException::StackTooSmallException
StackTooSmallException(std::string message, size_t allocated, size_t freeSpace, size_t requestedElementsNumber)
Builds an EmptyMultiStackException from an error message, the allocated size of this stack,...
Definition: stack.h:35
TuringSim::Utils::MessageException::msg
std::string msg
The error message.
Definition: messageException.h:78
TuringSim::Memory::Stack::StackTooSmallException::StackTooSmallException
StackTooSmallException()=delete
An EmptyMultiStackException must contain an error message, the allocated size of this stack,...
TuringSim::Memory::Stack::Stack::Stack
constexpr Stack()
Construct an empty stack.
Definition: stack.h:214
TuringSim::Memory::Stack::StackObserver
Observer for the Stack class.
Definition: stack.h:430
TuringSim::Utils::MessageException
The Base class for all custom exceptions.
Definition: messageException.h:12
TuringSim::Memory::Stack::StackTooSmallException::allocated
size_t allocated
the allocated space on the empty stack.
Definition: stack.h:63
TuringSim::Memory::Stack::Stack::empty
constexpr bool empty() const noexcept
Test if the stack is empty.
Definition: stack.h:381
TuringSim::Memory::Stack::StackModifier::allocate
constexpr void allocate() const
Allocate space on the stack.
Definition: stack.h:481
TuringSim::Memory::Stack::Stack::tops_opt
std::optional< std::vector< T > > tops_opt(size_t nb) const
Get the top elements of the stack.
Definition: stack.h:347
TuringSim::Memory::Stack::StackModifier::setSizeFactor
constexpr void setSizeFactor(size_t newSizeFactor)
Set the size factor.
Definition: stack.h:503
TuringSim::Memory::Stack::StackObserver::StackObserver
constexpr StackObserver(const Stack< T > &stack)
Construct an observer for the stack in parameter.
Definition: stack.h:437
TuringSim::Memory::Stack::Stack::MinAllocatedStackSize
static constexpr size_t MinAllocatedStackSize
The size allocated when constructing a stack.
Definition: stack.h:93
TuringSim::Memory::Stack::Stack::pushs
constexpr void pushs(const std::vector< T > &symbol)
Push multiple elements on the stack.
Definition: stack.h:282
TuringSim::Memory::Stack::Stack::top
const T & top() const
Get the top element of the stack.
Definition: stack.h:323
TuringSim::Memory::Stack::Stack
Class to represent a stack memory.
Definition: stack.h:77
TuringSim::Memory::Stack::StackObserver::getAllocatedSize
constexpr size_t getAllocatedSize() const
Return the allocated space.
Definition: stack.h:449
TuringSim::Memory::Stack::Stack::operator=
constexpr Stack< T > & operator=(const Stack< T > &other)
Copy a stack.
Definition: stack.h:236
TuringSim::Memory::Stack::StackObserver::getStack
constexpr const std::vector< T > & getStack() const
Return the stack.
Definition: stack.h:453
TuringSim::Memory::Stack::StackObserver::getSizeFactor
constexpr size_t getSizeFactor() const
Get the size factor.
Definition: stack.h:461
TuringSim::Memory::Stack::StackModifier::allocate
constexpr void allocate(size_t additionalSize) const
Allocate e boxes on the stack.
Definition: stack.h:485
TuringSim::Memory::Stack::Stack::tops
std::vector< T > tops(size_t nb) const
Get the top elements of the stack.
Definition: stack.h:339
TuringSim::Memory::Stack::Stack::pop
void pop()
Pop the top element of the stack.
Definition: stack.h:355
TuringSim::Memory::Stack::Stack::assertNonEmpty
void assertNonEmpty() const
Test if the stack is empty.
Definition: stack.h:386
TuringSim::Memory::MemoryStructure
Base class for all memory structures.
Definition: memoryStructure.h:117
TuringSim::Memory::Stack::StackObserver::getEnabledFree
constexpr bool getEnabledFree() const
Check whether the stack deallocate space when the used space is small enough.
Definition: stack.h:457
TuringSim::Memory::Stack::Stack::~Stack
~Stack()=default
Destruct the stack.
TuringSim::Memory::Stack::Stack::pops
void pops(size_t nb)
Pop multiple top elements of the stack.
Definition: stack.h:368
TuringSim::Memory::Stack::StackObserver::getFreeSpace
constexpr size_t getFreeSpace() const
Return the unused allocated stack.
Definition: stack.h:445
TuringSim::Memory::Stack::StackTooSmallException::requestedElementsNumber
size_t requestedElementsNumber
the number of elements requested.
Definition: stack.h:65
TuringSim::Memory::Stack::StackTooSmallException::getFreeSpace
size_t getFreeSpace() const noexcept
Get the free size on the empty stack.
Definition: stack.h:49
TuringSim::Memory::Stack::StackObserver::getSize
constexpr size_t getSize() const
Return the current size of the stack.
Definition: stack.h:441
TuringSim::Memory::Stack::StackTooSmallException::freeSpace
size_t freeSpace
the free space on the empty stack.
Definition: stack.h:64
TuringSim::Memory::Stack::StackModifier::StackModifier
constexpr StackModifier(Stack< T > &stack)
Construct an modifier for the stack in parameter.
Definition: stack.h:476
TuringSim::Memory::MemoryObserver
Base class for all memory observers.
Definition: memoryStructure.h:187
TuringSim::Memory::Stack::Stack::top_opt
std::optional< T > top_opt() const
Get the top element of the stack.
Definition: stack.h:331
TuringSim::Memory::MemoryModifier
Base class for all memory modifiers.
Definition: memoryStructure.h:307
TuringSim::Memory::Stack::Stack::push
constexpr void push(const T &symbol)
Push an element on the stack.
Definition: stack.h:260
TuringSim::Memory::Stack::StackModifier
Modifier for the Stack class.
Definition: stack.h:469
TuringSim::Memory::Stack::StackTooSmallException
Exception thrown when we try to pop or top an empty stack, or pops or tops a too small stack.
Definition: stack.h:18
TuringSim::Memory::Stack
Namespace for Stack, the observer and the modifier.
TuringSim::Memory::Stack::StackModifier::disableFree
constexpr void disableFree() const
Disable the deallocating.
Definition: stack.h:493