blob: d2447cec0847498dee43fa4aa8e8655c2c0e4fc1 [file] [log] [blame]
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/logging.h"
#include "services/media/framework/parts/sparse_byte_buffer.h"
namespace mojo {
namespace media {
SparseByteBuffer::Hole::Hole() {}
SparseByteBuffer::Hole::Hole(std::map<size_t, size_t>::iterator iter)
: iter_(iter) {}
SparseByteBuffer::Hole::Hole(const Hole& other) : iter_(other.iter_) {}
SparseByteBuffer::Hole::~Hole() {}
SparseByteBuffer::Region::Region() {}
SparseByteBuffer::Region::Region(
std::map<size_t, std::vector<uint8_t>>::iterator iter)
: iter_(iter) {}
SparseByteBuffer::Region::Region(const Region& other) : iter_(other.iter_) {}
SparseByteBuffer::Region::~Region() {}
SparseByteBuffer::SparseByteBuffer() {}
SparseByteBuffer::~SparseByteBuffer() {}
void SparseByteBuffer::Initialize(size_t size) {
holes_.clear();
regions_.clear();
size_ = size;
// Create one hole spanning the entire buffer.
holes_[0] = size_;
}
SparseByteBuffer::Region SparseByteBuffer::FindRegionContaining(size_t position,
Region hint) {
DCHECK(size_ > 0u);
DCHECK(position < size_);
RegionsIter iter = hint.iter_;
if (iter != regions_.end() && iter->first <= position) {
if (iter->first + iter->second.size() <= position) {
// iter is too close to the front. See if the next region is correct.
++iter;
if (iter != regions_.end() && iter->first <= position &&
position < iter->first + iter->second.size()) {
return Region(iter);
}
} else if (position < iter->first + iter->second.size()) {
return Region(iter);
}
}
iter = regions_.lower_bound(position);
if (iter != regions_.begin() &&
(iter == regions_.end() || iter->first > position)) {
--iter;
DCHECK(iter->first <= position);
if (iter->first + iter->second.size() <= position) {
iter = regions_.end();
}
}
return Region(iter);
}
SparseByteBuffer::Hole SparseByteBuffer::FindOrCreateHole(size_t position,
Hole hint) {
DCHECK(size_ > 0u);
DCHECK(!holes_.empty());
HolesIter result = hint.iter_;
if (result == holes_.end()) {
result = holes_.begin();
}
if (result->first != position) {
if (result->first > position ||
result->first + result->second <= position) {
// Need to find the hole containing the requested position.
result = FindHoleContaining(position).iter_;
DCHECK(result != holes_.end());
}
if (result->first != position) {
// Need to split this hole.
DCHECK(position > result->first);
size_t front_size = position - result->first;
DCHECK(result->second > front_size);
size_t back_size = result->second - front_size;
result->second = front_size;
result = holes_.insert(++result,
std::pair<size_t, size_t>(position, back_size));
}
}
DCHECK(result->first == position);
return Hole(result);
}
SparseByteBuffer::Hole SparseByteBuffer::FindHoleContaining(size_t position) {
DCHECK(size_ > 0u);
HolesIter iter = holes_.lower_bound(position);
if (iter != holes_.begin() &&
(iter == holes_.end() || iter->first > position)) {
--iter;
DCHECK(iter->first <= position);
if (iter->first + iter->second < position) {
iter = holes_.end();
}
}
return Hole(iter);
}
SparseByteBuffer::Hole SparseByteBuffer::Fill(Hole hole,
std::vector<uint8_t>&& buffer) {
DCHECK(size_ > 0u);
DCHECK(hole.iter_ != holes_.end());
DCHECK(buffer.size() != 0);
DCHECK(buffer.size() <= hole.size());
HolesIter holes_iter = hole.iter_;
size_t buffer_size = buffer.size();
size_t position = holes_iter->first;
regions_.emplace(std::make_pair(position, std::move(buffer)));
// Remove the region from holes_.
while (buffer_size != 0) {
DCHECK(holes_iter != holes_.end());
DCHECK(holes_iter->first == position);
if (buffer_size < holes_iter->second) {
// We've filled part of *holes_iter. Insert a hole after it to
// represent the remainder.
HolesIter hint = holes_iter;
holes_.insert(
++hint, std::pair<size_t, size_t>(holes_iter->first + buffer_size,
holes_iter->second - buffer_size));
// When we've erased holes_iter, we'll have accounted for the entire
// filled region.
position += buffer_size;
buffer_size = 0;
} else {
// Calculate where we'll be when we've erased holes_iter.
position += holes_iter->second;
buffer_size -= holes_iter->second;
}
holes_iter = holes_.erase(holes_iter);
if (holes_iter == holes_.end()) {
DCHECK(buffer_size == 0);
holes_iter = holes_.begin();
}
}
return Hole(holes_iter);
}
bool operator==(const SparseByteBuffer::Hole& a,
const SparseByteBuffer::Hole& b) {
return a.iter_ == b.iter_;
}
bool operator!=(const SparseByteBuffer::Hole& a,
const SparseByteBuffer::Hole& b) {
return a.iter_ != b.iter_;
}
bool operator==(const SparseByteBuffer::Region& a,
const SparseByteBuffer::Region& b) {
return a.iter_ == b.iter_;
}
bool operator!=(const SparseByteBuffer::Region& a,
const SparseByteBuffer::Region& b) {
return a.iter_ != b.iter_;
}
} // namespace media
} // namespace mojo