Home | History | Annotate | Download | only in layers
      1 /* Copyright (c) 2016-2019 The Khronos Group Inc.
      2  * Copyright (c) 2016-2019 Valve Corporation
      3  * Copyright (c) 2016-2019 LunarG, Inc.
      4  * Copyright (c) 2016-2019 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 pointer to an array 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 pointer to an array of format values are stored by the ParameterName object
     40  * that is 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  * Since the IndexVector is not copied into the object, the lifetime of the ParameterName should not outlast the lifetime of
     45  * the IndexVector, but that's fine given how it is used in parameter validation.
     46  */
     47 class ParameterName {
     48    public:
     49     /// Container for index values to be used with parameter name string formatting.
     50     typedef std::initializer_list<size_t> IndexVector;
     51 
     52     /// Format specifier for the parameter name string, to be replaced by an index value.  The parameter name string must contain
     53     /// one format specifier for each index value specified.
     54     const char *const IndexFormatSpecifier = "%i";
     55 
     56    public:
     57     /**
     58      * Construct a ParameterName object from a string literal, without formatting.
     59      *
     60      * @param source Paramater name string without format specifiers.
     61      *
     62      * @pre The source string must not contain the %i format specifier.
     63      */
     64     ParameterName(const char *source) : source_(source), num_indices_(0) { assert(IsValid()); }
     65 
     66     /**
     67      * Construct a ParameterName object from a string literal, with formatting.
     68      *
     69      * @param source Paramater name string with format specifiers.
     70      * @param args Array index values to be used for formatting.
     71      *
     72      * @pre The number of %i format specifiers contained by the source string must match the number of elements contained
     73      *      by the index vector.
     74      */
     75     ParameterName(const char *source, const IndexVector &args)
     76         : source_(source), args_(args.size() ? args.begin() : (const size_t *)nullptr), num_indices_(args.size()) {
     77         assert(IsValid());
     78     }
     79 
     80     /// Retrive the formatted name string.
     81     std::string get_name() const { return (num_indices_ == 0) ? std::string(source_) : Format(); }
     82 
     83    private:
     84     /// Replace the %i format specifiers in the source string with the values from the index vector.
     85     std::string Format() const {
     86         std::string::size_type current = 0;
     87         std::string::size_type last = 0;
     88         std::stringstream format;
     89 
     90         std::string source(source_);
     91 
     92         for (size_t i = 0; i < num_indices_; ++i) {
     93             auto index = args_[i];
     94             current = source.find(IndexFormatSpecifier, last);
     95             if (current == std::string::npos) {
     96                 break;
     97             }
     98             format << source.substr(last, (current - last)) << index;
     99             last = current + strlen(IndexFormatSpecifier);
    100         }
    101 
    102         format << source.substr(last, std::string::npos);
    103 
    104         return format.str();
    105     }
    106 
    107     /// Check that the number of %i format specifiers in the source string matches the number of elements in the index vector.
    108     bool IsValid() {
    109         // Count the number of occurances of the format specifier
    110         uint32_t count = 0;
    111 
    112         std::string source(source_);
    113 
    114         std::string::size_type pos = source.find(IndexFormatSpecifier);
    115 
    116         while (pos != std::string::npos) {
    117             ++count;
    118             pos = source.find(IndexFormatSpecifier, pos + 1);
    119         }
    120 
    121         return (count == num_indices_);
    122     }
    123 
    124    private:
    125     const char *source_;  ///< Format string.
    126     const size_t *args_;  ///< Array index values for formatting.
    127     size_t num_indices_;  ///< Number of array index values.
    128 };
    129 
    130 #endif  // PARAMETER_NAME_H
    131