blob: 118628fdec81bddae225c264e501e85737cb6fe1 [file] [log] [blame]
Igor Murashkinaaebaa02015-01-26 10:55:53 -08001/*
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
Igor Murashkinaaebaa02015-01-26 10:55:53 -080020#include <sstream>
Andreas Gampe8cf9cb32017-07-19 09:28:38 -070021#include <string>
Igor Murashkinaaebaa02015-01-26 10:55:53 -080022#include <vector>
23
24namespace 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,
Roland Levillain7cbd27f2016-08-11 23:53:33 +010038 std::remove_reference<decltype(os << value)>* = 0); // NOLINT [whitespace/operators] [3]
Igor Murashkinaaebaa02015-01-26 10:55:53 -080039
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,
Roland Levillain7cbd27f2016-08-11 23:53:33 +010056 std::remove_reference<decltype(left == right)>* = 0); // NOLINT [whitespace/operators] [3]
Igor Murashkinaaebaa02015-01-26 10:55:53 -080057
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_