err_t qbuffer_pop_back(qbuffer_t* buf) { qbytes_t* bytes; int64_t skip; int64_t len; qbuffer_iter_t chunk; if ( qbuffer_num_parts(buf) == 0 ) return EINVAL; chunk = qbuffer_end(buf); qbuffer_iter_prev_part(buf, &chunk); qbuffer_iter_get(chunk, qbuffer_end(buf), &bytes, &skip, &len); deque_pop_back(sizeof(qbuffer_part_t), &buf->deque); buf->offset_end -= len; return 0; }
qioerr qbuffer_pop_back(qbuffer_t* buf) { qbytes_t* bytes; int64_t skip; int64_t len; qbuffer_iter_t chunk; if ( qbuffer_num_parts(buf) == 0 ) QIO_RETURN_CONSTANT_ERROR(EINVAL, "cannot pop from empty buffer"); chunk = qbuffer_end(buf); qbuffer_iter_prev_part(buf, &chunk); qbuffer_iter_get(chunk, qbuffer_end(buf), &bytes, &skip, &len); deque_pop_back(sizeof(qbuffer_part_t), &buf->deque); buf->offset_end -= len; return 0; }
/* Advances an iterator using linear search. */ void qbuffer_iter_advance(qbuffer_t* buf, qbuffer_iter_t* iter, int64_t amt) { deque_iterator_t d_begin = deque_begin( & buf->deque ); deque_iterator_t d_end = deque_end( & buf->deque ); if( amt >= 0 ) { // forward search. iter->offset += amt; while( ! deque_it_equals(iter->iter, d_end) ) { qbuffer_part_t* qbp = (qbuffer_part_t*) deque_it_get_cur_ptr(sizeof(qbuffer_part_t), iter->iter); if( iter->offset < qbp->end_offset ) { // it's in this one. return; } deque_it_forward_one(sizeof(qbuffer_part_t), & iter->iter); } // If we get here, we didn't find it. Return the buffer end. *iter = qbuffer_end(buf); } else { // backward search. iter->offset += amt; // amt is negative if( ! deque_it_equals( iter->iter, d_end ) ) { // is it within the current buffer? qbuffer_part_t* qbp = (qbuffer_part_t*) deque_it_get_cur_ptr(sizeof(qbuffer_part_t), iter->iter); if( iter->offset >= qbp->end_offset - qbp->len_bytes ) { // it's in this one. return; } } // now we have a valid deque element. do { qbuffer_part_t* qbp; deque_it_back_one(sizeof(qbuffer_part_t), & iter->iter); qbp = (qbuffer_part_t*) deque_it_get_cur_ptr(sizeof(qbuffer_part_t), iter->iter); if( iter->offset >= qbp->end_offset - qbp->len_bytes ) { // it's in this one. return; } } while( ! deque_it_equals(iter->iter, d_begin) ); // If we get here, we didn't find it. Return the buffer start. *iter = qbuffer_begin(buf); } }
err_t qbuffer_pop_front(qbuffer_t* buf) { qbytes_t* bytes; int64_t skip; int64_t len; qbuffer_iter_t chunk; if ( qbuffer_num_parts(buf) == 0 ) return EINVAL; chunk = qbuffer_begin(buf); qbuffer_iter_get(chunk, qbuffer_end(buf), &bytes, &skip, &len); deque_pop_front(sizeof(qbuffer_part_t), &buf->deque); buf->offset_start += len; return 0; }
// find buffer iterator part in logarithmic time // finds an offset in the window [offset_start,offset_end] // (in other words, offset might not start at 0) qbuffer_iter_t qbuffer_iter_at(qbuffer_t* buf, int64_t offset) { qbuffer_iter_t ret; deque_iterator_t first = deque_begin(& buf->deque); deque_iterator_t last = deque_end(& buf->deque); deque_iterator_t middle; qbuffer_part_t* qbp; ssize_t num_parts = deque_it_difference(sizeof(qbuffer_part_t), last, first); ssize_t half; while( num_parts > 0 ) { half = num_parts >> 1; middle = first; deque_it_forward_n(sizeof(qbuffer_part_t), &middle, half); qbp = (qbuffer_part_t*) deque_it_get_cur_ptr(sizeof(qbuffer_part_t), middle); if( offset < qbp->end_offset ) { num_parts = half; } else { first = middle; deque_it_forward_one(sizeof(qbuffer_part_t), &first); num_parts = num_parts - half - 1; } } if( deque_it_equals(first, last) ) { ret = qbuffer_end(buf); } else { qbp = (qbuffer_part_t*) deque_it_get_cur_ptr(sizeof(qbuffer_part_t), first); if( offset < qbp->end_offset - qbp->len_bytes ) { ret = qbuffer_begin(buf); } else { ret.offset = offset; ret.iter = first; } } return ret; }