xref: /aosp_15_r20/system/media/audio_utils/include/audio_utils/StringUtils.h (revision b9df5ad1c9ac98a7fefaac271a55f7ae3db05414)
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