// Copyright 2017 Google Inc. All Rights Reserved. // // This file contains the helper classes and methods for using field tuples // used by metrics classes to record variations of a single metric. #ifndef WVCDM_METRICS_FIELD_TUPLES_H_ #define WVCDM_METRICS_FIELD_TUPLES_H_ #include #include #include #include #include #include #include namespace wvcdm { namespace metrics { namespace util { // This is a placeholder type for unused type parameters. It aids in supporting // templated classes with "variable" type arguments. struct Unused { // Required for compilation. Should never be used. inline friend std::ostream& operator<< (std::ostream& out, const Unused&) { return out; } }; // This utility method formats the collection of field name/value pairs. // The format of the string is: // // [{field:value[&field:value]*}] // // If there are no pairs, returns a blank string. template std::string MakeFieldNameString(const std::vector& field_names, const F1 field1, const F2 field2, const F3 field3, const F4 field4) { std::stringstream field_name_and_values; std::vector::const_iterator field_name_iterator = field_names.begin(); if (field_name_iterator == field_names.end()) { return field_name_and_values.str(); } // There is at least one name/value pair. Prepend open brace. field_name_and_values << "{"; field_name_and_values << *field_name_iterator << ':' << field1; if (++field_name_iterator == field_names.end()) { field_name_and_values << "}"; return field_name_and_values.str(); } field_name_and_values << '&' << *field_name_iterator << ':' << field2; if (++field_name_iterator == field_names.end()) { field_name_and_values << "}"; return field_name_and_values.str(); } field_name_and_values << '&' << *field_name_iterator << ':' << field3; if (++field_name_iterator == field_names.end()) { field_name_and_values << "}"; return field_name_and_values.str(); } field_name_and_values << '&' << *field_name_iterator << ':' << field4; field_name_and_values << "}"; return field_name_and_values.str(); } // This specialization of the helper method is a shortcut for class // instances with no fields. template<> inline std::string MakeFieldNameString( const std::vector& /* field_names */, const Unused /* unused1 */, const Unused /* unused2 */, const Unused /* unused3 */, const Unused /* unused4 */) { return ""; } // This helper function appends the field names to a vector of strings. inline void AppendFieldNames(std::vector* field_name_vector, int field_count, ...) { va_list field_names; va_start(field_names, field_count); for (int x = 0; x < field_count; x++) { field_name_vector->push_back(va_arg(field_names, const char*)); } va_end(field_names); } // These helper methods and FirstUnusedType assure that there is no mismatch // between the specified types for metrics type parameters and the constructors // and methods used for the specializations. template struct CompileAssert {}; #define COMPILE_ASSERT(expr, msg) \ typedef util::CompileAssert<(bool(expr))> msg[bool(expr) ? 1 : -1] template struct is_unused { static const bool value = false; }; template <> struct is_unused { static const bool value = true; }; template class FirstUnusedType { static const bool a = is_unused::value; static const bool b = is_unused::value; static const bool c = is_unused::value; static const bool d = is_unused::value; // Check that all types after the first Unused are also Unused. COMPILE_ASSERT(a <= b, Invalid_Unused_At_Position_2); COMPILE_ASSERT(b <= c, Invalid_Unused_At_Position_3); COMPILE_ASSERT(c <= d, Invalid_Unused_At_Position_4); public: static const int value = 5 - (a + b + c + d); }; // Asserts that no Unused types exist before N; after N, are all Unused types. #define ASSERT_METRIC_UNUSED_START_FROM(N) \ COMPILE_ASSERT((\ util::FirstUnusedType::value) == N, \ Unused_Start_From_##N) } // namespace util } // namespace metrics } // namespace wvcdm #endif // WVCDM_METRICS_FIELD_TUPLES_H_