3

I want to maintain a buffer of 5 seconds of sensor data. The sensor data consists, among other things, of accelerometer readings in x,y,z dimensions, gyroscope readings in x,y,z dimension and magnetometer readings in x,y,z dimension.

My initial idea is to use an std::deque<SensorReading> which stores 5 seconds of the following SensorReading struct:

struct SensorReading {
   double time
   gyroscope g;
   accelerometer a;
   magnetometer m;
  //more substructs
} S;

A common operation on the buffer is that the user provides a start and end time and wants two Iterators marking the first and last reading of the gyroscope (or magnetometer or accelerometer) within this time interval from the buffer (deqeue). (Sometimes the user of the gyroscope reading might also be interested in the corresponding time stamps of the parent struct S.)

In my mind I have the idea of providing some sort of “views” of the buffer, which lets the user only see the substructure he is interested in. But I have no clear idea how to achieve this.

The only conceptual solution I have so far, is to introduce custom Iterators to the deque, a magnetometerIterator, gyroscopeIterator, accelerometerIterator and then expose only the corresponding substructure to the user.

I do not like the idea of maintaining multiple buffers, one for each substructure, because it adds redundancy to the code.

What would be a way to achieve this?

  • Do you really need iterators for this, or do you only care about the most recent value? Also, could the three readings be kept in separate data structures? – user22815 Jun 19 '15 at 18:22
  • @Snowman Thanks for your comment. Yes I really care about subintervals of data, let's say from 4 seconds ago until 2 seconds ago. I don't like to keep them in separate structures because then all the operations I have to do on the buffer will have to be done for each structure. Furthermore, I think it's an interesting question from a theory standpoint – user695652 Jun 19 '15 at 18:32
  • given this is for a buffer, am I also correct in assuming it must be thread-safe? – user22815 Jun 19 '15 at 18:35
  • @ Snowman For now thread-safety is not needed – user695652 Jun 19 '15 at 18:43
  • The custom iterator solution seems reasonable to me – M.M Jun 22 '15 at 1:59
1
+50

It's certainly do-able, but it's not small. An incomplete minimal example looks something like:

template <typename BaseIterator, typename FieldType, FieldType SensorReading::*FieldPtr>
class FilteredIterator {
    BaseIterator base_;
    typedef FilteredIterator<BaseIterator, FieldType, FieldPtr> self_type;
public:
    // iterator type traits
    typedef FieldType value_type;
    typedef typename BaseIterator::difference_type difference_type;
    typedef typename BaseIterator::iterator_category iterator_category;
    typedef typename std::add_lvalue_reference<FieldType>::type reference_type;
    typedef typename std::add_pointer<FieldType>::type pointer_type;
    // construction and assignment
    FilteredIterator() = delete;
    explicit FilteredIterator(BaseIterator base) : base_(base) {}
    FilteredIterator(self_type const &) = default;
    FilteredIterator(self_type &&) = default;
    FilteredIterator& operator=(self_type const &) = default;
    FilteredIterator& operator=(self_type &&) = default;
    // increment/traversal
    self_type& operator++()    { ++base_; return *this; }
    self_type  operator++(int) { self_type tmp(*this); ++*this; return tmp; }
    // dereference
    reference_type operator* () { return (*base_).*FieldPtr; }
    std::add_const<reference_type> operator* () const { return (*base_).*FieldPtr; }
};

template <typename FieldType, FieldType SensorReading::*FieldPtr, typename BaseIterator>
FilteredIterator<BaseIterator, FieldType, FieldPtr> member_filter(BaseIterator iter) {
    return FilteredIterator<BaseIterator, FieldType, FieldPtr>(iter);
}

example use:

std::deque<SensorReading> d;
// populate d
auto fi = member_filter<accelerometer, &SensorReading::a>(d.begin());
assert (&*fi == &(d.begin()->a));

Note that this still omits:

  • decrement and reverse iteration
  • comparison (<, >, ==, etc.)
  • distance/subtraction
  • operator->
  • etc...
  • correct handling of cv-qualified, reference and pointer members

A simpler approach is to use the Boost.Iterator Adaptor as a starting point.

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.