move assignment operators for folly::Synchronized
[folly.git] / folly / io / TypedIOBuf.h
1 /*
2  * Copyright 2013 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #ifndef FOLLY_IO_TYPEDIOBUF_H_
18 #define FOLLY_IO_TYPEDIOBUF_H_
19
20 #include <algorithm>
21 #include <iterator>
22 #include <type_traits>
23 #include "folly/io/IOBuf.h"
24
25 namespace folly {
26
27 /**
28  * Wrapper class to handle a IOBuf as a typed buffer (to a standard layout
29  * class).
30  *
31  * This class punts on alignment, and assumes that you know what you're doing.
32  *
33  * All methods are wrappers around the corresponding IOBuf methods.  The
34  * TypedIOBuf object is stateless, so it's perfectly okay to access the
35  * underlying IOBuf in between TypedIOBuf method calls.
36  */
37 template <class T>
38 class TypedIOBuf {
39   static_assert(std::is_standard_layout<T>::value, "must be standard layout");
40  public:
41   typedef T value_type;
42   typedef value_type& reference;
43   typedef const value_type& const_reference;
44   typedef uint32_t size_type;
45   typedef value_type* iterator;
46   typedef const value_type* const_iterator;
47
48   explicit TypedIOBuf(IOBuf* buf) : buf_(buf) { }
49
50   IOBuf* ioBuf() {
51     return buf_;
52   }
53   const IOBuf* ioBuf() const {
54     return buf_;
55   }
56
57   bool empty() const {
58     return buf_->empty();
59   }
60   const T* data() const {
61     return cast(buf_->data());
62   }
63   T* writableData() {
64     return cast(buf_->writableData());
65   }
66   const T* tail() const {
67     return cast(buf_->tail());
68   }
69   T* writableTail() {
70     return cast(buf_->writableTail());
71   }
72   uint32_t length() const {
73     return sdiv(buf_->length());
74   }
75   uint32_t size() const { return length(); }
76
77   uint32_t headroom() const {
78     return sdiv(buf_->headroom());
79   }
80   uint32_t tailroom() const {
81     return sdiv(buf_->tailroom());
82   }
83   const T* buffer() const {
84     return cast(buf_->buffer());
85   }
86   T* writableBuffer() {
87     return cast(buf_->writableBuffer());
88   }
89   const T* bufferEnd() const {
90     return cast(buf_->bufferEnd());
91   }
92   uint32_t capacity() const {
93     return sdiv(buf_->capacity());
94   }
95   void advance(uint32_t n) {
96     buf_->advance(smul(n));
97   }
98   void retreat(uint32_t n) {
99     buf_->retreat(smul(n));
100   }
101   void prepend(uint32_t n) {
102     buf_->prepend(smul(n));
103   }
104   void append(uint32_t n) {
105     buf_->append(smul(n));
106   }
107   void trimStart(uint32_t n) {
108     buf_->trimStart(smul(n));
109   }
110   void trimEnd(uint32_t n) {
111     buf_->trimEnd(smul(n));
112   }
113   void clear() {
114     buf_->clear();
115   }
116   void reserve(uint32_t minHeadroom, uint32_t minTailroom) {
117     buf_->reserve(smul(minHeadroom), smul(minTailroom));
118   }
119   void reserve(uint32_t minTailroom) { reserve(0, minTailroom); }
120
121   const T* cbegin() const { return data(); }
122   const T* cend() const { return tail(); }
123   const T* begin() const { return cbegin(); }
124   const T* end() const { return cend(); }
125   T* begin() { return writableData(); }
126   T* end() { return writableTail(); }
127
128   const T& front() const {
129     assert(!empty());
130     return *begin();
131   }
132   T& front() {
133     assert(!empty());
134     return *begin();
135   }
136   const T& back() const {
137     assert(!empty());
138     return end()[-1];
139   }
140   T& back() {
141     assert(!empty());
142     return end()[-1];
143   }
144
145   /**
146    * Simple wrapper to make it easier to treat this TypedIOBuf as an array of
147    * T.
148    */
149   const T& operator[](ssize_t idx) const {
150     assert(idx >= 0 && idx < length());
151     return data()[idx];
152   }
153
154   /**
155    * Append one element.
156    */
157   void push(const T& data) {
158     push(&data, &data + 1);
159   }
160   void push_back(const T& data) { push(data); }
161
162   /**
163    * Append multiple elements in a sequence; will call distance().
164    */
165   template <class IT>
166   void push(IT begin, IT end) {
167     auto n = std::distance(begin, end);
168     reserve(headroom(), n);
169     std::copy(begin, end, writableTail());
170     append(n);
171   }
172
173   // Movable
174   TypedIOBuf(TypedIOBuf&&) = default;
175   TypedIOBuf& operator=(TypedIOBuf&&) = default;
176
177  private:
178   // Non-copyable
179   TypedIOBuf(const TypedIOBuf&) = delete;
180   TypedIOBuf& operator=(const TypedIOBuf&) = delete;
181
182   // cast to T*
183   static T* cast(uint8_t* p) {
184     return reinterpret_cast<T*>(p);
185   }
186   static const T* cast(const uint8_t* p) {
187     return reinterpret_cast<const T*>(p);
188   }
189   // divide by size
190   static uint32_t sdiv(uint32_t n) {
191     return n / sizeof(T);
192   }
193   // multiply by size
194   static uint32_t smul(uint32_t n) {
195     // In debug mode, check for overflow
196     assert((uint64_t(n) * sizeof(T)) < (uint64_t(1) << 32));
197     return n * sizeof(T);
198   }
199
200   IOBuf* buf_;
201 };
202
203 }  // namespace folly
204
205 #endif /* FOLLY_IO_TYPEDIOBUF_H_ */
206