1 /* Copyright (c) 2019 The Khronos Group Inc.
2  * Copyright (c) 2019 Valve Corporation
3  * Copyright (c) 2019 LunarG, Inc.
4  *
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at
8  *
9  *     http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  * Author: John Zulauf <jzulauf@lunarg.com>
18  *
19  */
20 #pragma once
21 #ifndef CAST_UTILS_H_
22 #define CAST_UTILS_H_
23 
24 #include <cassert>
25 #include <cstddef>
26 #include <cstdint>
27 #include <functional>
28 
29 #define CAST_TO_FROM_UTILS
30 // Casts to allow various types of less than 64 bits to be cast to and from uint64_t safely and portably
31 template <typename HandleType, typename Uint>
CastFromUint(Uint untyped_handle)32 static inline HandleType CastFromUint(Uint untyped_handle) {
33     static_assert(sizeof(HandleType) == sizeof(Uint), "HandleType must be the same size as untyped handle");
34     return *reinterpret_cast<HandleType *>(&untyped_handle);
35 }
36 template <typename HandleType, typename Uint>
CastToUint(HandleType handle)37 static inline Uint CastToUint(HandleType handle) {
38     static_assert(sizeof(HandleType) == sizeof(Uint), "HandleType must be the same size as untyped handle");
39     return *reinterpret_cast<Uint *>(&handle);
40 }
41 
42 // Ensure that the size changing casts are *static* to ensure portability
43 template <typename HandleType>
CastFromUint64(uint64_t untyped_handle)44 static inline HandleType CastFromUint64(uint64_t untyped_handle) {
45     static_assert(sizeof(HandleType) <= sizeof(uint64_t), "HandleType must be not larger than the untyped handle size");
46     typedef
47         typename std::conditional<sizeof(HandleType) == sizeof(uint8_t), uint8_t,
48                                   typename std::conditional<sizeof(HandleType) == sizeof(uint16_t), uint16_t,
49                                                             typename std::conditional<sizeof(HandleType) == sizeof(uint32_t),
50                                                                                       uint32_t, uint64_t>::type>::type>::type Uint;
51     return CastFromUint<HandleType, Uint>(static_cast<Uint>(untyped_handle));
52 }
53 
54 template <typename HandleType>
CastToUint64(HandleType handle)55 static uint64_t CastToUint64(HandleType handle) {
56     static_assert(sizeof(HandleType) <= sizeof(uint64_t), "HandleType must be not larger than the untyped handle size");
57     typedef
58         typename std::conditional<sizeof(HandleType) == sizeof(uint8_t), uint8_t,
59                                   typename std::conditional<sizeof(HandleType) == sizeof(uint16_t), uint16_t,
60                                                             typename std::conditional<sizeof(HandleType) == sizeof(uint32_t),
61                                                                                       uint32_t, uint64_t>::type>::type>::type Uint;
62     return static_cast<uint64_t>(CastToUint<HandleType, Uint>(handle));
63 }
64 
65 // Convenience functions to case between handles and the types the handles abstract, reflecting the Vulkan handle scheme, where
66 // Handles are either pointers (dispatchable) or sizeof(uint64_t) (non-dispatchable), s.t. full size-safe casts are used and
67 // we ensure that handles are large enough to contain the underlying type.
68 template <typename HandleType, typename ValueType>
CastToHandle(ValueType value,HandleType * handle)69 void CastToHandle(ValueType value, HandleType *handle) {
70     static_assert(sizeof(HandleType) >= sizeof(ValueType), "HandleType must large enough to hold internal value");
71     *handle = CastFromUint64<HandleType>(CastToUint64<ValueType>(value));
72 }
73 // This form is conveniently "inline", you should only need to specify the handle type (the value type being deducible from the arg)
74 template <typename HandleType, typename ValueType>
CastToHandle(ValueType value)75 HandleType CastToHandle(ValueType value) {
76     HandleType handle;
77     CastToHandle(value, &handle);
78     return handle;
79 }
80 
81 template <typename ValueType, typename HandleType>
CastFromHandle(HandleType handle,ValueType * value)82 void CastFromHandle(HandleType handle, ValueType *value) {
83     static_assert(sizeof(HandleType) >= sizeof(ValueType), "HandleType must large enough to hold internal value");
84     *value = CastFromUint64<ValueType>(CastToUint64<HandleType>(handle));
85 }
86 template <typename ValueType, typename HandleType>
CastFromHandle(HandleType handle)87 ValueType CastFromHandle(HandleType handle) {
88     ValueType value;
89     CastFromHandle(handle, &value);
90     return value;
91 }
92 
93 #endif  // CAST_UTILS_H_
94