Add TypedIOBuf.
authorTudor Bosman <tudorb@fb.com>
Fri, 15 Jun 2012 00:07:00 +0000 (17:07 -0700)
committerJordan DeLong <jdelong@fb.com>
Fri, 22 Jun 2012 02:38:51 +0000 (19:38 -0700)
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 [new file with mode: 0644]
folly/experimental/io/test/IOBufTest.cpp

diff --git a/folly/experimental/io/TypedIOBuf.h b/folly/experimental/io/TypedIOBuf.h
new file mode 100644 (file)
index 0000000..b3327dc
--- /dev/null
@@ -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 <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_ */
+
index 5072810fc550882f9d5b5708646e8853e689e002..3b88acb23267465484836b9fdef7274f252d3c97 100644 (file)
@@ -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);