diff --git a/include/tscpp/util/LocalBuffer.h b/include/tscpp/util/LocalBuffer.h new file mode 100644 index 00000000000..aaaac0a2ade --- /dev/null +++ b/include/tscpp/util/LocalBuffer.h @@ -0,0 +1,72 @@ +/** @file + + LocalBuffer + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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. + */ + +#pragma once + +namespace ts +{ +template class LocalBuffer +{ +public: + LocalBuffer(std::size_t size) + : _ptr(size == 0 ? nullptr : (size > EstSizeBound ? new T[size] : _buf)), + _size((0 < size && size <= EstSizeBound) ? EstSizeBound : size) + { + } + ~LocalBuffer(); + + // Don't allocate on heap + void *operator new(std::size_t) = delete; + void *operator new[](std::size_t) = delete; + + T *data() const; + std::size_t size() const; + +private: + T _buf[EstSizeBound]; + T *const _ptr; + const std::size_t _size; +}; + +template LocalBuffer::~LocalBuffer() +{ + if (_ptr && _ptr != _buf) { + delete[] _ptr; + } +} + +template +inline T * +LocalBuffer::data() const +{ + return _ptr; +} + +template +inline std::size_t +LocalBuffer::size() const +{ + return _size; +} + +} // namespace ts diff --git a/include/tscpp/util/Makefile.am b/include/tscpp/util/Makefile.am index 5fea12cd2d1..3424e6556d2 100644 --- a/include/tscpp/util/Makefile.am +++ b/include/tscpp/util/Makefile.am @@ -20,5 +20,6 @@ library_includedir=$(includedir)/tscpp/util library_include_HEADERS = \ IntrusiveDList.h \ - PostScript.h \ - TextView.h + LocalBuffer.h \ + PostScript.h \ + TextView.h diff --git a/src/tscpp/util/Makefile.am b/src/tscpp/util/Makefile.am index 9e972b4efb8..07351fde45c 100644 --- a/src/tscpp/util/Makefile.am +++ b/src/tscpp/util/Makefile.am @@ -38,6 +38,7 @@ test_tscpputil_CXXFLAGS = -Wno-array-bounds $(AM_CXXFLAGS) test_tscpputil_LDADD = libtscpputil.la test_tscpputil_SOURCES = \ unit_tests/unit_test_main.cc \ + unit_tests/test_LocalBuffer.cc \ unit_tests/test_MemSpan.cc \ unit_tests/test_PostScript.cc \ unit_tests/test_TextView.cc \ diff --git a/src/tscpp/util/unit_tests/test_LocalBuffer.cc b/src/tscpp/util/unit_tests/test_LocalBuffer.cc new file mode 100644 index 00000000000..9d4b3a3bbd0 --- /dev/null +++ b/src/tscpp/util/unit_tests/test_LocalBuffer.cc @@ -0,0 +1,111 @@ +/** @file + + Unit tests for LocalBuffer + + @section license License + + Licensed to the Apache Software Foundation (ASF) under one + or more contributor license agreements. See the NOTICE file + distributed with this work for additional information + regarding copyright ownership. The ASF licenses this file + to you 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 "catch.hpp" +#include "tscpp/util/LocalBuffer.h" + +#include + +TEST_CASE("LocalBuffer", "[libts][LocalBuffer]") +{ + SECTION("EstSizeBound = default") + { + SECTION("size = 0") + { + const size_t len = 0; + ts::LocalBuffer local_buffer(len); + uint8_t *buf = local_buffer.data(); + + CHECK(buf == nullptr); + CHECK(local_buffer.size() == 0); + } + + SECTION("size = 1024") + { + const size_t len = 1024; + ts::LocalBuffer local_buffer(len); + uint8_t *buf = local_buffer.data(); + + memset(buf, 0xAA, len); + + CHECK(buf[0] == 0xAA); + CHECK(buf[len - 1] == 0xAA); + CHECK(local_buffer.size() == 1024); + } + + SECTION("size = 2048") + { + const size_t len = 2048; + ts::LocalBuffer local_buffer(len); + uint8_t *buf = local_buffer.data(); + + memset(buf, 0xAA, len); + + CHECK(buf[0] == 0xAA); + CHECK(buf[len - 1] == 0xAA); + CHECK(local_buffer.size() == 2048); + } + } + + SECTION("EstSizeBound = 2048") + { + SECTION("size = 1024") + { + const size_t len = 1024; + ts::LocalBuffer local_buffer(len); + uint8_t *buf = local_buffer.data(); + + memset(buf, 0xAA, len); + + CHECK(buf[0] == 0xAA); + CHECK(buf[len - 1] == 0xAA); + CHECK(local_buffer.size() == 2048); + } + + SECTION("size = 2048") + { + const size_t len = 2048; + ts::LocalBuffer local_buffer(len); + uint8_t *buf = local_buffer.data(); + + memset(buf, 0xAA, len); + + CHECK(buf[0] == 0xAA); + CHECK(buf[len - 1] == 0xAA); + CHECK(local_buffer.size() == 2048); + } + + SECTION("size = 4096") + { + const size_t len = 4096; + ts::LocalBuffer local_buffer(len); + uint8_t *buf = local_buffer.data(); + + memset(buf, 0xAA, len); + + CHECK(buf[0] == 0xAA); + CHECK(buf[len - 1] == 0xAA); + CHECK(local_buffer.size() == 4096); + } + } +}