Home | History | Annotate | Download | only in detail
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef ART_CMDLINE_DETAIL_CMDLINE_PARSER_DETAIL_H_
     18 #define ART_CMDLINE_DETAIL_CMDLINE_PARSER_DETAIL_H_
     19 
     20 #include <string>
     21 #include <sstream>
     22 #include <vector>
     23 
     24 namespace art {
     25   // Implementation details for some template querying. Don't look inside if you hate templates.
     26   namespace detail {
     27     template <typename T>
     28     typename std::remove_reference<T>::type& FakeReference();
     29 
     30     // SupportsInsertionOperator<T, TStream>::value will evaluate to a boolean,
     31     // whose value is true if the TStream class supports the << operator against T,
     32     // and false otherwise.
     33     template <typename T2, typename TStream2 = std::ostream>
     34     struct SupportsInsertionOperator {
     35      private:
     36       template <typename TStream, typename T>
     37       static std::true_type InsertionOperatorTest(TStream& os, const T& value,
     38                                                   std::remove_reference<decltype(os << value)>* = 0); // NOLINT [whitespace/operators] [3]
     39 
     40       template <typename TStream, typename ... T>
     41       static std::false_type InsertionOperatorTest(TStream& os, const T& ... args);
     42 
     43      public:
     44       static constexpr bool value =
     45           decltype(InsertionOperatorTest(FakeReference<TStream2>(), std::declval<T2>()))::value;
     46     };
     47 
     48     template <typename TLeft, typename TRight = TLeft, bool IsFloatingPoint = false>
     49     struct SupportsEqualityOperatorImpl;
     50 
     51     template <typename TLeft, typename TRight>
     52     struct SupportsEqualityOperatorImpl<TLeft, TRight, false> {
     53      private:
     54       template <typename TL, typename TR>
     55       static std::true_type EqualityOperatorTest(const TL& left, const TR& right,
     56                                                  std::remove_reference<decltype(left == right)>* = 0); // NOLINT [whitespace/operators] [3]
     57 
     58       template <typename TL, typename ... T>
     59       static std::false_type EqualityOperatorTest(const TL& left, const T& ... args);
     60 
     61      public:
     62       static constexpr bool value =
     63           decltype(EqualityOperatorTest(std::declval<TLeft>(), std::declval<TRight>()))::value;
     64     };
     65 
     66     // Partial specialization when TLeft/TRight are both floating points.
     67     // This is a work-around because decltype(floatvar1 == floatvar2)
     68     // will not compile with clang:
     69     // error: comparing floating point with == or != is unsafe [-Werror,-Wfloat-equal]
     70     template <typename TLeft, typename TRight>
     71     struct SupportsEqualityOperatorImpl<TLeft, TRight, true> {
     72       static constexpr bool value = true;
     73     };
     74 
     75     // SupportsEqualityOperatorImpl<T1, T2>::value will evaluate to a boolean,
     76     // whose value is true if T1 can be compared against T2 with ==,
     77     // and false otherwise.
     78     template <typename TLeft, typename TRight = TLeft>
     79     struct SupportsEqualityOperator :
     80         SupportsEqualityOperatorImpl<TLeft, TRight,
     81                                      std::is_floating_point<TLeft>::value
     82                                      && std::is_floating_point<TRight>::value> {
     83     };
     84 
     85     // Convert any kind of type to an std::string, even if there's no
     86     // serialization support for it. Unknown types get converted to an
     87     // an arbitrary value.
     88     //
     89     // Meant for printing user-visible errors or unit test failures only.
     90     template <typename T>
     91     std::string ToStringAny(const T& value,
     92                             typename std::enable_if<
     93                                 SupportsInsertionOperator<T>::value>::type* = 0) {
     94       std::stringstream stream;
     95       stream << value;
     96       return stream.str();
     97     }
     98 
     99     template <typename T>
    100     std::string ToStringAny(const std::vector<T> value,
    101                             typename std::enable_if<
    102                                 SupportsInsertionOperator<T>::value>::type* = 0) {
    103       std::stringstream stream;
    104       stream << "vector{";
    105 
    106       for (size_t i = 0; i < value.size(); ++i) {
    107         stream << ToStringAny(value[i]);
    108 
    109         if (i != value.size() - 1) {
    110           stream << ',';
    111         }
    112       }
    113 
    114       stream << "}";
    115       return stream.str();
    116     }
    117 
    118     template <typename T>
    119     std::string ToStringAny(const T&,
    120                             typename std::enable_if<
    121                                 !SupportsInsertionOperator<T>::value>::type* = 0
    122     ) {
    123       return std::string("(unknown type [no operator<< implemented] for )");
    124     }
    125   }  // namespace detail  // NOLINT [readability/namespace] [5]
    126 }  // namespace art
    127 
    128 #endif  // ART_CMDLINE_DETAIL_CMDLINE_PARSER_DETAIL_H_
    129