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