rlogiacco / CircularBuffer

Arduino circular buffer library
GNU Lesser General Public License v3.0
312 stars 85 forks source link

Add 'copy to array' method #52

Closed pulquero closed 8 months ago

pulquero commented 3 years ago

I'm using the cyclicbuffer to maintain a fixed size history/lookback of samples. Every so often I need to process the contents of the buffer. Using the buffer directly is too slow, so I first copy out the contents to an array via [] operator. A dedicated copy-to-array method would be more optimal as for starters, the if statement to check index bound could be skipped. I think it would just need a loop to copy everything from head to end of buffer, and another loop to copy from start of buffer to tail. This would also avoid the expensive of having to do % operation.

rlogiacco commented 3 years ago

Feel free to submit a pull request along one or two examples/test programs

rlogiacco commented 3 years ago

On second thought I don't think I get your request, so can you please provide a code example of what's your usage? Please consider the copy-to-array operation is going to double up your buffer memory consumption and starters will still have to loop and check they are not getting out of array boundary...

pulquero commented 3 years ago

I have a polynomial operation, say O(N^3). Running directly on the buffer introduces alot of overhead. Yes, copying to an array increases memory consumption, but it is worth it for the reduction in time.


template<typename T, size_t S, typename IT>
void inline CircularBuffer<T,S,IT>::copyTo(T* out) const {
    const T* bufEnd = buffer + capacity;
    const T* outEnd = out + count;
    for (const T* t = head; t < bufEnd && out < outEnd; t++, out++) {
        *out = *t;
    }
    for (const T* t = buffer; t <= tail && out < outEnd; t++, out++) {
        *out = *t;
    }
}

template<typename T, size_t S, typename IT>
template<typename R>
void inline CircularBuffer<T,S,IT>::copyTo(R* out, R (&convert)(const T&)) const {
    const T* bufEnd = buffer + capacity;
    const R* outEnd = out + count;
    for (const T* t = head; t < bufEnd && out < outEnd; t++, out++) {
        *out = convert(*t);
    }
    for (const T* t = buffer; t <= tail && out < outEnd; t++, out++) {
        *out = convert(*t);
    }
}
rlogiacco commented 3 years ago

Do you want to submit a pull request so your contribution gets traced and you get credited? Also a usage example and some documentation for the README would be nice.

pulquero commented 3 years ago

No, it's fine. Probably quicker if you just do it. You can probably fix-up the 2nd method to accept lambdas too.

rlogiacco commented 3 years ago

Ok. Thanks for your contribution.

Quick question: are you 100% sure the two separate loops are faster than the modulus? I'm not assembly guy...

pulquero commented 3 years ago

Yes, modulus is going to be implemented in software - most MCUs dont have an instruction for it.

rlogiacco commented 8 months ago

resolved in release 1.4.0