libbio
Loading...
Searching...
No Matches
CowPtr.h
Go to the documentation of this file.
1/*
2 * This file is a part of the Biology project by eons LLC.
3 * Biology (aka Develop Biology) is a framework for approaching software
4 * development from a natural sciences perspective.
5 *
6 * Copyright (C) 2026 Séon O'Shannon & eons LLC
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU Affero General Public License as
10 * published by the Free Software Foundation, either version 3 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU Affero General Public License for more details.
17 *
18 * You should have received a copy of the GNU Affero General Public License
19 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 */
21
22#pragma once
23
26
27#ifndef NULL
28 #include <cstddef>
29#endif
30
31#include <cassert>
32#include <stdint.h> // uintptr_t — for the tagged borrowed-reference encoding (cpp98-safe)
33
68namespace bio {
69
89template < typename T >
90class CowPtr
91{
92public:
93 typedef T Type;
94
99 :
100 mSlot(NULL)
101 {
102 }
103
110 explicit CowPtr(
111 T* owned,
112 bool immutable = false
113 )
114 :
116 {
117 }
118
128 {
130 if (borrowed)
131 {
132 assert(!(reinterpret_cast< uintptr_t >(borrowed) & TAG)
133 && "CowPtr::Borrow() requires a 2-byte-aligned payload");
134 result.mSlot = reinterpret_cast< CowControlBlock< T >* >(
135 reinterpret_cast< uintptr_t >(borrowed) | TAG);
136 }
137 return result;
138 }
139
143 bool IsBorrowed() const
144 {
145 return IsBorrowedSlot(mSlot);
146 }
147
153 :
154 mSlot(other.mSlot)
155 {
156 if (mSlot && !IsBorrowedSlot(mSlot))
157 {
158 CowInc(mSlot->mRefCount);
159 }
160 }
161
167 {
168 if (mSlot != other.mSlot)
169 {
170 CowControlBlock< T >* old = mSlot;
171 mSlot = other.mSlot;
172 if (mSlot && !IsBorrowedSlot(mSlot))
173 {
174 CowInc(mSlot->mRefCount);
175 }
176 if (old && !IsBorrowedSlot(old))
177 {
178 Release(old);
179 }
180 }
181 return *this;
182 }
183
188 {
189 if (mSlot && !IsBorrowedSlot(mSlot))
190 {
191 Release(mSlot);
192 }
193 }
194
200 const T* View() const
201 {
202 if (!mSlot)
203 {
204 return NULL;
205 }
206 if (IsBorrowedSlot(mSlot))
207 {
208 return BorrowedPayload(mSlot);
209 }
210 return mSlot->mPayload;
211 }
212
217 bool IsShared() const
218 {
219 return mSlot && !IsBorrowedSlot(mSlot) && CowLoad(mSlot->mRefCount) > 1;
220 }
221
225 bool IsNull() const
226 {
227 return !mSlot;
228 }
229
243 template < typename CLONE >
245 {
246 if (!mSlot)
247 {
248 return NULL;
249 }
250 if (IsBorrowedSlot(mSlot))
251 {
252 return BorrowedPayload(mSlot);
253 }
254 if (mSlot->mImmutable || CowLoad(mSlot->mRefCount) > 1)
255 {
256 T* fresh = cloneFn(mSlot->mPayload); // one deep copy at the leaf type
257 CowControlBlock< T >* old = mSlot;
258 mSlot = new CowControlBlock< T >(fresh, false); // private, refcount 1
259 Release(old); // old was >1 or an (un-freed) prototype: never frees a live share
260 }
261 return mSlot->mPayload;
262 }
263
279 {
280 if (IsBorrowedSlot(mSlot))
281 {
282 return BorrowedPayload(mSlot);
283 }
284 assert(!IsShared() && "CowPtr::Mutable() on a shared payload — use Moo(cloner)");
285 return mSlot ? mSlot->mPayload : NULL;
286 }
287
293 void Reset(T* owned)
294 {
295 if (mSlot && !IsBorrowedSlot(mSlot))
296 {
297 Release(mSlot);
298 }
299 mSlot = owned ? new CowControlBlock< T >(owned, false) : NULL;
300 }
301
302private:
303 // The low-bit tag marking a borrowed (block-less) slot. Free because heap blocks
304 // and heap payloads are >= 2-byte aligned.
305 static const uintptr_t TAG = 1;
306
307 // mSlot is either a CowControlBlock< T >* (owned, low bit clear) or a tagged T*
308 // (borrowed, low bit set), or NULL.
310
311 static bool IsBorrowedSlot(CowControlBlock< T >* slot)
312 {
313 return (reinterpret_cast< uintptr_t >(slot) & TAG) != 0;
314 }
315
316 static T* BorrowedPayload(CowControlBlock< T >* slot)
317 {
318 return reinterpret_cast< T* >(reinterpret_cast< uintptr_t >(slot) & ~TAG);
319 }
320
321 static void Release(CowControlBlock< T >* block)
322 {
323 if (CowDecAndIsLast(block->mRefCount))
324 {
325 if (!block->mImmutable)
326 {
327 //@formatter:off
328 #if BIO_COMPACT_POINTER_STORAGE
329 if (::bio::pointer_arena::Owns(block->mPayload))
330 {
331 ::bio::pointer_arena::Delete(block->mPayload);
332 }
333 else
334 {
335 delete block->mPayload;
336 }
337 #else
338 delete block->mPayload;
339 #endif
340 //@formatter:on
341 delete block;
342 }
343 // Immutable prototypes are process-lifetime: intentionally never freed.
344 }
345 }
346};
347
348} // namespace bio
Definition CowPtr.h:91
bool IsNull() const
Definition CowPtr.h:225
const T * View() const
Definition CowPtr.h:200
~CowPtr()
Definition CowPtr.h:187
T Type
Definition CowPtr.h:93
CowPtr(const CowPtr &other)
Definition CowPtr.h:152
T * Moo(CLONE cloneFn)
Definition CowPtr.h:244
static CowPtr Borrow(T *borrowed)
Definition CowPtr.h:127
CowPtr & operator=(const CowPtr &other)
Definition CowPtr.h:166
CowPtr(T *owned, bool immutable=false)
Definition CowPtr.h:110
CowPtr()
Definition CowPtr.h:98
bool IsShared() const
Definition CowPtr.h:217
bool IsBorrowed() const
Definition CowPtr.h:143
void Reset(T *owned)
Definition CowPtr.h:293
T * Mutable()
Definition CowPtr.h:278
Definition Pointer.h:115
bool Owns(const void *raw)
Definition PointerArena.cpp:2302
void Delete(T *raw)
Definition PointerArena.h:525
Definition FinalCell.h:29
bool CowDecAndIsLast(CowRefCount &count)
Definition CowRefCount.h:98
unsigned int CowLoad(const CowRefCount &count)
Definition CowRefCount.h:103
void CowInc(CowRefCount &count)
Definition CowRefCount.h:93
Definition CowControlBlock.h:36