cc17.h 9.77 KB
Newer Older
yanyan's avatar
yanyan committed
1
2
3
4
5
6
7
8
9
/*
From PyTorch:

Copyright (c) 2016-     Facebook, Inc            (Adam Paszke)
Copyright (c) 2014-     Facebook, Inc            (Soumith Chintala)
Copyright (c) 2011-2014 Idiap Research Institute (Ronan Collobert)
Copyright (c) 2012-2014 Deepmind Technologies    (Koray Kavukcuoglu)
Copyright (c) 2011-2012 NEC Laboratories America (Koray Kavukcuoglu)
Copyright (c) 2011-2013 NYU                      (Clement Farabet)
yanyan's avatar
yanyan committed
10
11
12
13
Copyright (c) 2006-2010 NEC Laboratories America (Ronan Collobert, Leon Bottou,
Iain Melvin, Jason Weston) Copyright (c) 2006      Idiap Research Institute
(Samy Bengio) Copyright (c) 2001-2004 Idiap Research Institute (Ronan Collobert,
Samy Bengio, Johnny Mariethoz)
yanyan's avatar
yanyan committed
14
15
16
17
18
19
20

From Caffe2:

Copyright (c) 2016-present, Facebook Inc. All rights reserved.

All contributions by Facebook:
Copyright (c) 2016 Facebook Inc.
yanyan's avatar
yanyan committed
21

yanyan's avatar
yanyan committed
22
23
24
All contributions by Google:
Copyright (c) 2015 Google Inc.
All rights reserved.
yanyan's avatar
yanyan committed
25

yanyan's avatar
yanyan committed
26
27
28
All contributions by Yangqing Jia:
Copyright (c) 2015 Yangqing Jia
All rights reserved.
yanyan's avatar
yanyan committed
29

yanyan's avatar
yanyan committed
30
31
32
All contributions from Caffe:
Copyright(c) 2013, 2014, 2015, the respective contributors
All rights reserved.
yanyan's avatar
yanyan committed
33

yanyan's avatar
yanyan committed
34
35
36
All other contributions:
Copyright(c) 2015, 2016 the respective contributors
All rights reserved.
yanyan's avatar
yanyan committed
37

yanyan's avatar
yanyan committed
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
Caffe2 uses a copyright model similar to Caffe: each contributor holds
copyright over their contributions to Caffe2. The project versioning records
all such contribution and copyright details. If a contributor wants to further
mark their specific copyright on a particular contribution, they should
indicate their copyright solely in the commit message of the change when it is
committed.

All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright
   notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright
   notice, this list of conditions and the following disclaimer in the
   documentation and/or other materials provided with the distribution.

yanyan's avatar
yanyan committed
57
58
3. Neither the names of Facebook, Deepmind Technologies, NYU, NEC Laboratories
America and IDIAP Research Institute nor the names of its contributors may be
yanyan's avatar
yanyan committed
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
   used to endorse or promote products derived from this software without
   specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <type_traits>
#include <utility>

namespace tv {
yanyan's avatar
yanyan committed
79

yanyan's avatar
yanyan committed
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
#ifdef __cpp_lib_void_t

template <class T> using void_t = std::void_t<T>;

#else

// Implementation taken from http://en.cppreference.com/w/cpp/types/void_t
// (it takes CWG1558 into account and also works for older compilers)
template <typename... Ts> struct make_void { typedef void type; };
template <typename... Ts> using void_t = typename make_void<Ts...>::type;

#endif

namespace detail {
struct _identity final {
  template <class T> using type_identity = T;

  template <class T> decltype(auto) operator()(T &&arg) {
    return std::forward<T>(arg);
  }
};
yanyan's avatar
yanyan committed
101
template <class Func, class Enable = void>
yanyan's avatar
yanyan committed
102
103
struct function_takes_identity_argument : std::false_type {};
#if defined(_MSC_VER)
yanyan's avatar
yanyan committed
104
105
106
107
108
109
110
// For some weird reason, MSVC shows a compiler error when using guts::void_t
// instead of std::void_t. But we're only building on MSVC versions that have
// std::void_t, so let's just use that one.
template <class Func>
struct function_takes_identity_argument<
    Func, std::void_t<decltype(std::declval<Func>()(_identity()))>>
    : std::true_type {};
yanyan's avatar
yanyan committed
111
#else
yanyan's avatar
yanyan committed
112
113
114
115
template <class Func>
struct function_takes_identity_argument<
    Func, void_t<decltype(std::declval<Func>()(_identity()))>>
    : std::true_type {};
yanyan's avatar
yanyan committed
116
117
#endif

yanyan's avatar
yanyan committed
118
template <bool Condition> struct _if_constexpr;
yanyan's avatar
yanyan committed
119

yanyan's avatar
yanyan committed
120
121
122
123
124
125
126
127
128
129
template <> struct _if_constexpr<true> final {
  template <
      class ThenCallback, class ElseCallback,
      std::enable_if_t<function_takes_identity_argument<ThenCallback>::value,
                       void *> = nullptr>
  static decltype(auto) call(ThenCallback &&thenCallback,
                             ElseCallback && /* elseCallback */) {
    // The _identity instance passed in can be used to delay evaluation of an
    // expression, because the compiler can't know that it's just the identity
    // we're passing in.
yanyan's avatar
yanyan committed
130
131
132
    return thenCallback(_identity());
  }

