blob: 40f173e1ab3bf4d5d138ab74fa40a88f88eb1901 [file] [log] [blame]
Joel Scherpelzf3fa5cc2017-05-22 12:30:03 +09001/*
2 * Copyright (C) 2017 The Android Open Source Project
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 NETUTILS_SLICE_H
18#define NETUTILS_SLICE_H
19
20#include <algorithm>
21#include <array>
22#include <cstring>
23#include <ostream>
24#include <tuple>
25#include <vector>
26
27namespace android {
28namespace netdutils {
29
30// Immutable wrapper for a linear region of unowned bytes.
31// Slice represents memory as a half-closed interval [base, limit).
32//
33// Note that without manually invoking the Slice() constructor, it is
34// impossible to increase the size of a slice. This guarantees that
35// applications that properly use the slice API will never access
36// memory outside of a slice.
37//
38// Note that const Slice still wraps mutable memory, however copy
39// assignment and move assignment to slice are disabled.
40class Slice {
41 public:
42 Slice() = default;
43
44 // Create a slice beginning at base and continuing to but not including limit
45 Slice(void* base, void* limit) : mBase(toUint8(base)), mLimit(toUint8(limit)) {}
46
47 // Create a slice beginning at base and continuing for size bytes
48 Slice(void* base, size_t size) : Slice(base, toUint8(base) + size) {}
49
50 // Return the address of the first byte in this slice
51 uint8_t* base() const { return mBase; }
52
53 // Return the address of the first byte following this slice
54 uint8_t* limit() const { return mLimit; }
55
56 // Return the size of this slice in bytes
57 size_t size() const { return limit() - base(); }
58
59 // Return true if size() == 0
60 bool empty() const { return base() == limit(); }
61
62 private:
63 static uint8_t* toUint8(void* ptr) { return reinterpret_cast<uint8_t*>(ptr); }
64
65 uint8_t* mBase = nullptr;
66 uint8_t* mLimit = nullptr;
67};
68
69// Return slice representation of ref which must be a POD type
70template <typename T>
71inline const Slice makeSlice(const T& ref) {
72 static_assert(std::is_pod<T>::value, "value must be a POD type");
73 static_assert(!std::is_pointer<T>::value, "value must not be a pointer type");
74 return {const_cast<T*>(&ref), sizeof(ref)};
75}
76
77// Return slice representation of vector data()
78template <typename T>
79inline const Slice makeSlice(const std::vector<T>& v) {
80 return {const_cast<T*>(v.data()), v.size() * sizeof(T)};
81}
82
83// Return slice representation of array data()
84template <typename U, size_t V>
85inline const Slice makeSlice(const std::array<U, V>& a) {
86 return {const_cast<U*>(a.data()), a.size() * sizeof(U)};
87}
88
89// Return prefix and suffix of Slice s ending and starting at position cut
90inline std::pair<const Slice, const Slice> split(const Slice s, size_t cut) {
91 const size_t tmp = std::min(cut, s.size());
92 return {{s.base(), s.base() + tmp}, {s.base() + tmp, s.limit()}};
93}
94
95// Return prefix of Slice s ending at position cut
96inline const Slice take(const Slice s, size_t cut) {
97 return std::get<0>(split(s, cut));
98}
99
100// Return suffix of Slice s starting at position cut
101inline const Slice drop(const Slice s, size_t cut) {
102 return std::get<1>(split(s, cut));
103}
104
105// Copy from src into dst. Bytes copied is the lesser of dst.size() and src.size()
106inline size_t copy(const Slice dst, const Slice src) {
107 const auto min = std::min(dst.size(), src.size());
108 memcpy(dst.base(), src.base(), min);
109 return min;
110}
111
112// Base case for variadic extract below
113template <typename Head>
114inline size_t extract(const Slice src, Head& head) {
115 return copy(makeSlice(head), src);
116}
117
118// Copy from src into one or more pointers to POD data. If src.size()
119// is less than the sum of all data pointers a suffix of data will be
120// left unmodified. Return the number of bytes copied.
121template <typename Head, typename... Tail>
122inline size_t extract(const Slice src, Head& head, Tail... tail) {
123 const auto extracted = extract(src, head);
124 return extracted + extract(drop(src, extracted), tail...);
125}
126
127// Return a string containing a copy of the contents of s
128std::string toString(const Slice s);
129
130// Return a string containing a hexadecimal representation of the contents of s.
131// This function inserts a newline into its output every wrap bytes.
132std::string toHex(const Slice s, int wrap);
133
134inline bool operator==(const Slice& lhs, const Slice& rhs) {
135 return (lhs.base() == rhs.base()) && (lhs.limit() == rhs.limit());
136}
137
138inline bool operator!=(const Slice& lhs, const Slice& rhs) {
139 return !(lhs == rhs);
140}
141
142std::ostream& operator<<(std::ostream& os, const Slice& slice);
143
144} // namespace netdutils
145} // namespace android
146
147#endif /* NETUTILS_SLICE_H */