1f5cc5b140c1c00c536e02b5cfbe158bb2d5c2c15bungeman@google.com/*
2f5cc5b140c1c00c536e02b5cfbe158bb2d5c2c15bungeman@google.com * Copyright 2013 Google Inc.
3f5cc5b140c1c00c536e02b5cfbe158bb2d5c2c15bungeman@google.com *
4f5cc5b140c1c00c536e02b5cfbe158bb2d5c2c15bungeman@google.com * Use of this source code is governed by a BSD-style license that can be
5f5cc5b140c1c00c536e02b5cfbe158bb2d5c2c15bungeman@google.com * found in the LICENSE file.
6f5cc5b140c1c00c536e02b5cfbe158bb2d5c2c15bungeman@google.com *
7f5cc5b140c1c00c536e02b5cfbe158bb2d5c2c15bungeman@google.com *
8221524de3be1fc343ad328c5e99562f32b5cad9cbungeman * This header provides some of the helpers (like std::enable_if_t) which will
9221524de3be1fc343ad328c5e99562f32b5cad9cbungeman * become available with C++14 in the type_traits header (in the skstd
10221524de3be1fc343ad328c5e99562f32b5cad9cbungeman * namespace). This header also provides several Skia specific additions such
11221524de3be1fc343ad328c5e99562f32b5cad9cbungeman * as SK_WHEN and the sknonstd namespace.
12f5cc5b140c1c00c536e02b5cfbe158bb2d5c2c15bungeman@google.com */
13f5cc5b140c1c00c536e02b5cfbe158bb2d5c2c15bungeman@google.com
14f5cc5b140c1c00c536e02b5cfbe158bb2d5c2c15bungeman@google.com#ifndef SkTLogic_DEFINED
15f5cc5b140c1c00c536e02b5cfbe158bb2d5c2c15bungeman@google.com#define SkTLogic_DEFINED
16f5cc5b140c1c00c536e02b5cfbe158bb2d5c2c15bungeman@google.com
17a3434d83cf988f930a73aaca5ba88f6f6fa8f547bungeman#include "SkTypes.h"
18a3434d83cf988f930a73aaca5ba88f6f6fa8f547bungeman
19a3434d83cf988f930a73aaca5ba88f6f6fa8f547bungeman#include <stddef.h>
202bd028590d9db472e5b9ee44ca8961be5c036432bungeman#include <stdint.h>
21221524de3be1fc343ad328c5e99562f32b5cad9cbungeman#include <type_traits>
22221524de3be1fc343ad328c5e99562f32b5cad9cbungeman#include <utility>
232bd028590d9db472e5b9ee44ca8961be5c036432bungeman
24761cf6186e291ee8e4761e1280634cfe9c42ecccbungemannamespace skstd {
25761cf6186e291ee8e4761e1280634cfe9c42ecccbungeman
26221524de3be1fc343ad328c5e99562f32b5cad9cbungemantemplate <bool B> using bool_constant = std::integral_constant<bool, B>;
27a3434d83cf988f930a73aaca5ba88f6f6fa8f547bungeman
28221524de3be1fc343ad328c5e99562f32b5cad9cbungemantemplate <bool B, typename T, typename F> using conditional_t = typename std::conditional<B, T, F>::type;
29221524de3be1fc343ad328c5e99562f32b5cad9cbungemantemplate <bool B, typename T = void> using enable_if_t = typename std::enable_if<B, T>::type;
30761cf6186e291ee8e4761e1280634cfe9c42ecccbungeman
31221524de3be1fc343ad328c5e99562f32b5cad9cbungemantemplate <typename T> using remove_const_t = typename std::remove_const<T>::type;
32221524de3be1fc343ad328c5e99562f32b5cad9cbungemantemplate <typename T> using remove_volatile_t = typename std::remove_volatile<T>::type;
33221524de3be1fc343ad328c5e99562f32b5cad9cbungemantemplate <typename T> using remove_cv_t = typename std::remove_cv<T>::type;
3454e63082191f337084f96083ca90d7c35273d6ffbungemantemplate <typename T> using remove_pointer_t = typename std::remove_pointer<T>::type;
35221524de3be1fc343ad328c5e99562f32b5cad9cbungemantemplate <typename T> using remove_reference_t = typename std::remove_reference<T>::type;
36221524de3be1fc343ad328c5e99562f32b5cad9cbungemantemplate <typename T> using remove_extent_t = typename std::remove_extent<T>::type;
37761cf6186e291ee8e4761e1280634cfe9c42ecccbungeman
38a3434d83cf988f930a73aaca5ba88f6f6fa8f547bungeman// template<typename R, typename... Args> struct is_function<
39221524de3be1fc343ad328c5e99562f32b5cad9cbungeman//     R [calling-convention] (Args...[, ...]) [const] [volatile] [&|&&]> : std::true_type {};
40a3434d83cf988f930a73aaca5ba88f6f6fa8f547bungeman// The cv and ref-qualified versions are strange types we're currently avoiding, so not supported.
410e101667d604e4902eb24e0c0939d4f5b12c96ecbungeman// These aren't supported in msvc either until vs2015u2.
42a3434d83cf988f930a73aaca5ba88f6f6fa8f547bungeman// On all platforms, variadic functions only exist in the c calling convention.
430e101667d604e4902eb24e0c0939d4f5b12c96ecbungeman// mcvc 2013 introduced __vectorcall, but it wan't until 2015 that it was added to is_function.
44221524de3be1fc343ad328c5e99562f32b5cad9cbungemantemplate <typename> struct is_function : std::false_type {};
45a3434d83cf988f930a73aaca5ba88f6f6fa8f547bungeman#if !defined(SK_BUILD_FOR_WIN)
46221524de3be1fc343ad328c5e99562f32b5cad9cbungemantemplate <typename R, typename... Args> struct is_function<R(Args...)> : std::true_type {};
47a3434d83cf988f930a73aaca5ba88f6f6fa8f547bungeman#else
48221524de3be1fc343ad328c5e99562f32b5cad9cbungemantemplate <typename R, typename... Args> struct is_function<R __cdecl (Args...)> : std::true_type {};
49c721196067b78226b97709998a96e0f037d8fb64cjacek#if defined(_M_IX86)
50221524de3be1fc343ad328c5e99562f32b5cad9cbungemantemplate <typename R, typename... Args> struct is_function<R __stdcall (Args...)> : std::true_type {};
51221524de3be1fc343ad328c5e99562f32b5cad9cbungemantemplate <typename R, typename... Args> struct is_function<R __fastcall (Args...)> : std::true_type {};
52c19247fd03b3498d3d6a6b44421ba75dd49a6ca0lsalzman#endif
53c721196067b78226b97709998a96e0f037d8fb64cjacek#if defined(_MSC_VER) && SK_CPU_SSE_LEVEL >= SK_CPU_SSE_LEVEL_SSE2
54221524de3be1fc343ad328c5e99562f32b5cad9cbungemantemplate <typename R, typename... Args> struct is_function<R __vectorcall (Args...)> : std::true_type {};
55a3434d83cf988f930a73aaca5ba88f6f6fa8f547bungeman#endif
56a3434d83cf988f930a73aaca5ba88f6f6fa8f547bungeman#endif
57221524de3be1fc343ad328c5e99562f32b5cad9cbungemantemplate <typename R, typename... Args> struct is_function<R(Args..., ...)> : std::true_type {};
58f5cc5b140c1c00c536e02b5cfbe158bb2d5c2c15bungeman@google.com
59221524de3be1fc343ad328c5e99562f32b5cad9cbungemantemplate <typename T> using add_const_t = typename std::add_const<T>::type;
60221524de3be1fc343ad328c5e99562f32b5cad9cbungemantemplate <typename T> using add_volatile_t = typename std::add_volatile<T>::type;
61221524de3be1fc343ad328c5e99562f32b5cad9cbungemantemplate <typename T> using add_cv_t = typename std::add_cv<T>::type;
62221524de3be1fc343ad328c5e99562f32b5cad9cbungemantemplate <typename T> using add_pointer_t = typename std::add_pointer<T>::type;
630e101667d604e4902eb24e0c0939d4f5b12c96ecbungemantemplate <typename T> using add_lvalue_reference_t = typename std::add_lvalue_reference<T>::type;
64f5cc5b140c1c00c536e02b5cfbe158bb2d5c2c15bungeman@google.com
65de029d0e41d2acb3cf49bd0d64b91add1aae9bd6bungemantemplate <typename S, typename D,
66de029d0e41d2acb3cf49bd0d64b91add1aae9bd6bungeman          bool=std::is_void<S>::value || is_function<D>::value || std::is_array<D>::value>
67a3434d83cf988f930a73aaca5ba88f6f6fa8f547bungemanstruct is_convertible_detector {
68de029d0e41d2acb3cf49bd0d64b91add1aae9bd6bungeman    static const/*expr*/ bool value = std::is_void<D>::value;
69a3434d83cf988f930a73aaca5ba88f6f6fa8f547bungeman};
70a3434d83cf988f930a73aaca5ba88f6f6fa8f547bungemantemplate <typename S, typename D> struct is_convertible_detector<S, D, false> {
71a3434d83cf988f930a73aaca5ba88f6f6fa8f547bungeman    using yes_type = uint8_t;
72a3434d83cf988f930a73aaca5ba88f6f6fa8f547bungeman    using no_type = uint16_t;
73a3434d83cf988f930a73aaca5ba88f6f6fa8f547bungeman
74a3434d83cf988f930a73aaca5ba88f6f6fa8f547bungeman    template <typename To> static void param_convertable_to(To);
75a3434d83cf988f930a73aaca5ba88f6f6fa8f547bungeman
76a3434d83cf988f930a73aaca5ba88f6f6fa8f547bungeman    template <typename From, typename To>
77221524de3be1fc343ad328c5e99562f32b5cad9cbungeman    static decltype(param_convertable_to<To>(std::declval<From>()), yes_type()) convertible(int);
78a3434d83cf988f930a73aaca5ba88f6f6fa8f547bungeman
79a3434d83cf988f930a73aaca5ba88f6f6fa8f547bungeman    template <typename, typename> static no_type convertible(...);
80a3434d83cf988f930a73aaca5ba88f6f6fa8f547bungeman
81a3434d83cf988f930a73aaca5ba88f6f6fa8f547bungeman    static const/*expr*/ bool value = sizeof(convertible<S, D>(0)) == sizeof(yes_type);
82a3434d83cf988f930a73aaca5ba88f6f6fa8f547bungeman};
830e101667d604e4902eb24e0c0939d4f5b12c96ecbungeman// std::is_convertable is known to be broken (not work with incomplete types) in Android clang NDK.
840e101667d604e4902eb24e0c0939d4f5b12c96ecbungeman// This is currently what prevents us from using std::unique_ptr.
85a3434d83cf988f930a73aaca5ba88f6f6fa8f547bungemantemplate<typename S, typename D> struct is_convertible
86221524de3be1fc343ad328c5e99562f32b5cad9cbungeman    : bool_constant<is_convertible_detector<S, D>::value> {};
87a3434d83cf988f930a73aaca5ba88f6f6fa8f547bungeman
88761cf6186e291ee8e4761e1280634cfe9c42ecccbungeman}  // namespace skstd
89761cf6186e291ee8e4761e1280634cfe9c42ecccbungeman
90761cf6186e291ee8e4761e1280634cfe9c42ecccbungeman// The sknonstd namespace contains things we would like to be proposed and feel std-ish.
91761cf6186e291ee8e4761e1280634cfe9c42ecccbungemannamespace sknonstd {
92761cf6186e291ee8e4761e1280634cfe9c42ecccbungeman
93761cf6186e291ee8e4761e1280634cfe9c42ecccbungeman// The name 'copy' here is fraught with peril. In this case it means 'append', not 'overwrite'.
94761cf6186e291ee8e4761e1280634cfe9c42ecccbungeman// Alternate proposed names are 'propagate', 'augment', or 'append' (and 'add', but already taken).
95761cf6186e291ee8e4761e1280634cfe9c42ecccbungeman// std::experimental::propagate_const already exists for other purposes in TSv2.
96761cf6186e291ee8e4761e1280634cfe9c42ecccbungeman// These also follow the <dest, source> pattern used by boost.
97761cf6186e291ee8e4761e1280634cfe9c42ecccbungemantemplate <typename D, typename S> struct copy_const {
98de029d0e41d2acb3cf49bd0d64b91add1aae9bd6bungeman    using type = skstd::conditional_t<std::is_const<S>::value, skstd::add_const_t<D>, D>;
99f5cc5b140c1c00c536e02b5cfbe158bb2d5c2c15bungeman@google.com};
100761cf6186e291ee8e4761e1280634cfe9c42ecccbungemantemplate <typename D, typename S> using copy_const_t = typename copy_const<D, S>::type;
101f5cc5b140c1c00c536e02b5cfbe158bb2d5c2c15bungeman@google.com
102761cf6186e291ee8e4761e1280634cfe9c42ecccbungemantemplate <typename D, typename S> struct copy_volatile {
103de029d0e41d2acb3cf49bd0d64b91add1aae9bd6bungeman    using type = skstd::conditional_t<std::is_volatile<S>::value, skstd::add_volatile_t<D>, D>;
104f5cc5b140c1c00c536e02b5cfbe158bb2d5c2c15bungeman@google.com};
105761cf6186e291ee8e4761e1280634cfe9c42ecccbungemantemplate <typename D, typename S> using copy_volatile_t = typename copy_volatile<D, S>::type;
106f5cc5b140c1c00c536e02b5cfbe158bb2d5c2c15bungeman@google.com
107761cf6186e291ee8e4761e1280634cfe9c42ecccbungemantemplate <typename D, typename S> struct copy_cv {
108761cf6186e291ee8e4761e1280634cfe9c42ecccbungeman    using type = copy_volatile_t<copy_const_t<D, S>, S>;
1092e0c32af0508a1e544c9953ea2fe128dbae7d429commit-bot@chromium.org};
110761cf6186e291ee8e4761e1280634cfe9c42ecccbungemantemplate <typename D, typename S> using copy_cv_t = typename copy_cv<D, S>::type;
111761cf6186e291ee8e4761e1280634cfe9c42ecccbungeman
112761cf6186e291ee8e4761e1280634cfe9c42ecccbungeman// The name 'same' here means 'overwrite'.
113761cf6186e291ee8e4761e1280634cfe9c42ecccbungeman// Alternate proposed names are 'replace', 'transfer', or 'qualify_from'.
114761cf6186e291ee8e4761e1280634cfe9c42ecccbungeman// same_xxx<D, S> can be written as copy_xxx<remove_xxx_t<D>, S>
115761cf6186e291ee8e4761e1280634cfe9c42ecccbungemantemplate <typename D, typename S> using same_const = copy_const<skstd::remove_const_t<D>, S>;
116761cf6186e291ee8e4761e1280634cfe9c42ecccbungemantemplate <typename D, typename S> using same_const_t = typename same_const<D, S>::type;
117761cf6186e291ee8e4761e1280634cfe9c42ecccbungemantemplate <typename D, typename S> using same_volatile =copy_volatile<skstd::remove_volatile_t<D>,S>;
118761cf6186e291ee8e4761e1280634cfe9c42ecccbungemantemplate <typename D, typename S> using same_volatile_t = typename same_volatile<D, S>::type;
119761cf6186e291ee8e4761e1280634cfe9c42ecccbungemantemplate <typename D, typename S> using same_cv = copy_cv<skstd::remove_cv_t<D>, S>;
120761cf6186e291ee8e4761e1280634cfe9c42ecccbungemantemplate <typename D, typename S> using same_cv_t = typename same_cv<D, S>::type;
1212e0c32af0508a1e544c9953ea2fe128dbae7d429commit-bot@chromium.org
122761cf6186e291ee8e4761e1280634cfe9c42ecccbungeman}  // namespace sknonstd
1232e0c32af0508a1e544c9953ea2fe128dbae7d429commit-bot@chromium.org
124449d9b7e2d1b2e20963f18639c6e541ef953f069mtklein// Just a pithier wrapper for enable_if_t.
125449d9b7e2d1b2e20963f18639c6e541ef953f069mtklein#define SK_WHEN(condition, T) skstd::enable_if_t<!!(condition), T>
12673fffeb83aab56bc8c2c5ce143ee9d132d64ac37commit-bot@chromium.org
1274b3ef5ad33aa3dcef083101177dd8a91978cc7debungeman@google.com#endif
128