4#include <mutable/mutable-config.hpp>
20 friend std::hash<Value>;
30#ifdef M_ENABLE_SANITY_FIELDS
47 memset(&val_, 0,
sizeof(val_));
48#ifdef M_ENABLE_SANITY_FIELDS
55 static_assert(std::is_fundamental_v<T> or std::is_pointer_v<T> or std::is_same_v<T, m::ThreadSafePooledString>,
56 "type T must be either a fundamental, a pointer, or a pooled string type");
57#ifdef M_ENABLE_SANITY_FIELDS
58#define SET_TYPE(TY) this->type = V##TY
62#define SET(TY) { val_.TY = val; SET_TYPE(TY); }
63 if constexpr (std::is_same_v<T, bool>)
SET(b)
64 else if constexpr (std::is_integral_v<T>)
SET(i)
65 else if constexpr (std::is_same_v<T, float>)
SET(f)
66 else if constexpr (std::is_same_v<T, double>)
SET(d)
67 else if constexpr (std::is_same_v<T, m::ThreadSafePooledString>) {
68 val_.p = (
void*)(
const char*)(val);
SET_TYPE(p);
70 else if constexpr (std::is_pointer_v<T>) { val_.p = (
void*)(val);
SET_TYPE(p); }
71 else static_assert(not std::is_same_v<T, T>,
"unspoorted type T");
79 std::conditional_t<std::is_pointer_v<T>,
T,
T&>
as() {
80#ifdef M_ENABLE_SANITY_FIELDS
81#define VALIDATE_TYPE(TY) M_insist(this->type == V##TY)
83#define VALIDATE_TYPE(TY)
85#define GET(TY) { VALIDATE_TYPE(TY); return val_.TY; }
86 if constexpr (std::is_same_v<T, bool>)
GET(b)
87 else if constexpr (std::is_same_v<T, int64_t>)
GET(i)
88 else if constexpr (std::is_same_v<T, float>)
GET(f)
89 else if constexpr (std::is_same_v<T, double>)
GET(d)
90 else if constexpr (std::is_pointer_v<T>) {
VALIDATE_TYPE(p);
return reinterpret_cast<T>(val_.p); }
91 else static_assert(not std::is_same_v<T, T>,
"unsupported type");
98 T as()
const {
return const_cast<Value*
>(
this)->as<T>(); }
101 auto &
as_b() {
return as<bool>(); }
103 auto &
as_i() {
return as<int64_t>(); }
105 auto &
as_f() {
return as<float>(); }
107 auto &
as_d() {
return as<double>(); }
109 auto as_p() {
return as<void*>(); }
112 auto as_b()
const {
return as<bool>(); }
114 auto as_i()
const {
return as<int64_t>(); }
116 auto as_f()
const {
return as<float>(); }
118 auto as_d()
const {
return as<double>(); }
120 auto as_p()
const {
return as<void*>(); }
122 explicit operator bool()
const {
return as_b(); }
123 explicit operator int32_t()
const {
return as_i(); }
124 explicit operator int64_t()
const {
return as_i(); }
125 explicit operator float()
const {
return as_f(); }
126 explicit operator double()
const {
return as_d(); }
129 explicit operator T*()
const {
return reinterpret_cast<T*
>(as_p()); }
135#ifdef M_ENABLE_SANITY_FIELDS
137 case VNone:
return out <<
"<none>";
138 case Vb:
return out << (val.
as_b() ?
"TRUE" :
"FALSE");
139 case Vi:
return out << val.
as_i();
140 case Vf:
return out << val.
as_f();
141 case Vd:
return out << val.
as_d();
142 case Vp:
return out << val.
as_p();
145 out <<
"0x" << std::hex;
146 auto prev_fill = out.fill(
'0');
147 for (uint8_t *end =
reinterpret_cast<uint8_t*
>(&val.
val_), *ptr = end +
sizeof(val.
val_); ptr != end; )
148 out << std::setw(2) << uint32_t(*--ptr);
151 return out << std::dec;
156 void print(std::ostream &out,
const Type &ty)
const;
161#ifdef M_ENABLE_SANITY_FIELDS
162 M_insist(this->type == other.type,
"comparing values of different type");
164 return memcmp(&this->val_, &other.
val_,
sizeof(this->val_)) == 0;
170 void dump(std::ostream &out)
const;
174static_assert(std::is_move_constructible_v<Value>,
"Value must be move constructible");
175static_assert(std::is_trivially_destructible_v<Value>,
"Value must be trivially destructible");
176#ifndef M_ENABLE_SANITY_FIELDS
177static_assert(
sizeof(Value) == 8,
"Value exceeds expected size");
182 friend std::hash<Tuple>;
188#ifdef M_ENABLE_SANITY_FIELDS
189 swap(first.num_values_, second.num_values_);
196#ifdef M_ENABLE_SANITY_FIELDS
197 std::size_t num_values_ = 0;
198#define INBOUNDS(VAR) M_insist((VAR) < num_values_, "index out of bounds")
206 explicit Tuple(
const Schema &S);
207 explicit Tuple(std::vector<const Type*> types);
221 return null_mask_(idx);
227 null_mask_(idx) =
true;
236 null_mask_(idx) =
false;
247 void set(std::size_t idx,
Value val,
bool is_null) {
249 null_mask_(idx) = is_null;
265 M_insist(not is_null(idx),
"Value must not be NULL");
274 void insert(
const Tuple &other, std::size_t pos, std::size_t len) {
275 for (std::size_t i = 0; i != len; ++i)
276 set(pos + i, other[i], other.
is_null(i));
284#ifdef M_ENABLE_SANITY_FIELDS
286 for (std::size_t i = 0; i != tup.num_values_; ++i) {
287 if (i != 0) out <<
", ";
288 if (tup.
is_null(i)) out <<
"NULL";
296 out <<
"\n [" << std::setw(2) << i <<
"]: " << tup.
values_[i];
303 if (this->null_mask_ != other.
null_mask_)
return false;
305 for (
auto idx : alive) {
306 if (this->get(idx) != other.
get(idx))
314 void print(std::ostream &out,
const Schema &schema)
const;
316 void dump(std::ostream &out)
const;
329 uint64_t hash = 0xcbf29ce484222325;
330 for (uint64_t *p =
reinterpret_cast<uint64_t*
>(&val.
val_), *end = p +
sizeof(val.
val_) /
sizeof(uint64_t);
334 hash *= 1099511628211;
344 std::hash<m::Value> h;
347 for (
auto idx : mask) {
349 hash *= 1099511628211;
#define VALIDATE_TYPE(TY)
void swap(PlanTableBase< Actual > &first, PlanTableBase< Actual > &second)
A Schema represents a sequence of identifiers, optionally with a prefix, and their associated types.
Implements a small and efficient set over integers in the range of 0 to 63 (including).
const Value & get(std::size_t idx) const
Returns a reference to the Value at index idx.
Value & get(std::size_t idx)
Returns a reference to the Value at index idx.
Value * values_
the Values in this Tuple
void clear()
Sets all Values of this Tuple to NULL.
void insert(const Tuple &other, std::size_t pos, std::size_t len)
Inserts the Tuple other of length len into this Tuple starting at index pos.
bool operator!=(const Tuple &other) const
M_LCOV_EXCL_STOP bool operator==(const Tuple &other) const
Tuple & operator=(Tuple &&other)
const Value & operator[](std::size_t idx) const
Returns the Value at index idx.
Tuple(const Tuple &)=delete
Tuple & operator=(const Tuple &)=delete
SmallBitset null_mask_
a bit mask for the NULL values; 1 represents NULL
friend void swap(Tuple &first, Tuple &second)
void null(std::size_t idx)
Sets the Value at index idx to NULL.
Value & operator[](std::size_t idx)
Returns a reference to the Value at index idx.
void set(std::size_t idx, Value val, bool is_null)
Assigns the Value val to this Tuple at index idx and sets the respective NULL bit to is_null.
M_LCOV_EXCL_START friend std::ostream & operator<<(std::ostream &out, const Tuple &tup)
bool is_null(std::size_t idx) const
Returns true iff the Value at index idx is NULL.
void not_null(std::size_t idx)
Sets the Value at index idx to not-NULL.
void set(std::size_t idx, Value val)
Assigns the Value val to this Tuple at index idx and clears the respective NULL bit.
This class represents types in the SQL type system.
This class holds a SQL attribute value.
auto & as_f()
Returns a reference to the value interpreted as of type float.
bool operator!=(Value other) const
Checks whether this Value is not equal to other.
bool operator==(Value other) const
Checks whether this Value is equal to other.
auto as_f() const
Returns the value interpreted as of type float.
auto as_p()
Returns a reference to the value interpreted as of type void*.
auto & as_b()
Returns a reference to the value interpreted as of type bool.
auto & as_d()
Returns a reference to the value interpreted as of type double.
auto as_i() const
Returns the value interpreted as of type int64_t.
auto & as_i()
Returns a reference to the value interpreted as of type int64_t.
auto as_d() const
Returns the value interpreted as of type double.
T as() const
Returns the value interpreted as of type T.
std::conditional_t< std::is_pointer_v< T >, T, T & > as()
Returns a reference to the value interpreted as of type T.
M_LCOV_EXCL_START friend std::ostream & operator<<(std::ostream &out, Value val)
Print a hexdump of val to out.
auto as_p() const
Returns the value interpreted as of type void*.
auto as_b() const
Returns the value interpreted as of type bool.
uint64_t operator()(const m::Tuple &tup) const
uint64_t operator()(m::Value val) const