Device interface library for multiple platforms including Mbed.
Dependents: DeepCover Embedded Security in IoT MaximInterface MAXREFDES155#
Maxim Interface is a library framework focused on providing flexible and expressive hardware interfaces. Both communication interfaces such as I2C and 1-Wire and device interfaces such as DS18B20 are supported. Modern C++ concepts are used extensively while keeping compatibility with C++98/C++03 and requiring no external dependencies. The embedded-friendly design does not depend on exceptions or RTTI.
The full version of the project is hosted on GitLab: https://gitlab.com/iabenz/MaximInterface
Diff: Utilities/Function.hpp
- Revision:
- 0:f77ad7f72d04
- Child:
- 5:a8c83a2e6fa4
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Utilities/Function.hpp Mon Nov 06 14:39:18 2017 -0600 @@ -0,0 +1,466 @@ +/******************************************************************************* +* Copyright (C) 2017 Maxim Integrated Products, Inc., All Rights Reserved. +* +* 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 MAXIM INTEGRATED 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. +* +* Except as contained in this notice, the name of Maxim Integrated +* Products, Inc. shall not be used except as stated in the Maxim Integrated +* Products, Inc. Branding Policy. +* +* The mere transfer of this software does not imply any licenses +* of trade secrets, proprietary technology, copyrights, patents, +* trademarks, maskwork rights, or any other form of intellectual +* property whatsoever. Maxim Integrated Products, Inc. retains all +* ownership rights. +*******************************************************************************/ + +#ifndef MaximInterface_Function +#define MaximInterface_Function + +#include <stddef.h> +#include "type_traits.hpp" + +// Include for std::swap. +#include <algorithm> +#include <utility> + +namespace MaximInterface { +namespace detail { + +// Provides char buffer storage for a given type. +// Suitability of alignment for type should be verified with alignment_of. +template <typename Type, size_t TypeSize> union TypeStorage { +public: + operator const Type *() const { return reinterpret_cast<const Type *>(data); } + + operator Type *() { + return const_cast<Type *>( + static_cast<const Type *>(static_cast<const TypeStorage &>(*this))); + } + + const Type & operator*() const { return **this; } + + Type & operator*() { + return const_cast<Type &>( + static_cast<const TypeStorage &>(*this).operator*()); + } + + const Type * operator->() const { return *this; } + + Type * operator->() { + return const_cast<Type *>( + static_cast<const TypeStorage &>(*this).operator->()); + } + +private: + char data[TypeSize]; + long double aligner; +}; + +// Computes the internal target size for TypeStorage based on a desired total +// size. No internal storage will be allocated if the requested size is smaller +// than the required data elements of TypeWrapper or if the requested size is +// smaller than minimum size of TypeStorage. +template <typename Target, size_t totalSize> class TypeWrapperTotalSize { +private: + typedef TypeStorage<Target, 1> MinSizeStorage; + static const size_t otherDataSize = sizeof(Target *); + // Round down to be a multiple of alignment_of<MinSizeTargetStorage>::value. + static const size_t internalTargetRawSize = + (totalSize - otherDataSize) / alignment_of<MinSizeStorage>::value * + alignment_of<MinSizeStorage>::value; + +public: + // Use internal storage if internalTargetRawSize is valid and at least as + // large as the minimum size of TypeStorage. + static const size_t internalTargetSize = + ((totalSize > otherDataSize) && + (internalTargetRawSize >= sizeof(MinSizeStorage))) + ? internalTargetRawSize + : 0; +}; + +// Basic type erasure implementation with small object optimization. +template <typename Target, template <typename> class TargetAdapter, + size_t internalTargetSize = + TypeWrapperTotalSize<Target, 32>::internalTargetSize> +class TypeWrapper { +private: + typedef TypeStorage<Target, internalTargetSize> TargetStorage; + +public: + TypeWrapper() : currentTarget(NULL) {} + + TypeWrapper(const TypeWrapper & other) { + if (other.currentTarget == other.internalTarget) { + other.currentTarget->clone(internalTarget); + currentTarget = internalTarget; + } else if (other.currentTarget) { + currentTarget = other.currentTarget->clone(); + } else { + currentTarget = NULL; + } + } + + template <typename Source> TypeWrapper(Source source) { + if (sizeof(TargetAdapter<Source>) <= internalTargetSize && + alignment_of<TargetAdapter<Source> >::value <= + alignment_of<TargetStorage>::value) { + new (internalTarget) TargetAdapter<Source>(source); + currentTarget = internalTarget; + } else { + currentTarget = new TargetAdapter<Source>(source); + } + } + + ~TypeWrapper() { + if (currentTarget == internalTarget) { + currentTarget->~Target(); + } else { + delete currentTarget; + } + } + + const TypeWrapper & operator=(const TypeWrapper & rhs) { + TypeWrapper(rhs).swap(*this); + return *this; + } + + template <typename Source> const TypeWrapper & operator=(Source source) { + TypeWrapper(source).swap(*this); + return *this; + } + + void clear() { TypeWrapper().swap(*this); } + + void swap(TypeWrapper & other) { + if (this == &other) { + return; + } + + if (currentTarget == internalTarget && + other.currentTarget == other.internalTarget) { + TargetStorage temp; + currentTarget->clone(temp); + currentTarget->~Target(); + currentTarget = NULL; + other.currentTarget->clone(internalTarget); + other.currentTarget->~Target(); + other.currentTarget = NULL; + currentTarget = internalTarget; + temp->clone(other.internalTarget); + temp->~Target(); + other.currentTarget = other.internalTarget; + } else if (currentTarget == internalTarget) { + currentTarget->clone(other.internalTarget); + currentTarget->~Target(); + currentTarget = other.currentTarget; + other.currentTarget = other.internalTarget; + } else if (other.currentTarget == other.internalTarget) { + other.currentTarget->clone(internalTarget); + other.currentTarget->~Target(); + other.currentTarget = currentTarget; + currentTarget = internalTarget; + } else { + using std::swap; + swap(currentTarget, other.currentTarget); + } + } + + const Target * target() const { return currentTarget; } + +private: + TargetStorage internalTarget; + Target * currentTarget; +}; + +// TypeWrapper specialization with no internal storage space. +template <typename Target, template <typename> class TargetAdapter> +class TypeWrapper<Target, TargetAdapter, 0> { +public: + TypeWrapper() : currentTarget(NULL) {} + + TypeWrapper(const TypeWrapper & other) { + if (other.currentTarget) { + currentTarget = other.currentTarget->clone(); + } else { + currentTarget = NULL; + } + } + + template <typename Source> + TypeWrapper(Source source) + : currentTarget(new TargetAdapter<Source>(source)) {} + + ~TypeWrapper() { delete currentTarget; } + + const TypeWrapper & operator=(const TypeWrapper & rhs) { + TypeWrapper(rhs).swap(*this); + return *this; + } + + template <typename Source> const TypeWrapper & operator=(Source source) { + TypeWrapper(source).swap(*this); + return *this; + } + + void clear() { TypeWrapper().swap(*this); } + + void swap(TypeWrapper & other) { + using std::swap; + swap(currentTarget, other.currentTarget); + } + + const Target * target() const { return currentTarget; } + +private: + Target * currentTarget; +}; + +} // namespace detail + +// Function wrapper similar to std::function for 0-2 argument functions. +template <typename> class Function; + +// Function implementation for zero argument functions. +template <typename ResultType> class Function<ResultType()> { +public: + typedef ResultType result_type; + + Function(ResultType (*func)() = NULL) : callableWrapper() { + if (func) { + callableWrapper = func; + } + } + + template <typename F> Function(F func) : callableWrapper(func) {} + + const Function & operator=(ResultType (*func)()) { + if (func) { + callableWrapper = func; + } else { + callableWrapper.clear(); + } + return *this; + } + + template <typename F> const Function & operator=(F func) { + callableWrapper = func; + return *this; + } + + void swap(Function & other) { callableWrapper.swap(other.callableWrapper); } + + operator bool() const { return callableWrapper.target() != NULL; } + + ResultType operator()() const { + return callableWrapper.target() ? (*callableWrapper.target())() + : ResultType(); + } + +private: + class Callable { + public: + virtual ~Callable() {} + virtual ResultType operator()() const = 0; + virtual Callable * clone() const = 0; + virtual void clone(void * buffer) const = 0; + }; + + template <typename F> class CallableAdapter : public Callable { + public: + CallableAdapter(F func) : func(func) {} + + virtual ResultType operator()() const { return func(); } + + virtual Callable * clone() const { return new CallableAdapter(*this); } + + virtual void clone(void * buffer) const { + new (buffer) CallableAdapter(*this); + } + + private: + F func; + }; + + detail::TypeWrapper<Callable, CallableAdapter> callableWrapper; +}; + +template <typename ResultType> +inline void swap(Function<ResultType()> & lhs, Function<ResultType()> & rhs) { + lhs.swap(rhs); +} + +// Function implementation for one argument functions. +template <typename ArgumentType, typename ResultType> +class Function<ResultType(ArgumentType)> { +public: + typedef ArgumentType argument_type; + typedef ResultType result_type; + + Function(ResultType (*func)(ArgumentType) = NULL) : callableWrapper() { + if (func) { + callableWrapper = func; + } + } + + template <typename F> Function(F func) : callableWrapper(func) {} + + const Function & operator=(ResultType (*func)(ArgumentType)) { + if (func) { + callableWrapper = func; + } else { + callableWrapper.clear(); + } + return *this; + } + + template <typename F> const Function & operator=(F func) { + callableWrapper = func; + return *this; + } + + void swap(Function & other) { callableWrapper.swap(other.callableWrapper); } + + operator bool() const { return callableWrapper.target() != NULL; } + + ResultType operator()(ArgumentType arg) const { + return callableWrapper.target() ? (*callableWrapper.target())(arg) + : ResultType(); + } + +private: + class Callable { + public: + virtual ~Callable() {} + virtual ResultType operator()(ArgumentType) const = 0; + virtual Callable * clone() const = 0; + virtual void clone(void * buffer) const = 0; + }; + + template <typename F> class CallableAdapter : public Callable { + public: + CallableAdapter(F func) : func(func) {} + + virtual ResultType operator()(ArgumentType arg) const { return func(arg); } + + virtual Callable * clone() const { return new CallableAdapter(*this); } + + virtual void clone(void * buffer) const { + new (buffer) CallableAdapter(*this); + } + + private: + F func; + }; + + detail::TypeWrapper<Callable, CallableAdapter> callableWrapper; +}; + +template <typename ArgumentType, typename ResultType> +inline void swap(Function<ResultType(ArgumentType)> & lhs, + Function<ResultType(ArgumentType)> & rhs) { + lhs.swap(rhs); +} + +// Function implementation for two argument functions. +template <typename FirstArgumentType, typename SecondArgumentType, + typename ResultType> +class Function<ResultType(FirstArgumentType, SecondArgumentType)> { +public: + typedef FirstArgumentType first_argument_type; + typedef SecondArgumentType second_argument_type; + typedef ResultType result_type; + + Function(ResultType (*func)(FirstArgumentType, SecondArgumentType) = NULL) + : callableWrapper() { + if (func) { + callableWrapper = func; + } + } + + template <typename F> Function(F func) : callableWrapper(func) {} + + const Function & operator=(ResultType (*func)(FirstArgumentType, + SecondArgumentType)) { + if (func) { + callableWrapper = func; + } else { + callableWrapper.clear(); + } + return *this; + } + + template <typename F> const Function & operator=(F func) { + callableWrapper = func; + return *this; + } + + void swap(Function & other) { callableWrapper.swap(other.callableWrapper); } + + operator bool() const { return callableWrapper.target() != NULL; } + + ResultType operator()(FirstArgumentType arg1, SecondArgumentType arg2) const { + return callableWrapper.target() ? (*callableWrapper.target())(arg1, arg2) + : ResultType(); + } + +private: + class Callable { + public: + virtual ~Callable() {} + virtual ResultType operator()(FirstArgumentType, + SecondArgumentType) const = 0; + virtual Callable * clone() const = 0; + virtual void clone(void * buffer) const = 0; + }; + + template <typename F> class CallableAdapter : public Callable { + public: + CallableAdapter(F func) : func(func) {} + + virtual ResultType operator()(FirstArgumentType arg1, + SecondArgumentType arg2) const { + return func(arg1, arg2); + } + + virtual Callable * clone() const { return new CallableAdapter(*this); } + + virtual void clone(void * buffer) const { + new (buffer) CallableAdapter(*this); + } + + private: + F func; + }; + + detail::TypeWrapper<Callable, CallableAdapter> callableWrapper; +}; + +template <typename FirstArgumentType, typename SecondArgumentType, + typename ResultType> +inline void +swap(Function<ResultType(FirstArgumentType, SecondArgumentType)> & lhs, + Function<ResultType(FirstArgumentType, SecondArgumentType)> & rhs) { + lhs.swap(rhs); +} + +} // namespace MaximInterface + +#endif