Commit 9eaebc0d authored by Tudor Bosman's avatar Tudor Bosman Committed by Jordan DeLong

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
parent fdbbdb8f
/*
* 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 <type_traits>
#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 T>
class TypedIOBuf {
static_assert(std::is_standard_layout<T>::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<T*>(p);
}
static const T* cast(const uint8_t* p) {
return reinterpret_cast<const T*>(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_ */
......@@ -15,6 +15,7 @@
*/
#include "folly/experimental/io/IOBuf.h"
#include "folly/experimental/io/TypedIOBuf.h"
#include <gflags/gflags.h>
#include <boost/random.hpp>
......@@ -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<uint64_t> 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);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment