1/*
2 * Copyright (C) 2018 Yusuke Suzuki <yusukesuzuki@slowstart.org>.
3 * Copyright (C) 2016-2017 Apple Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26// The idea of Markable<T> is derived from markable<T> at
27// https://github.com/akrzemi1/markable.
28//
29// Copyright (C) 2015-2018 Andrzej Krzemienski.
30//
31// Use, modification, and distribution is subject to the Boost Software
32// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
33// http://www.boost.org/LICENSE_1_0.txt)
34
35#pragma once
36
37#include <type_traits>
38#include <wtf/Optional.h>
39#include <wtf/StdLibExtras.h>
40
41namespace WTF {
42
43// Example:
44// enum class Type { Value1, Value2, Value3 };
45// Markable<Type, EnumMarkableTraits<Type, 42>> optional;
46template<
47 typename EnumType,
48 typename std::underlying_type<EnumType>::type constant = std::numeric_limits<typename std::underlying_type<EnumType>::type>::max()>
49struct EnumMarkableTraits {
50 static_assert(std::is_enum<EnumType>::value, "");
51 using UnderlyingType = typename std::underlying_type<EnumType>::type;
52
53 constexpr static bool isEmptyValue(EnumType value)
54 {
55 return static_cast<UnderlyingType>(value) == constant;
56 }
57
58 constexpr static EnumType emptyValue()
59 {
60 return static_cast<EnumType>(constant);
61 }
62};
63
64template<typename IntegralType, IntegralType constant = 0>
65struct IntegralMarkableTraits {
66 static_assert(std::is_integral<IntegralType>::value, "");
67 constexpr static bool isEmptyValue(IntegralType value)
68 {
69 return value == constant;
70 }
71
72 constexpr static IntegralType emptyValue()
73 {
74 return constant;
75 }
76};
77
78// The goal of Markable is offering Optional without sacrificing storage efficiency.
79// Markable takes Traits, which should have isEmptyValue and emptyValue functions. By using
80// one value of T as an empty value, we can remove bool flag in Optional. This strategy is
81// similar to WTF::HashTable, which uses two values of T as an empty value and a deleted value.
82// This class is intended to be used as a member of a class to compact the size of the class.
83// Otherwise, you should use Optional.
84template<typename T, typename Traits>
85class Markable {
86public:
87 constexpr Markable()
88 : m_value(Traits::emptyValue())
89 { }
90
91 constexpr Markable(WTF::nullopt_t)
92 : Markable()
93 { }
94
95 constexpr Markable(T&& value)
96 : m_value(WTFMove(value))
97 { }
98
99 constexpr Markable(const T& value)
100 : m_value(value)
101 { }
102
103 template<typename... Args>
104 constexpr explicit Markable(std::in_place_t, Args&&... args)
105 : m_value(std::forward<Args>(args)...)
106 { }
107
108 constexpr Markable(const Optional<T>& value)
109 : m_value(bool(value) ? *value : Traits::emptyValue())
110 { }
111
112 constexpr Markable(Optional<T>&& value)
113 : m_value(bool(value) ? WTFMove(*value) : Traits::emptyValue())
114 { }
115
116 constexpr explicit operator bool() const { return !Traits::isEmptyValue(m_value); }
117
118 void reset() { m_value = Traits::emptyValue(); }
119
120 constexpr const T& value() const& { return m_value; }
121 constexpr T& value() & { return m_value; }
122 constexpr T&& value() && { return WTFMove(m_value); }
123
124 constexpr const T* operator->() const { return std::addressof(m_value); }
125 constexpr T* operator->() { return std::addressof(m_value); }
126
127 constexpr const T& operator*() const& { return m_value; }
128 constexpr T& operator*() & { return m_value; }
129
130 operator Optional<T>() &&
131 {
132 if (bool(*this))
133 return WTFMove(m_value);
134 return WTF::nullopt;
135 }
136
137 operator Optional<T>() const&
138 {
139 if (bool(*this))
140 return m_value;
141 return WTF::nullopt;
142 }
143
144private:
145 T m_value;
146};
147
148} // namespace WTF
149
150using WTF::Markable;
151using WTF::IntegralMarkableTraits;
152using WTF::EnumMarkableTraits;
153