Built motion from commit 6a09e18b.|2.6.11
[motion2.git] / legacy-libs / grpc-cloned / deps / grpc / src / core / lib / channel / channel_args.cc
1 /*
2  *
3  * Copyright 2015 gRPC 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
19 #include <grpc/support/port_platform.h>
20
21 #include <limits.h>
22 #include <string.h>
23
24 #include <grpc/grpc.h>
25 #include <grpc/support/alloc.h>
26 #include <grpc/support/log.h>
27 #include <grpc/support/string_util.h>
28
29 #include "src/core/lib/channel/channel_args.h"
30 #include "src/core/lib/gpr/string.h"
31 #include "src/core/lib/gpr/useful.h"
32
33 static grpc_arg copy_arg(const grpc_arg* src) {
34   grpc_arg dst;
35   dst.type = src->type;
36   dst.key = gpr_strdup(src->key);
37   switch (dst.type) {
38     case GRPC_ARG_STRING:
39       dst.value.string = gpr_strdup(src->value.string);
40       break;
41     case GRPC_ARG_INTEGER:
42       dst.value.integer = src->value.integer;
43       break;
44     case GRPC_ARG_POINTER:
45       dst.value.pointer = src->value.pointer;
46       dst.value.pointer.p =
47           src->value.pointer.vtable->copy(src->value.pointer.p);
48       break;
49   }
50   return dst;
51 }
52
53 grpc_channel_args* grpc_channel_args_copy_and_add(const grpc_channel_args* src,
54                                                   const grpc_arg* to_add,
55                                                   size_t num_to_add) {
56   return grpc_channel_args_copy_and_add_and_remove(src, nullptr, 0, to_add,
57                                                    num_to_add);
58 }
59
60 grpc_channel_args* grpc_channel_args_copy_and_remove(
61     const grpc_channel_args* src, const char** to_remove,
62     size_t num_to_remove) {
63   return grpc_channel_args_copy_and_add_and_remove(src, to_remove,
64                                                    num_to_remove, nullptr, 0);
65 }
66
67 static bool should_remove_arg(const grpc_arg* arg, const char** to_remove,
68                               size_t num_to_remove) {
69   for (size_t i = 0; i < num_to_remove; ++i) {
70     if (strcmp(arg->key, to_remove[i]) == 0) return true;
71   }
72   return false;
73 }
74
75 grpc_channel_args* grpc_channel_args_copy_and_add_and_remove(
76     const grpc_channel_args* src, const char** to_remove, size_t num_to_remove,
77     const grpc_arg* to_add, size_t num_to_add) {
78   // Figure out how many args we'll be copying.
79   size_t num_args_to_copy = 0;
80   if (src != nullptr) {
81     for (size_t i = 0; i < src->num_args; ++i) {
82       if (!should_remove_arg(&src->args[i], to_remove, num_to_remove)) {
83         ++num_args_to_copy;
84       }
85     }
86   }
87   // Create result.
88   grpc_channel_args* dst =
89       static_cast<grpc_channel_args*>(gpr_malloc(sizeof(grpc_channel_args)));
90   dst->num_args = num_args_to_copy + num_to_add;
91   if (dst->num_args == 0) {
92     dst->args = nullptr;
93     return dst;
94   }
95   dst->args =
96       static_cast<grpc_arg*>(gpr_malloc(sizeof(grpc_arg) * dst->num_args));
97   // Copy args from src that are not being removed.
98   size_t dst_idx = 0;
99   if (src != nullptr) {
100     for (size_t i = 0; i < src->num_args; ++i) {
101       if (!should_remove_arg(&src->args[i], to_remove, num_to_remove)) {
102         dst->args[dst_idx++] = copy_arg(&src->args[i]);
103       }
104     }
105   }
106   // Add args from to_add.
107   for (size_t i = 0; i < num_to_add; ++i) {
108     dst->args[dst_idx++] = copy_arg(&to_add[i]);
109   }
110   GPR_ASSERT(dst_idx == dst->num_args);
111   return dst;
112 }
113
114 grpc_channel_args* grpc_channel_args_copy(const grpc_channel_args* src) {
115   return grpc_channel_args_copy_and_add(src, nullptr, 0);
116 }
117
118 grpc_channel_args* grpc_channel_args_union(const grpc_channel_args* a,
119                                            const grpc_channel_args* b) {
120   if (a == nullptr) return grpc_channel_args_copy(b);
121   if (b == nullptr) return grpc_channel_args_copy(a);
122   const size_t max_out = (a->num_args + b->num_args);
123   grpc_arg* uniques =
124       static_cast<grpc_arg*>(gpr_malloc(sizeof(*uniques) * max_out));
125   for (size_t i = 0; i < a->num_args; ++i) uniques[i] = a->args[i];
126
127   size_t uniques_idx = a->num_args;
128   for (size_t i = 0; i < b->num_args; ++i) {
129     const char* b_key = b->args[i].key;
130     if (grpc_channel_args_find(a, b_key) == nullptr) {  // not found
131       uniques[uniques_idx++] = b->args[i];
132     }
133   }
134   grpc_channel_args* result =
135       grpc_channel_args_copy_and_add(nullptr, uniques, uniques_idx);
136   gpr_free(uniques);
137   return result;
138 }
139
140 static int cmp_arg(const grpc_arg* a, const grpc_arg* b) {
141   int c = GPR_ICMP(a->type, b->type);
142   if (c != 0) return c;
143   c = strcmp(a->key, b->key);
144   if (c != 0) return c;
145   switch (a->type) {
146     case GRPC_ARG_STRING:
147       return strcmp(a->value.string, b->value.string);
148     case GRPC_ARG_INTEGER:
149       return GPR_ICMP(a->value.integer, b->value.integer);
150     case GRPC_ARG_POINTER:
151       c = GPR_ICMP(a->value.pointer.p, b->value.pointer.p);
152       if (c != 0) {
153         c = GPR_ICMP(a->value.pointer.vtable, b->value.pointer.vtable);
154         if (c == 0) {
155           c = a->value.pointer.vtable->cmp(a->value.pointer.p,
156                                            b->value.pointer.p);
157         }
158       }
159       return c;
160   }
161   GPR_UNREACHABLE_CODE(return 0);
162 }
163
164 /* stabilizing comparison function: since channel_args ordering matters for
165  * keys with the same name, we need to preserve that ordering */
166 static int cmp_key_stable(const void* ap, const void* bp) {
167   const grpc_arg* const* a = static_cast<const grpc_arg* const*>(ap);
168   const grpc_arg* const* b = static_cast<const grpc_arg* const*>(bp);
169   int c = strcmp((*a)->key, (*b)->key);
170   if (c == 0) c = GPR_ICMP(*a, *b);
171   return c;
172 }
173
174 grpc_channel_args* grpc_channel_args_normalize(const grpc_channel_args* a) {
175   grpc_arg** args =
176       static_cast<grpc_arg**>(gpr_malloc(sizeof(grpc_arg*) * a->num_args));
177   for (size_t i = 0; i < a->num_args; i++) {
178     args[i] = &a->args[i];
179   }
180   if (a->num_args > 1)
181     qsort(args, a->num_args, sizeof(grpc_arg*), cmp_key_stable);
182
183   grpc_channel_args* b =
184       static_cast<grpc_channel_args*>(gpr_malloc(sizeof(grpc_channel_args)));
185   b->num_args = a->num_args;
186   b->args = static_cast<grpc_arg*>(gpr_malloc(sizeof(grpc_arg) * b->num_args));
187   for (size_t i = 0; i < a->num_args; i++) {
188     b->args[i] = copy_arg(args[i]);
189   }
190
191   gpr_free(args);
192   return b;
193 }
194
195 void grpc_channel_args_destroy(grpc_channel_args* a) {
196   size_t i;
197   if (!a) return;
198   for (i = 0; i < a->num_args; i++) {
199     switch (a->args[i].type) {
200       case GRPC_ARG_STRING:
201         gpr_free(a->args[i].value.string);
202         break;
203       case GRPC_ARG_INTEGER:
204         break;
205       case GRPC_ARG_POINTER:
206         a->args[i].value.pointer.vtable->destroy(a->args[i].value.pointer.p);
207         break;
208     }
209     gpr_free(a->args[i].key);
210   }
211   gpr_free(a->args);
212   gpr_free(a);
213 }
214
215 int grpc_channel_args_compare(const grpc_channel_args* a,
216                               const grpc_channel_args* b) {
217   if (a == nullptr && b == nullptr) return 0;
218   if (a == nullptr || b == nullptr) return a == nullptr ? -1 : 1;
219   int c = GPR_ICMP(a->num_args, b->num_args);
220   if (c != 0) return c;
221   for (size_t i = 0; i < a->num_args; i++) {
222     c = cmp_arg(&a->args[i], &b->args[i]);
223     if (c != 0) return c;
224   }
225   return 0;
226 }
227
228 const grpc_arg* grpc_channel_args_find(const grpc_channel_args* args,
229                                        const char* name) {
230   if (args != nullptr) {
231     for (size_t i = 0; i < args->num_args; ++i) {
232       if (strcmp(args->args[i].key, name) == 0) {
233         return &args->args[i];
234       }
235     }
236   }
237   return nullptr;
238 }
239
240 int grpc_channel_arg_get_integer(const grpc_arg* arg,
241                                  const grpc_integer_options options) {
242   if (arg == nullptr) return options.default_value;
243   if (arg->type != GRPC_ARG_INTEGER) {
244     gpr_log(GPR_ERROR, "%s ignored: it must be an integer", arg->key);
245     return options.default_value;
246   }
247   if (arg->value.integer < options.min_value) {
248     gpr_log(GPR_ERROR, "%s ignored: it must be >= %d", arg->key,
249             options.min_value);
250     return options.default_value;
251   }
252   if (arg->value.integer > options.max_value) {
253     gpr_log(GPR_ERROR, "%s ignored: it must be <= %d", arg->key,
254             options.max_value);
255     return options.default_value;
256   }
257   return arg->value.integer;
258 }
259
260 int grpc_channel_args_find_integer(const grpc_channel_args* args,
261                                    const char* name,
262                                    const grpc_integer_options options) {
263   const grpc_arg* arg = grpc_channel_args_find(args, name);
264   return grpc_channel_arg_get_integer(arg, options);
265 }
266
267 char* grpc_channel_arg_get_string(const grpc_arg* arg) {
268   if (arg == nullptr) return nullptr;
269   if (arg->type != GRPC_ARG_STRING) {
270     gpr_log(GPR_ERROR, "%s ignored: it must be an string", arg->key);
271     return nullptr;
272   }
273   return arg->value.string;
274 }
275
276 char* grpc_channel_args_find_string(const grpc_channel_args* args,
277                                     const char* name) {
278   const grpc_arg* arg = grpc_channel_args_find(args, name);
279   return grpc_channel_arg_get_string(arg);
280 }
281
282 bool grpc_channel_arg_get_bool(const grpc_arg* arg, bool default_value) {
283   if (arg == nullptr) return default_value;
284   if (arg->type != GRPC_ARG_INTEGER) {
285     gpr_log(GPR_ERROR, "%s ignored: it must be an integer", arg->key);
286     return default_value;
287   }
288   switch (arg->value.integer) {
289     case 0:
290       return false;
291     case 1:
292       return true;
293     default:
294       gpr_log(GPR_ERROR, "%s treated as bool but set to %d (assuming true)",
295               arg->key, arg->value.integer);
296       return true;
297   }
298 }
299
300 bool grpc_channel_args_find_bool(const grpc_channel_args* args,
301                                  const char* name, bool default_value) {
302   const grpc_arg* arg = grpc_channel_args_find(args, name);
303   return grpc_channel_arg_get_bool(arg, default_value);
304 }
305
306 bool grpc_channel_args_want_minimal_stack(const grpc_channel_args* args) {
307   return grpc_channel_arg_get_bool(
308       grpc_channel_args_find(args, GRPC_ARG_MINIMAL_STACK), false);
309 }
310
311 grpc_arg grpc_channel_arg_string_create(char* name, char* value) {
312   grpc_arg arg;
313   arg.type = GRPC_ARG_STRING;
314   arg.key = name;
315   arg.value.string = value;
316   return arg;
317 }
318
319 grpc_arg grpc_channel_arg_integer_create(char* name, int value) {
320   grpc_arg arg;
321   arg.type = GRPC_ARG_INTEGER;
322   arg.key = name;
323   arg.value.integer = value;
324   return arg;
325 }
326
327 grpc_arg grpc_channel_arg_pointer_create(
328     char* name, void* value, const grpc_arg_pointer_vtable* vtable) {
329   grpc_arg arg;
330   arg.type = GRPC_ARG_POINTER;
331   arg.key = name;
332   arg.value.pointer.p = value;
333   arg.value.pointer.vtable = vtable;
334   return arg;
335 }
336
337 char* grpc_channel_args_string(const grpc_channel_args* args) {
338   if (args == nullptr) return nullptr;
339   gpr_strvec v;
340   gpr_strvec_init(&v);
341   for (size_t i = 0; i < args->num_args; ++i) {
342     const grpc_arg& arg = args->args[i];
343     char* s;
344     switch (arg.type) {
345       case GRPC_ARG_INTEGER:
346         gpr_asprintf(&s, "%s=%d", arg.key, arg.value.integer);
347         break;
348       case GRPC_ARG_STRING:
349         gpr_asprintf(&s, "%s=%s", arg.key, arg.value.string);
350         break;
351       case GRPC_ARG_POINTER:
352         gpr_asprintf(&s, "%s=%p", arg.key, arg.value.pointer.p);
353         break;
354       default:
355         gpr_asprintf(&s, "arg with unknown type");
356     }
357     gpr_strvec_add(&v, s);
358   }
359   char* result =
360       gpr_strjoin_sep(const_cast<const char**>(v.strs), v.count, ", ", nullptr);
361   gpr_strvec_destroy(&v);
362   return result;
363 }