PtrStepLen

Files CCore/inc/gadget/PtrStepLen.h CCore/src/gadget/PtrStepLen.cpp

PtrStepLen is similar to the PtrLen. It represents a range of objects.


template <class T>
struct PtrStepLen
 {
  T *ptr;
  ulen step;
  ulen len;

Three members are used to specify a range: ptr, step and len. ptr is the address of the first range element. len is the number of elements of the range. step is the distance from any range element to the next. I.e. the range consists of the elements { ptr[0] , ptr[step] , ... , ptr[index*step] , ... , ptr[(len-1)*step] }.

  
  // constructors
  
  PtrStepLen() noexcept : ptr(0),step(0),len(0) {}
  
  PtrStepLen(NothingType) : PtrStepLen() {}
  
  PtrStepLen(T *ptr_,ulen step_,ulen len_) : ptr(ptr_),step(step_),len(len_) {}

  operator PtrStepLen<const T>() const { return {ptr,step,len}; }

Three constructors are provided: two to create a null range and third to create a range with the given ptr, step and len values. You can also cast to the const version. All other methods have direct equivalents and the same behavior as methods of the PtrLen.

Cursor methods:


  // cursor
  
  ulen operator + () const { return len; } // get length
                                           // range is not empty
  
  bool operator ! () const { return !len; } // range is empty
  
  T & operator * () const { return *ptr; } // first element
  
  T * operator -> () const { return ptr; } // pointer to the first element
  
  void operator ++ () { ptr+=step; len--; } // advance 
  
  void operator -- () { ptr-=step; len++; } // back
  
  PtrStepLen<T> operator += (ulen delta); // assume delta<=len, advance on delta
   
  PtrStepLen<T> takeup(ulen delta); // advance up to delta elements
  
  T & take(); // assume len>0, take first element and advance

  PtrStepLen<T> getFinal() const { return {ptr+len*step,step,0}; }

Methods fit() can be used to check the length of the range:

  
  // fit
   
  bool fit(ulen length) const { return length<=len; }
  
  bool fit(ulen off,ulen length) const { return off<=len && length<=(len-off) ; }

The first checks is there at least the length elements. The second can be used to check if the subrange with the given off(set) from the begin and length can be selected.

You can select a desired part of the range using parts methods:

  
  // parts
  
  PtrStepLen<T> prefix(ulen length) const;          // assume fit(length), prefix of the given length
  
  PtrStepLen<T> prefix(PtrStepLen<T> suffix) const; // prefix, complementary to the given suffix
  
  PtrStepLen<T> suffix(ulen length) const;          // assume fit(length), suffix of the given length
  
  PtrStepLen<T> part(ulen off,ulen length) const;   // assume fit(off,length), inner part with the given off(set) and length
  
  PtrStepLen<T> part(ulen off) const;               // assume fit(off), suffix with the given off(set)
  
  PtrStepLen<T> inner(ulen off,ulen endoff) const;  // assume fit(off,endoff), inner part with the given off(set) and offset from the end (endoff)

You can pick an element of the range based on its index:

   
  // index access
  
  T & operator [] (ulen index) const;
   
  T & at(ulen index) const; // with the index guard
  
  T & back(ulen index) const; // reverse order, index 1 means the last element

The last method is required to support range-based for with the PtrStepLen:


  // begin()/end() support
  
  bool operator != (PtrStepLen<T> end) const { return len!=end.len; }
 };

/* begin()/end() */

template <class T>
PtrStepLen<T> begin(PtrStepLen<T> a) { return a; }
 
template <class T>
PtrStepLen<T> end(PtrStepLen<T>) { return Nothing; }