1/* 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 string data() 78inline const Slice makeSlice(const std::string& s) { 79 using ValueT = std::string::value_type; 80 return {const_cast<ValueT*>(s.data()), s.size() * sizeof(ValueT)}; 81} 82 83// Return slice representation of vector data() 84template <typename T> 85inline const Slice makeSlice(const std::vector<T>& v) { 86 return {const_cast<T*>(v.data()), v.size() * sizeof(T)}; 87} 88 89// Return slice representation of array data() 90template <typename U, size_t V> 91inline const Slice makeSlice(const std::array<U, V>& a) { 92 return {const_cast<U*>(a.data()), a.size() * sizeof(U)}; 93} 94 95// Return prefix and suffix of Slice s ending and starting at position cut 96inline std::pair<const Slice, const Slice> split(const Slice s, size_t cut) { 97 const size_t tmp = std::min(cut, s.size()); 98 return {{s.base(), s.base() + tmp}, {s.base() + tmp, s.limit()}}; 99} 100 101// Return prefix of Slice s ending at position cut 102inline const Slice take(const Slice s, size_t cut) { 103 return std::get<0>(split(s, cut)); 104} 105 106// Return suffix of Slice s starting at position cut 107inline const Slice drop(const Slice s, size_t cut) { 108 return std::get<1>(split(s, cut)); 109} 110 111// Copy from src into dst. Bytes copied is the lesser of dst.size() and src.size() 112inline size_t copy(const Slice dst, const Slice src) { 113 const auto min = std::min(dst.size(), src.size()); 114 memcpy(dst.base(), src.base(), min); 115 return min; 116} 117 118// Base case for variadic extract below 119template <typename Head> 120inline size_t extract(const Slice src, Head& head) { 121 return copy(makeSlice(head), src); 122} 123 124// Copy from src into one or more pointers to POD data. If src.size() 125// is less than the sum of all data pointers a suffix of data will be 126// left unmodified. Return the number of bytes copied. 127template <typename Head, typename... Tail> 128inline size_t extract(const Slice src, Head& head, Tail... tail) { 129 const auto extracted = extract(src, head); 130 return extracted + extract(drop(src, extracted), tail...); 131} 132 133// Return a string containing a copy of the contents of s 134std::string toString(const Slice s); 135 136// Return a string containing a hexadecimal representation of the contents of s. 137// This function inserts a newline into its output every wrap bytes. 138std::string toHex(const Slice s, int wrap); 139 140inline bool operator==(const Slice& lhs, const Slice& rhs) { 141 return (lhs.base() == rhs.base()) && (lhs.limit() == rhs.limit()); 142} 143 144inline bool operator!=(const Slice& lhs, const Slice& rhs) { 145 return !(lhs == rhs); 146} 147 148std::ostream& operator<<(std::ostream& os, const Slice& slice); 149 150} // namespace netdutils 151} // namespace android 152 153#endif /* NETUTILS_SLICE_H */ 154