Extracting elements from a struct stored in an std::container

96 Views Asked by At

I have a std::vector which stores a complex struct S (coming from a real time source) which consists of nested structs N1, N2, N3. The struct S has a time field.

A common task, is to retrieve any of the 3 nested structs between two times, for example getSequenceN1(startTime, stopTime, itrStart, itrStop), which gives 2 iterators to the start and end of the subsequence.

So the code would look something like this:

struct {
   double time
   struct N1;
   struct N2;
   struct N3;
} S;

class D {


public: 
   void getSequenceN1(startTime, stopTime, itrStart, itrStop);
   void getSequenceN2(startTime, stopTime, itrStart, itrStop);
   void getSequenceN3(startTime, stopTime, itrStart, itrStop);

private: 
  std::vector<S> stream;
};

What would the right way of implementing the functionality of getSequenceN1?

One way would of course be to have a vector for each N1, N2, N3, (in real live there are more than 3 subtracts) but i am wondering if std offers some nice feature for this?

I am not forced to use a vector btw, any std container (maybe even boost) works. I was hoping I could provide something like a view for the vector where we either only see N1 N2 or N3.

One way would be to provide customized Iterators which give back N1 N2 and N3 respectively.

1

There are 1 best solutions below

2
On
void getSequenceN1(double startTime, 
                   double stopTime, 
                   vector<struct N1>& sequence)
{
    
    for( S cur: stream)
    {
        if (s.time >= startTime && s.time < endTime)
        {
             sequence.push-back(s.N1's_name);
        }
    }
}

Optimize and adjust start and end conditions to suit. For example, if S is not going to be modified while you are examining the sequence, you can use a vector of pointers to struct N1 and save a some copying.

EDIT

Playing around with the concept. Still need to abstract it because declaring a different iterator for each sub structure is a pretty stupid solution. Suggestions greatly appreciated.

#include<iostream>
#include<vector>

struct N1
{
    int count;
    bool operator==(const N1 & rhs) const
    {
        return count == rhs.count;
    }
    bool operator!=(const N1 & rhs) const
    {
        return count != rhs.count;
    }
};

struct S
{
    double time;
    struct N1 n1;
    bool operator<(const S & rhs) const
    {
        return time < rhs.time;
    }
};

class N1Iterator: public std::iterator<std::input_iterator_tag, struct N1>
{
    std::vector<S>::iterator mIt;
public:
    N1Iterator()
    {

    }
    N1Iterator(std::vector<S>::iterator it) :
            mIt(it)
    {

    }
    N1Iterator(const N1Iterator& it) :
            mIt(it.mIt)
    {

    }
    N1Iterator& operator++()
    {
        ++mIt;
        return *this;
    }
    N1Iterator operator++(int)
    {
        N1Iterator tmp(*this);
        operator++();
        return tmp;
    }
    bool operator==(const N1Iterator& rhs)
    {
        return mIt->n1 == rhs.mIt->n1;
    }
    bool operator!=(const N1Iterator& rhs)
    {
        return mIt->n1 != rhs.mIt->n1;
    }
    N1& operator*()
    {
        return mIt->n1;
    }
    N1* operator->()
    {
        return &mIt->n1;
    }
};

std::vector<S> stream;

N1Iterator & getSequenceN1(double startTime,
                         double stopTime,
                         N1Iterator & begin,
                         N1Iterator & end)
{
    S key;
    key.time = startTime;
    begin=N1Iterator(std::lower_bound(stream.begin(), stream.end(), key));
    key.time = stopTime;
    end=N1Iterator(std::lower_bound(stream.begin(), stream.end(), key));

    return begin;
}

int main(int argc, char **argsv)
{
    for (int count = 0; count < 10; count++)
    {
        S s1;
        s1.time = count;
        s1.n1.count = count;
        stream.push_back(s1);
    }
    N1Iterator begin;
    N1Iterator end;

    getSequenceN1(3, 7, begin, end);

    while (begin != end)
    {
        std::cout << begin->count << std::endl;
        ++begin;
    }
}