| // Copyright 2017 Google Inc. All Rights Reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // 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. |
| |
| #include "nb/multipart_allocator.h" |
| |
| #include <algorithm> |
| |
| #include "starboard/log.h" |
| #include "starboard/memory.h" |
| |
| namespace nb { |
| |
| MultipartAllocator::Allocations::Allocations(void* buffer, int buffer_size) |
| : number_of_buffers_(1), |
| buffers_(&buffer_), |
| buffer_sizes_(&buffer_size_), |
| buffer_(buffer), |
| buffer_size_(buffer_size) { |
| SB_DCHECK(buffer != NULL); |
| SB_DCHECK(buffer_size > 0); |
| } |
| |
| MultipartAllocator::Allocations::Allocations(int number_of_buffers, |
| void** buffers, |
| const int* buffer_sizes) |
| : number_of_buffers_(0), buffers_(NULL), buffer_sizes_(NULL) { |
| SB_DCHECK(number_of_buffers > 0); |
| SB_DCHECK(buffers != NULL); |
| SB_DCHECK(buffer_sizes != NULL); |
| |
| Assign(number_of_buffers, buffers, buffer_sizes); |
| |
| for (int i = 0; i < number_of_buffers_; ++i) { |
| SB_DCHECK(buffers_[i] != NULL); |
| SB_DCHECK(buffer_sizes_[i] > 0); |
| } |
| } |
| |
| MultipartAllocator::Allocations::Allocations(const Allocations& that) |
| : number_of_buffers_(0), buffers_(NULL), buffer_sizes_(NULL) { |
| Assign(that.number_of_buffers_, that.buffers_, that.buffer_sizes_); |
| } |
| |
| MultipartAllocator::Allocations::~Allocations() { |
| Destroy(); |
| } |
| |
| MultipartAllocator::Allocations& MultipartAllocator::Allocations::operator=( |
| const Allocations& that) { |
| Destroy(); |
| Assign(that.number_of_buffers_, that.buffers_, that.buffer_sizes_); |
| return *this; |
| } |
| |
| int MultipartAllocator::Allocations::size() const { |
| int size = 0; |
| |
| for (size_t i = 0; i < number_of_buffers_; ++i) { |
| size += buffer_sizes_[i]; |
| } |
| |
| return size; |
| } |
| |
| void MultipartAllocator::Allocations::ShrinkTo(int size) { |
| for (size_t i = 0; i < number_of_buffers_; ++i) { |
| if (size >= buffer_sizes_[i]) { |
| size -= buffer_sizes_[i]; |
| } else { |
| buffer_sizes_[i] = size; |
| size = 0; |
| ++i; |
| while (i < number_of_buffers_) { |
| buffer_sizes_[i] = 0; |
| ++i; |
| } |
| break; |
| } |
| } |
| |
| SB_DCHECK(size == 0); |
| } |
| |
| void MultipartAllocator::Allocations::Write(int destination_offset, |
| const void* src, |
| int size) { |
| size_t buffer_index = 0; |
| const uint8_t* src_in_uint8 = static_cast<const uint8_t*>(src); |
| while (size > 0) { |
| if (buffer_index >= number_of_buffers_) { |
| SB_NOTREACHED(); |
| return; |
| } |
| if (buffer_sizes_[buffer_index] <= destination_offset) { |
| destination_offset -= buffer_sizes_[buffer_index]; |
| } else { |
| int bytes_to_copy = |
| std::min(size, buffer_sizes_[buffer_index] - destination_offset); |
| uint8_t* destination_in_uint8 = |
| static_cast<uint8_t*>(buffers_[buffer_index]); |
| SbMemoryCopy(destination_in_uint8 + destination_offset, src_in_uint8, |
| bytes_to_copy); |
| destination_offset = 0; |
| src_in_uint8 += bytes_to_copy; |
| size -= bytes_to_copy; |
| } |
| ++buffer_index; |
| } |
| } |
| |
| void MultipartAllocator::Allocations::Read(void* destination) const { |
| uint8_t* destination_in_uint8 = static_cast<uint8_t*>(destination); |
| |
| for (size_t i = 0; i < number_of_buffers_; ++i) { |
| SbMemoryCopy(destination_in_uint8, buffers_[i], buffer_sizes_[i]); |
| destination_in_uint8 += buffer_sizes_[i]; |
| } |
| } |
| |
| void MultipartAllocator::Allocations::Assign(int number_of_buffers, |
| void** buffers, |
| const int* buffer_sizes) { |
| SB_DCHECK(number_of_buffers_ == 0); |
| SB_DCHECK(buffers_ == NULL); |
| SB_DCHECK(buffer_sizes_ == NULL); |
| |
| number_of_buffers_ = number_of_buffers; |
| if (number_of_buffers_ == 0) { |
| buffers_ = NULL; |
| buffer_sizes_ = NULL; |
| return; |
| } |
| if (number_of_buffers_ == 1) { |
| buffers_ = &buffer_; |
| buffer_sizes_ = &buffer_size_; |
| buffer_ = buffers[0]; |
| buffer_size_ = buffer_sizes[0]; |
| return; |
| } |
| buffers_ = new void*[number_of_buffers_]; |
| buffer_sizes_ = new int[number_of_buffers_]; |
| SbMemoryCopy(buffers_, buffers, sizeof(*buffers_) * number_of_buffers_); |
| SbMemoryCopy(buffer_sizes_, buffer_sizes, |
| sizeof(*buffer_sizes_) * number_of_buffers_); |
| } |
| |
| void MultipartAllocator::Allocations::Destroy() { |
| if (number_of_buffers_ > 1) { |
| delete[] buffers_; |
| delete[] buffer_sizes_; |
| } |
| number_of_buffers_ = 0; |
| buffers_ = NULL; |
| buffer_sizes_ = NULL; |
| } |
| |
| } // namespace nb |