diff options
Diffstat (limited to 'Source/WTF/wtf/BlockPtr.h')
-rw-r--r-- | Source/WTF/wtf/BlockPtr.h | 169 |
1 files changed, 169 insertions, 0 deletions
diff --git a/Source/WTF/wtf/BlockPtr.h b/Source/WTF/wtf/BlockPtr.h new file mode 100644 index 000000000..1b79d4178 --- /dev/null +++ b/Source/WTF/wtf/BlockPtr.h @@ -0,0 +1,169 @@ +/* + * Copyright (C) 2016 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF + * THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include <Block.h> +#include <wtf/Assertions.h> + +namespace WTF { + +extern "C" void* _NSConcreteMallocBlock[32]; + +template<typename> class BlockPtr; + +template<typename R, typename... Args> +class BlockPtr<R (Args...)> { +public: + using BlockType = R (^)(Args...); + + template<typename F> + static BlockPtr fromCallable(F function) + { + struct Descriptor { + uintptr_t reserved; + uintptr_t size; + void (*copy)(void *dst, const void *src); + void (*dispose)(const void *); + }; + + struct Block { + void* isa; + int32_t flags; + int32_t reserved; + R (*invoke)(void *, Args...); + const struct Descriptor* descriptor; + F f; + }; + + static const Descriptor descriptor { + 0, + sizeof(Block), + + // We keep the copy function null - the block is already on the heap + // so it should never be copied. + nullptr, + + [](const void* ptr) { + static_cast<Block*>(const_cast<void*>(ptr))->f.~F(); + } + }; + + Block* block = static_cast<Block*>(malloc(sizeof(Block))); + block->isa = _NSConcreteMallocBlock; + + enum { + BLOCK_NEEDS_FREE = (1 << 24), + BLOCK_HAS_COPY_DISPOSE = (1 << 25), + }; + const unsigned retainCount = 1; + + block->flags = BLOCK_HAS_COPY_DISPOSE | BLOCK_NEEDS_FREE | (retainCount << 1); + block->reserved = 0; + block->invoke = [](void *ptr, Args... args) -> R { + return static_cast<Block*>(ptr)->f(std::forward<Args>(args)...); + }; + block->descriptor = &descriptor; + + new (&block->f) F { std::move(function) }; + + BlockPtr blockPtr; + blockPtr.m_block = reinterpret_cast<BlockType>(block); + + return blockPtr; + } + + BlockPtr() + : m_block(nullptr) + { + } + + BlockPtr(BlockType block) + : m_block(Block_copy(block)) + { + } + + BlockPtr(const BlockPtr& other) + : m_block(Block_copy(other.m_block)) + { + } + + BlockPtr(BlockPtr&& other) + : m_block(std::exchange(other.m_block, nullptr)) + { + } + + ~BlockPtr() + { + Block_release(m_block); + } + + BlockPtr& operator=(const BlockPtr& other) + { + if (this != &other) { + Block_release(m_block); + m_block = Block_copy(other.m_block); + } + + return *this; + } + + BlockPtr& operator=(BlockPtr&& other) + { + ASSERT(this != &other); + + Block_release(m_block); + m_block = std::exchange(other.m_block, nullptr); + + return *this; + } + + BlockType get() const { return m_block; } + + explicit operator bool() const { return m_block; } + bool operator!() const { return !m_block; } + + R operator()(Args... arguments) const + { + ASSERT(m_block); + + return m_block(std::forward<Args>(arguments)...); + } + +private: + BlockType m_block; +}; + +template<typename R, typename... Args> +inline BlockPtr<R (Args...)> makeBlockPtr(R (^block)(Args...)) +{ + return BlockPtr<R (Args...)>(block); +} + +} + +using WTF::BlockPtr; +using WTF::makeBlockPtr; + |