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