Home | History | Annotate | Download | only in netdutils
      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 
     27 namespace android {
     28 namespace 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.
     40 class 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
     70 template <typename T>
     71 inline 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()
     78 inline 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()
     84 template <typename T>
     85 inline 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()
     90 template <typename U, size_t V>
     91 inline 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
     96 inline 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
    102 inline 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
    107 inline 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()
    112 inline 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
    119 template <typename Head>
    120 inline 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.
    127 template <typename Head, typename... Tail>
    128 inline 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
    134 std::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.
    138 std::string toHex(const Slice s, int wrap);
    139 
    140 inline bool operator==(const Slice& lhs, const Slice& rhs) {
    141     return (lhs.base() == rhs.base()) && (lhs.limit() == rhs.limit());
    142 }
    143 
    144 inline bool operator!=(const Slice& lhs, const Slice& rhs) {
    145     return !(lhs == rhs);
    146 }
    147 
    148 std::ostream& operator<<(std::ostream& os, const Slice& slice);
    149 
    150 // Return suffix of Slice s starting at the first match of byte c. If no matched
    151 // byte, return an empty Slice.
    152 inline const Slice findFirstMatching(const Slice s, uint8_t c) {
    153     uint8_t* match = (uint8_t*)memchr(s.base(), c, s.size());
    154     if (!match) return Slice();
    155     return drop(s, match - s.base());
    156 }
    157 
    158 }  // namespace netdutils
    159 }  // namespace android
    160 
    161 #endif /* NETUTILS_SLICE_H */
    162