/usr/include/hphp/util/either.h is in hhvm-dev 3.11.1+dfsg-1ubuntu1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 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 | /*
+----------------------------------------------------------------------+
| HipHop for PHP |
+----------------------------------------------------------------------+
| Copyright (c) 2010-2015 Facebook, Inc. (http://www.facebook.com) |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
*/
#ifndef incl_HPHP_EITHER_H_
#define incl_HPHP_EITHER_H_
#include <cassert>
#include <cstdint>
#include <cstddef>
#include <type_traits>
// Workaround a bug that using std::common_type<void, void> causes error with
// libc++. See https://llvm.org/bugs/show_bug.cgi?id=22135
#ifdef _LIBCPP_VERSION
namespace std {
template<>
struct common_type<void, void> {
typedef void type;
};
}
#endif
namespace HPHP {
//////////////////////////////////////////////////////////////////////
/*
* Discriminated pointer to one of two types, or a nullptr.
*
* It does not distinguish between two types of null (for left and
* right)---if the Either is nullptr it is effectively a third state.
*
* This class does not do any intelligent automatic ownership, and is
* guaranteed to be a trivially copyable, standard layout class.
* Zero-initializing it is guaranteed to have a nullptr value
* (assuming null is represented with all bits zero, which of course
* it is on our supported architectures).
*
* Requirements:
*
* - The two types must be unrelated, and must be pointers.
*
* - The pointer types used with this class must be known to be at least
* 2-byte aligned with the default arguments, since it discriminates using
* the low bit (NB: this is not the case for string literals on gcc). You
* can pass either_policy::high_bit to use the highest bit as the tag
* instead in cases where this doesn't apply.
*
* - This class assumes pointers of L and R types never alias.
*
*/
namespace either_policy { struct high_bit {}; }
template<class L, class R, class TagBitPolicy = void>
struct Either {
static_assert(
std::is_same<TagBitPolicy,void>::value ||
std::is_same<TagBitPolicy,either_policy::high_bit>::value,
"Unknown policy in Either"
);
static constexpr uintptr_t TagBit =
std::conditional<
std::is_same<TagBitPolicy,void>::value,
std::integral_constant<uintptr_t,0x1>,
std::integral_constant<uintptr_t,0x8000000000000000>
>::type::value;
/*
* The default constructor creates an Either that isNull.
*
* Post: left() == nullptr && right() == nullptr
* isNull()
*/
Either() : bits{0} {}
/*
* Create an Either that isNull.
*
* Post: left() == nullptr && right() == nullptr
* isNull()
*/
/* implicit */ Either(std::nullptr_t) : bits{0} {}
/*
* Create an Either in the left mode.
*
* Post: left() == l && right() == nullptr
*/
/* implicit */ Either(L l)
: bits{reinterpret_cast<uintptr_t>(l)}
{
assert(!(reinterpret_cast<uintptr_t>(l) & TagBit));
}
/*
* Create an Either in the right mode.
*
* Post: left() == nullptr && right() == r
*/
/* implicit */ Either(R r)
: bits{reinterpret_cast<uintptr_t>(r) | TagBit}
{
assert(!(reinterpret_cast<uintptr_t>(r) & TagBit));
}
/*
* Equality comparison is shallow. If the pointers are equal, the
* Eithers are equal.
*/
bool operator==(Either<L,R> o) const {
// We assume L* and R* don't alias, so we don't need to check type tags
// when comparing. But we have to put the TagBit in in case we constructed
// a null from the right (we'll have a tagged null).
return (bits | TagBit) == (o.bits | TagBit);
}
bool operator!=(Either<L,R> o) const {
return !(*this == o);
}
/*
* Matching on Eithers takes two functions, for left and right. If
* you know that the either is non-null, this is reasonable. If it's
* potentially null, the null case is passed as a null pointer to the
* right branch.
*
* Example usage:
*
* Either<A*,B*> foo;
* auto const count = foo.match(
* [&] (A* a) { return a->size(); },
* [&] (B* b) { return b->size(); }
* );
*/
template<class LF, class RF>
typename std::common_type<
typename std::result_of<LF(L)>::type,
typename std::result_of<RF(R)>::type
>::type match(const LF& lf, const RF& rf) const {
if (auto const l = left()) return lf(l);
return rf(reinterpret_cast<R>(bits & ~TagBit));
}
/*
* Functions that simultaneously query the type tag and extract the
* pointer of that type. Both return nullptr if the Either does not
* hold that type.
*/
L left() const {
return bits & TagBit ? nullptr : reinterpret_cast<L>(bits);
}
R right() const {
return bits & TagBit ? reinterpret_cast<R>(bits & ~TagBit) : nullptr;
}
/*
* Returns whether this Either contains neither left nor right.
*/
bool isNull() const { return !(bits & ~TagBit); }
private:
static_assert(
!std::is_convertible<L,R>::value && !std::is_convertible<R,L>::value,
"Either<L,R> should not be used with compatible pointer types"
);
// Not implemented in gcc:
// static_assert(
// std::is_standard_layout<Either>::value,
// "Either<L,R> should be a standard layout class"
// );
static_assert(
std::is_pointer<L>::value && std::is_pointer<R>::value,
"Either<L,R> should only be used with pointer types"
);
private:
uintptr_t bits;
};
//////////////////////////////////////////////////////////////////////
}
#endif
|