//===- llvm/ADT/PointerUnion.h - Discriminated Union of 2 Ptrs --*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// /// /// \file /// This file defines the PointerUnion class, which is a discriminated union of /// pointer types. /// //===----------------------------------------------------------------------===// #ifndef LLVM_ADT_POINTERUNION_H #define LLVM_ADT_POINTERUNION_H #include "llvm/ADT/DenseMapInfo.h" #include "llvm/ADT/PointerIntPair.h" #include "llvm/ADT/STLExtras.h" #include "llvm/Support/Casting.h" #include "llvm/Support/PointerLikeTypeTraits.h" #include <algorithm> #include <cassert> #include <cstddef> #include <cstdint> namespace llvm { namespace pointer_union_detail { /// Determine the number of bits required to store integers with values < n. /// This is ceil(log2(n)). constexpr int bitsRequired(unsigned n) { … } template <typename... Ts> constexpr int lowBitsAvailable() { … } /// Find the first type in a list of types. template <typename T, typename...> struct GetFirstType { … }; /// Provide PointerLikeTypeTraits for void* that is used by PointerUnion /// for the template arguments. template <typename ...PTs> class PointerUnionUIntTraits { … }; template <typename Derived, typename ValTy, int I, typename ...Types> class PointerUnionMembers; PointerUnionMembers<Derived, ValTy, I>; PointerUnionMembers<Derived, ValTy, I, Type, Types...>; } // This is a forward declaration of CastInfoPointerUnionImpl // Refer to its definition below for further details template <typename... PTs> struct CastInfoPointerUnionImpl; /// A discriminated union of two or more pointer types, with the discriminator /// in the low bit of the pointer. /// /// This implementation is extremely efficient in space due to leveraging the /// low bits of the pointer, while exposing a natural and type-safe API. /// /// Common use patterns would be something like this: /// PointerUnion<int*, float*> P; /// P = (int*)0; /// printf("%d %d", P.is<int*>(), P.is<float*>()); // prints "1 0" /// X = P.get<int*>(); // ok. /// Y = P.get<float*>(); // runtime assertion failure. /// Z = P.get<double*>(); // compile time failure. /// P = (float*)0; /// Y = P.get<float*>(); // ok. /// X = P.get<int*>(); // runtime assertion failure. /// PointerUnion<int*, int*> Q; // compile time failure. template <typename... PTs> class PointerUnion : public pointer_union_detail::PointerUnionMembers< PointerUnion<PTs...>, PointerIntPair< void *, pointer_union_detail::bitsRequired(sizeof...(PTs)), int, pointer_union_detail::PointerUnionUIntTraits<PTs...>>, 0, PTs...> { … }; template <typename ...PTs> bool operator==(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) { … } template <typename ...PTs> bool operator!=(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) { … } template <typename ...PTs> bool operator<(PointerUnion<PTs...> lhs, PointerUnion<PTs...> rhs) { … } /// We can't (at least, at this moment with C++14) declare CastInfo /// as a friend of PointerUnion like this: /// ``` /// template<typename To> /// friend struct CastInfo<To, PointerUnion<PTs...>>; /// ``` /// The compiler complains 'Partial specialization cannot be declared as a /// friend'. /// So we define this struct to be a bridge between CastInfo and /// PointerUnion. template <typename... PTs> struct CastInfoPointerUnionImpl { … }; // Specialization of CastInfo for PointerUnion CastInfo<To, PointerUnion<PTs...>>; CastInfo<To, const PointerUnion<PTs...>>; // Teach SmallPtrSet that PointerUnion is "basically a pointer", that has // # low bits available = min(PT1bits,PT2bits)-1. PointerLikeTypeTraits<PointerUnion<PTs...>>; // Teach DenseMap how to use PointerUnions as keys. DenseMapInfo<PointerUnion<PTs...>>; } // end namespace llvm #endif // LLVM_ADT_POINTERUNION_H