We can utilize the std::data and std::size utility functions to support
passthrough-ing data for any container that satisfies the
ContiguousContainer concept, which would be either std::array,
std::string, or std::vector.
This way we can utilize std::array internally without exposing the
inclusion within the header.
Same thing, but strongly enforces the type of the array. This also
allows removing the <type_traits> include, since we can just query the
size of the array.
Reduces binary size a little, as only the string data will be stored in
the executable and not a pointer to accompany it as well.
A trivial change that's essentially "free".
Performs the same thing as the previous change, but applies it to
setViewport() instead. This also allows unindenting all code within the
function by one level.
Makes the arrays strongly-typed and enforces explicit array->pointer
decay. It also allows querying the array size, which can allow us to
easily dehardcode magic values within code.
Alphabetizes includes and resolves quite a few instances of indirect
inclusions, making the requirements of several interfaces explicit. This
also trims out includes that aren't actually necessary (likely due to
changes in the API over time).
Now that decrement() doesn't lock a mutex every time its executed, we
can mark it as noexcept. This allows us to make most of the interface
noexcept. In particular, the move constructor and move assignment
operator can now be noexcept. This allows all Boo objects to play nicely
with interfaces that may make use of std::move_if_noexcept, like some of
the standard library facilities, without always taking the copy
constructor/copy assignment.
Now that we have the fencing and atomic operations in place to ensure
access to data on other threads will always occur before the use of
delete, we can remove the destructor lock. This will be useful for
making ObjToken's move assignment operator noexcept.
Increasing a reference count is able to always be relaxed. New
references to an object can only be formed from an existing reference.
The passing of an existing reference from one thread to another will
already necessitate the use of synchronization primitives, so this is a
safe change to make. Regardless, nothing other than the object itself
directly relies on the reference count, so this will always be a
suitably atomic operation, even in the face of no synchronization
primitives.
In the case of decrementing the reference count, it's sufficient to
treat it with release semantics and follow it up with an atomic thread
fence. This ensures that all accesses to the object in one thread will
occur before the delete occurs in another thread (if the situation ever
occurs).
This should make for a slightly more efficient increment and decrement.