Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

buffer zero alloc #146

Open
wants to merge 15 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 15 additions & 20 deletions src/eckit/io/Buffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* does it submit to any jurisdiction.
*/

#include <algorithm>
#include <cstring>

#include "eckit/exception/Exceptions.h"
Expand All @@ -19,31 +20,29 @@ namespace eckit {

namespace {

static char* allocate(size_t size) {
return new char[size];
static char* allocate(const size_t size) {
return size == 0 ? nullptr : new char[size];
}

static void deallocate(char* buffer) {
static void deallocate(char*& buffer) {
delete[] buffer;
buffer = nullptr;
}

} // namespace

//----------------------------------------------------------------------------------------------------------------------

Buffer::Buffer(size_t size) :
buffer_{nullptr}, size_{size} {
Buffer::Buffer(const size_t size): size_ {size} {
create();
}

Buffer::Buffer(const void* p, size_t len) :
buffer_{nullptr}, size_{len} {
Buffer::Buffer(const void* p, size_t len): size_ {len} {
create();
copy(p, len);
}

Buffer::Buffer(const std::string& s) :
buffer_{nullptr}, size_{s.length() + 1} {
Buffer::Buffer(const std::string& s): size_ {s.length() + 1} {
create();
copy(s);
}
Expand Down Expand Up @@ -85,26 +84,22 @@ void Buffer::create() {
}

void Buffer::destroy() {
if (buffer_) {
deallocate(buffer_);
buffer_ = nullptr;
size_ = 0;
}
deallocate(buffer_);
size_ = 0;
}

void Buffer::copy(const std::string& s) {
ASSERT(buffer_);
::strncpy(buffer_, s.c_str(), std::min(size_, s.size() + 1));
if (buffer_) { ::strncpy(buffer_, s.c_str(), std::min(size_, s.size() + 1)); }
}

void Buffer::copy(const void* p, size_t size, size_t pos) {
ASSERT(buffer_ && size_ >= pos + size);
if (size) {
void Buffer::copy(const void* p, const size_t size, const size_t pos) {
ASSERT(size_ >= pos + size);
if (buffer_ && size > 0) {
::memcpy(buffer_ + pos, p, size);
}
}

void Buffer::resize(size_t size, bool preserveData) {
void Buffer::resize(const size_t size, const bool preserveData) {
if (size != size_) {
if (preserveData) {
char* newbuffer = allocate(size);
Expand Down
50 changes: 42 additions & 8 deletions tests/io/test_buffer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <ctime>

#include <algorithm>
#include <memory>

#include "eckit/io/Buffer.h"
#include "eckit/testing/Test.h"
Expand All @@ -18,21 +19,22 @@ namespace eckit::test {

//----------------------------------------------------------------------------------------------------------------------

unsigned char* random_bytestream(size_t sz) {
::srand((unsigned int)::time(0));
unsigned char* random_bytestream(const size_t sz) {
::srand(static_cast<unsigned int>(::time(nullptr)));
unsigned char* stream = static_cast<unsigned char*>(::malloc(sz));
auto rnd = []() -> unsigned char { return ::rand(); };
std::generate(stream, stream + sz, rnd);
// std::for_each(stream, stream + sz, [](unsigned char c) { std::cout << c ; });
return stream;
}

const char* msg = "Once upon a midnight dreary";
constexpr auto msg = "Once upon a midnight dreary";
constexpr auto msgLen = std::char_traits<char>::length(msg);

CASE("Test eckit Buffer default constructor") {
Buffer buf;
EXPECT(buf.size() == 0);
EXPECT(buf.data() != nullptr);
EXPECT(buf.data() == nullptr);
}

CASE("Test eckit Buffer constructor 1") {
Expand Down Expand Up @@ -68,7 +70,8 @@ CASE("Test eckit Buffer move constructor") {
const char* out = buf2;
EXPECT(std::strcmp(msg, out) == 0);

EXPECT(static_cast<const char*>(buf1) == nullptr && buf1.size() == 0);
EXPECT(static_cast<const char*>(buf1) == nullptr);
EXPECT_EQUAL(buf1.size(), 0);
}

CASE("Test eckit Buffer move assignment") {
Expand All @@ -81,8 +84,8 @@ CASE("Test eckit Buffer move assignment") {
const char* out = buf2;
EXPECT(std::strcmp(msg, out) == 0);

// EXPECT(static_cast<const char*>(buf1) == nullptr)
EXPECT(buf1.size() == 0);
EXPECT(static_cast<const char*>(buf1) == nullptr);
EXPECT_EQUAL(buf1.size(), 0);
}

// This includes a self-move but is legitimate, if pointless, so it should be tested
Expand Down Expand Up @@ -114,14 +117,17 @@ CASE("Test eckit Buffer Zero") {

// NOTE: resize allocates a new buffer whenever the new size is different -- this is inefficient
CASE("Test eckit Buffer resize") {
const size_t sz = std::strlen(msg) + 1;
constexpr auto sz = msgLen + 1;
Buffer buf;
EXPECT(buf.size() == 0);

EXPECT_THROWS(buf.copy(msg, sz));

EXPECT_NO_THROW(buf.resize(sz));
EXPECT_EQUAL(buf.size(), sz);

EXPECT_NO_THROW(buf.copy(msg, sz));
EXPECT_EQUAL(std::strncmp(msg, static_cast<const char*>(buf), sz), 0);

size_t newSize = 41;
buf.resize(newSize, true);
Expand All @@ -139,6 +145,34 @@ CASE("Test eckit Buffer resize") {
newSize = 41;
buf.resize(newSize, false);
EXPECT(buf.size() == newSize);

buf.resize(0, false);
EXPECT_EQUAL(buf.size(), 0);
EXPECT(buf.data() == nullptr);

buf.resize(0, true);
EXPECT_EQUAL(buf.size(), 0);
EXPECT(buf.data() == nullptr);
}

CASE("Test copy from temp buffer") {
struct BufferTester {
explicit BufferTester(const Buffer& buffer = Buffer {0}): buf_ {buffer, buffer.size()} { }

Buffer buf_;
};

std::unique_ptr<BufferTester> tester;

// empty
EXPECT_NO_THROW(tester = std::make_unique<BufferTester>());
EXPECT(tester->buf_.data() == nullptr);
EXPECT_EQUAL(tester->buf_.size(), 0);

// non-empty
EXPECT_NO_THROW(tester = std::make_unique<BufferTester>(Buffer {msg, msgLen}));
EXPECT_EQUAL(std::strncmp(msg, static_cast<const char*>(tester->buf_), msgLen), 0);
EXPECT_EQUAL(tester->buf_.size(), msgLen);
}

CASE("Test copying and construction from of std::string") {
Expand Down
Loading