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