Advertisement
Guest User

Untitled

a guest
Mar 29th, 2020
137
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 7.72 KB | None | 0 0
  1.  
  2.  
  3. #include<array>
  4.  
  5.  
  6. /* =======================================================================================
  7. /*      Ring Buffer class. Static Array of Data which cycles around when it reaches the
  8. /*  end The below Implementation is Thread Safe and Lock Free
  9. /*  TODO: Pack the Reader and Writer into a Single Atomic Int to save on overhead
  10. /* =======================================================================================*/
  11. template<typename _Ty, size_t _SZ>
  12. class ring_buffer
  13. {
  14. public:
  15.  
  16.     class iterator
  17.     {
  18.         /*  RANGE FOR Returns an Iterator for Begin and End. Inorder to properly wrap the Ring Buffer that Iterator needs to wrap
  19.             auto __begin = begin_expr;
  20.             auto __end = end_expr;
  21.         /* =======================================================================================================================*/
  22.     public:
  23.         using self_type  = iterator;
  24.         using value_type = std::atomic<_Ty>;
  25.         using reference  = value_type&;
  26.         using pointer    = value_type*;
  27.         using iterator_category = std::forward_iterator_tag;
  28.         using difference_type   = int;
  29.        
  30.         size_t Difference{ 0 };
  31.         iterator(pointer ptr, ring_buffer<_Ty, _SZ>* _rb)
  32.             :
  33.             ptr_(ptr),
  34.             Parent(_rb)
  35.         {
  36.             Difference = ((ptr - _rb->front()) / sizeof(std::atomic<_Ty>));
  37.         }
  38.  
  39.         self_type operator++()                { self_type i = *this; get_Next(ptr_); return i; }
  40.         self_type operator++(int junk)        { get_Next(ptr_); return *this;                  }  //{ ptr_++; return *this;                  }
  41.         reference operator* ()                { return *ptr_;                          }  // { return *ptr_;                          }
  42.         pointer   operator->()                { return ptr_;                           }
  43.         bool operator==(const self_type& rhs) { return ptr_ == rhs.ptr_;               }
  44.         bool operator!=(const self_type& rhs) { return ptr_ != rhs.ptr_;               }
  45.     private:
  46.         void get_Next(pointer _location)
  47.         {
  48.             ++_location >= Parent->back() ? _location = Parent->front() : _location;
  49.         }
  50.  
  51.         pointer ptr_;
  52.         ring_buffer<_Ty, _SZ> *Parent;
  53.     };
  54.  
  55.     /* begin() to allow for Range For Loops */
  56.     iterator begin()
  57.     {
  58.         CurrentPosition.store(ReadPosition.load());
  59.         return iterator(&Data[ReadPosition], this);
  60.     }
  61.     /* end() to allow for Range For Loops  */
  62.     iterator end()
  63.     {       // iterator Itr = iterator(&Data[WritePosition], this);//Address;
  64.         return iterator(&Data[WritePosition], this);
  65.     }
  66.  
  67.     ring_buffer() = default;
  68.  
  69.     using value_type = _Ty;
  70.     using reference = _Ty&;
  71.     using pointer = const _Ty*;
  72.  
  73.     using atomic_value_type = std::atomic<_Ty>;
  74.     using atomic_ptr = std::atomic<_Ty>*;
  75.  
  76.     /* Returns Index from a pointer by Subtracting the Starting Address from provided Address */
  77.     size_t get_Index(void *_ptr)
  78.     {
  79.         size_t result = (static_cast<atomic_ptr>(_ptr) - front());
  80.         return result;
  81.     }
  82.     /* Gets a Pointer to _element in the Ring Buffer */
  83.     void* get_Ptr(size_t _element)
  84.     {
  85.         atomic_ptr result = &Data[_element % BufferSize];
  86.         return result;
  87.     }
  88.  
  89.     /* Return the number of Elements in the Ring Buffer before it Rolls Over */
  90.     size_t element_Count()
  91.     {
  92.         return BufferSize ;
  93.     }
  94.  
  95.    /* pushRange   (InputIterator* first, InputIterator* last); */
  96.    /* pushElements(InputIterator* first, size_t numElements);  */
  97.    /* popElements (outputIterator*  itr, size_t numElements);  */
  98.    /* popAll      (Output* itr);                               */
  99.  
  100.  
  101.     /* Forwards an Element to the Ring Buffer */
  102.     bool push(_Ty&& _element)
  103.     {
  104.         auto OldWritePosition = WritePosition.load();
  105.         auto NewWritePosition = nextElement(OldWritePosition);
  106.  
  107.         if (NewWritePosition == ReadPosition.load())
  108.         {/* If Read position and Write position are the same Buffer is Full */
  109.          //   DEBUG_CODE(Print("Error: Ring Buffer Full attempting to Forward a value:");)
  110.             return false;
  111.         }
  112.         Data[OldWritePosition].store(std::forward<value_type>(_element));
  113.         WritePosition.store(NewWritePosition);
  114.         return true;
  115.     }
  116.  
  117.     /* Adds a new Element to the Ring Buffer*/
  118.     bool push(const reference _element)
  119.     {// Adds new Element to Queue
  120.         auto OldWritePosition = WritePosition.load();
  121.         auto NewWritePosition = nextElement(OldWritePosition);
  122.  
  123.         if (NewWritePosition == ReadPosition.load())
  124.         {/* If Read position and Write position are the same Buffer is Full */
  125.            // DEBUG_CODE(Print("Error: Ring Buffer Full and you are Attempting to Add more Elements to it:" << _element);)
  126.             return false;
  127.         }
  128.         Data[OldWritePosition].store(_element);
  129.         WritePosition.store(NewWritePosition);
  130.         return true;
  131.     }
  132.  
  133.     /* Pops an Element from the back of the Buffer and returns it as a parameter  */
  134.     bool pop(reference _returnElement)
  135.     {/* Returns True if more elements in Queue*/
  136.         while (true)
  137.         {/* READER: Multiple in Existance */
  138.             auto OldWritePosition = WritePosition.load();
  139.             auto OldReadPosition = ReadPosition.load();
  140.  
  141.             if (OldWritePosition == OldReadPosition)
  142.             {// If attempting to read the same position again or buffer is full return false;
  143.              //   DEBUG_CODE(Print("Error: Ring Buffer Empty. You are Attempting to Pop Elements from empty buffer"); );
  144.                 return false;
  145.             }
  146.  
  147.             _returnElement = Data[OldReadPosition].load();
  148.  
  149.             if (ReadPosition.compare_exchange_strong(OldReadPosition, nextElement(OldReadPosition)))
  150.             {
  151.                 return true;
  152.             }
  153.         }
  154.     }/// WE MIGHT BE ABLE TO PACK THE READER AND WRITER INTO THE SAME ATOMIC INTEGER WHICH WILL REDUCE THE OVERHEAD
  155.  
  156.     /* Get the Start of the Ring Buffer */
  157.     auto front()    { return &Data[0];    }
  158.     /* Get the Start of the Ring Buffer */
  159.     auto back()    { return &Data[BufferSize - 1];    }
  160.  
  161.     /* Remove the First Element in the Ring Buffer */
  162.     void pop_front()    { ReadPosition = nextElement(ReadPosition);    }
  163.  
  164.     /* Test if container is Empty
  165.        NOTE: Change this to is_Empty() because the STL naming convention is retarded */
  166.     bool is_Empty()    { return (ReadPosition == WritePosition);    }
  167.  
  168.     /* Deletes the Ring Buffers Data */
  169.     bool destroy()    { delete[](Data);    }//return BufferSize; b<0- This is not Correct, We need WritePosition - ReadPosition;
  170.  
  171.     /* Current size of the Ring Buffer from Start to End */
  172.     size_t size()    { return WritePosition - ReadPosition;     }
  173.  //[ReadPosition % BufferSize];
  174.     /* Overload to properly wrap the _offset in the Ring Buffer */
  175.     reference operator[](const int _offset)    { return Data[_offset % BufferSize];    }
  176.  
  177. private:
  178.  
  179.     /* Retrieved the next Element in the RB taking care to wrap when needed */
  180.     size_t nextElement(size_t _pos)
  181.     {// Note: This can be accomplished Via Bit operations extremely fast if the Size is proper
  182.         return ++_pos == BufferSize ? 0 : _pos;
  183.     }
  184.     /* Retrieved the next Element in the RB taking care to wrap when needed */
  185.     pointer incMemory(size_t _pos)
  186.     {// Note: This can be accomplished Via Bit operations extremely fast if the Size is proper
  187.         size_t Index =  ++_pos == BufferSize ? 0 : _pos;
  188.  
  189.     }
  190.  
  191.  
  192.     std::atomic<size_t>
  193.         ReadPosition{ 0 },
  194.         WritePosition{ 0 },
  195.         CurrentPosition{ 0 };
  196.  
  197.     size_t BufferSize = _SZ + 1;
  198.     std::array<std::atomic<_Ty>, _SZ + 1> Data;
  199. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement