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 <sstream>
     21 #include <string>
     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 :  // NOLINT [whitespace/labels] [4]
     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* = nullptr) {
     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* = nullptr) {
    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* = nullptr
    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