1 /*
2 * Copyright 2024 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 #pragma once
18
19 #include <string>
20 #include <vector>
21
22 namespace android::audio_utils::stringutils {
23
24 // C++ String Utilities
25 //
26 // Original file extracted from frameworks/av/services/mediametrics
27
28 /**
29 * Return string tokens from iterator, separated by spaces and reserved chars.
30 */
31 std::string tokenizer(std::string::const_iterator& it,
32 const std::string::const_iterator& end, const char* reserved);
33
34 /**
35 * Splits flags string based on delimiters (or, whitespace which is removed).
36 */
37 std::vector<std::string> split(const std::string& flags, const char* delim);
38
39
40 /**
41 * Parses a vector of integers using ',' '{' and '}' as delimiters. Leaves
42 * vector unmodified if the parsing fails.
43 */
44 bool parseVector(const std::string& str, std::vector<int32_t>* vector);
45
46 /**
47 * Returns a vector of device address pairs from the devices string.
48 *
49 * A failure to parse returns early with the contents that were able to be parsed.
50 */
51 std::vector<std::pair<std::string, std::string>>
52 getDeviceAddressPairs(const std::string& devices);
53
54 /**
55 * For purposes of field naming and logging, we have common formats:
56 *
57 * Lower camel case: Often used for variables or method names.
58 * "helloWorld" "toString()"
59 *
60 * Upper camel case: Often used for classes or structs.
61 * "HelloWorld" "MyClass"
62 *
63 * Lower snake case: Often used for variable names or method names.
64 * "hello_world" "to_string()"
65 *
66 * Upper snake case: Often used for MACRO names or constants.
67 * "HELLO_WORLD" "TO_STRING()"
68 */
69 enum class NameFormat {
70 kFormatLowerCamelCase, // Example: helloWorld
71 kFormatUpperCamelCase, // Example: HelloWorld
72 kFormatLowerSnakeCase, // Example: hello_world
73 kFormatUpperSnakeCase, // Example: HELLO_WORLD
74 };
75
76 /**
77 * Returns a string with the name tokens converted to a particular format.
78 *
79 * changeNameFormat("hello_world", NameFormat::kFormatLowerCamelCase) -> "helloWorld"
80 *
81 * This is used for consistent logging, where the log convention may differ from
82 * the string/stringify convention of the name.
83 *
84 * The following rules are used:
85 *
86 * 1) A name consists of one or more concatenated words, connected by a case change,
87 * a '_', or a switch between number to alpha sequence.
88 *
89 * 2) A '_', a number, or a lower to upper case transition will count as a new word.
90 * A number sequence counts as a word.
91 *
92 * 3) A non alphanumeric character (such as '.') signifies a new name follows
93 * and is copied through. For example, "helloWorld.toString".
94 *
95 * 4) Conversion of multiple numeric fields separated by '_' will preserve the underscore
96 * to avoid confusion. As an example:
97 * changeNameFormat("alpha_10_100", NameFormat::kFormatUpperCamelCase)
98 * -> "Alpha10_100" (not Alpha10100)
99 *
100 * 5) When the target format is upper or lower snake case, attempt to preserve underscores.
101 */
102 std::string changeNameFormat(const std::string& name, NameFormat format);
103
toLowerCamelCase(const std::string & name)104 inline std::string toLowerCamelCase(const std::string& name) {
105 return changeNameFormat(name, NameFormat::kFormatLowerCamelCase);
106 }
107
toUpperCamelCase(const std::string & name)108 inline std::string toUpperCamelCase(const std::string& name) {
109 return changeNameFormat(name, NameFormat::kFormatUpperCamelCase);
110 }
111
toLowerSnakeCase(const std::string & name)112 inline std::string toLowerSnakeCase(const std::string& name) {
113 return changeNameFormat(name, NameFormat::kFormatLowerSnakeCase);
114 }
115
toUpperSnakeCase(const std::string & name)116 inline std::string toUpperSnakeCase(const std::string& name) {
117 return changeNameFormat(name, NameFormat::kFormatUpperSnakeCase);
118 }
119
120 /**
121 * Appends a suffix string, with replacement of a character.
122 *
123 * \param s string to append suffix to.
124 * \param suffix string suffix.
125 * \param from target character to replace in suffix.
126 * \param to character to replace with.
127 */
appendWithReplacement(std::string & s,const std::string & suffix,char from,char to)128 inline void appendWithReplacement(std::string& s, const std::string& suffix, char from, char to) {
129 std::transform(suffix.begin(), suffix.end(), std::back_inserter(s),
130 [from, to](char in) { return in == from ? to : in; });
131 }
132
133 } // android::audio_utils::stringutils
134