|
|
@@ -0,0 +1,106 @@ |
|
|
|
/*! |
|
|
|
* \file utility/shared.h |
|
|
|
* \brief |
|
|
|
* A CRTP base class to provide acquire/release functionality for shared resources |
|
|
|
* without handle pointers. |
|
|
|
* |
|
|
|
* \copyright Copyright (C) 2021 Christos Choutouridis <christos@choutouridis.net> |
|
|
|
* |
|
|
|
* <dl class=\"section copyright\"><dt>License</dt><dd> |
|
|
|
* The MIT License (MIT) |
|
|
|
* |
|
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy |
|
|
|
* of this software and associated documentation files (the "Software"), to deal |
|
|
|
* in the Software without restriction, including without limitation the rights |
|
|
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
|
|
|
* copies of the Software, and to permit persons to whom the Software is |
|
|
|
* furnished to do so, subject to the following conditions: |
|
|
|
* |
|
|
|
* The above copyright notice and this permission notice shall be included in all |
|
|
|
* copies or substantial portions of the Software. |
|
|
|
* |
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
|
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
|
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
|
|
|
* SOFTWARE. |
|
|
|
* </dd></dl> |
|
|
|
*/ |
|
|
|
|
|
|
|
#ifndef utl_utility_shared_h__ |
|
|
|
#define utl_utility_shared_h__ |
|
|
|
|
|
|
|
#include <utl/core/impl.h> |
|
|
|
|
|
|
|
#include <utility> |
|
|
|
|
|
|
|
namespace utl { |
|
|
|
|
|
|
|
/*! |
|
|
|
* A CRTP base class to provide acquire/release functionality for shared resources |
|
|
|
* without handle pointers. |
|
|
|
* |
|
|
|
* \example |
|
|
|
* \code |
|
|
|
* class GPIOClock : public shared<GPIOClock> { |
|
|
|
* friend shared<GPIOClock>; |
|
|
|
* void acquire_impl() { // HAL enable gpio clock } |
|
|
|
* void release_impl() { // HAL disable gpio clock } |
|
|
|
* }; |
|
|
|
* GPIOClock clk; |
|
|
|
* class Pin { |
|
|
|
* Pin() { |
|
|
|
* clk.acquire(); |
|
|
|
* // init pin |
|
|
|
* } |
|
|
|
* ~Pin() { |
|
|
|
* // de-init pin |
|
|
|
* clk.release(); |
|
|
|
* } |
|
|
|
* }; |
|
|
|
* \endcode |
|
|
|
* |
|
|
|
* \tparam Impl_t The derived class type |
|
|
|
*/ |
|
|
|
template <typename Impl_t> |
|
|
|
class shared { |
|
|
|
_CRTP_IMPL(Impl_t); |
|
|
|
int count {}; //!< acquisition counter |
|
|
|
|
|
|
|
protected: |
|
|
|
shared() noexcept = default; |
|
|
|
shared(const shared&) = delete; //!< No copies |
|
|
|
shared operator=(const shared&) = delete; //!< No copies |
|
|
|
|
|
|
|
public: |
|
|
|
/*! |
|
|
|
* Acquires the recourse. If it is the first call to acquire the resource we actually acquire it. |
|
|
|
* Otherwise we just keep track of how many acquisition have made. |
|
|
|
* |
|
|
|
* \tparam Ts The types of possible arguments |
|
|
|
* \param args Possible arguments to pass to acquire_impl() of derived class |
|
|
|
*/ |
|
|
|
template <typename ...Ts> |
|
|
|
void acquire (Ts&&... args) { |
|
|
|
if (!count++) impl().acquire_impl(std::forward<Ts>(args)...); |
|
|
|
} |
|
|
|
/*! |
|
|
|
* Release the recourse. On every call we decrease the count of acquisitions. If we reach zero |
|
|
|
* we actually release the resource. |
|
|
|
* |
|
|
|
* \tparam Ts The types of possible arguments |
|
|
|
* \param args Possible arguments to pass to release_impl() of derived class |
|
|
|
*/ |
|
|
|
template <typename ...Ts> |
|
|
|
void release (Ts&&... args) noexcept { |
|
|
|
if (--count <= 0) { |
|
|
|
impl().release_impl(std::forward<Ts>(args)...); |
|
|
|
count =0; |
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
} // namespace utl; |
|
|
|
#endif /* utl_utility_shared_h__ */ |