diff --git a/include/utl/utility/shared.h b/include/utl/utility/shared.h new file mode 100644 index 0000000..db2cfad --- /dev/null +++ b/include/utl/utility/shared.h @@ -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 + * + *
License
+ * 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. + *
+ */ + +#ifndef utl_utility_shared_h__ +#define utl_utility_shared_h__ + +#include + +#include + +namespace utl { + +/*! + * A CRTP base class to provide acquire/release functionality for shared resources + * without handle pointers. + * + * \example + * \code + * class GPIOClock : public shared { + * friend shared; + * 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 +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 + void acquire (Ts&&... args) { + if (!count++) impl().acquire_impl(std::forward(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 + void release (Ts&&... args) noexcept { + if (--count <= 0) { + impl().release_impl(std::forward(args)...); + count =0; + } + } +}; + +} // namespace utl; +#endif /* utl_utility_shared_h__ */