From 9eaebc0db46b3d59f52224a2c0e44f63657314b0 Mon Sep 17 00:00:00 2001 From: Tudor Bosman Date: Thu, 14 Jun 2012 17:07:00 -0700 Subject: [PATCH] Add TypedIOBuf. Summary: Simple class to handle IOBuf as an array of objects of fixed size. Test Plan: test added Reviewed By: brianp@fb.com FB internal diff: D497287 --- folly/experimental/io/TypedIOBuf.h | 142 +++++++++++++++++++++++ folly/experimental/io/test/IOBufTest.cpp | 18 +++ 2 files changed, 160 insertions(+) create mode 100644 folly/experimental/io/TypedIOBuf.h diff --git a/folly/experimental/io/TypedIOBuf.h b/folly/experimental/io/TypedIOBuf.h new file mode 100644 index 00000000..b3327dc7 --- /dev/null +++ b/folly/experimental/io/TypedIOBuf.h @@ -0,0 +1,142 @@ +/* + * Copyright 2012 Facebook, Inc. + * + * 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. + */ + +#ifndef FOLLY_IO_TYPEDIOBUF_H_ +#define FOLLY_IO_TYPEDIOBUF_H_ + +#include +#include "folly/experimental/io/IOBuf.h" + +namespace folly { + +/** + * Wrapper class to handle a IOBuf as a typed buffer (to a standard layout + * class). + * + * This class punts on alignment, and assumes that you know what you're doing. + * + * All methods are wrappers around the corresponding IOBuf methods. The + * TypedIOBuf object is stateless, so it's perfectly okay to access the + * underlying IOBuf in between TypedIOBuf method calls. + */ +template +class TypedIOBuf { + static_assert(std::is_standard_layout::value, "must be standard layout"); + public: + explicit TypedIOBuf(IOBuf* buf) : buf_(buf) { } + + IOBuf* ioBuf() { + return buf_; + } + const IOBuf* ioBuf() const { + return buf_; + } + + bool empty() const { + return buf_->empty(); + } + const T* data() const { + return cast(buf_->data()); + } + T* writableData() { + return cast(buf_->writableData()); + } + const T* tail() const { + return cast(buf_->tail()); + } + T* writableTail() { + return cast(buf_->writableTail()); + } + uint32_t length() const { + return sdiv(buf_->length()); + } + uint32_t headroom() const { + return sdiv(buf_->headroom()); + } + uint32_t tailroom() const { + return sdiv(buf_->tailroom()); + } + const T* buffer() const { + return cast(buf_->buffer()); + } + T* writableBuffer() { + return cast(buf_->writableBuffer()); + } + const T* bufferEnd() const { + return cast(buf_->bufferEnd()); + } + uint32_t capacity() const { + return sdiv(buf_->capacity()); + } + void advance(uint32_t n) { + buf_->advance(smul(n)); + } + void retreat(uint32_t n) { + buf_->retreat(smul(n)); + } + void prepend(uint32_t n) { + buf_->prepend(smul(n)); + } + void append(uint32_t n) { + buf_->append(smul(n)); + } + void trimStart(uint32_t n) { + buf_->trimStart(smul(n)); + } + void trimEnd(uint32_t n) { + buf_->trimEnd(smul(n)); + } + void clear() { + buf_->clear(); + } + void reserve(uint32_t minHeadroom, uint32_t minTailroom) { + buf_->reserve(smul(minHeadroom), smul(minTailroom)); + } + + // Movable + TypedIOBuf(TypedIOBuf&&) = default; + TypedIOBuf& operator=(TypedIOBuf&&) = default; + + private: + // Non-copyable + TypedIOBuf(const TypedIOBuf&) = delete; + TypedIOBuf& operator=(const TypedIOBuf&) = delete; + + // cast to T* + static T* cast(uint8_t* p) { + return reinterpret_cast(p); + } + static const T* cast(const uint8_t* p) { + return reinterpret_cast(p); + } + // divide by size + static uint32_t sdiv(uint32_t n) { + return n / sizeof(T); + } + // multiply by size + static uint32_t smul(uint32_t n) { + // In debug mode, check for overflow + assert((uint64_t(n) * sizeof(T)) < (uint64_t(1) << 32)); + return n * sizeof(T); + } + + IOBuf* buf_; +}; + +} // namespace folly + +#endif /* FOLLY_IO_TYPEDIOBUF_H_ */ + diff --git a/folly/experimental/io/test/IOBufTest.cpp b/folly/experimental/io/test/IOBufTest.cpp index 5072810f..3b88acb2 100644 --- a/folly/experimental/io/test/IOBufTest.cpp +++ b/folly/experimental/io/test/IOBufTest.cpp @@ -15,6 +15,7 @@ */ #include "folly/experimental/io/IOBuf.h" +#include "folly/experimental/io/TypedIOBuf.h" #include #include @@ -24,6 +25,7 @@ #include "folly/Range.h" using folly::IOBuf; +using folly::TypedIOBuf; using folly::StringPiece; using std::unique_ptr; @@ -614,6 +616,22 @@ TEST(IOBuf, Alignment) { } } +TEST(TypedIOBuf, Simple) { + auto buf = IOBuf::create(0); + TypedIOBuf typed(buf.get()); + const uint64_t n = 10000; + typed.reserve(0, n); + EXPECT_LE(n, typed.capacity()); + for (uint64_t i = 0; i < n; i++) { + *typed.writableTail() = i; + typed.append(1); + } + EXPECT_EQ(n, typed.length()); + for (uint64_t i = 0; i < n; i++) { + EXPECT_EQ(i, typed.data()[i]); + } +} + int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); google::ParseCommandLineFlags(&argc, &argv, true); -- 2.34.1