blob: 1796f425bb5b1518fd064908c46e591fab9c003f [file] [log] [blame]
/*
* The MIT License (MIT)
*
* Copyright (c) 2015 Microsoft Corporation
*
* -=- Robust Distributed System Nucleus (rDSN) -=-
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
#include "binary_writer.h"
#include <memory>
#include "utils.h"
#include "utils/blob.h"
namespace dsn {
int binary_writer::_reserved_size_per_buffer_static = 256;
binary_writer::binary_writer(int reserveBufferSize)
{
_total_size = 0;
_buffers.reserve(1);
_reserved_size_per_buffer =
(reserveBufferSize == 0) ? _reserved_size_per_buffer_static : reserveBufferSize;
_current_buffer = nullptr;
_current_offset = 0;
_current_buffer_length = 0;
}
binary_writer::binary_writer(blob &buffer)
{
_total_size = 0;
_buffers.reserve(1);
_reserved_size_per_buffer = _reserved_size_per_buffer_static;
_buffers.push_back(buffer);
_current_buffer = (char *)buffer.data();
_current_offset = 0;
_current_buffer_length = buffer.length();
}
binary_writer::~binary_writer() {}
void binary_writer::flush() { commit(); }
void binary_writer::create_buffer(size_t size)
{
commit();
blob bb;
create_new_buffer(size, bb);
_buffers.push_back(bb);
_current_buffer = (char *)bb.data();
_current_buffer_length = bb.length();
}
void binary_writer::create_new_buffer(size_t size, /*out*/ blob &bb)
{
bb.assign(::dsn::utils::make_shared_array<char>(size), 0, (int)size);
}
void binary_writer::commit()
{
if (_current_offset > 0) {
*_buffers.rbegin() = _buffers.rbegin()->range(0, _current_offset);
_current_offset = 0;
_current_buffer_length = 0;
}
}
blob binary_writer::get_buffer()
{
commit();
if (_buffers.size() == 1) {
return _buffers[0];
} else if (_total_size == 0) {
return blob();
} else {
std::shared_ptr<char> bptr(::dsn::utils::make_shared_array<char>(_total_size));
blob bb(bptr, _total_size);
const char *ptr = bb.data();
for (int i = 0; i < static_cast<int>(_buffers.size()); i++) {
memcpy((void *)ptr, (const void *)_buffers[i].data(), (size_t)_buffers[i].length());
ptr += _buffers[i].length();
}
return bb;
}
}
blob binary_writer::get_current_buffer()
{
if (_buffers.size() == 1) {
return _current_offset > 0 ? _buffers[0].range(0, _current_offset) : _buffers[0];
} else {
std::shared_ptr<char> bptr(::dsn::utils::make_shared_array<char>(_total_size));
blob bb(bptr, _total_size);
const char *ptr = bb.data();
for (int i = 0; i < static_cast<int>(_buffers.size()); i++) {
size_t len = (size_t)_buffers[i].length();
if (_current_offset > 0 && i + 1 == (int)_buffers.size()) {
len = _current_offset;
}
memcpy((void *)ptr, (const void *)_buffers[i].data(), len);
ptr += _buffers[i].length();
}
return bb;
}
}
void binary_writer::write_empty(int sz)
{
int sz0 = sz;
int rem_size = _current_buffer_length - _current_offset;
if (rem_size >= sz) {
_current_offset += sz;
} else {
_current_offset += rem_size;
sz -= rem_size;
int allocSize = _reserved_size_per_buffer;
if (sz > allocSize)
allocSize = sz;
create_buffer(allocSize);
_current_offset += sz;
}
_total_size += sz0;
}
void binary_writer::write(const char *buffer, int sz)
{
int rem_size = _current_buffer_length - _current_offset;
if (rem_size >= sz) {
memcpy((void *)(_current_buffer + _current_offset), buffer, (size_t)sz);
_current_offset += sz;
_total_size += sz;
} else {
if (rem_size > 0) {
memcpy((void *)(_current_buffer + _current_offset), buffer, (size_t)rem_size);
_current_offset += rem_size;
_total_size += rem_size;
sz -= rem_size;
}
int allocSize = _reserved_size_per_buffer;
if (sz > allocSize)
allocSize = sz;
create_buffer(allocSize);
memcpy((void *)(_current_buffer + _current_offset), buffer + rem_size, (size_t)sz);
_current_offset += sz;
_total_size += sz;
}
}
bool binary_writer::next(void **data, int *size)
{
int rem_size = _current_buffer_length - _current_offset;
if (rem_size == 0) {
create_buffer(_reserved_size_per_buffer);
rem_size = _current_buffer_length;
}
*size = rem_size;
*data = (void *)(_current_buffer + _current_offset);
_current_offset = _current_buffer_length;
_total_size += rem_size;
return true;
}
bool binary_writer::backup(int count)
{
assert(count <= _current_offset);
_current_offset -= count;
_total_size -= count;
return true;
}
}