Line data Source code
1 : /* 2 : * 3 : * Copyright (c) 2020 Project CHIP Authors 4 : * 5 : * Licensed under the Apache License, Version 2.0 (the "License"); 6 : * you may not use this file except in compliance with the License. 7 : * You may obtain a copy of the License at 8 : * 9 : * http://www.apache.org/licenses/LICENSE-2.0 10 : * 11 : * Unless required by applicable law or agreed to in writing, software 12 : * distributed under the License is distributed on an "AS IS" BASIS, 13 : * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 : * See the License for the specific language governing permissions and 15 : * limitations under the License. 16 : */ 17 : 18 : #pragma once 19 : 20 : #include "QName.h" 21 : 22 : namespace mdns { 23 : namespace Minimal { 24 : 25 : /// A void* implementation that stores QNames as 26 : /// [ptr array] [name1] #0 [name2] #0 .... [namen] #0 27 : /// 28 : /// Usage: 29 : /// - RequiredStorageSize("some", "name", "here") provides the memory block 30 : /// - Build(ptr, "some", "name", "here") stores all data in [ptr] 31 : /// 32 : namespace FlatAllocatedQName { 33 : 34 117 : inline size_t RequiredStorageSize() 35 : { 36 117 : return 0; 37 : } 38 : 39 : /// Determines the memory size required to store the given qname parts. 40 : /// 41 : /// Example: 42 : /// malloc(RequiredStorageSize("myhostname", "local")); 43 : template <typename... Args> 44 465 : inline size_t RequiredStorageSize(QNamePart name, Args &&... rest) 45 : { 46 : static_assert(CHAR_BIT == 8, "Assumption is that names can be stored in 1 byte"); 47 : 48 : // need to store a pointer entry in the array, the name and null terminator plus 49 : // the rest of the data 50 465 : return sizeof(QNamePart) + strlen(name) + 1 + RequiredStorageSize(std::forward<Args>(rest)...); 51 : } 52 : 53 20 : inline size_t RequiredStorageSizeFromArray(char const * const * names, size_t num) 54 : { 55 20 : size_t ret = 0; 56 108 : for (size_t i = 0; i < num; ++i) 57 : { 58 88 : ret += sizeof(QNamePart) + strlen(names[i]) + 1; 59 : } 60 20 : return ret; 61 : } 62 : namespace Internal { 63 : 64 : // nothing left to initialize 65 205 : inline void Initialize(QNamePart * ptrLocation, char * nameLocation) {} 66 : 67 : template <typename... Args> 68 553 : inline void Initialize(QNamePart * ptrLocation, char * nameLocation, const char * name, Args &&... rest) 69 : { 70 553 : *ptrLocation = nameLocation; 71 553 : strcpy(nameLocation, name); 72 : 73 553 : Initialize(ptrLocation + 1, nameLocation + strlen(nameLocation) + 1, std::forward<Args>(rest)...); 74 553 : } 75 : 76 : } // namespace Internal 77 : 78 : /// Builds a qname inside the given storage. 79 : /// 80 : /// storage MUST be aligned to hold pointers 81 : /// 82 : /// Example: 83 : /// void * data = malloc(RequiredStorageSize("myhostname", "local")); 84 : /// FullQName value = Build(data, "myhostname", "local"); 85 : template <typename... Args> 86 117 : inline FullQName Build(void * storage, Args &&... args) 87 : { 88 117 : QNamePart * names = reinterpret_cast<QNamePart *>(storage); 89 117 : char * nameOut = reinterpret_cast<char *>(names + sizeof...(args)); 90 : 91 117 : Internal::Initialize(names, nameOut, std::forward<Args>(args)...); 92 : 93 117 : FullQName result; 94 117 : result.names = names; 95 117 : result.nameCount = sizeof...(args); 96 117 : return result; 97 : } 98 : 99 20 : inline FullQName BuildFromArray(void * storage, char const * const * parts, size_t num) 100 : { 101 : // Storage memory holds pointers to each name, then copies of the names after 102 20 : QNamePart * names = reinterpret_cast<QNamePart *>(storage); 103 20 : char * nameOut = reinterpret_cast<char *>(names + num); 104 108 : for (size_t i = 0; i < num; ++i) 105 : { 106 88 : QNamePart * ptrLocation = names + i; 107 88 : Internal::Initialize(ptrLocation, nameOut, parts[i]); 108 88 : nameOut += strlen(parts[i]) + 1; 109 : } 110 20 : FullQName result; 111 20 : result.names = names; 112 20 : result.nameCount = num; 113 20 : return result; 114 : } 115 : 116 : } // namespace FlatAllocatedQName 117 : 118 : } // namespace Minimal 119 : } // namespace mdns