1 /* Copyright (c) 2016 The Khronos Group Inc.
2  * Copyright (c) 2016 Valve Corporation
3  * Copyright (c) 2016 LunarG, Inc.
4  * Copyright (c) 2016 Google Inc.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 #ifndef PARAMETER_NAME_H
19 #define PARAMETER_NAME_H
20 
21 #include <cassert>
22 #include <sstream>
23 #include <string>
24 #include <vector>
25 
26 /**
27  * Parameter name string supporting deferred formatting for array subscripts.
28  *
29  * Custom parameter name class with support for deferred formatting of names containing array subscripts.  The class stores
30  * a format string and a vector of index values, and performs string formatting when an accessor function is called to
31  * retrieve the name string.  This class was primarily designed to be used with validation functions that receive a parameter name
32  * string and value as arguments, and print an error message that includes the parameter name when the value fails a validation
33  * test.  Using standard strings with these validation functions requires that parameter names containing array subscripts be
34  * formatted before each validation function is called, performing the string formatting even when the value passes validation
35  * and the string is not used:
36  *         sprintf(name, "pCreateInfo[%d].sType", i);
37  *         validate_stype(name, pCreateInfo[i].sType);
38  *
39  * With the ParameterName class, a format string and a vector of format values are stored by the ParameterName object that is
40  * provided to the validation function.  String formatting is then performed only when the validation function retrieves the
41  * name string from the ParameterName object:
42  *         validate_stype(ParameterName("pCreateInfo[%i].sType", IndexVector{ i }), pCreateInfo[i].sType);
43  */
44 class ParameterName {
45   public:
46     /// Container for index values to be used with parameter name string formatting.
47     typedef std::vector<size_t> IndexVector;
48 
49     /// Format specifier for the parameter name string, to be replaced by an index value.  The parameter name string must contain
50     /// one format specifier for each index value specified.
51     const std::string IndexFormatSpecifier = "%i";
52 
53   public:
54     /**
55      * Construct a ParameterName object from a string literal, without formatting.
56      *
57      * @param source Paramater name string without format specifiers.
58      *
59      * @pre The source string must not contain the %i format specifier.
60      */
ParameterName(const char * source)61     ParameterName(const char *source) : source_(source) { assert(IsValid()); }
62 
63     /**
64     * Construct a ParameterName object from a std::string object, without formatting.
65     *
66     * @param source Paramater name string without format specifiers.
67     *
68     * @pre The source string must not contain the %i format specifier.
69     */
ParameterName(const std::string & source)70     ParameterName(const std::string &source) : source_(source) { assert(IsValid()); }
71 
72     /**
73     * Construct a ParameterName object from a std::string object, without formatting.
74     *
75     * @param source Paramater name string without format specifiers.
76     *
77     * @pre The source string must not contain the %i format specifier.
78     */
ParameterName(const std::string && source)79     ParameterName(const std::string &&source) : source_(std::move(source)) { assert(IsValid()); }
80 
81     /**
82     * Construct a ParameterName object from a std::string object, with formatting.
83     *
84     * @param source Paramater name string with format specifiers.
85     * @param args Array index values to be used for formatting.
86     *
87     * @pre The number of %i format specifiers contained by the source string must match the number of elements contained
88     *      by the index vector.
89     */
ParameterName(const std::string & source,const IndexVector & args)90     ParameterName(const std::string &source, const IndexVector &args) : source_(source), args_(args) { assert(IsValid()); }
91 
92     /**
93     * Construct a ParameterName object from a std::string object, with formatting.
94     *
95     * @param source Paramater name string with format specifiers.
96     * @param args Array index values to be used for formatting.
97     *
98     * @pre The number of %i format specifiers contained by the source string must match the number of elements contained
99     *      by the index vector.
100     */
ParameterName(const std::string && source,const IndexVector && args)101     ParameterName(const std::string &&source, const IndexVector &&args) : source_(std::move(source)), args_(std::move(args)) {
102         assert(IsValid());
103     }
104 
105     /// Retrive the formatted name string.
get_name()106     std::string get_name() const { return (args_.empty()) ? source_ : Format(); }
107 
108   private:
109     /// Replace the %i format specifiers in the source string with the values from the index vector.
Format()110     std::string Format() const {
111         std::string::size_type current = 0;
112         std::string::size_type last = 0;
113         std::stringstream format;
114 
115         for (size_t index : args_) {
116             current = source_.find(IndexFormatSpecifier, last);
117             if (current == std::string::npos) {
118                 break;
119             }
120             format << source_.substr(last, (current - last)) << index;
121             last = current + IndexFormatSpecifier.length();
122         }
123 
124         format << source_.substr(last, std::string::npos);
125 
126         return format.str();
127     }
128 
129     /// Check that the number of %i format specifiers in the source string matches the number of elements in the index vector.
IsValid()130     bool IsValid() {
131         // Count the number of occurances of the format specifier
132         uint32_t count = 0;
133         std::string::size_type pos = source_.find(IndexFormatSpecifier);
134 
135         while (pos != std::string::npos) {
136             ++count;
137             pos = source_.find(IndexFormatSpecifier, pos + 1);
138         }
139 
140         return (count == args_.size());
141     }
142 
143   private:
144     std::string source_; ///< Format string.
145     IndexVector args_;   ///< Array index values for formatting.
146 };
147 
148 #endif // PARAMETER_NAME_H
149