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