Home | History | Annotate | Download | only in layers
      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      */
     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     */
     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     */
     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     */
     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     */
    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.
    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.
    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.
    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