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
MaximInterfaceCore/Function.hpp
- Committer:
- IanBenzMaxim
- Date:
- 2020-05-29
- Revision:
- 12:7eb41621ba22
- Parent:
- 11:3f3bf6bf5e6c
File content as of revision 12:7eb41621ba22:
/******************************************************************************* * Copyright (C) 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 MaximInterfaceCore_Function_hpp #define MaximInterfaceCore_Function_hpp #include <stddef.h> #include "None.hpp" #include "SafeBool.hpp" #include "type_traits.hpp" // Include for std::swap. #include <algorithm> #include <utility> namespace MaximInterfaceCore { 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 aligner1; long int aligner2; void * aligner3; }; // 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(None) : 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=(None) { TypeWrapper().swap(*this); return *this; } 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 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(None) : 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=(None) { TypeWrapper().swap(*this); return *this; } 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 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-3 argument functions. template <typename> class Function; /// Function implementation for zero argument functions. template <typename ResultType> class Function<ResultType()> { public: typedef ResultType result_type; Function() : callableWrapper() {} Function(None) : callableWrapper() {} Function(ResultType (*func)()) : callableWrapper() { if (func) { callableWrapper = func; } } template <typename F> Function(F func) : callableWrapper(func) {} const Function & operator=(None) { callableWrapper = none; return *this; } const Function & operator=(ResultType (*func)()) { if (func) { callableWrapper = func; } else { callableWrapper = none; } return *this; } template <typename F> const Function & operator=(F func) { callableWrapper = func; return *this; } void swap(Function & other) { callableWrapper.swap(other.callableWrapper); } operator SafeBool() const { return makeSafeBool(callableWrapper.target() != NULL); } ResultType operator()() const { return callableWrapper.target() ? callableWrapper.target()->invoke() : ResultType(); } private: class Callable { public: virtual ~Callable() {} virtual ResultType invoke() 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 invoke() 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> 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() : callableWrapper() {} Function(None) : callableWrapper() {} Function(ResultType (*func)(ArgumentType)) : callableWrapper() { if (func) { callableWrapper = func; } } template <typename F> Function(F func) : callableWrapper(func) {} const Function & operator=(None) { callableWrapper = none; return *this; } const Function & operator=(ResultType (*func)(ArgumentType)) { if (func) { callableWrapper = func; } else { callableWrapper = none; } return *this; } template <typename F> const Function & operator=(F func) { callableWrapper = func; return *this; } void swap(Function & other) { callableWrapper.swap(other.callableWrapper); } operator SafeBool() const { return makeSafeBool(callableWrapper.target() != NULL); } ResultType operator()(ArgumentType arg) const { return callableWrapper.target() ? callableWrapper.target()->invoke(arg) : ResultType(); } private: class Callable { public: virtual ~Callable() {} virtual ResultType invoke(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 invoke(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> 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() : callableWrapper() {} Function(None) : callableWrapper() {} Function(ResultType (*func)(FirstArgumentType, SecondArgumentType)) : callableWrapper() { if (func) { callableWrapper = func; } } template <typename F> Function(F func) : callableWrapper(func) {} const Function & operator=(None) { callableWrapper = none; return *this; } const Function & operator=(ResultType (*func)(FirstArgumentType, SecondArgumentType)) { if (func) { callableWrapper = func; } else { callableWrapper = none; } return *this; } template <typename F> const Function & operator=(F func) { callableWrapper = func; return *this; } void swap(Function & other) { callableWrapper.swap(other.callableWrapper); } operator SafeBool() const { return makeSafeBool(callableWrapper.target() != NULL); } ResultType operator()(FirstArgumentType arg1, SecondArgumentType arg2) const { return callableWrapper.target() ? callableWrapper.target()->invoke(arg1, arg2) : ResultType(); } private: class Callable { public: virtual ~Callable() {} virtual ResultType invoke(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 invoke(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> void swap(Function<ResultType(FirstArgumentType, SecondArgumentType)> & lhs, Function<ResultType(FirstArgumentType, SecondArgumentType)> & rhs) { lhs.swap(rhs); } /// Function implementation for three argument functions. template <typename FirstArgumentType, typename SecondArgumentType, typename ThirdArgumentType, typename ResultType> class Function<ResultType(FirstArgumentType, SecondArgumentType, ThirdArgumentType)> { public: typedef ResultType result_type; Function() : callableWrapper() {} Function(None) : callableWrapper() {} Function(ResultType (*func)(FirstArgumentType, SecondArgumentType, ThirdArgumentType)) : callableWrapper() { if (func) { callableWrapper = func; } } template <typename F> Function(F func) : callableWrapper(func) {} const Function & operator=(None) { callableWrapper = none; return *this; } const Function & operator=(ResultType (*func)(FirstArgumentType, SecondArgumentType, ThirdArgumentType)) { if (func) { callableWrapper = func; } else { callableWrapper = none; } return *this; } template <typename F> const Function & operator=(F func) { callableWrapper = func; return *this; } void swap(Function & other) { callableWrapper.swap(other.callableWrapper); } operator SafeBool() const { return makeSafeBool(callableWrapper.target() != NULL); } ResultType operator()(FirstArgumentType arg1, SecondArgumentType arg2, ThirdArgumentType arg3) const { return callableWrapper.target() ? callableWrapper.target()->invoke(arg1, arg2, arg3) : ResultType(); } private: class Callable { public: virtual ~Callable() {} virtual ResultType invoke(FirstArgumentType, SecondArgumentType, ThirdArgumentType) 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 invoke(FirstArgumentType arg1, SecondArgumentType arg2, ThirdArgumentType arg3) const { return func(arg1, arg2, arg3); } 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 ThirdArgumentType, typename ResultType> void swap(Function<ResultType(FirstArgumentType, SecondArgumentType, ThirdArgumentType)> & lhs, Function<ResultType(FirstArgumentType, SecondArgumentType, ThirdArgumentType)> & rhs) { lhs.swap(rhs); } } // namespace MaximInterfaceCore #endif