yanyan's avatar
yanyan committed
133
134
135
136
137
138
  template <
      class ThenCallback, class ElseCallback,
      std::enable_if_t<!function_takes_identity_argument<ThenCallback>::value,
                       void *> = nullptr>
  static decltype(auto) call(ThenCallback &&thenCallback,
                             ElseCallback && /* elseCallback */) {
yanyan's avatar
yanyan committed
139
140
141
142
    return thenCallback();
  }
};

yanyan's avatar
yanyan committed
143
144
145
146
147
148
149
150
151
152
template <> struct _if_constexpr<false> final {
  template <
      class ThenCallback, class ElseCallback,
      std::enable_if_t<function_takes_identity_argument<ElseCallback>::value,
                       void *> = nullptr>
  static decltype(auto) call(ThenCallback && /* thenCallback */,
                             ElseCallback &&elseCallback) {
    // The _identity instance passed in can be used to delay evaluation of an
    // expression, because the compiler can't know that it's just the identity
    // we're passing in.
yanyan's avatar
yanyan committed
153
154
155
    return elseCallback(_identity());
  }

yanyan's avatar
yanyan committed
156
157
158
159
160
161
  template <
      class ThenCallback, class ElseCallback,
      std::enable_if_t<!function_takes_identity_argument<ElseCallback>::value,
                       void *> = nullptr>
  static decltype(auto) call(ThenCallback && /* thenCallback */,
                             ElseCallback &&elseCallback) {
yanyan's avatar
yanyan committed
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
    return elseCallback();
  }
};
} // namespace detail

