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