Skip to content

Commit f932830

Browse files
committed
Add tools to mark a field as never-non-zero while constructed
1 parent e78b0c1 commit f932830

File tree

1 file changed

+73
-0
lines changed

1 file changed

+73
-0
lines changed

mem/layout.h

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Copyright 2022 Google LLC
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// https://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
#pragma once
16+
17+
#include <stddef.h>
18+
19+
#include "marker/unsafe.h"
20+
21+
namespace sus::mem::layout {
22+
23+
namespace __private {
24+
25+
template <class T>
26+
struct layout_nonzero_tag final {
27+
static constexpr bool has_field(...) { return false; }
28+
static constexpr bool has_field(int)
29+
requires(std::is_same_v<
30+
decltype(std::declval<T>().SusUnsafeNonZeroIsNonZero()), bool>)
31+
{
32+
return true;
33+
};
34+
35+
static constexpr bool is_non_zero(const T* t) {
36+
return t->SusUnsafeNonZeroIsNonZero();
37+
};
38+
static constexpr void set_zero(T* t) { t->SusUnsafeNonZeroSetZero(); };
39+
};
40+
41+
} // namespace __private
42+
43+
template <class T>
44+
struct nonzero_field {
45+
static constexpr bool has_field =
46+
__private::layout_nonzero_tag<T>::has_field(0);
47+
48+
static constexpr bool is_non_zero(::sus::marker::UnsafeFnMarker,
49+
const T* t) noexcept {
50+
return __private::layout_nonzero_tag<T>::is_non_zero(t);
51+
}
52+
static constexpr void set_zero(::sus::marker::UnsafeFnMarker, T* t) noexcept {
53+
__private::layout_nonzero_tag<T>::set_zero(t);
54+
}
55+
};
56+
57+
} // namespace sus::mem::layout
58+
59+
/// Mark a class field as never being zero (after a constructor has run, until
60+
/// the destructor has completed).
61+
#define sus_class_nonzero_field(unsafe_fn, T, name) \
62+
static_assert(std::is_same_v<decltype(unsafe_fn), \
63+
const ::sus::marker::UnsafeFnMarker>); \
64+
template <class SusOuterClassTypeForNonZeroField> \
65+
friend struct ::sus::mem::layout::__private::layout_nonzero_tag; \
66+
constexpr inline bool SusUnsafeNonZeroIsNonZero() const noexcept { \
67+
static_assert(std::same_as<decltype(*this), const T&>); \
68+
return static_cast<bool>(name); \
69+
} \
70+
constexpr inline void SusUnsafeNonZeroSetZero() noexcept { \
71+
name = static_cast<decltype(name)>(0u); \
72+
} \
73+
static_assert(true)

0 commit comments

Comments
 (0)