/*
 * Get something like C++17 if constexpr in C++14.
 *
 * Example 1: simple constexpr if/then/else
 *   template<int arg> int increment_absolute_value() {
 *     int result = arg;
 *     if_constexpr<(arg > 0)>(
 *       [&] { ++result; }  // then-case
 *       [&] { --result; }  // else-case
 *     );
 *     return result;
 *   }
 *
 * Example 2: without else case (i.e. conditionally prune code from assembly)
 *   template<int arg> int decrement_if_positive() {
 *     int result = arg;
 *     if_constexpr<(arg > 0)>(
 *       // This decrement operation is only present in the assembly for
 *       // template instances with arg > 0.
 *       [&] { --result; }
 *     );
 *     return result;
 *   }
 *
 * Example 3: branch based on type (i.e. replacement for SFINAE)
 *   struct MyClass1 {int value;};
 *   struct MyClass2 {int val};
 *   template <class T>
 *   int func(T t) {
 *     return if_constexpr<std::is_same<T, MyClass1>::value>(
yanyan's avatar
yanyan committed
197
198
199
200
 *       [&](auto _) { return _(t).value; }, // this code is invalid for T ==
 * MyClass2, so a regular non-constexpr if statement wouldn't compile
 *       [&](auto _) { return _(t).val; }    // this code is invalid for T ==
 * MyClass1
yanyan's avatar
yanyan committed
201
202
203
 *     );
 *   }
 *
yanyan's avatar
yanyan committed
204
205
206
207
208
 * Note: The _ argument passed in Example 3 is the identity function, i.e. it
 * does nothing. It is used to force the compiler to delay type checking,
 * because the compiler doesn't know what kind of _ is passed in. Without it,
 * the compiler would fail when you try to access t.value but the member doesn't
 * exist.
yanyan's avatar
yanyan committed
209
 *
yanyan's avatar
yanyan committed
210
211
212
213
 * Note: In Example 3, both branches return int, so func() returns int. This is
 * not necessary. If func() had a return type of "auto", then both branches
 * could return different types, say func<MyClass1>() could return int and
 * func<MyClass2>() could return string.
yanyan's avatar
yanyan committed
214
 */
yanyan's avatar
yanyan committed
215
216
217
template <bool Condition, class ThenCallback, class ElseCallback>
decltype(auto) if_constexpr(ThenCallback &&thenCallback,
                            ElseCallback &&elseCallback) {
yanyan's avatar
yanyan committed
218
#if defined(__cpp_if_constexpr)
yanyan's avatar
yanyan committed
219
220
221
222
223
  // If we have C++17, just use it's "if constexpr" feature instead of wrapping
  // it. This will give us better error messages.
  if constexpr (Condition) {
    if constexpr (detail::function_takes_identity_argument<
                      ThenCallback>::value) {
yanyan's avatar
yanyan committed
224
225
226
227
228
      return std::forward<ThenCallback>(thenCallback)(detail::_identity());
    } else {
      return std::forward<ThenCallback>(thenCallback)();
    }
  } else {
yanyan's avatar
yanyan committed
229
230
    if constexpr (detail::function_takes_identity_argument<
                      ElseCallback>::value) {
yanyan's avatar
yanyan committed
231
232
233
234
235
236
237
      return std::forward<ElseCallback>(elseCallback)(detail::_identity());
    } else {
      return std::forward<ElseCallback>(elseCallback)();
    }
  }
#else
  // C++14 implementation of if constexpr
yanyan's avatar
yanyan committed
238
239
240
  return detail::_if_constexpr<Condition>::call(
      std::forward<ThenCallback>(thenCallback),
      std::forward<ElseCallback>(elseCallback));
yanyan's avatar
yanyan committed
241
242
243
#endif
}

yanyan's avatar
yanyan committed
244
245
template <bool Condition, class ThenCallback>
decltype(auto) if_constexpr(ThenCallback &&thenCallback) {
yanyan's avatar
yanyan committed
246
#if defined(__cpp_if_constexpr)
yanyan's avatar
yanyan committed
247
248
249
250
251
  // If we have C++17, just use it's "if constexpr" feature instead of wrapping
  // it. This will give us better error messages.
  if constexpr (Condition) {
    if constexpr (detail::function_takes_identity_argument<
                      ThenCallback>::value) {
yanyan's avatar
yanyan committed
252
253
254
255
256
257
258
      return std::forward<ThenCallback>(thenCallback)(detail::_identity());
    } else {
      return std::forward<ThenCallback>(thenCallback)();
    }
  }
#else
  // C++14 implementation of if constexpr
yanyan's avatar
yanyan committed
259
260
  return if_constexpr<Condition>(std::forward<ThenCallback>(thenCallback),
                                 [](auto) {});
yanyan's avatar
yanyan committed
261
262
263
#endif
}

yanyan's avatar
yanyan committed
264
} // namespace tv