mirror of
https://github.com/Tencent/flare.git
synced 2026-10-26 10:49:42 +08:00
249 lines
7.3 KiB
C++
249 lines
7.3 KiB
C++
// Copyright (C) 2021 THL A29 Limited, a Tencent company. All rights reserved.
|
|
//
|
|
// Licensed under the BSD 3-Clause License (the "License"); you may not use this
|
|
// file except in compliance with the License. You may obtain a copy of the
|
|
// License at
|
|
//
|
|
// https://opensource.org/licenses/BSD-3-Clause
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
// License for the specific language governing permissions and limitations under
|
|
// the License.
|
|
|
|
#ifndef FLARE_BASE_BUFFER_VIEW_H_
|
|
#define FLARE_BASE_BUFFER_VIEW_H_
|
|
|
|
#include <algorithm>
|
|
#include <iterator>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
#include "flare/base/buffer.h"
|
|
#include "flare/base/internal/early_init.h"
|
|
|
|
namespace flare {
|
|
|
|
// This class provides a visually contiguous byte-wise view of a buffer.
|
|
//
|
|
// Performance note: Due to implementation details, scanning through a buffer
|
|
// via this class is much slower than scanning the buffer in a non-contiguous
|
|
// fashion.
|
|
//
|
|
// A `ForwardIterator` is returned. Random access is not supported.
|
|
class NoncontiguousBufferForwardView {
|
|
public:
|
|
class const_iterator;
|
|
using iterator = const_iterator;
|
|
|
|
NoncontiguousBufferForwardView() = default;
|
|
explicit NoncontiguousBufferForwardView(const NoncontiguousBuffer& buffer)
|
|
: buffer_(&buffer) {}
|
|
|
|
const_iterator begin() const noexcept;
|
|
const_iterator end() const noexcept;
|
|
|
|
bool empty() const noexcept { return buffer_->Empty(); }
|
|
std::size_t size() const noexcept { return buffer_->ByteSize(); }
|
|
|
|
private:
|
|
const NoncontiguousBuffer* buffer_ =
|
|
&internal::EarlyInitConstant<NoncontiguousBuffer>();
|
|
};
|
|
|
|
// This class provides random access into a buffer.
|
|
//
|
|
// Internally this class build a mapping of all discontiguous buffer blocks.
|
|
// This comes at a cost. Therefore, unless you absolutely need it, stick with
|
|
// "forward" view.
|
|
//
|
|
// Same performance consideration as of `NoncontiguousBufferForwardView` also
|
|
// applies here.
|
|
class NoncontiguousBufferRandomView {
|
|
public:
|
|
class const_iterator;
|
|
using iterator = const_iterator;
|
|
|
|
NoncontiguousBufferRandomView();
|
|
explicit NoncontiguousBufferRandomView(const NoncontiguousBuffer& buffer);
|
|
|
|
// Random access. This is slower than traversal.
|
|
char operator[](std::size_t offset) const noexcept {
|
|
FLARE_DCHECK_LT(offset, size());
|
|
auto&& [off, iter] = FindSegmentMustSucceed(offset);
|
|
return iter->data()[offset - off];
|
|
}
|
|
|
|
const_iterator begin() const noexcept;
|
|
const_iterator end() const noexcept;
|
|
|
|
bool empty() const noexcept { return byte_size_ == 0; }
|
|
std::size_t size() const noexcept { return byte_size_; }
|
|
|
|
private:
|
|
std::pair<std::size_t, NoncontiguousBuffer::const_iterator>
|
|
FindSegmentMustSucceed(std::size_t offset) const noexcept;
|
|
|
|
private:
|
|
std::size_t byte_size_ = 0;
|
|
// [Starting offset -> iterator].
|
|
std::vector<std::pair<std::size_t, NoncontiguousBuffer::const_iterator>>
|
|
offsets_;
|
|
};
|
|
|
|
///////////////////////////////////////
|
|
// Implementation goes below. //
|
|
///////////////////////////////////////
|
|
|
|
class NoncontiguousBufferForwardView::const_iterator {
|
|
public:
|
|
using difference_type = std::ptrdiff_t;
|
|
using value_type = char;
|
|
using pointer = const char*;
|
|
using reference = const char&;
|
|
using iterator_category = std::forward_iterator_tag;
|
|
|
|
const_iterator() = default; // `end()`.
|
|
|
|
char operator*() const noexcept {
|
|
FLARE_DCHECK(current_ != end_, "Dereferencing an invalid iterator.");
|
|
FLARE_DCHECK_LT(byte_offset_, current_->size());
|
|
return *(current_->data() + byte_offset_);
|
|
}
|
|
|
|
const_iterator& operator++() noexcept {
|
|
FLARE_DCHECK(current_ != end_);
|
|
FLARE_DCHECK(byte_offset_ < current_->size());
|
|
++byte_offset_;
|
|
if (FLARE_UNLIKELY(byte_offset_ == current_->size())) {
|
|
byte_offset_ = 0;
|
|
++current_;
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
bool operator==(const const_iterator& iter) const noexcept {
|
|
return current_ == iter.current_ && byte_offset_ == iter.byte_offset_;
|
|
}
|
|
bool operator!=(const const_iterator& iter) const noexcept {
|
|
return current_ != iter.current_ || byte_offset_ != iter.byte_offset_;
|
|
}
|
|
|
|
private:
|
|
friend class NoncontiguousBufferForwardView;
|
|
|
|
const_iterator(NoncontiguousBuffer::const_iterator begin,
|
|
NoncontiguousBuffer::const_iterator end)
|
|
: current_(begin), end_(end), byte_offset_(0) {}
|
|
|
|
private:
|
|
NoncontiguousBuffer::const_iterator current_, end_;
|
|
std::size_t byte_offset_;
|
|
};
|
|
|
|
inline NoncontiguousBufferForwardView::const_iterator
|
|
NoncontiguousBufferForwardView::begin() const noexcept {
|
|
return const_iterator(buffer_->begin(), buffer_->end());
|
|
}
|
|
|
|
inline NoncontiguousBufferForwardView::const_iterator
|
|
NoncontiguousBufferForwardView::end() const noexcept {
|
|
return const_iterator();
|
|
}
|
|
|
|
class NoncontiguousBufferRandomView::const_iterator {
|
|
public:
|
|
using difference_type = std::ptrdiff_t;
|
|
using value_type = char;
|
|
using pointer = const char*;
|
|
using reference = const char&;
|
|
using iterator_category = std::forward_iterator_tag;
|
|
|
|
const_iterator() = default; // `end()`.
|
|
|
|
char operator*() const noexcept {
|
|
FLARE_DCHECK(current_ != end_, "Dereferencing an invalid iterator.");
|
|
FLARE_DCHECK_LT(seg_offset_, current_->size());
|
|
return *(current_->data() + seg_offset_);
|
|
}
|
|
|
|
const_iterator& operator+=(std::ptrdiff_t offset) noexcept {
|
|
SeekTo(offset);
|
|
return *this;
|
|
}
|
|
|
|
const_iterator operator+(std::ptrdiff_t offset) noexcept {
|
|
auto copy(*this);
|
|
copy += offset;
|
|
return copy;
|
|
}
|
|
|
|
std::ptrdiff_t operator-(const const_iterator& other) const noexcept {
|
|
return byte_offset_ - other.byte_offset_;
|
|
}
|
|
|
|
const_iterator& operator++() noexcept {
|
|
FLARE_DCHECK(current_ != end_);
|
|
FLARE_DCHECK(seg_offset_ < current_->size());
|
|
++seg_offset_;
|
|
if (FLARE_UNLIKELY(seg_offset_ == current_->size())) {
|
|
seg_offset_ = 0;
|
|
++current_;
|
|
}
|
|
++byte_offset_;
|
|
return *this;
|
|
}
|
|
|
|
// TODO(luobogao): Other operators.
|
|
|
|
bool operator==(const const_iterator& iter) const noexcept {
|
|
FLARE_CHECK_EQ(view_, iter.view_);
|
|
return byte_offset_ == iter.byte_offset_;
|
|
}
|
|
bool operator!=(const const_iterator& iter) const noexcept {
|
|
FLARE_CHECK_EQ(view_, iter.view_);
|
|
return byte_offset_ != iter.byte_offset_;
|
|
}
|
|
|
|
private:
|
|
friend class NoncontiguousBufferRandomView;
|
|
|
|
explicit const_iterator(const NoncontiguousBufferRandomView* view)
|
|
: view_(view) {
|
|
byte_offset_ = seg_offset_ = 0;
|
|
current_ = view->offsets_.front().second;
|
|
end_ = view->offsets_.back().second;
|
|
}
|
|
|
|
void SeekTo(std::size_t offset) noexcept {
|
|
FLARE_CHECK_LE(offset, view_->size());
|
|
auto&& [off, iter] = view_->FindSegmentMustSucceed(offset);
|
|
byte_offset_ = offset;
|
|
seg_offset_ = offset - off;
|
|
current_ = iter;
|
|
}
|
|
|
|
private:
|
|
const NoncontiguousBufferRandomView* view_;
|
|
std::size_t byte_offset_;
|
|
NoncontiguousBuffer::const_iterator current_, end_;
|
|
std::size_t seg_offset_;
|
|
};
|
|
|
|
inline NoncontiguousBufferRandomView::const_iterator
|
|
NoncontiguousBufferRandomView::begin() const noexcept {
|
|
return const_iterator(this);
|
|
}
|
|
|
|
inline NoncontiguousBufferRandomView::const_iterator
|
|
NoncontiguousBufferRandomView::end() const noexcept {
|
|
const_iterator result(this);
|
|
result.SeekTo(size());
|
|
return result;
|
|
}
|
|
|
|
} // namespace flare
|
|
|
|
#endif // FLARE_BASE_BUFFER_VIEW_H_
|