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 110 : inline size_t RequiredStorageSize()
35 : {
36 110 : 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 436 : 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 436 : return sizeof(QNamePart) + strlen(name) + 1 + RequiredStorageSize(std::forward<Args>(rest)...);
51 : }
52 :
53 19 : inline size_t RequiredStorageSizeFromArray(char const * const * names, size_t num)
54 : {
55 19 : size_t ret = 0;
56 105 : for (size_t i = 0; i < num; ++i)
57 : {
58 86 : ret += sizeof(QNamePart) + strlen(names[i]) + 1;
59 : }
60 19 : return ret;
61 : }
62 : namespace Internal {
63 :
64 : // nothing left to initialize
65 196 : inline void Initialize(QNamePart * ptrLocation, char * nameLocation) {}
66 :
67 : template <typename... Args>
68 522 : inline void Initialize(QNamePart * ptrLocation, char * nameLocation, const char * name, Args &&... rest)
69 : {
70 522 : *ptrLocation = nameLocation;
71 522 : strcpy(nameLocation, name);
72 :
73 522 : Initialize(ptrLocation + 1, nameLocation + strlen(nameLocation) + 1, std::forward<Args>(rest)...);
74 522 : }
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 110 : inline FullQName Build(void * storage, Args &&... args)
87 : {
88 110 : QNamePart * names = reinterpret_cast<QNamePart *>(storage);
89 110 : char * nameOut = reinterpret_cast<char *>(names + sizeof...(args));
90 :
91 110 : Internal::Initialize(names, nameOut, std::forward<Args>(args)...);
92 :
93 110 : FullQName result;
94 110 : result.names = names;
95 110 : result.nameCount = sizeof...(args);
96 110 : return result;
97 : }
98 :
99 19 : 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 19 : QNamePart * names = reinterpret_cast<QNamePart *>(storage);
103 19 : char * nameOut = reinterpret_cast<char *>(names + num);
104 105 : for (size_t i = 0; i < num; ++i)
105 : {
106 86 : QNamePart * ptrLocation = names + i;
107 86 : Internal::Initialize(ptrLocation, nameOut, parts[i]);
108 86 : nameOut += strlen(parts[i]) + 1;
109 : }
110 19 : FullQName result;
111 19 : result.names = names;
112 19 : result.nameCount = num;
113 19 : return result;
114 : }
115 :
116 : } // namespace FlatAllocatedQName
117 :
118 : } // namespace Minimal
119 : } // namespace mdns
|