From 5f8de423f190bbb79a62f804151bc24824fa32d8 Mon Sep 17 00:00:00 2001 From: "Matt A. Tobin" Date: Fri, 2 Feb 2018 04:16:08 -0500 Subject: Add m-esr52 at 52.6.0 --- mfbt/Function.h | 223 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) create mode 100644 mfbt/Function.h (limited to 'mfbt/Function.h') diff --git a/mfbt/Function.h b/mfbt/Function.h new file mode 100644 index 000000000..d6de9c833 --- /dev/null +++ b/mfbt/Function.h @@ -0,0 +1,223 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +/* A type-erased callable wrapper. */ + +#ifndef mozilla_Function_h +#define mozilla_Function_h + +#include "mozilla/Attributes.h" // for MOZ_IMPLICIT +#include "mozilla/Move.h" +#include "mozilla/RefCounted.h" +#include "mozilla/RefPtr.h" + +// |function| is a wrapper that can hold any type of callable +// object that can be invoked in a way that's compatible with |Signature|. +// The standard "type erasure" technique is used to avoid the type of the +// wrapper depending on the concrete type of the wrapped callable. +// +// Supported callable types include non-member functions, static member +// functions, and function objects (that is to say, objects with an overloaded +// call operator; this includes C++11 lambdas). Member functions aren't +// directly supported; they first need to be wrapped into a function object +// using |std::mem_fn()| or an equivalent. +// +// |Signature| is a type of the form |ReturnType(Arguments...)|. Syntactically, +// this is a function type; it's not used in any way other than serving as a +// vehicle to encode the return and argument types into a single type. +// +// |function| is default-constructible. A default-constructed instance is +// considered "empty". Invoking an empty instance is undefined behaviour. +// An empty instance can be populated with a callable by assigning to it. +// +// This class is intended to provide functionality similar to the C++11 +// standard library class |std::function|. + +namespace mozilla { + +namespace detail { + +template +class FunctionImplBase : public mozilla::RefCounted> +{ +public: + MOZ_DECLARE_REFCOUNTED_TYPENAME(FunctionImplBase) + + virtual ~FunctionImplBase() {} + virtual ReturnType call(Arguments... aArguments) = 0; +}; + +// Normal Callable Object. +template +class FunctionImpl : public FunctionImplBase +{ + public: + explicit FunctionImpl(const Callable& aCallable) + : mCallable(aCallable) {} + + ReturnType call(Arguments... aArguments) override + { + return mCallable(Forward(aArguments)...); + } + private: + Callable mCallable; +}; + +// Base class for passing pointer to member function. +template +class MemberFunctionImplBase : public FunctionImplBase +{ +public: + explicit MemberFunctionImplBase(const Callable& aCallable) + : mCallable(aCallable) {} + + ReturnType call(Arguments... aArguments) override + { + return callInternal(Forward(aArguments)...); + } +private: + template + ReturnType callInternal(ThisType* aThis, Args&&... aArguments) + { + return (aThis->*mCallable)(Forward(aArguments)...); + } + + template + ReturnType callInternal(ThisType&& aThis, Args&&... aArguments) + { + return (aThis.*mCallable)(Forward(aArguments)...); + } + Callable mCallable; +}; + +// For non-const member function specialization of FunctionImpl. +template +class FunctionImpl + : public MemberFunctionImplBase +{ +public: + explicit FunctionImpl(ReturnType(ThisType::*aMemberFunc)(Args...)) + : MemberFunctionImplBase(aMemberFunc) + {} +}; + +// For const member function specialization of FunctionImpl. +template +class FunctionImpl + : public MemberFunctionImplBase +{ +public: + explicit FunctionImpl(ReturnType(ThisType::*aConstMemberFunc)(Args...) const) + : MemberFunctionImplBase(aConstMemberFunc) + {} +}; + +} // namespace detail + +// The primary template is never defined. As |Signature| is required to be +// of the form |ReturnType(Arguments...)|, we only define a partial +// specialization that matches this form. This allows us to use |ReturnType| +// and |Arguments| in the definition of the specialization without having to +// introspect |Signature|. +template +class function; + +template +class function +{ +public: + function() {} + + // This constructor is implicit to match the interface of |std::function|. + template + MOZ_IMPLICIT function(const Callable& aCallable) + : mImpl(new detail::FunctionImpl(aCallable)) + {} + MOZ_IMPLICIT function(const function& aFunction) + : mImpl(aFunction.mImpl) + {} + MOZ_IMPLICIT function(decltype(nullptr)) + {} + + // Move constructor and move assingment operator. + // These should be generated automatically, but MSVC doesn't do that yet. + function(function&& aOther) : mImpl(Move(aOther.mImpl)) {} + function& operator=(function&& aOther) { + mImpl = Move(aOther.mImpl); + return *this; + } + + template + function& operator=(const Callable& aCallable) + { + mImpl = new detail::FunctionImpl(aCallable); + return *this; + } + function& operator=(const function& aFunction) + { + mImpl = aFunction.mImpl; + return *this; + } + function& operator=(decltype(nullptr)) + { + mImpl = nullptr; + return *this; + } + + template + ReturnType operator()(Args&&... aArguments) const + { + MOZ_ASSERT(mImpl); + return mImpl->call(Forward(aArguments)...); + } + + explicit operator bool() const + { + return bool(mImpl); + } + +private: + // TODO: Consider implementing a small object optimization. + RefPtr> mImpl; +}; + +template +bool +operator==(const function& aX, decltype(nullptr)) +{ + return !aX; +} + +template +bool +operator==(decltype(nullptr), const function& aX) +{ + return !aX; +} + +template +bool +operator!=(const function& aX, decltype(nullptr)) +{ + return bool(aX); +} + +template +bool +operator!=(decltype(nullptr), const function& aX) +{ + return bool(aX); +} + +} // namespace mozilla + +#endif /* mozilla_Function_h */ -- cgit v1.2.3