Create header folder again

This commit is contained in:
Andrew Hyatt 2018-01-05 14:15:29 -08:00
parent 48466209ad
commit fc0f8616ea
293 changed files with 57369 additions and 0 deletions

View File

@ -5,6 +5,9 @@ set(CMAKE_CXX_STANDARD 14)
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/wtf
${CMAKE_CURRENT_SOURCE_DIR}/wtf/spi/darwin
${CMAKE_CURRENT_SOURCE_DIR}/wtf/text
${CMAKE_CURRENT_SOURCE_DIR}/wtf/text/icu
${CMAKE_CURRENT_SOURCE_DIR}/include/wtf
${CMAKE_CURRENT_SOURCE_DIR}/include/wtf/spi/darwin
${CMAKE_CURRENT_SOURCE_DIR}/include/wtf/text

273
include/ASCIICType.h Normal file
View File

@ -0,0 +1,273 @@
/*
* Copyright (C) 2007-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.
* 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE 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 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.
*/
#ifndef WTF_ASCIICType_h
#define WTF_ASCIICType_h
#include <wtf/Assertions.h>
#include <wtf/text/LChar.h>
// The behavior of many of the functions in the <ctype.h> header is dependent
// on the current locale. But in the WebKit project, all uses of those functions
// are in code processing something that's not locale-specific. These equivalents
// for some of the <ctype.h> functions are named more explicitly, not dependent
// on the C library locale, and we should also optimize them as needed.
// All functions return false or leave the character unchanged if passed a character
// that is outside the range 0-7F. So they can be used on Unicode strings or
// characters if the intent is to do processing only if the character is ASCII.
namespace WTF {
template<typename CharacterType> bool isASCII(CharacterType);
template<typename CharacterType> bool isASCIIAlpha(CharacterType);
template<typename CharacterType> bool isASCIIAlphanumeric(CharacterType);
template<typename CharacterType> bool isASCIIBinaryDigit(CharacterType);
template<typename CharacterType> bool isASCIIDigit(CharacterType);
template<typename CharacterType> bool isASCIIHexDigit(CharacterType);
template<typename CharacterType> bool isASCIILower(CharacterType);
template<typename CharacterType> bool isASCIIOctalDigit(CharacterType);
template<typename CharacterType> bool isASCIIPrintable(CharacterType);
template<typename CharacterType> bool isASCIISpace(CharacterType);
template<typename CharacterType> bool isASCIIUpper(CharacterType);
template<typename CharacterType> CharacterType toASCIILower(CharacterType);
template<typename CharacterType> CharacterType toASCIIUpper(CharacterType);
template<typename CharacterType> uint8_t toASCIIHexValue(CharacterType);
template<typename CharacterType> uint8_t toASCIIHexValue(CharacterType firstCharacter, CharacterType secondCharacter);
char lowerNibbleToASCIIHexDigit(uint8_t);
char upperNibbleToASCIIHexDigit(uint8_t);
char lowerNibbleToLowercaseASCIIHexDigit(uint8_t);
char upperNibbleToLowercaseASCIIHexDigit(uint8_t);
template<typename CharacterType> bool isASCIIAlphaCaselessEqual(CharacterType, char expectedASCIILowercaseLetter);
// The toASCIILowerUnchecked function can be used for comparing any input character
// to a lowercase English character. The isASCIIAlphaCaselessEqual function should
// be used for regular comparison of ASCII alpha characters, but switch statements
// in the CSS tokenizer, for example, instead make direct use toASCIILowerUnchecked.
template<typename CharacterType> CharacterType toASCIILowerUnchecked(CharacterType);
const unsigned char asciiCaseFoldTable[256] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
};
template<typename CharacterType> inline bool isASCII(CharacterType character)
{
return !(character & ~0x7F);
}
template<typename CharacterType> inline bool isASCIILower(CharacterType character)
{
return character >= 'a' && character <= 'z';
}
template<typename CharacterType> inline CharacterType toASCIILowerUnchecked(CharacterType character)
{
// This function can be used for comparing any input character
// to a lowercase English character. The isASCIIAlphaCaselessEqual
// below should be used for regular comparison of ASCII alpha
// characters, but switch statements in CSS tokenizer instead make
// direct use of this function.
return character | 0x20;
}
template<typename CharacterType> inline bool isASCIIAlpha(CharacterType character)
{
return isASCIILower(toASCIILowerUnchecked(character));
}
template<typename CharacterType> inline bool isASCIIDigit(CharacterType character)
{
return character >= '0' && character <= '9';
}
template<typename CharacterType> inline bool isASCIIAlphanumeric(CharacterType character)
{
return isASCIIDigit(character) || isASCIIAlpha(character);
}
template<typename CharacterType> inline bool isASCIIHexDigit(CharacterType character)
{
return isASCIIDigit(character) || (toASCIILowerUnchecked(character) >= 'a' && toASCIILowerUnchecked(character) <= 'f');
}
template<typename CharacterType> inline bool isASCIIBinaryDigit(CharacterType character)
{
return character == '0' || character == '1';
}
template<typename CharacterType> inline bool isASCIIOctalDigit(CharacterType character)
{
return character >= '0' && character <= '7';
}
template<typename CharacterType> inline bool isASCIIPrintable(CharacterType character)
{
return character >= ' ' && character <= '~';
}
/*
Statistics from a run of Apple's page load test for callers of isASCIISpace:
character count
--------- -----
non-spaces 689383
20 space 294720
0A \n 89059
09 \t 28320
0D \r 0
0C \f 0
0B \v 0
Because of those, we first check to quickly return false for non-control characters,
then check for space itself to quickly return true for that case, then do the rest.
*/
template<typename CharacterType> inline bool isASCIISpace(CharacterType character)
{
return character <= ' ' && (character == ' ' || (character <= 0xD && character >= 0x9));
}
template<typename CharacterType> inline bool isASCIIUpper(CharacterType character)
{
return character >= 'A' && character <= 'Z';
}
template<typename CharacterType> inline CharacterType toASCIILower(CharacterType character)
{
return character | (isASCIIUpper(character) << 5);
}
template<> inline char toASCIILower(char character)
{
return static_cast<char>(asciiCaseFoldTable[static_cast<uint8_t>(character)]);
}
template<> inline LChar toASCIILower(LChar character)
{
return asciiCaseFoldTable[character];
}
template<typename CharacterType> inline CharacterType toASCIIUpper(CharacterType character)
{
return character & ~(isASCIILower(character) << 5);
}
template<typename CharacterType> inline uint8_t toASCIIHexValue(CharacterType character)
{
ASSERT(isASCIIHexDigit(character));
return character < 'A' ? character - '0' : (character - 'A' + 10) & 0xF;
}
template<typename CharacterType> inline uint8_t toASCIIHexValue(CharacterType firstCharacter, CharacterType secondCharacter)
{
return toASCIIHexValue(firstCharacter) << 4 | toASCIIHexValue(secondCharacter);
}
inline char lowerNibbleToASCIIHexDigit(uint8_t value)
{
uint8_t nibble = value & 0xF;
return nibble + (nibble < 10 ? '0' : 'A' - 10);
}
inline char upperNibbleToASCIIHexDigit(uint8_t value)
{
uint8_t nibble = value >> 4;
return nibble + (nibble < 10 ? '0' : 'A' - 10);
}
inline char lowerNibbleToLowercaseASCIIHexDigit(uint8_t value)
{
uint8_t nibble = value & 0xF;
return nibble + (nibble < 10 ? '0' : 'a' - 10);
}
inline char upperNibbleToLowercaseASCIIHexDigit(uint8_t value)
{
uint8_t nibble = value >> 4;
return nibble + (nibble < 10 ? '0' : 'a' - 10);
}
template<typename CharacterType> inline bool isASCIIAlphaCaselessEqual(CharacterType inputCharacter, char expectedASCIILowercaseLetter)
{
// Name of this argument says this must be a lowercase letter, but it can actually be:
// - a lowercase letter
// - a numeric digit
// - a space
// - punctuation in the range 0x21-0x3F, including "-", "/", and "+"
// It cannot be:
// - an uppercase letter
// - a non-ASCII character
// - other punctuation, such as underscore and backslash
// - a control character such as "\n"
// FIXME: Would be nice to make both the function name and expectedASCIILowercaseLetter argument name clearer.
ASSERT(toASCIILowerUnchecked(expectedASCIILowercaseLetter) == expectedASCIILowercaseLetter);
return LIKELY(toASCIILowerUnchecked(inputCharacter) == expectedASCIILowercaseLetter);
}
}
using WTF::isASCII;
using WTF::isASCIIAlpha;
using WTF::isASCIIAlphaCaselessEqual;
using WTF::isASCIIAlphanumeric;
using WTF::isASCIIBinaryDigit;
using WTF::isASCIIDigit;
using WTF::isASCIIHexDigit;
using WTF::isASCIILower;
using WTF::isASCIIOctalDigit;
using WTF::isASCIIPrintable;
using WTF::isASCIISpace;
using WTF::isASCIIUpper;
using WTF::lowerNibbleToASCIIHexDigit;
using WTF::lowerNibbleToLowercaseASCIIHexDigit;
using WTF::toASCIIHexValue;
using WTF::toASCIILower;
using WTF::toASCIILowerUnchecked;
using WTF::toASCIIUpper;
using WTF::upperNibbleToASCIIHexDigit;
using WTF::upperNibbleToLowercaseASCIIHexDigit;
#endif

58
include/Algorithms.h Normal file
View File

@ -0,0 +1,58 @@
/*
* Copyright (C) 2017 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
namespace WTF {
template<typename ContainerType, typename ForEachFunction>
void forEach(ContainerType container, ForEachFunction forEachFunction)
{
for (auto& value : container)
forEachFunction(value);
}
template<typename ContainerType, typename AnyOfFunction>
bool anyOf(ContainerType container, AnyOfFunction anyOfFunction)
{
for (auto& value : container) {
if (anyOfFunction(value))
return true;
}
return false;
}
template<typename ContainerType, typename AllOfFunction>
bool allOf(ContainerType container, AllOfFunction allOfFunction)
{
for (auto& value : container) {
if (!allOfFunction(value))
return false;
}
return true;
}
}

528
include/Assertions.h Normal file
View File

@ -0,0 +1,528 @@
/*
* Copyright (C) 2003, 2006, 2007, 2013 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. ``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
* 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.
*/
#ifndef WTF_Assertions_h
#define WTF_Assertions_h
#include <wtf/Platform.h>
/*
no namespaces because this file has to be includable from C and Objective-C
Note, this file uses many GCC extensions, but it should be compatible with
C, Objective C, C++, and Objective C++.
For non-debug builds, everything is disabled by default except for "always
on" logging. Defining any of the symbols explicitly prevents this from
having any effect.
*/
#undef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stddef.h>
#include <wtf/ExportMacros.h>
#if USE(OS_LOG)
#include <os/log.h>
#endif
#ifdef __cplusplus
#include <type_traits>
#if OS(WINDOWS)
#if !COMPILER(GCC_OR_CLANG)
extern "C" void _ReadWriteBarrier(void);
#pragma intrinsic(_ReadWriteBarrier)
#endif
#include <intrin.h>
#endif
#endif
#ifdef NDEBUG
/* Disable ASSERT* macros in release mode. */
#define ASSERTIONS_DISABLED_DEFAULT 1
#else
#define ASSERTIONS_DISABLED_DEFAULT 0
#endif
#ifndef BACKTRACE_DISABLED
#define BACKTRACE_DISABLED ASSERTIONS_DISABLED_DEFAULT
#endif
#ifndef ASSERT_DISABLED
#define ASSERT_DISABLED ASSERTIONS_DISABLED_DEFAULT
#endif
#ifndef ASSERT_MSG_DISABLED
#define ASSERT_MSG_DISABLED ASSERTIONS_DISABLED_DEFAULT
#endif
#ifndef ASSERT_ARG_DISABLED
#define ASSERT_ARG_DISABLED ASSERTIONS_DISABLED_DEFAULT
#endif
#ifndef FATAL_DISABLED
#define FATAL_DISABLED ASSERTIONS_DISABLED_DEFAULT
#endif
#ifndef ERROR_DISABLED
#define ERROR_DISABLED ASSERTIONS_DISABLED_DEFAULT
#endif
#ifndef LOG_DISABLED
#define LOG_DISABLED ASSERTIONS_DISABLED_DEFAULT
#endif
#ifndef RELEASE_LOG_DISABLED
#define RELEASE_LOG_DISABLED !(USE(OS_LOG))
#endif
#if COMPILER(GCC_OR_CLANG)
#define WTF_PRETTY_FUNCTION __PRETTY_FUNCTION__
#else
#define WTF_PRETTY_FUNCTION __FUNCTION__
#endif
#if COMPILER(MINGW)
/* By default MinGW emits warnings when C99 format attributes are used, even if __USE_MINGW_ANSI_STDIO is defined */
#define WTF_ATTRIBUTE_PRINTF(formatStringArgument, extraArguments) __attribute__((__format__(gnu_printf, formatStringArgument, extraArguments)))
#elif COMPILER(GCC_OR_CLANG) && !defined(__OBJC__)
/* WTF logging functions can process %@ in the format string to log a NSObject* but the printf format attribute
emits a warning when %@ is used in the format string. Until <rdar://problem/5195437> is resolved we can't include
the attribute when being used from Objective-C code in case it decides to use %@. */
#define WTF_ATTRIBUTE_PRINTF(formatStringArgument, extraArguments) __attribute__((__format__(printf, formatStringArgument, extraArguments)))
#else
#define WTF_ATTRIBUTE_PRINTF(formatStringArgument, extraArguments)
#endif
#if PLATFORM(IOS)
/* For a project that uses WTF but has no config.h, we need to explicitly set the export defines here. */
#ifndef WTF_EXPORT_PRIVATE
#define WTF_EXPORT_PRIVATE
#endif
#endif // PLATFORM(IOS)
/* These helper functions are always declared, but not necessarily always defined if the corresponding function is disabled. */
#ifdef __cplusplus
extern "C" {
#endif
/* CRASH() - Raises a fatal error resulting in program termination and triggering either the debugger or the crash reporter.
Use CRASH() in response to known, unrecoverable errors like out-of-memory.
Macro is enabled in both debug and release mode.
To test for unknown errors and verify assumptions, use ASSERT instead, to avoid impacting performance in release builds.
Signals are ignored by the crash reporter on OS X so we must do better.
*/
#if COMPILER(GCC_OR_CLANG) || COMPILER(MSVC)
#define NO_RETURN_DUE_TO_CRASH NO_RETURN
#else
#define NO_RETURN_DUE_TO_CRASH
#endif
typedef enum { WTFLogChannelOff, WTFLogChannelOn, WTFLogChannelOnWithAccumulation } WTFLogChannelState;
typedef struct {
WTFLogChannelState state;
const char* name;
#if !RELEASE_LOG_DISABLED
const char* subsystem;
__unsafe_unretained os_log_t osLogChannel;
#endif
} WTFLogChannel;
#define LOG_CHANNEL(name) JOIN_LOG_CHANNEL_WITH_PREFIX(LOG_CHANNEL_PREFIX, name)
#define LOG_CHANNEL_ADDRESS(name) &LOG_CHANNEL(name),
#define JOIN_LOG_CHANNEL_WITH_PREFIX(prefix, channel) JOIN_LOG_CHANNEL_WITH_PREFIX_LEVEL_2(prefix, channel)
#define JOIN_LOG_CHANNEL_WITH_PREFIX_LEVEL_2(prefix, channel) prefix ## channel
#define LOG_CHANNEL_WEBKIT_SUBSYSTEM "com.apple.WebKit"
#define DECLARE_LOG_CHANNEL(name) \
extern WTFLogChannel LOG_CHANNEL(name);
#if !defined(DEFINE_LOG_CHANNEL)
#if RELEASE_LOG_DISABLED
#define DEFINE_LOG_CHANNEL(name, subsystem) \
WTFLogChannel LOG_CHANNEL(name) = { WTFLogChannelOff, #name };
#else
#define DEFINE_LOG_CHANNEL(name, subsystem) \
WTFLogChannel LOG_CHANNEL(name) = { WTFLogChannelOff, #name, subsystem, OS_LOG_DEFAULT };
#endif
#endif
WTF_EXPORT_PRIVATE void WTFReportAssertionFailure(const char* file, int line, const char* function, const char* assertion);
WTF_EXPORT_PRIVATE void WTFReportAssertionFailureWithMessage(const char* file, int line, const char* function, const char* assertion, const char* format, ...) WTF_ATTRIBUTE_PRINTF(5, 6);
WTF_EXPORT_PRIVATE void WTFReportArgumentAssertionFailure(const char* file, int line, const char* function, const char* argName, const char* assertion);
WTF_EXPORT_PRIVATE void WTFReportFatalError(const char* file, int line, const char* function, const char* format, ...) WTF_ATTRIBUTE_PRINTF(4, 5);
WTF_EXPORT_PRIVATE void WTFReportError(const char* file, int line, const char* function, const char* format, ...) WTF_ATTRIBUTE_PRINTF(4, 5);
WTF_EXPORT_PRIVATE void WTFLog(WTFLogChannel*, const char* format, ...) WTF_ATTRIBUTE_PRINTF(2, 3);
WTF_EXPORT_PRIVATE void WTFLogVerbose(const char* file, int line, const char* function, WTFLogChannel*, const char* format, ...) WTF_ATTRIBUTE_PRINTF(5, 6);
WTF_EXPORT_PRIVATE void WTFLogAlwaysV(const char* format, va_list);
WTF_EXPORT_PRIVATE void WTFLogAlways(const char* format, ...) WTF_ATTRIBUTE_PRINTF(1, 2);
WTF_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH void WTFLogAlwaysAndCrash(const char* format, ...) WTF_ATTRIBUTE_PRINTF(1, 2);
WTF_EXPORT_PRIVATE WTFLogChannel* WTFLogChannelByName(WTFLogChannel*[], size_t count, const char*);
WTF_EXPORT_PRIVATE void WTFInitializeLogChannelStatesFromString(WTFLogChannel*[], size_t count, const char*);
WTF_EXPORT_PRIVATE void WTFGetBacktrace(void** stack, int* size);
WTF_EXPORT_PRIVATE void WTFReportBacktrace();
WTF_EXPORT_PRIVATE void WTFPrintBacktrace(void** stack, int size);
typedef void (*WTFCrashHookFunction)();
WTF_EXPORT_PRIVATE void WTFSetCrashHook(WTFCrashHookFunction);
WTF_EXPORT_PRIVATE void WTFInstallReportBacktraceOnCrashHook();
WTF_EXPORT_PRIVATE bool WTFIsDebuggerAttached();
#if CPU(X86_64) || CPU(X86)
#define WTFBreakpointTrap() __asm__ volatile ("int3")
#elif CPU(ARM_THUMB2)
#define WTFBreakpointTrap() __asm__ volatile ("bkpt #0")
#elif CPU(ARM64)
#define WTFBreakpointTrap() __asm__ volatile ("brk #0")
#else
#define WTFBreakpointTrap() WTFCrash() // Not implemented.
#endif
#ifndef CRASH
#if defined(NDEBUG) && OS(DARWIN)
// Crash with a SIGTRAP i.e EXC_BREAKPOINT.
// We are not using __builtin_trap because it is only guaranteed to abort, but not necessarily
// trigger a SIGTRAP. Instead, we use inline asm to ensure that we trigger the SIGTRAP.
#define CRASH() do { \
WTFBreakpointTrap(); \
__builtin_unreachable(); \
} while (0)
#else
#define CRASH() WTFCrash()
#endif
#endif // !defined(CRASH)
WTF_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH void WTFCrash();
#ifndef CRASH_WITH_SECURITY_IMPLICATION
#define CRASH_WITH_SECURITY_IMPLICATION() WTFCrashWithSecurityImplication()
#endif
WTF_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH void WTFCrashWithSecurityImplication();
#ifdef __cplusplus
}
#endif
/* BACKTRACE
Print a backtrace to the same location as ASSERT messages.
*/
#if BACKTRACE_DISABLED
#define BACKTRACE() ((void)0)
#else
#define BACKTRACE() do { \
WTFReportBacktrace(); \
} while(false)
#endif
/* ASSERT, ASSERT_NOT_REACHED, ASSERT_UNUSED
These macros are compiled out of release builds.
Expressions inside them are evaluated in debug builds only.
*/
#if OS(WINDOWS)
/* FIXME: Change to use something other than ASSERT to avoid this conflict with the underlying platform */
#undef ASSERT
#endif
#if ASSERT_DISABLED
#define ASSERT(assertion) ((void)0)
#define ASSERT_AT(assertion, file, line, function) ((void)0)
#define ASSERT_NOT_REACHED() ((void)0)
#define ASSERT_IMPLIES(condition, assertion) ((void)0)
#define NO_RETURN_DUE_TO_ASSERT
#define ASSERT_UNUSED(variable, assertion) ((void)variable)
#if ENABLE(SECURITY_ASSERTIONS)
#define ASSERT_WITH_SECURITY_IMPLICATION(assertion) \
(!(assertion) ? \
(WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #assertion), \
CRASH_WITH_SECURITY_IMPLICATION()) : \
(void)0)
#define ASSERT_WITH_SECURITY_IMPLICATION_DISABLED 0
#else
#define ASSERT_WITH_SECURITY_IMPLICATION(assertion) ((void)0)
#define ASSERT_WITH_SECURITY_IMPLICATION_DISABLED 1
#endif
#else
#define ASSERT(assertion) do { \
if (!(assertion)) { \
WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #assertion); \
CRASH(); \
} \
} while (0)
#define ASSERT_AT(assertion, file, line, function) do { \
if (!(assertion)) { \
WTFReportAssertionFailure(file, line, function, #assertion); \
CRASH(); \
} \
} while (0)
#define ASSERT_NOT_REACHED() do { \
WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, 0); \
CRASH(); \
} while (0)
#define ASSERT_IMPLIES(condition, assertion) do { \
if ((condition) && !(assertion)) { \
WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #condition " => " #assertion); \
CRASH(); \
} \
} while (0)
#define ASSERT_UNUSED(variable, assertion) ASSERT(assertion)
#define NO_RETURN_DUE_TO_ASSERT NO_RETURN_DUE_TO_CRASH
/* ASSERT_WITH_SECURITY_IMPLICATION
Failure of this assertion indicates a possible security vulnerability.
Class of vulnerabilities that it tests include bad casts, out of bounds
accesses, use-after-frees, etc. Please file a bug using the security
template - https://bugs.webkit.org/enter_bug.cgi?product=Security.
*/
#define ASSERT_WITH_SECURITY_IMPLICATION(assertion) \
(!(assertion) ? \
(WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #assertion), \
CRASH_WITH_SECURITY_IMPLICATION()) : \
(void)0)
#define ASSERT_WITH_SECURITY_IMPLICATION_DISABLED 0
#endif
/* ASSERT_WITH_MESSAGE */
#if ASSERT_MSG_DISABLED
#define ASSERT_WITH_MESSAGE(assertion, ...) ((void)0)
#else
#define ASSERT_WITH_MESSAGE(assertion, ...) do { \
if (!(assertion)) { \
WTFReportAssertionFailureWithMessage(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #assertion, __VA_ARGS__); \
CRASH(); \
} \
} while (0)
#endif
/* ASSERT_WITH_MESSAGE_UNUSED */
#if ASSERT_MSG_DISABLED
#define ASSERT_WITH_MESSAGE_UNUSED(variable, assertion, ...) ((void)variable)
#else
#define ASSERT_WITH_MESSAGE_UNUSED(variable, assertion, ...) do { \
if (!(assertion)) { \
WTFReportAssertionFailureWithMessage(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #assertion, __VA_ARGS__); \
CRASH(); \
} \
} while (0)
#endif
/* ASSERT_ARG */
#if ASSERT_ARG_DISABLED
#define ASSERT_ARG(argName, assertion) ((void)0)
#else
#define ASSERT_ARG(argName, assertion) do { \
if (!(assertion)) { \
WTFReportArgumentAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #argName, #assertion); \
CRASH(); \
} \
} while (0)
#endif
/* COMPILE_ASSERT */
#ifndef COMPILE_ASSERT
#if COMPILER_SUPPORTS(C_STATIC_ASSERT)
/* Unlike static_assert below, this also works in plain C code. */
#define COMPILE_ASSERT(exp, name) _Static_assert((exp), #name)
#else
#define COMPILE_ASSERT(exp, name) static_assert((exp), #name)
#endif
#endif
/* FATAL */
#if FATAL_DISABLED
#define FATAL(...) ((void)0)
#else
#define FATAL(...) do { \
WTFReportFatalError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, __VA_ARGS__); \
CRASH(); \
} while (0)
#endif
/* LOG_ERROR */
#if ERROR_DISABLED
#define LOG_ERROR(...) ((void)0)
#else
#define LOG_ERROR(...) WTFReportError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, __VA_ARGS__)
#endif
/* LOG */
#if LOG_DISABLED
#define LOG(channel, ...) ((void)0)
#else
#define LOG(channel, ...) WTFLog(&LOG_CHANNEL(channel), __VA_ARGS__)
#endif
/* LOG_VERBOSE */
#if LOG_DISABLED
#define LOG_VERBOSE(channel, ...) ((void)0)
#else
#define LOG_VERBOSE(channel, ...) WTFLogVerbose(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, &LOG_CHANNEL(channel), __VA_ARGS__)
#endif
/* RELEASE_LOG */
#if RELEASE_LOG_DISABLED
#define RELEASE_LOG( channel, format, ...) ((void)0)
#define RELEASE_LOG_ERROR(channel, format, ...) LOG_ERROR(format, ##__VA_ARGS__)
#define RELEASE_LOG_IF( isAllowed, channel, format, ...) ((void)0)
#define RELEASE_LOG_ERROR_IF(isAllowed, channel, format, ...) do { if (isAllowed) RELEASE_LOG_ERROR(channel, format, ##__VA_ARGS__); } while (0)
#else
#define RELEASE_LOG( channel, format, ...) os_log( LOG_CHANNEL(channel).osLogChannel, format, ##__VA_ARGS__)
#define RELEASE_LOG_ERROR(channel, format, ...) os_log_error(LOG_CHANNEL(channel).osLogChannel, format, ##__VA_ARGS__)
#define RELEASE_LOG_IF( isAllowed, channel, format, ...) do { if (isAllowed) RELEASE_LOG( channel, format, ##__VA_ARGS__); } while (0)
#define RELEASE_LOG_ERROR_IF(isAllowed, channel, format, ...) do { if (isAllowed) RELEASE_LOG_ERROR(channel, format, ##__VA_ARGS__); } while (0)
#endif
/* RELEASE_ASSERT */
#if ASSERT_DISABLED
#define RELEASE_ASSERT(assertion) do { \
if (UNLIKELY(!(assertion))) \
CRASH(); \
} while (0)
#define RELEASE_ASSERT_WITH_MESSAGE(assertion, ...) RELEASE_ASSERT(assertion)
#define RELEASE_ASSERT_NOT_REACHED() CRASH()
#else
#define RELEASE_ASSERT(assertion) ASSERT(assertion)
#define RELEASE_ASSERT_WITH_MESSAGE(assertion, ...) ASSERT_WITH_MESSAGE(assertion, __VA_ARGS__)
#define RELEASE_ASSERT_NOT_REACHED() ASSERT_NOT_REACHED()
#endif
/* UNREACHABLE_FOR_PLATFORM */
#if COMPILER(CLANG)
// This would be a macro except that its use of #pragma works best around
// a function. Hence it uses macro naming convention.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmissing-noreturn"
static inline void UNREACHABLE_FOR_PLATFORM()
{
// This *MUST* be a release assert. We use it in places where it's better to crash than to keep
// going.
RELEASE_ASSERT_NOT_REACHED();
}
#pragma clang diagnostic pop
#else
#define UNREACHABLE_FOR_PLATFORM() RELEASE_ASSERT_NOT_REACHED()
#endif
#ifdef __cplusplus
// The combination of line, file, function, and counter should be a unique number per call to this crash. This tricks the compiler into not coalescing calls to WTFCrashWithInfo.
// The easiest way to fill these values per translation unit is to pass __LINE__, __FILE__, WTF_PRETTY_FUNCTION, and __COUNTER__.
WTF_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH NOT_TAIL_CALLED void WTFCrashWithInfo(int line, const char* file, const char* function, int counter, uint64_t reason, uint64_t misc1, uint64_t misc2, uint64_t misc3, uint64_t misc4);
WTF_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH NOT_TAIL_CALLED void WTFCrashWithInfo(int line, const char* file, const char* function, int counter, uint64_t reason, uint64_t misc1, uint64_t misc2, uint64_t misc3);
WTF_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH NOT_TAIL_CALLED void WTFCrashWithInfo(int line, const char* file, const char* function, int counter, uint64_t reason, uint64_t misc1, uint64_t misc2);
WTF_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH NOT_TAIL_CALLED void WTFCrashWithInfo(int line, const char* file, const char* function, int counter, uint64_t reason, uint64_t misc1);
WTF_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH NOT_TAIL_CALLED void WTFCrashWithInfo(int line, const char* file, const char* function, int counter, uint64_t reason);
WTF_EXPORT_PRIVATE NO_RETURN_DUE_TO_CRASH NOT_TAIL_CALLED void WTFCrashWithInfo(int line, const char* file, const char* function, int counter);
namespace WTF {
inline void isIntegralType() { }
template<typename T, typename... Types>
void isIntegralType(T, Types... types)
{
static_assert(std::is_integral<T>::value || std::is_enum<T>::value, "All types need to be integral bitwise_cast to integral type for logging");
isIntegralType(types...);
}
}
inline void compilerFenceForCrash()
{
#if OS(WINDOWS) && !COMPILER(GCC_OR_CLANG)
_ReadWriteBarrier();
#else
asm volatile("" ::: "memory");
#endif
}
#ifndef CRASH_WITH_SECURITY_IMPLICATION_AND_INFO
// This is useful if you are going to stuff data into registers before crashing. Like the crashWithInfo functions below...
// GCC doesn't like the ##__VA_ARGS__ here since this macro is called from another macro so we just CRASH instead there.
#if COMPILER(CLANG) || COMPILER(MSVC)
#define CRASH_WITH_SECURITY_IMPLICATION_AND_INFO(...) do { \
WTF::isIntegralType(__VA_ARGS__); \
compilerFenceForCrash(); \
WTFCrashWithInfo(__LINE__, __FILE__, WTF_PRETTY_FUNCTION, __COUNTER__, ##__VA_ARGS__); \
} while (false)
#else
#define CRASH_WITH_SECURITY_IMPLICATION_AND_INFO(...) CRASH()
#endif
#endif // CRASH_WITH_SECURITY_IMPLICATION_AND_INFO
#endif // __cplusplus
#endif /* WTF_Assertions_h */

479
include/Atomics.h Normal file
View File

@ -0,0 +1,479 @@
/*
* Copyright (C) 2007-2017 Apple Inc. All rights reserved.
* Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
*
* 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.
*/
#ifndef Atomics_h
#define Atomics_h
#include <atomic>
#include <wtf/StdLibExtras.h>
#if OS(WINDOWS)
#if !COMPILER(GCC_OR_CLANG)
extern "C" void _ReadWriteBarrier(void);
#pragma intrinsic(_ReadWriteBarrier)
#endif
#include <windows.h>
#include <intrin.h>
#endif
namespace WTF {
ALWAYS_INLINE bool hasFence(std::memory_order order)
{
return order != std::memory_order_relaxed;
}
// Atomic wraps around std::atomic with the sole purpose of making the compare_exchange
// operations not alter the expected value. This is more in line with how we typically
// use CAS in our code.
//
// Atomic is a struct without explicitly defined constructors so that it can be
// initialized at compile time.
template<typename T>
struct Atomic {
// Don't pass a non-default value for the order parameter unless you really know
// what you are doing and have thought about it very hard. The cost of seq_cst
// is usually not high enough to justify the risk.
ALWAYS_INLINE T load(std::memory_order order = std::memory_order_seq_cst) const { return value.load(order); }
ALWAYS_INLINE T loadRelaxed() const { return load(std::memory_order_relaxed); }
// This is a load that simultaneously does a full fence - neither loads nor stores will move
// above or below it.
ALWAYS_INLINE T loadFullyFenced() const
{
Atomic<T>* ptr = const_cast<Atomic<T>*>(this);
return ptr->exchangeAdd(T());
}
ALWAYS_INLINE void store(T desired, std::memory_order order = std::memory_order_seq_cst) { value.store(desired, order); }
ALWAYS_INLINE void storeRelaxed(T desired) { store(desired, std::memory_order_relaxed); }
// This is a store that simultaneously does a full fence - neither loads nor stores will move
// above or below it.
ALWAYS_INLINE void storeFullyFenced(T desired)
{
exchange(desired);
}
ALWAYS_INLINE bool compareExchangeWeak(T expected, T desired, std::memory_order order = std::memory_order_seq_cst)
{
T expectedOrActual = expected;
return value.compare_exchange_weak(expectedOrActual, desired, order);
}
ALWAYS_INLINE bool compareExchangeWeakRelaxed(T expected, T desired)
{
return compareExchangeWeak(expected, desired, std::memory_order_relaxed);
}
ALWAYS_INLINE bool compareExchangeWeak(T expected, T desired, std::memory_order order_success, std::memory_order order_failure)
{
T expectedOrActual = expected;
return value.compare_exchange_weak(expectedOrActual, desired, order_success, order_failure);
}
// WARNING: This does not have strong fencing guarantees when it fails. For example, stores could
// sink below it in that case.
ALWAYS_INLINE T compareExchangeStrong(T expected, T desired, std::memory_order order = std::memory_order_seq_cst)
{
T expectedOrActual = expected;
value.compare_exchange_strong(expectedOrActual, desired, order);
return expectedOrActual;
}
ALWAYS_INLINE T compareExchangeStrong(T expected, T desired, std::memory_order order_success, std::memory_order order_failure)
{
T expectedOrActual = expected;
value.compare_exchange_strong(expectedOrActual, desired, order_success, order_failure);
return expectedOrActual;
}
template<typename U>
ALWAYS_INLINE T exchangeAdd(U operand, std::memory_order order = std::memory_order_seq_cst) { return value.fetch_add(operand, order); }
template<typename U>
ALWAYS_INLINE T exchangeAnd(U operand, std::memory_order order = std::memory_order_seq_cst) { return value.fetch_and(operand, order); }
template<typename U>
ALWAYS_INLINE T exchangeOr(U operand, std::memory_order order = std::memory_order_seq_cst) { return value.fetch_or(operand, order); }
template<typename U>
ALWAYS_INLINE T exchangeSub(U operand, std::memory_order order = std::memory_order_seq_cst) { return value.fetch_sub(operand, order); }
template<typename U>
ALWAYS_INLINE T exchangeXor(U operand, std::memory_order order = std::memory_order_seq_cst) { return value.fetch_xor(operand, order); }
ALWAYS_INLINE T exchange(T newValue, std::memory_order order = std::memory_order_seq_cst) { return value.exchange(newValue, order); }
template<typename Func>
ALWAYS_INLINE bool transaction(const Func& func, std::memory_order order = std::memory_order_seq_cst)
{
for (;;) {
T oldValue = load(std::memory_order_relaxed);
T newValue = oldValue;
if (!func(newValue))
return false;
if (compareExchangeWeak(oldValue, newValue, order))
return true;
}
}
template<typename Func>
ALWAYS_INLINE bool transactionRelaxed(const Func& func)
{
return transaction(func, std::memory_order_relaxed);
}
Atomic() = default;
constexpr Atomic(T initial)
: value(std::forward<T>(initial))
{
}
std::atomic<T> value;
};
template<typename T>
inline T atomicLoad(T* location, std::memory_order order = std::memory_order_seq_cst)
{
return bitwise_cast<Atomic<T>*>(location)->load(order);
}
template<typename T>
inline T atomicLoadFullyFenced(T* location)
{
return bitwise_cast<Atomic<T>*>(location)->loadFullyFenced();
}
template<typename T>
inline void atomicStore(T* location, T newValue, std::memory_order order = std::memory_order_seq_cst)
{
bitwise_cast<Atomic<T>*>(location)->store(newValue, order);
}
template<typename T>
inline void atomicStoreFullyFenced(T* location, T newValue)
{
bitwise_cast<Atomic<T>*>(location)->storeFullyFenced(newValue);
}
template<typename T>
inline bool atomicCompareExchangeWeak(T* location, T expected, T newValue, std::memory_order order = std::memory_order_seq_cst)
{
return bitwise_cast<Atomic<T>*>(location)->compareExchangeWeak(expected, newValue, order);
}
template<typename T>
inline bool atomicCompareExchangeWeakRelaxed(T* location, T expected, T newValue)
{
return bitwise_cast<Atomic<T>*>(location)->compareExchangeWeakRelaxed(expected, newValue);
}
template<typename T>
inline T atomicCompareExchangeStrong(T* location, T expected, T newValue, std::memory_order order = std::memory_order_seq_cst)
{
return bitwise_cast<Atomic<T>*>(location)->compareExchangeStrong(expected, newValue, order);
}
template<typename T, typename U>
inline T atomicExchangeAdd(T* location, U operand, std::memory_order order = std::memory_order_seq_cst)
{
return bitwise_cast<Atomic<T>*>(location)->exchangeAdd(operand, order);
}
template<typename T, typename U>
inline T atomicExchangeAnd(T* location, U operand, std::memory_order order = std::memory_order_seq_cst)
{
return bitwise_cast<Atomic<T>*>(location)->exchangeAnd(operand, order);
}
template<typename T, typename U>
inline T atomicExchangeOr(T* location, U operand, std::memory_order order = std::memory_order_seq_cst)
{
return bitwise_cast<Atomic<T>*>(location)->exchangeOr(operand, order);
}
template<typename T, typename U>
inline T atomicExchangeSub(T* location, U operand, std::memory_order order = std::memory_order_seq_cst)
{
return bitwise_cast<Atomic<T>*>(location)->exchangeSub(operand, order);
}
template<typename T, typename U>
inline T atomicExchangeXor(T* location, U operand, std::memory_order order = std::memory_order_seq_cst)
{
return bitwise_cast<Atomic<T>*>(location)->exchangeXor(operand, order);
}
template<typename T>
inline T atomicExchange(T* location, T newValue, std::memory_order order = std::memory_order_seq_cst)
{
return bitwise_cast<Atomic<T>*>(location)->exchange(newValue, order);
}
// Just a compiler fence. Has no effect on the hardware, but tells the compiler
// not to move things around this call. Should not affect the compiler's ability
// to do things like register allocation and code motion over pure operations.
inline void compilerFence()
{
#if OS(WINDOWS) && !COMPILER(GCC_OR_CLANG)
_ReadWriteBarrier();
#else
asm volatile("" ::: "memory");
#endif
}
#if CPU(ARM_THUMB2) || CPU(ARM64)
// Full memory fence. No accesses will float above this, and no accesses will sink
// below it.
inline void arm_dmb()
{
asm volatile("dmb ish" ::: "memory");
}
// Like the above, but only affects stores.
inline void arm_dmb_st()
{
asm volatile("dmb ishst" ::: "memory");
}
inline void arm_isb()
{
asm volatile("isb" ::: "memory");
}
inline void loadLoadFence() { arm_dmb(); }
inline void loadStoreFence() { arm_dmb(); }
inline void storeLoadFence() { arm_dmb(); }
inline void storeStoreFence() { arm_dmb_st(); }
inline void memoryBarrierAfterLock() { arm_dmb(); }
inline void memoryBarrierBeforeUnlock() { arm_dmb(); }
inline void crossModifyingCodeFence() { arm_isb(); }
#elif CPU(X86) || CPU(X86_64)
inline void x86_ortop()
{
#if OS(WINDOWS)
MemoryBarrier();
#elif CPU(X86_64)
// This has acqrel semantics and is much cheaper than mfence. For exampe, in the JSC GC, using
// mfence as a store-load fence was a 9% slow-down on Octane/splay while using this was neutral.
asm volatile("lock; orl $0, (%%rsp)" ::: "memory");
#else
asm volatile("lock; orl $0, (%%esp)" ::: "memory");
#endif
}
inline void x86_cpuid()
{
#if OS(WINDOWS)
int info[4];
__cpuid(info, 0);
#elif CPU(X86)
// GCC 4.9 on x86 in PIC mode can't use %ebx, so we have to save and restore it manually.
// But since we don't care about what cpuid returns (we use it as a serializing instruction),
// we can simply throw away what cpuid put in %ebx.
intptr_t a = 0, c, d;
asm volatile(
"pushl %%ebx\n\t"
"cpuid\n\t"
"popl %%ebx\n\t"
: "+a"(a), "=c"(c), "=d"(d)
:
: "memory");
#else
intptr_t a = 0, b, c, d;
asm volatile(
"cpuid"
: "+a"(a), "=b"(b), "=c"(c), "=d"(d)
:
: "memory");
#endif
}
inline void loadLoadFence() { compilerFence(); }
inline void loadStoreFence() { compilerFence(); }
inline void storeLoadFence() { x86_ortop(); }
inline void storeStoreFence() { compilerFence(); }
inline void memoryBarrierAfterLock() { compilerFence(); }
inline void memoryBarrierBeforeUnlock() { compilerFence(); }
inline void crossModifyingCodeFence() { x86_cpuid(); }
#else
inline void loadLoadFence() { std::atomic_thread_fence(std::memory_order_seq_cst); }
inline void loadStoreFence() { std::atomic_thread_fence(std::memory_order_seq_cst); }
inline void storeLoadFence() { std::atomic_thread_fence(std::memory_order_seq_cst); }
inline void storeStoreFence() { std::atomic_thread_fence(std::memory_order_seq_cst); }
inline void memoryBarrierAfterLock() { std::atomic_thread_fence(std::memory_order_seq_cst); }
inline void memoryBarrierBeforeUnlock() { std::atomic_thread_fence(std::memory_order_seq_cst); }
inline void crossModifyingCodeFence() { std::atomic_thread_fence(std::memory_order_seq_cst); } // Probably not strong enough.
#endif
typedef unsigned Dependency;
ALWAYS_INLINE Dependency nullDependency()
{
return 0;
}
template <typename T, typename std::enable_if<sizeof(T) == 8>::type* = nullptr>
ALWAYS_INLINE Dependency dependency(T value)
{
unsigned dependency;
uint64_t copy = bitwise_cast<uint64_t>(value);
#if CPU(ARM64)
// Create a magical zero value through inline assembly, whose computation
// isn't visible to the optimizer. This zero is then usable as an offset in
// further address computations: adding zero does nothing, but the compiler
// doesn't know it. It's magical because it creates an address dependency
// from the load of `location` to the uses of the dependency, which triggers
// the ARM ISA's address dependency rule, a.k.a. the mythical C++ consume
// ordering. This forces weak memory order CPUs to observe `location` and
// dependent loads in their store order without the reader using a barrier
// or an acquire load.
asm("eor %w[dependency], %w[in], %w[in]"
: [dependency] "=r"(dependency)
: [in] "r"(copy));
#elif CPU(ARM)
asm("eor %[dependency], %[in], %[in]"
: [dependency] "=r"(dependency)
: [in] "r"(copy));
#else
// No dependency is needed for this architecture.
loadLoadFence();
dependency = 0;
UNUSED_PARAM(copy);
#endif
return dependency;
}
// FIXME: This code is almost identical to the other dependency() overload.
// https://bugs.webkit.org/show_bug.cgi?id=169405
template <typename T, typename std::enable_if<sizeof(T) == 4>::type* = nullptr>
ALWAYS_INLINE Dependency dependency(T value)
{
unsigned dependency;
uint32_t copy = bitwise_cast<uint32_t>(value);
#if CPU(ARM64)
asm("eor %w[dependency], %w[in], %w[in]"
: [dependency] "=r"(dependency)
: [in] "r"(copy));
#elif CPU(ARM)
asm("eor %[dependency], %[in], %[in]"
: [dependency] "=r"(dependency)
: [in] "r"(copy));
#else
loadLoadFence();
dependency = 0;
UNUSED_PARAM(copy);
#endif
return dependency;
}
template <typename T, typename std::enable_if<sizeof(T) == 2>::type* = nullptr>
ALWAYS_INLINE Dependency dependency(T value)
{
return dependency(static_cast<uint32_t>(value));
}
template <typename T, typename std::enable_if<sizeof(T) == 1>::type* = nullptr>
ALWAYS_INLINE Dependency dependency(T value)
{
return dependency(static_cast<uint32_t>(value));
}
template<typename T>
struct DependencyWith {
public:
DependencyWith()
: dependency(nullDependency())
, value()
{
}
DependencyWith(Dependency dependency, const T& value)
: dependency(dependency)
, value(value)
{
}
Dependency dependency;
T value;
};
template<typename T>
inline DependencyWith<T> dependencyWith(Dependency dependency, const T& value)
{
return DependencyWith<T>(dependency, value);
}
template<typename T>
inline T* consume(T* pointer, Dependency dependency)
{
#if CPU(ARM64) || CPU(ARM)
return bitwise_cast<T*>(bitwise_cast<char*>(pointer) + dependency);
#else
UNUSED_PARAM(dependency);
return pointer;
#endif
}
template<typename T, typename Func>
ALWAYS_INLINE T& ensurePointer(Atomic<T*>& pointer, const Func& func)
{
for (;;) {
T* oldValue = pointer.load(std::memory_order_relaxed);
if (oldValue) {
// On all sensible CPUs, we get an implicit dependency-based load-load barrier when
// loading this.
return *oldValue;
}
T* newValue = func();
if (pointer.compareExchangeWeak(oldValue, newValue))
return *newValue;
delete newValue;
}
}
} // namespace WTF
using WTF::Atomic;
using WTF::Dependency;
using WTF::DependencyWith;
using WTF::consume;
using WTF::dependency;
using WTF::dependencyWith;
using WTF::ensurePointer;
using WTF::nullDependency;
#endif // Atomics_h

61
include/AutodrainedPool.h Normal file
View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2007, 2013 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.
* 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE 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 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.
*/
#ifndef AutodrainedPool_h
#define AutodrainedPool_h
#include <wtf/Noncopyable.h>
#if USE(FOUNDATION) && !defined(__OBJC__)
typedef struct objc_object *id;
#endif
namespace WTF {
class AutodrainedPool {
WTF_MAKE_NONCOPYABLE(AutodrainedPool);
public:
#if USE(FOUNDATION)
WTF_EXPORT_PRIVATE AutodrainedPool();
WTF_EXPORT_PRIVATE ~AutodrainedPool();
#else
explicit AutodrainedPool() { }
~AutodrainedPool() { }
#endif
private:
#if USE(FOUNDATION)
id m_pool;
#endif
};
} // namespace WTF
using WTF::AutodrainedPool;
#endif

192
include/AutomaticThread.h Normal file
View File

@ -0,0 +1,192 @@
/*
* Copyright (C) 2016-2017 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. ``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
* 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.
*/
#ifndef WTF_AutomaticThread_h
#define WTF_AutomaticThread_h
#include <wtf/Box.h>
#include <wtf/Condition.h>
#include <wtf/Lock.h>
#include <wtf/ThreadSafeRefCounted.h>
#include <wtf/Vector.h>
namespace WTF {
// Often, we create threads that have this as their body:
//
// for (;;) {
// {
// LockHolder locker(m_lock);
// for (;;) {
// [1] stuff that could break, return, or fall through;
// m_condition.wait(m_lock);
// }
// }
//
// [2] do work;
// }
//
// When we do this, we don't always do a good job of managing this thread's lifetime, which may lead
// to this thread sitting around even when it is not needed.
//
// AutomaticThread is here to help you in these situations. It encapsulates a lock, a condition
// variable, and a thread. It will automatically shut the thread down after a timeout of inactivity.
// You use AutomaticThread by subclassing it, and put any state that is needed between [1] and [2]
// in the subclass.
//
// The terminology we use is:
//
// [1] PollResult AutomaticThread::poll()
// [2] WorkResult AutomaticThread::work()
//
// Note that poll() and work() may not be called on the same thread every time, since this will shut
// down the thread as necessary. This is legal since m_condition.wait(m_lock) can drop the lock, and
// so there is no reason to keep the thread around.
class AutomaticThread;
class AutomaticThreadCondition : public ThreadSafeRefCounted<AutomaticThreadCondition> {
public:
static WTF_EXPORT_PRIVATE RefPtr<AutomaticThreadCondition> create();
WTF_EXPORT_PRIVATE ~AutomaticThreadCondition();
WTF_EXPORT_PRIVATE void notifyOne(const AbstractLocker&);
WTF_EXPORT_PRIVATE void notifyAll(const AbstractLocker&);
// You can reuse this condition for other things, just as you would any other condition.
// However, since conflating conditions could lead to thundering herd, it's best to avoid it.
// One known-good case for one-true-condition is when the communication involves just two
// threads. In such cases, the thread doing the notifyAll() can wake up at most one thread -
// its partner.
WTF_EXPORT_PRIVATE void wait(Lock&);
WTF_EXPORT_PRIVATE bool waitFor(Lock&, Seconds);
private:
friend class AutomaticThread;
WTF_EXPORT_PRIVATE AutomaticThreadCondition();
void add(const AbstractLocker&, AutomaticThread*);
void remove(const AbstractLocker&, AutomaticThread*);
bool contains(const AbstractLocker&, AutomaticThread*);
Condition m_condition;
Vector<AutomaticThread*> m_threads;
};
class WTF_EXPORT_PRIVATE AutomaticThread : public ThreadSafeRefCounted<AutomaticThread> {
public:
// Note that if you drop all of your references to an AutomaticThread then as soon as there is a
// timeout during which it doesn't get woken up, it will simply die on its own. This is a
// permanent kind of death where the AutomaticThread object goes away, rather than the temporary
// kind of death where AutomaticThread lives but its underlying thread dies. All you have to do
// to prevent permanent death is keep a ref to AutomaticThread. At time of writing, every user of
// AutomaticThread keeps a ref to it and does join() as part of the shutdown process, so only the
// temporary kind of automatic death happens in practice. We keep the permanent death feature
// because it leads to an easy-to-understand reference counting discipline (AutomaticThread holds
// strong ref to AutomaticThreadCondition and the underlying thread holds a strong ref to
// AutomaticThread).
virtual ~AutomaticThread();
// Sometimes it's possible to optimize for the case that there is no underlying thread.
bool hasUnderlyingThread(const AbstractLocker&) const { return m_hasUnderlyingThread; }
// This attempts to quickly stop the thread. This will succeed if the thread happens to not be
// running. Returns true if the thread has been stopped. A good idiom for stopping your automatic
// thread is to first try this, and if that doesn't work, to tell the thread using your own
// mechanism (set some flag and then notify the condition).
bool tryStop(const AbstractLocker&);
bool isWaiting(const AbstractLocker&);
bool notify(const AbstractLocker&);
void join();
protected:
// This logically creates the thread, but in reality the thread won't be created until someone
// calls AutomaticThreadCondition::notifyOne() or notifyAll().
AutomaticThread(const AbstractLocker&, Box<Lock>, RefPtr<AutomaticThreadCondition>);
// To understand PollResult and WorkResult, imagine that poll() and work() are being called like
// so:
//
// void AutomaticThread::runThread()
// {
// for (;;) {
// {
// LockHolder locker(m_lock);
// for (;;) {
// PollResult result = poll();
// if (result == PollResult::Work)
// break;
// if (result == PollResult::Stop)
// return;
// RELEASE_ASSERT(result == PollResult::Wait);
// m_condition.wait(m_lock);
// }
// }
//
// WorkResult result = work();
// if (result == WorkResult::Stop)
// return;
// RELEASE_ASSERT(result == WorkResult::Continue);
// }
// }
enum class PollResult { Work, Stop, Wait };
virtual PollResult poll(const AbstractLocker&) = 0;
enum class WorkResult { Continue, Stop };
virtual WorkResult work() = 0;
// It's sometimes useful to allocate resources while the thread is running, and to destroy them
// when the thread dies. These methods let you do this. You can override these methods, and you
// can be sure that the default ones don't do anything (so you don't need a super call).
virtual void threadDidStart();
virtual void threadIsStopping(const AbstractLocker&);
private:
friend class AutomaticThreadCondition;
void start(const AbstractLocker&);
Box<Lock> m_lock;
RefPtr<AutomaticThreadCondition> m_condition;
bool m_isRunning { true };
bool m_isWaiting { false };
bool m_hasUnderlyingThread { false };
Condition m_waitCondition;
Condition m_isRunningCondition;
};
} // namespace WTF
using WTF::AutomaticThread;
using WTF::AutomaticThreadCondition;
#endif // WTF_AutomaticThread_h

295
include/BackwardsGraph.h Normal file
View File

@ -0,0 +1,295 @@
/*
* 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. ``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
* 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.
*/
#ifndef WTF_BackwardsGraph_h
#define WTF_BackwardsGraph_h
#include <wtf/FastMalloc.h>
#include <wtf/GraphNodeWorklist.h>
#include <wtf/Noncopyable.h>
#include <wtf/StdLibExtras.h>
namespace WTF {
template<typename Graph>
class BackwardsGraph {
WTF_MAKE_NONCOPYABLE(BackwardsGraph);
WTF_MAKE_FAST_ALLOCATED;
public:
// We use "#end" to refer to the synthetic root we have created.
static const char* rootName() { return "#end"; };
class Node {
public:
Node(typename Graph::Node node = typename Graph::Node())
: m_node(node)
{
}
static Node root()
{
Node result;
result.m_node = 0;
result.m_isRoot = true;
return result;
}
bool operator==(const Node& other) const
{
return m_node == other.m_node
&& m_isRoot == other.m_isRoot;
}
bool operator!=(const Node& other) const
{
return !(*this == other);
}
explicit operator bool() const { return *this != Node(); }
bool isRoot() const
{
return m_isRoot;
}
typename Graph::Node node() const { return m_node; }
private:
typename Graph::Node m_node;
bool m_isRoot { false };
};
class Set {
public:
Set()
{
}
bool add(const Node& node)
{
if (node.isRoot())
return checkAndSet(m_hasRoot, true);
return m_set.add(node.node());
}
bool remove(const Node& node)
{
if (node.isRoot())
return checkAndSet(m_hasRoot, false);
return m_set.remove(node.node());
}
bool contains(const Node& node)
{
if (node.isRoot())
return m_hasRoot;
return m_set.contains(node.node());
}
void dump(PrintStream& out) const
{
if (m_hasRoot)
out.print(rootName(), " ");
out.print(m_set);
}
private:
typename Graph::Set m_set;
bool m_hasRoot { false };
};
template<typename T>
class Map {
public:
Map(Graph& graph)
: m_map(graph.template newMap<T>())
{
}
void clear()
{
m_map.clear();
m_root = T();
}
size_t size() const { return m_map.size() + 1; }
T& operator[](size_t index)
{
if (!index)
return m_root;
return m_map[index - 1];
}
const T& operator[](size_t index) const
{
return (*const_cast<Map*>(this))[index];
}
T& operator[](const Node& node)
{
if (node.isRoot())
return m_root;
return m_map[node.node()];
}
const T& operator[](const Node& node) const
{
return (*const_cast<Map*>(this))[node];
}
private:
typename Graph::template Map<T> m_map;
T m_root;
};
typedef Vector<Node, 4> List;
BackwardsGraph(Graph& graph)
: m_graph(graph)
{
GraphNodeWorklist<typename Graph::Node, typename Graph::Set> worklist;
auto addRootSuccessor = [&] (typename Graph::Node node) {
if (worklist.push(node)) {
m_rootSuccessorList.append(node);
m_rootSuccessorSet.add(node);
while (typename Graph::Node node = worklist.pop())
worklist.pushAll(graph.predecessors(node));
}
};
for (unsigned i = 0; i < graph.numNodes(); ++i) {
if (typename Graph::Node node = graph.node(i)) {
if (!graph.successors(node).size())
addRootSuccessor(node);
}
}
// At this point there will be some nodes in the graph that aren't known to the worklist. We
// could add any or all of them to the root successors list. Adding all of them would be a bad
// pessimisation. Ideally we would pick the ones that have backward edges but no forward
// edges. That would require thinking, so we just use a rough heuristic: add the highest
// numbered nodes first, which is totally fine if the input program is already sorted nicely.
for (unsigned i = graph.numNodes(); i--;) {
if (typename Graph::Node node = graph.node(i))
addRootSuccessor(node);
}
}
Node root() { return Node::root(); }
template<typename T>
Map<T> newMap() { return Map<T>(m_graph); }
List successors(const Node& node) const
{
if (node.isRoot())
return m_rootSuccessorList;
List result;
for (typename Graph::Node predecessor : m_graph.predecessors(node.node()))
result.append(predecessor);
return result;
}
List predecessors(const Node& node) const
{
if (node.isRoot())
return { };
List result;
if (m_rootSuccessorSet.contains(node.node()))
result.append(Node::root());
for (typename Graph::Node successor : m_graph.successors(node.node()))
result.append(successor);
return result;
}
unsigned index(const Node& node) const
{
if (node.isRoot())
return 0;
return m_graph.index(node.node()) + 1;
}
Node node(unsigned index) const
{
if (!index)
return Node::root();
return m_graph.node(index - 1);
}
unsigned numNodes() const
{
return m_graph.numNodes() + 1;
}
CString dump(Node node) const
{
StringPrintStream out;
if (!node)
out.print("<null>");
else if (node.isRoot())
out.print(rootName());
else
out.print(m_graph.dump(node.node()));
return out.toCString();
}
void dump(PrintStream& out) const
{
for (unsigned i = 0; i < numNodes(); ++i) {
Node node = this->node(i);
if (!node)
continue;
out.print(dump(node), ":\n");
out.print(" Preds: ");
CommaPrinter comma;
for (Node predecessor : predecessors(node))
out.print(comma, dump(predecessor));
out.print("\n");
out.print(" Succs: ");
comma = CommaPrinter();
for (Node successor : successors(node))
out.print(comma, dump(successor));
out.print("\n");
}
}
private:
Graph& m_graph;
List m_rootSuccessorList;
typename Graph::Set m_rootSuccessorSet;
};
} // namespace WTF
using WTF::BackwardsGraph;
#endif // WTF_BackwardsGraph_h

148
include/Bag.h Normal file
View File

@ -0,0 +1,148 @@
/*
* Copyright (C) 2013 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.
*/
#ifndef Bag_h
#define Bag_h
#include <wtf/FastMalloc.h>
#include <wtf/Noncopyable.h>
namespace WTF {
template<typename T>
class Bag {
WTF_MAKE_NONCOPYABLE(Bag);
WTF_MAKE_FAST_ALLOCATED;
private:
class Node {
WTF_MAKE_FAST_ALLOCATED;
public:
template<typename... Args>
Node(Args&&... args)
: m_item(std::forward<Args>(args)...)
{
}
T m_item;
Node* m_next { nullptr };
};
public:
Bag()
{
}
Bag(Bag<T>&& other)
{
ASSERT(!m_head);
m_head = other.m_head;
other.m_head = nullptr;
}
Bag& operator=(Bag<T>&& other)
{
m_head = other.m_head;
other.m_head = nullptr;
return *this;
}
~Bag()
{
clear();
}
void clear()
{
while (m_head) {
Node* current = m_head;
m_head = current->m_next;
delete current;
}
m_head = nullptr;
}
template<typename... Args>
T* add(Args&&... args)
{
Node* newNode = new Node(std::forward<Args>(args)...);
newNode->m_next = m_head;
m_head = newNode;
return &newNode->m_item;
}
class iterator {
public:
iterator()
: m_node(0)
{
}
// This is sort of cheating; it's equivalent to iter == end().
bool operator!() const { return !m_node; }
T* operator*() const { return &m_node->m_item; }
iterator& operator++()
{
m_node = m_node->m_next;
return *this;
}
bool operator==(const iterator& other) const
{
return m_node == other.m_node;
}
bool operator!=(const iterator& other) const
{
return !(*this == other);
}
private:
template<typename U> friend class WTF::Bag;
Node* m_node;
};
iterator begin()
{
iterator result;
result.m_node = m_head;
return result;
}
iterator end() { return iterator(); }
bool isEmpty() const { return !m_head; }
private:
Node* m_head { nullptr };
};
} // namespace WTF
using WTF::Bag;
#endif // Bag_h

49
include/BagToHashMap.h Normal file
View File

@ -0,0 +1,49 @@
/*
* Copyright (C) 2013, 2014 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.
*/
#ifndef BagToHashMap_h
#define BagToHashMap_h
#include <wtf/Bag.h>
#include <wtf/HashMap.h>
namespace WTF {
template<typename ElementType, typename KeyType, typename HashArg, typename KeyGetterFunctor>
void toHashMap(Bag<ElementType>& bag, KeyGetterFunctor& getKey, HashMap<KeyType, ElementType*, HashArg>& result)
{
for (typename Bag<ElementType>::iterator iter = bag.begin(); !!iter; ++iter) {
ElementType* element = *iter;
KeyType key = getKey(*element);
result.add(key, element);
}
}
} // namespace WTF
using WTF::toHashMap;
#endif // BagToHashMap_h

485
include/BitVector.h Normal file
View File

@ -0,0 +1,485 @@
/*
* Copyright (C) 2011, 2014, 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. ``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
* 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.
*/
#ifndef BitVector_h
#define BitVector_h
#include <stdio.h>
#include <wtf/Assertions.h>
#include <wtf/DataLog.h>
#include <wtf/HashFunctions.h>
#include <wtf/HashTraits.h>
#include <wtf/PrintStream.h>
#include <wtf/StdLibExtras.h>
namespace WTF {
// This is a space-efficient, resizeable bitvector class. In the common case it
// occupies one word, but if necessary, it will inflate this one word to point
// to a single chunk of out-of-line allocated storage to store an arbitrary number
// of bits.
//
// - The bitvector remembers the bound of how many bits can be stored, but this
// may be slightly greater (by as much as some platform-specific constant)
// than the last argument passed to ensureSize().
//
// - The bitvector can resize itself automatically (set, clear, get) or can be used
// in a manual mode, which is faster (quickSet, quickClear, quickGet, ensureSize).
//
// - Accesses ASSERT that you are within bounds.
//
// - Bits are automatically initialized to zero.
//
// On the other hand, this BitVector class may not be the fastest around, since
// it does conditionals on every get/set/clear. But it is great if you need to
// juggle a lot of variable-length BitVectors and you're worried about wasting
// space.
class BitVector {
public:
BitVector()
: m_bitsOrPointer(makeInlineBits(0))
{
}
explicit BitVector(size_t numBits)
: m_bitsOrPointer(makeInlineBits(0))
{
ensureSize(numBits);
}
BitVector(const BitVector& other)
: m_bitsOrPointer(makeInlineBits(0))
{
(*this) = other;
}
~BitVector()
{
if (isInline())
return;
OutOfLineBits::destroy(outOfLineBits());
}
BitVector& operator=(const BitVector& other)
{
if (isInline() && other.isInline())
m_bitsOrPointer = other.m_bitsOrPointer;
else
setSlow(other);
return *this;
}
size_t size() const
{
if (isInline())
return maxInlineBits();
return outOfLineBits()->numBits();
}
void ensureSize(size_t numBits)
{
if (numBits <= size())
return;
resizeOutOfLine(numBits);
}
// Like ensureSize(), but supports reducing the size of the bitvector.
WTF_EXPORT_PRIVATE void resize(size_t numBits);
WTF_EXPORT_PRIVATE void clearAll();
bool quickGet(size_t bit) const
{
ASSERT_WITH_SECURITY_IMPLICATION(bit < size());
return !!(bits()[bit / bitsInPointer()] & (static_cast<uintptr_t>(1) << (bit & (bitsInPointer() - 1))));
}
bool quickSet(size_t bit)
{
ASSERT_WITH_SECURITY_IMPLICATION(bit < size());
uintptr_t& word = bits()[bit / bitsInPointer()];
uintptr_t mask = static_cast<uintptr_t>(1) << (bit & (bitsInPointer() - 1));
bool result = !!(word & mask);
word |= mask;
return result;
}
bool quickClear(size_t bit)
{
ASSERT_WITH_SECURITY_IMPLICATION(bit < size());
uintptr_t& word = bits()[bit / bitsInPointer()];
uintptr_t mask = static_cast<uintptr_t>(1) << (bit & (bitsInPointer() - 1));
bool result = !!(word & mask);
word &= ~mask;
return result;
}
bool quickSet(size_t bit, bool value)
{
if (value)
return quickSet(bit);
return quickClear(bit);
}
bool get(size_t bit) const
{
if (bit >= size())
return false;
return quickGet(bit);
}
bool contains(size_t bit) const
{
return get(bit);
}
bool set(size_t bit)
{
ensureSize(bit + 1);
return quickSet(bit);
}
// This works like the add methods of sets. Instead of returning the previous value, like set(),
// it returns whether the bit transitioned from false to true.
bool add(size_t bit)
{
return !set(bit);
}
bool ensureSizeAndSet(size_t bit, size_t size)
{
ensureSize(size);
return quickSet(bit);
}
bool clear(size_t bit)
{
if (bit >= size())
return false;
return quickClear(bit);
}
bool remove(size_t bit)
{
return clear(bit);
}
bool set(size_t bit, bool value)
{
if (value)
return set(bit);
return clear(bit);
}
void merge(const BitVector& other)
{
if (!isInline() || !other.isInline()) {
mergeSlow(other);
return;
}
m_bitsOrPointer |= other.m_bitsOrPointer;
ASSERT(isInline());
}
void filter(const BitVector& other)
{
if (!isInline() || !other.isInline()) {
filterSlow(other);
return;
}
m_bitsOrPointer &= other.m_bitsOrPointer;
ASSERT(isInline());
}
void exclude(const BitVector& other)
{
if (!isInline() || !other.isInline()) {
excludeSlow(other);
return;
}
m_bitsOrPointer &= ~other.m_bitsOrPointer;
m_bitsOrPointer |= (static_cast<uintptr_t>(1) << maxInlineBits());
ASSERT(isInline());
}
size_t bitCount() const
{
if (isInline())
return bitCount(cleanseInlineBits(m_bitsOrPointer));
return bitCountSlow();
}
size_t findBit(size_t index, bool value) const
{
size_t result = findBitFast(index, value);
if (!ASSERT_DISABLED) {
size_t expectedResult = findBitSimple(index, value);
if (result != expectedResult) {
dataLog("findBit(", index, ", ", value, ") on ", *this, " should have gotten ", expectedResult, " but got ", result, "\n");
ASSERT_NOT_REACHED();
}
}
return result;
}
WTF_EXPORT_PRIVATE void dump(PrintStream& out) const;
enum EmptyValueTag { EmptyValue };
enum DeletedValueTag { DeletedValue };
BitVector(EmptyValueTag)
: m_bitsOrPointer(0)
{
}
BitVector(DeletedValueTag)
: m_bitsOrPointer(1)
{
}
bool isEmptyValue() const { return !m_bitsOrPointer; }
bool isDeletedValue() const { return m_bitsOrPointer == 1; }
bool isEmptyOrDeletedValue() const { return m_bitsOrPointer <= 1; }
bool operator==(const BitVector& other) const
{
if (isInline() && other.isInline())
return m_bitsOrPointer == other.m_bitsOrPointer;
return equalsSlowCase(other);
}
unsigned hash() const
{
// This is a very simple hash. Just xor together the words that hold the various
// bits and then compute the hash. This makes it very easy to deal with bitvectors
// that have a lot of trailing zero's.
uintptr_t value;
if (isInline())
value = cleanseInlineBits(m_bitsOrPointer);
else
value = hashSlowCase();
return IntHash<uintptr_t>::hash(value);
}
class iterator {
public:
iterator()
: m_bitVector(nullptr)
, m_index(0)
{
}
iterator(const BitVector& bitVector, size_t index)
: m_bitVector(&bitVector)
, m_index(index)
{
}
size_t operator*() const { return m_index; }
iterator& operator++()
{
m_index = m_bitVector->findBit(m_index + 1, true);
return *this;
}
bool isAtEnd() const
{
return m_index >= m_bitVector->size();
}
bool operator==(const iterator& other) const
{
return m_index == other.m_index;
}
bool operator!=(const iterator& other) const
{
return !(*this == other);
}
private:
const BitVector* m_bitVector;
size_t m_index;
};
// Use this to iterate over set bits.
iterator begin() const { return iterator(*this, findBit(0, true)); }
iterator end() const { return iterator(*this, size()); }
private:
static unsigned bitsInPointer()
{
return sizeof(void*) << 3;
}
static unsigned maxInlineBits()
{
return bitsInPointer() - 1;
}
static size_t byteCount(size_t bitCount)
{
return (bitCount + 7) >> 3;
}
static uintptr_t makeInlineBits(uintptr_t bits)
{
ASSERT(!(bits & (static_cast<uintptr_t>(1) << maxInlineBits())));
return bits | (static_cast<uintptr_t>(1) << maxInlineBits());
}
static uintptr_t cleanseInlineBits(uintptr_t bits)
{
return bits & ~(static_cast<uintptr_t>(1) << maxInlineBits());
}
static size_t bitCount(uintptr_t bits)
{
if (sizeof(uintptr_t) == 4)
return WTF::bitCount(static_cast<unsigned>(bits));
return WTF::bitCount(static_cast<uint64_t>(bits));
}
size_t findBitFast(size_t startIndex, bool value) const
{
if (isInline()) {
size_t index = startIndex;
findBitInWord(m_bitsOrPointer, index, maxInlineBits(), value);
return index;
}
const OutOfLineBits* bits = outOfLineBits();
// value = true: casts to 1, then xors to 0, then negates to 0.
// value = false: casts to 0, then xors to 1, then negates to -1 (i.e. all one bits).
uintptr_t skipValue = -(static_cast<uintptr_t>(value) ^ 1);
size_t numWords = bits->numWords();
size_t wordIndex = startIndex / bitsInPointer();
size_t startIndexInWord = startIndex - wordIndex * bitsInPointer();
while (wordIndex < numWords) {
uintptr_t word = bits->bits()[wordIndex];
if (word != skipValue) {
size_t index = startIndexInWord;
if (findBitInWord(word, index, bitsInPointer(), value))
return wordIndex * bitsInPointer() + index;
}
wordIndex++;
startIndexInWord = 0;
}
return bits->numBits();
}
size_t findBitSimple(size_t index, bool value) const
{
while (index < size()) {
if (get(index) == value)
return index;
index++;
}
return size();
}
class OutOfLineBits {
public:
size_t numBits() const { return m_numBits; }
size_t numWords() const { return (m_numBits + bitsInPointer() - 1) / bitsInPointer(); }
uintptr_t* bits() { return bitwise_cast<uintptr_t*>(this + 1); }
const uintptr_t* bits() const { return bitwise_cast<const uintptr_t*>(this + 1); }
static WTF_EXPORT_PRIVATE OutOfLineBits* create(size_t numBits);
static WTF_EXPORT_PRIVATE void destroy(OutOfLineBits*);
private:
OutOfLineBits(size_t numBits)
: m_numBits(numBits)
{
}
size_t m_numBits;
};
bool isInline() const { return m_bitsOrPointer >> maxInlineBits(); }
const OutOfLineBits* outOfLineBits() const { return bitwise_cast<const OutOfLineBits*>(m_bitsOrPointer << 1); }
OutOfLineBits* outOfLineBits() { return bitwise_cast<OutOfLineBits*>(m_bitsOrPointer << 1); }
WTF_EXPORT_PRIVATE void resizeOutOfLine(size_t numBits);
WTF_EXPORT_PRIVATE void setSlow(const BitVector& other);
WTF_EXPORT_PRIVATE void mergeSlow(const BitVector& other);
WTF_EXPORT_PRIVATE void filterSlow(const BitVector& other);
WTF_EXPORT_PRIVATE void excludeSlow(const BitVector& other);
WTF_EXPORT_PRIVATE size_t bitCountSlow() const;
WTF_EXPORT_PRIVATE bool equalsSlowCase(const BitVector& other) const;
bool equalsSlowCaseFast(const BitVector& other) const;
bool equalsSlowCaseSimple(const BitVector& other) const;
WTF_EXPORT_PRIVATE uintptr_t hashSlowCase() const;
uintptr_t* bits()
{
if (isInline())
return &m_bitsOrPointer;
return outOfLineBits()->bits();
}
const uintptr_t* bits() const
{
if (isInline())
return &m_bitsOrPointer;
return outOfLineBits()->bits();
}
uintptr_t m_bitsOrPointer;
};
struct BitVectorHash {
static unsigned hash(const BitVector& vector) { return vector.hash(); }
static bool equal(const BitVector& a, const BitVector& b) { return a == b; }
static const bool safeToCompareToEmptyOrDeleted = false;
};
template<typename T> struct DefaultHash;
template<> struct DefaultHash<BitVector> {
typedef BitVectorHash Hash;
};
template<typename T> struct HashTraits;
template<> struct HashTraits<BitVector> : public CustomHashTraits<BitVector> { };
} // namespace WTF
using WTF::BitVector;
#endif // BitVector_h

401
include/Bitmap.h Normal file
View File

@ -0,0 +1,401 @@
/*
* Copyright (C) 2010-2017 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
*/
#ifndef Bitmap_h
#define Bitmap_h
#include <array>
#include <wtf/Atomics.h>
#include <wtf/StdLibExtras.h>
#include <stdint.h>
#include <string.h>
namespace WTF {
template<size_t bitmapSize, typename WordType = uint32_t>
class Bitmap {
WTF_MAKE_FAST_ALLOCATED;
static_assert(sizeof(WordType) <= sizeof(unsigned), "WordType must not be bigger than unsigned");
public:
Bitmap();
static constexpr size_t size()
{
return bitmapSize;
}
bool get(size_t, Dependency = nullDependency()) const;
void set(size_t);
void set(size_t, bool);
bool testAndSet(size_t);
bool testAndClear(size_t);
bool concurrentTestAndSet(size_t, Dependency = nullDependency());
bool concurrentTestAndClear(size_t, Dependency = nullDependency());
size_t nextPossiblyUnset(size_t) const;
void clear(size_t);
void clearAll();
int64_t findRunOfZeros(size_t runLength) const;
size_t count(size_t start = 0) const;
size_t isEmpty() const;
size_t isFull() const;
void merge(const Bitmap&);
void filter(const Bitmap&);
void exclude(const Bitmap&);
bool subsumes(const Bitmap&) const;
template<typename Func>
void forEachSetBit(const Func&) const;
size_t findBit(size_t startIndex, bool value) const;
class iterator {
public:
iterator()
: m_bitmap(nullptr)
, m_index(0)
{
}
iterator(const Bitmap& bitmap, size_t index)
: m_bitmap(&bitmap)
, m_index(index)
{
}
size_t operator*() const { return m_index; }
iterator& operator++()
{
m_index = m_bitmap->findBit(m_index + 1, true);
return *this;
}
bool operator==(const iterator& other) const
{
return m_index == other.m_index;
}
bool operator!=(const iterator& other) const
{
return !(*this == other);
}
private:
const Bitmap* m_bitmap;
size_t m_index;
};
// Use this to iterate over set bits.
iterator begin() const { return iterator(*this, findBit(0, true)); }
iterator end() const { return iterator(*this, bitmapSize); }
void mergeAndClear(Bitmap&);
void setAndClear(Bitmap&);
bool operator==(const Bitmap&) const;
bool operator!=(const Bitmap&) const;
unsigned hash() const;
private:
static const unsigned wordSize = sizeof(WordType) * 8;
static const unsigned words = (bitmapSize + wordSize - 1) / wordSize;
// the literal '1' is of type signed int. We want to use an unsigned
// version of the correct size when doing the calculations because if
// WordType is larger than int, '1 << 31' will first be sign extended
// and then casted to unsigned, meaning that set(31) when WordType is
// a 64 bit unsigned int would give 0xffff8000
static const WordType one = 1;
std::array<WordType, words> bits;
};
template<size_t bitmapSize, typename WordType>
inline Bitmap<bitmapSize, WordType>::Bitmap()
{
clearAll();
}
template<size_t bitmapSize, typename WordType>
inline bool Bitmap<bitmapSize, WordType>::get(size_t n, Dependency dependency) const
{
return !!(bits[n / wordSize + dependency] & (one << (n % wordSize)));
}
template<size_t bitmapSize, typename WordType>
inline void Bitmap<bitmapSize, WordType>::set(size_t n)
{
bits[n / wordSize] |= (one << (n % wordSize));
}
template<size_t bitmapSize, typename WordType>
inline void Bitmap<bitmapSize, WordType>::set(size_t n, bool value)
{
if (value)
set(n);
else
clear(n);
}
template<size_t bitmapSize, typename WordType>
inline bool Bitmap<bitmapSize, WordType>::testAndSet(size_t n)
{
WordType mask = one << (n % wordSize);
size_t index = n / wordSize;
bool result = bits[index] & mask;
bits[index] |= mask;
return result;
}
template<size_t bitmapSize, typename WordType>
inline bool Bitmap<bitmapSize, WordType>::testAndClear(size_t n)
{
WordType mask = one << (n % wordSize);
size_t index = n / wordSize;
bool result = bits[index] & mask;
bits[index] &= ~mask;
return result;
}
template<size_t bitmapSize, typename WordType>
ALWAYS_INLINE bool Bitmap<bitmapSize, WordType>::concurrentTestAndSet(size_t n, Dependency dependency)
{
WordType mask = one << (n % wordSize);
size_t index = n / wordSize;
WordType* data = bits.data() + index + dependency;
return !bitwise_cast<Atomic<WordType>*>(data)->transactionRelaxed(
[&] (WordType& value) -> bool {
if (value & mask)
return false;
value |= mask;
return true;
});
}
template<size_t bitmapSize, typename WordType>
ALWAYS_INLINE bool Bitmap<bitmapSize, WordType>::concurrentTestAndClear(size_t n, Dependency dependency)
{
WordType mask = one << (n % wordSize);
size_t index = n / wordSize;
WordType* data = bits.data() + index + dependency;
return !bitwise_cast<Atomic<WordType>*>(data)->transactionRelaxed(
[&] (WordType& value) -> bool {
if (!(value & mask))
return false;
value &= ~mask;
return true;
});
}
template<size_t bitmapSize, typename WordType>
inline void Bitmap<bitmapSize, WordType>::clear(size_t n)
{
bits[n / wordSize] &= ~(one << (n % wordSize));
}
template<size_t bitmapSize, typename WordType>
inline void Bitmap<bitmapSize, WordType>::clearAll()
{
memset(bits.data(), 0, sizeof(bits));
}
template<size_t bitmapSize, typename WordType>
inline size_t Bitmap<bitmapSize, WordType>::nextPossiblyUnset(size_t start) const
{
if (!~bits[start / wordSize])
return ((start / wordSize) + 1) * wordSize;
return start + 1;
}
template<size_t bitmapSize, typename WordType>
inline int64_t Bitmap<bitmapSize, WordType>::findRunOfZeros(size_t runLength) const
{
if (!runLength)
runLength = 1;
for (size_t i = 0; i <= (bitmapSize - runLength) ; i++) {
bool found = true;
for (size_t j = i; j <= (i + runLength - 1) ; j++) {
if (get(j)) {
found = false;
break;
}
}
if (found)
return i;
}
return -1;
}
template<size_t bitmapSize, typename WordType>
inline size_t Bitmap<bitmapSize, WordType>::count(size_t start) const
{
size_t result = 0;
for ( ; (start % wordSize); ++start) {
if (get(start))
++result;
}
for (size_t i = start / wordSize; i < words; ++i)
result += WTF::bitCount(static_cast<unsigned>(bits[i]));
return result;
}
template<size_t bitmapSize, typename WordType>
inline size_t Bitmap<bitmapSize, WordType>::isEmpty() const
{
for (size_t i = 0; i < words; ++i)
if (bits[i])
return false;
return true;
}
template<size_t bitmapSize, typename WordType>
inline size_t Bitmap<bitmapSize, WordType>::isFull() const
{
for (size_t i = 0; i < words; ++i)
if (~bits[i])
return false;
return true;
}
template<size_t bitmapSize, typename WordType>
inline void Bitmap<bitmapSize, WordType>::merge(const Bitmap& other)
{
for (size_t i = 0; i < words; ++i)
bits[i] |= other.bits[i];
}
template<size_t bitmapSize, typename WordType>
inline void Bitmap<bitmapSize, WordType>::filter(const Bitmap& other)
{
for (size_t i = 0; i < words; ++i)
bits[i] &= other.bits[i];
}
template<size_t bitmapSize, typename WordType>
inline void Bitmap<bitmapSize, WordType>::exclude(const Bitmap& other)
{
for (size_t i = 0; i < words; ++i)
bits[i] &= ~other.bits[i];
}
template<size_t bitmapSize, typename WordType>
inline bool Bitmap<bitmapSize, WordType>::subsumes(const Bitmap& other) const
{
for (size_t i = 0; i < words; ++i) {
WordType myBits = bits[i];
WordType otherBits = other.bits[i];
if ((myBits | otherBits) != myBits)
return false;
}
return true;
}
template<size_t bitmapSize, typename WordType>
template<typename Func>
inline void Bitmap<bitmapSize, WordType>::forEachSetBit(const Func& func) const
{
for (size_t i = 0; i < words; ++i) {
WordType word = bits[i];
if (!word)
continue;
size_t base = i * wordSize;
for (size_t j = 0; j < wordSize; ++j) {
if (word & 1)
func(base + j);
word >>= 1;
}
}
}
template<size_t bitmapSize, typename WordType>
inline size_t Bitmap<bitmapSize, WordType>::findBit(size_t startIndex, bool value) const
{
WordType skipValue = -(static_cast<WordType>(value) ^ 1);
size_t wordIndex = startIndex / wordSize;
size_t startIndexInWord = startIndex - wordIndex * wordSize;
while (wordIndex < words) {
WordType word = bits[wordIndex];
if (word != skipValue) {
size_t index = startIndexInWord;
if (findBitInWord(word, index, wordSize, value))
return wordIndex * wordSize + index;
}
wordIndex++;
startIndexInWord = 0;
}
return bitmapSize;
}
template<size_t bitmapSize, typename WordType>
inline void Bitmap<bitmapSize, WordType>::mergeAndClear(Bitmap& other)
{
for (size_t i = 0; i < words; ++i) {
bits[i] |= other.bits[i];
other.bits[i] = 0;
}
}
template<size_t bitmapSize, typename WordType>
inline void Bitmap<bitmapSize, WordType>::setAndClear(Bitmap& other)
{
for (size_t i = 0; i < words; ++i) {
bits[i] = other.bits[i];
other.bits[i] = 0;
}
}
template<size_t bitmapSize, typename WordType>
inline bool Bitmap<bitmapSize, WordType>::operator==(const Bitmap& other) const
{
for (size_t i = 0; i < words; ++i) {
if (bits[i] != other.bits[i])
return false;
}
return true;
}
template<size_t bitmapSize, typename WordType>
inline bool Bitmap<bitmapSize, WordType>::operator!=(const Bitmap& other) const
{
return !(*this == other);
}
template<size_t bitmapSize, typename WordType>
inline unsigned Bitmap<bitmapSize, WordType>::hash() const
{
unsigned result = 0;
for (size_t i = 0; i < words; ++i)
result ^= IntHash<WordType>::hash(bits[i]);
return result;
}
} // namespace WTF
using WTF::Bitmap;
#endif

View File

@ -0,0 +1,32 @@
/*
* Copyright (C) 2003, 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. ``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
* 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.
*/
#import <Foundation/NSException.h>
WTF_EXPORT_PRIVATE NO_RETURN_DUE_TO_ASSERT void ReportBlockedObjCException(NSException *);
#define BEGIN_BLOCK_OBJC_EXCEPTIONS @try {
#define END_BLOCK_OBJC_EXCEPTIONS } @catch(NSException *localException) { ReportBlockedObjCException(localException); }

170
include/BlockPtr.h Normal file
View File

@ -0,0 +1,170 @@
/*
* 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 <utility>
#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;

96
include/BlockStack.h Normal file
View File

@ -0,0 +1,96 @@
/*
* Copyright (C) 2011 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.
*/
#ifndef BlockStack_h
#define BlockStack_h
#include <wtf/Assertions.h>
#include <wtf/FastMalloc.h>
#include <wtf/Vector.h>
namespace WTF {
template <typename T> class BlockStack {
public:
static const size_t blockSize = 4096;
static const size_t blockLength = blockSize / sizeof(T);
BlockStack();
~BlockStack();
T* grow();
void shrink(T*);
const Vector<T*>& blocks();
private:
Vector<T*> m_blocks;
T* m_spareBlock; // Used to avoid thrash at block boundaries.
};
template <typename T> BlockStack<T>::BlockStack()
: m_spareBlock(0)
{
}
template <typename T> BlockStack<T>::~BlockStack()
{
if (m_spareBlock)
fastFree(m_spareBlock);
for (size_t i = 0; i < m_blocks.size(); ++i)
fastFree(m_blocks[i]);
}
template <typename T> inline const Vector<T*>& BlockStack<T>::blocks()
{
return m_blocks;
}
template <typename T> T* BlockStack<T>::grow()
{
T* block = m_spareBlock ? m_spareBlock : static_cast<T*>(fastMalloc(blockSize));
m_spareBlock = 0;
m_blocks.append(block);
return block;
}
template <typename T> void BlockStack<T>::shrink(T* newEnd)
{
ASSERT(newEnd != m_blocks.last() + blockLength);
m_spareBlock = m_blocks.last();
m_blocks.removeLast();
while (m_blocks.last() + blockLength != newEnd) {
fastFree(m_blocks.last());
m_blocks.removeLast();
}
}
}
using WTF::BlockStack;
#endif

267
include/BloomFilter.h Normal file
View File

@ -0,0 +1,267 @@
/*
* Copyright (C) 2011, 2015 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.
*/
#ifndef BloomFilter_h
#define BloomFilter_h
#include <array>
#include <wtf/text/AtomicString.h>
namespace WTF {
// Bloom filter with k=2. Uses 2^keyBits/8 bytes of memory.
// False positive rate is approximately (1-e^(-2n/m))^2, where n is the number of unique
// keys and m is the table size (==2^keyBits).
// See http://en.wikipedia.org/wiki/Bloom_filter
template <unsigned keyBits>
class BloomFilter {
WTF_MAKE_FAST_ALLOCATED;
public:
static const size_t tableSize = 1 << keyBits;
BloomFilter();
void add(unsigned hash);
// For example SHA1::Digest.
template <size_t hashSize> void add(const std::array<uint8_t, hashSize>&);
void add(const BloomFilter&);
// The filter may give false positives (claim it may contain a key it doesn't)
// but never false negatives (claim it doesn't contain a key it does).
bool mayContain(unsigned hash) const;
template <size_t hashSize> bool mayContain(const std::array<uint8_t, hashSize>&) const;
void clear();
void add(const AtomicString& string) { add(string.impl()->existingHash()); }
void add(const String& string) { add(string.impl()->hash()); }
bool mayContain(const AtomicString& string) const { return mayContain(string.impl()->existingHash()); }
bool mayContain(const String& string) const { return mayContain(string.impl()->hash()); }
private:
static const unsigned bitsPerPosition = 8 * sizeof(unsigned);
static const unsigned keyMask = (1 << keyBits) - 1;
static unsigned arrayIndex(unsigned key) { return key / bitsPerPosition; }
static unsigned bitMask(unsigned key) { return 1 << (key % bitsPerPosition); }
template <size_t hashSize> static std::pair<unsigned, unsigned> keysFromHash(const std::array<uint8_t, hashSize>&);
bool isBitSet(unsigned key) const;
void setBit(unsigned key);
std::array<unsigned, tableSize / bitsPerPosition> m_bitArray;
};
template <unsigned keyBits>
inline BloomFilter<keyBits>::BloomFilter()
: m_bitArray()
{
}
template <unsigned keyBits>
inline bool BloomFilter<keyBits>::mayContain(unsigned hash) const
{
// The top and bottom bits of the incoming hash are treated as independent bloom filter hash functions.
// This works well as long as the filter size is not much above 2^16.
return isBitSet(hash) && isBitSet(hash >> 16);
}
template <unsigned keyBits>
inline void BloomFilter<keyBits>::add(unsigned hash)
{
setBit(hash);
setBit(hash >> 16);
}
template <unsigned keyBits>
template <size_t hashSize>
inline std::pair<unsigned, unsigned> BloomFilter<keyBits>::keysFromHash(const std::array<uint8_t, hashSize>& hash)
{
// We could use larger k value than 2 for long hashes.
static_assert(hashSize >= 2 * sizeof(unsigned), "Hash array too short");
return {
*reinterpret_cast<const unsigned*>(hash.data()),
*reinterpret_cast<const unsigned*>(hash.data() + sizeof(unsigned))
};
}
template <unsigned keyBits>
template <size_t hashSize>
inline bool BloomFilter<keyBits>::mayContain(const std::array<uint8_t, hashSize>& hash) const
{
auto keys = keysFromHash(hash);
return isBitSet(keys.first) && isBitSet(keys.second);
}
template <unsigned keyBits>
template <size_t hashSize>
inline void BloomFilter<keyBits>::add(const std::array<uint8_t, hashSize>& hash)
{
auto keys = keysFromHash(hash);
setBit(keys.first);
setBit(keys.second);
}
template <unsigned keyBits>
inline void BloomFilter<keyBits>::add(const BloomFilter& other)
{
for (size_t i = 0; i < m_bitArray.size(); ++i)
m_bitArray[i] |= other.m_bitArray[i];
}
template <unsigned keyBits>
bool BloomFilter<keyBits>::isBitSet(unsigned key) const
{
unsigned maskedKey = key & keyMask;
ASSERT(arrayIndex(maskedKey) < m_bitArray.size());
return m_bitArray[arrayIndex(maskedKey)] & bitMask(maskedKey);
}
template <unsigned keyBits>
void BloomFilter<keyBits>::setBit(unsigned key)
{
unsigned maskedKey = key & keyMask;
ASSERT(arrayIndex(maskedKey) < m_bitArray.size());
m_bitArray[arrayIndex(maskedKey)] |= bitMask(maskedKey);
}
template <unsigned keyBits>
inline void BloomFilter<keyBits>::clear()
{
m_bitArray.fill(0);
}
// Counting bloom filter with 8 bit counters. Uses 2^keyBits bytes of memory. Error rates as above.
// See http://en.wikipedia.org/wiki/Bloom_filter#Counting_filters
template <unsigned keyBits>
class CountingBloomFilter {
WTF_MAKE_FAST_ALLOCATED;
public:
static const size_t tableSize = 1 << keyBits;
static unsigned maximumCount() { return std::numeric_limits<uint8_t>::max(); }
CountingBloomFilter();
void add(unsigned hash);
void remove(unsigned hash);
// The filter may give false positives (claim it may contain a key it doesn't)
// but never false negatives (claim it doesn't contain a key it does).
bool mayContain(unsigned hash) const { return firstBucket(hash) && secondBucket(hash); }
// The filter must be cleared before reuse even if all keys are removed.
// Otherwise overflowed keys will stick around.
void clear();
void add(const AtomicString& string) { add(string.impl()->existingHash()); }
void add(const String& string) { add(string.impl()->hash()); }
void remove(const AtomicString& string) { remove(string.impl()->existingHash()); }
void remove(const String& string) { remove(string.impl()->hash()); }
bool mayContain(const AtomicString& string) const { return mayContain(string.impl()->existingHash()); }
bool mayContain(const String& string) const { return mayContain(string.impl()->hash()); }
#if !ASSERT_DISABLED
// Slow.
bool likelyEmpty() const;
bool isClear() const;
#endif
private:
static const unsigned keyMask = (1 << keyBits) - 1;
uint8_t& firstBucket(unsigned hash) { return m_buckets[hash & keyMask]; }
uint8_t& secondBucket(unsigned hash) { return m_buckets[(hash >> 16) & keyMask]; }
const uint8_t& firstBucket(unsigned hash) const { return m_buckets[hash & keyMask]; }
const uint8_t& secondBucket(unsigned hash) const { return m_buckets[(hash >> 16) & keyMask]; }
std::array<uint8_t, tableSize> m_buckets;
};
template <unsigned keyBits>
inline CountingBloomFilter<keyBits>::CountingBloomFilter()
: m_buckets()
{
}
template <unsigned keyBits>
inline void CountingBloomFilter<keyBits>::add(unsigned hash)
{
auto& first = firstBucket(hash);
auto& second = secondBucket(hash);
if (LIKELY(first < maximumCount()))
++first;
if (LIKELY(second < maximumCount()))
++second;
}
template <unsigned keyBits>
inline void CountingBloomFilter<keyBits>::remove(unsigned hash)
{
auto& first = firstBucket(hash);
auto& second = secondBucket(hash);
ASSERT(first);
ASSERT(second);
// In case of an overflow, the bucket sticks in the table until clear().
if (LIKELY(first < maximumCount()))
--first;
if (LIKELY(second < maximumCount()))
--second;
}
template <unsigned keyBits>
inline void CountingBloomFilter<keyBits>::clear()
{
m_buckets.fill(0);
}
#if !ASSERT_DISABLED
template <unsigned keyBits>
bool CountingBloomFilter<keyBits>::likelyEmpty() const
{
for (auto& bucket : m_buckets) {
if (bucket && bucket != maximumCount())
return false;
}
return true;
}
template <unsigned keyBits>
bool CountingBloomFilter<keyBits>::isClear() const
{
for (auto& bucket : m_buckets) {
if (bucket)
return false;
}
return true;
}
#endif
}
using WTF::BloomFilter;
using WTF::CountingBloomFilter;
#endif

81
include/Box.h Normal file
View File

@ -0,0 +1,81 @@
/*
* Copyright (C) 2015 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. ``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
* 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.
*/
#ifndef WTF_Box_h
#define WTF_Box_h
#include <wtf/RefPtr.h>
#include <wtf/ThreadSafeRefCounted.h>
namespace WTF {
// Box<T> is a reference-counted pointer to T that allocates T using FastMalloc and prepends a reference
// count to it.
template<typename T>
class Box {
public:
Box()
{
}
Box(std::nullptr_t)
{
}
template<typename... Arguments>
static Box create(Arguments&&... arguments)
{
Box result;
result.m_data = adoptRef(new Data(std::forward<Arguments>(arguments)...));
return result;
}
T* get() const { return &m_data->value; }
T& operator*() const { return m_data->value; }
T* operator->() const { return &m_data->value; }
explicit operator bool() { return m_data; }
private:
struct Data : ThreadSafeRefCounted<Data> {
template<typename... Arguments>
Data(Arguments&&... arguments)
: value(std::forward<Arguments>(arguments)...)
{
}
T value;
};
RefPtr<Data> m_data;
};
} // namespace WTF
using WTF::Box;
#endif // WTF_Box_h

2488
include/Brigand.h Normal file

File diff suppressed because it is too large Load Diff

102
include/BubbleSort.h Normal file
View File

@ -0,0 +1,102 @@
/*
* Copyright (C) 2015 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. ``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
* 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.
*/
#ifndef BubbleSort_h
#define BubbleSort_h
namespace WTF {
// Why would you want to use bubble sort? When you know that your input is already mostly
// sorted! This sort is guaranteed stable (it won't reorder elements that were equal), it
// doesn't require any scratch memory, and is the fastest available sorting algorithm if your
// input already happens to be sorted. This sort is also likely to have competetive performance
// for small inputs, even if they are very unsorted.
// We use this sorting algorithm for compiler insertion sets. An insertion set is usually very
// nearly sorted. It shouldn't take more than a few bubbles to make it fully sorted. We made
// this decision deliberately. Here's the performance of the testb3 Complex(64, 384) benchmark
// with the Air::InsertionSet doing no sorting, std::stable_sorting, and bubbleSorting:
//
// no sort: 8.8222 +- 0.1911 ms.
// std::stable_sort: 9.0135 +- 0.1418 ms.
// bubbleSort: 8.8457 +- 0.1511 ms.
//
// Clearly, bubble sort is superior.
//
// Note that the critical piece here is that insertion sets tend to be small, they must be
// sorted, the sort must be stable, they are usually already sorted to begin with, and when they
// are unsorted it's usually because of a few out-of-place elements.
template<typename IteratorType, typename LessThan>
void bubbleSort(IteratorType begin, IteratorType end, const LessThan& lessThan)
{
for (;;) {
bool changed = false;
ASSERT(end >= begin);
size_t limit = end - begin;
for (size_t i = limit; i-- > 1;) {
if (lessThan(begin[i], begin[i - 1])) {
std::swap(begin[i], begin[i - 1]);
changed = true;
}
}
if (!changed)
return;
// After one run, the first element in the list is guaranteed to be the smallest.
begin++;
// Now go in the other direction. This eliminates most sorting pathologies.
changed = false;
ASSERT(end >= begin);
limit = end - begin;
for (size_t i = 1; i < limit; ++i) {
if (lessThan(begin[i], begin[i - 1])) {
std::swap(begin[i], begin[i - 1]);
changed = true;
}
}
if (!changed)
return;
// Now the last element is guaranteed to be the largest.
end--;
}
}
template<typename IteratorType>
void bubbleSort(IteratorType begin, IteratorType end)
{
bubbleSort(
begin, end,
[](auto& left, auto& right) {
return left < right;
});
}
} // namespace WTF
using WTF::bubbleSort;
#endif // BubbleSort_h

View File

@ -0,0 +1,252 @@
/*
* Copyright (C) 2010 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. ``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
* 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.
*/
#ifndef BumpPointerAllocator_h
#define BumpPointerAllocator_h
#include <algorithm>
#include <wtf/PageAllocation.h>
#include <wtf/PageBlock.h>
namespace WTF {
#define MINIMUM_BUMP_POOL_SIZE 0x1000
class BumpPointerPool {
public:
// ensureCapacity will check whether the current pool has capacity to
// allocate 'size' bytes of memory If it does not, it will attempt to
// allocate a new pool (which will be added to this one in a chain).
//
// If allocation fails (out of memory) this method will return null.
// If the return value is non-null, then callers should update any
// references they have to this current (possibly full) BumpPointerPool
// to instead point to the newly returned BumpPointerPool.
BumpPointerPool* ensureCapacity(size_t size)
{
void* allocationEnd = static_cast<char*>(m_current) + size;
ASSERT_WITH_SECURITY_IMPLICATION(allocationEnd > m_current); // check for overflow
if (allocationEnd <= static_cast<void*>(this))
return this;
return ensureCapacityCrossPool(this, size);
}
// alloc should only be called after calling ensureCapacity; as such
// alloc will never fail.
void* alloc(size_t size)
{
void* current = m_current;
void* allocationEnd = static_cast<char*>(current) + size;
ASSERT_WITH_SECURITY_IMPLICATION(allocationEnd > current); // check for overflow
ASSERT(allocationEnd <= static_cast<void*>(this));
m_current = allocationEnd;
return current;
}
// The dealloc method releases memory allocated using alloc. Memory
// must be released in a LIFO fashion, e.g. if the client calls alloc
// four times, returning pointer A, B, C, D, then the only valid order
// in which these may be deallocaed is D, C, B, A.
//
// The client may optionally skip some deallocations. In the example
// above, it would be valid to only explicitly dealloc C, A (D being
// dealloced along with C, B along with A).
//
// If pointer was not allocated from this pool (or pools) then dealloc
// will CRASH(). Callers should update any references they have to
// this current BumpPointerPool to instead point to the returned
// BumpPointerPool.
BumpPointerPool* dealloc(void* position)
{
if ((position >= m_start) && (position <= static_cast<void*>(this))) {
ASSERT(position <= m_current);
m_current = position;
return this;
}
return deallocCrossPool(this, position);
}
private:
// Placement operator new, returns the last 'size' bytes of allocation for use as this.
void* operator new(size_t size, const PageAllocation& allocation)
{
ASSERT(size < allocation.size());
return reinterpret_cast<char*>(reinterpret_cast<intptr_t>(allocation.base()) + allocation.size()) - size;
}
BumpPointerPool(const PageAllocation& allocation)
: m_current(allocation.base())
, m_start(allocation.base())
, m_next(0)
, m_previous(0)
, m_allocation(allocation)
{
}
static BumpPointerPool* create(size_t minimumCapacity = 0)
{
// Add size of BumpPointerPool object, check for overflow.
minimumCapacity += sizeof(BumpPointerPool);
if (minimumCapacity < sizeof(BumpPointerPool))
return 0;
size_t poolSize = std::max(static_cast<size_t>(MINIMUM_BUMP_POOL_SIZE), WTF::pageSize());
while (poolSize < minimumCapacity) {
poolSize <<= 1;
// The following if check relies on MINIMUM_BUMP_POOL_SIZE being a power of 2!
ASSERT(!(MINIMUM_BUMP_POOL_SIZE & (MINIMUM_BUMP_POOL_SIZE - 1)));
if (!poolSize)
return 0;
}
PageAllocation allocation = PageAllocation::allocate(poolSize);
if (!!allocation)
return new (allocation) BumpPointerPool(allocation);
return 0;
}
void shrink()
{
ASSERT(!m_previous);
m_current = m_start;
while (m_next) {
BumpPointerPool* nextNext = m_next->m_next;
m_next->destroy();
m_next = nextNext;
}
}
void destroy()
{
m_allocation.deallocate();
}
static BumpPointerPool* ensureCapacityCrossPool(BumpPointerPool* previousPool, size_t size)
{
// The pool passed should not have capacity, so we'll start with the next one.
ASSERT(previousPool);
ASSERT((static_cast<char*>(previousPool->m_current) + size) > previousPool->m_current); // check for overflow
ASSERT((static_cast<char*>(previousPool->m_current) + size) > static_cast<void*>(previousPool));
BumpPointerPool* pool = previousPool->m_next;
while (true) {
if (!pool) {
// We've run to the end; allocate a new pool.
pool = BumpPointerPool::create(size);
previousPool->m_next = pool;
pool->m_previous = previousPool;
return pool;
}
//
void* current = pool->m_current;
void* allocationEnd = static_cast<char*>(current) + size;
ASSERT_WITH_SECURITY_IMPLICATION(allocationEnd > current); // check for overflow
if (allocationEnd <= static_cast<void*>(pool))
return pool;
}
}
static BumpPointerPool* deallocCrossPool(BumpPointerPool* pool, void* position)
{
// Should only be called if position is not in the current pool.
ASSERT((position < pool->m_start) || (position > static_cast<void*>(pool)));
while (true) {
// Unwind the current pool to the start, move back in the chain to the previous pool.
pool->m_current = pool->m_start;
pool = pool->m_previous;
// position was nowhere in the chain!
if (!pool)
CRASH();
if ((position >= pool->m_start) && (position <= static_cast<void*>(pool))) {
ASSERT(position <= pool->m_current);
pool->m_current = position;
return pool;
}
}
}
void* m_current;
void* m_start;
BumpPointerPool* m_next;
BumpPointerPool* m_previous;
PageAllocation m_allocation;
friend class BumpPointerAllocator;
};
// A BumpPointerAllocator manages a set of BumpPointerPool objects, which
// can be used for LIFO (stack like) allocation.
//
// To begin allocating using this class call startAllocator(). The result
// of this method will be null if the initial pool allocation fails, or a
// pointer to a BumpPointerPool object that can be used to perform
// allocations. Whilst running no memory will be released until
// stopAllocator() is called. At this point all allocations made through
// this allocator will be reaped, and underlying memory may be freed.
//
// (In practice we will still hold on to the initial pool to allow allocation
// to be quickly restared, but aditional pools will be freed).
//
// This allocator is non-renetrant, it is encumbant on the clients to ensure
// startAllocator() is not called again until stopAllocator() has been called.
class BumpPointerAllocator {
public:
BumpPointerAllocator()
: m_head(0)
{
}
~BumpPointerAllocator()
{
if (m_head)
m_head->destroy();
}
BumpPointerPool* startAllocator()
{
if (!m_head)
m_head = BumpPointerPool::create();
return m_head;
}
void stopAllocator()
{
if (m_head)
m_head->shrink();
}
private:
BumpPointerPool* m_head;
};
}
using WTF::BumpPointerAllocator;
#endif // BumpPointerAllocator_h

65
include/ByteOrder.h Normal file
View File

@ -0,0 +1,65 @@
/*
* Copyright (C) 2012 Google 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:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
* OWNER OR 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.
*/
#ifndef WTF_ByteOrder_h
#define WTF_ByteOrder_h
#if OS(UNIX)
#include <arpa/inet.h>
#endif
#if OS(WINDOWS)
namespace WTF {
inline uint32_t wswap32(uint32_t x) { return ((x & 0xffff0000) >> 16) | ((x & 0x0000ffff) << 16); }
inline uint32_t bswap32(uint32_t x) { return ((x & 0xff000000) >> 24) | ((x & 0x00ff0000) >> 8) | ((x & 0x0000ff00) << 8) | ((x & 0x000000ff) << 24); }
inline uint16_t bswap16(uint16_t x) { return ((x & 0xff00) >> 8) | ((x & 0x00ff) << 8); }
} // namespace WTF
#if CPU(BIG_ENDIAN)
inline uint16_t ntohs(uint16_t x) { return x; }
inline uint16_t htons(uint16_t x) { return x; }
inline uint32_t ntohl(uint32_t x) { return x; }
inline uint32_t htonl(uint32_t x) { return x; }
#elif CPU(MIDDLE_ENDIAN)
inline uint16_t ntohs(uint16_t x) { return x; }
inline uint16_t htons(uint16_t x) { return x; }
inline uint32_t ntohl(uint32_t x) { return WTF::wswap32(x); }
inline uint32_t htonl(uint32_t x) { return WTF::wswap32(x); }
#else
inline uint16_t ntohs(uint16_t x) { return WTF::bswap16(x); }
inline uint16_t htons(uint16_t x) { return WTF::bswap16(x); }
inline uint32_t ntohl(uint32_t x) { return WTF::bswap32(x); }
inline uint32_t htonl(uint32_t x) { return WTF::bswap32(x); }
#endif
#endif // OS(WINDOWS)
#endif // WTF_ByteOrder_h

46
include/CPUTime.h Normal file
View File

@ -0,0 +1,46 @@
/*
* Copyright (C) 2017 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 <wtf/MonotonicTime.h>
#include <wtf/Optional.h>
#include <wtf/Seconds.h>
namespace WTF {
struct CPUTime {
MonotonicTime cpuTime;
Seconds userTime;
Seconds systemTime;
WTF_EXPORT_PRIVATE double percentageCPUUsageSince(const CPUTime&) const;
WTF_EXPORT_PRIVATE static std::optional<CPUTime> get();
};
} // namespace WTF
using WTF::CPUTime;

852
include/CheckedArithmetic.h Normal file
View File

@ -0,0 +1,852 @@
/*
* Copyright (C) 2011 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. ``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
* 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.
*/
#ifndef CheckedArithmetic_h
#define CheckedArithmetic_h
#include <wtf/Assertions.h>
#include <limits>
#include <stdint.h>
#include <type_traits>
/* Checked<T>
*
* This class provides a mechanism to perform overflow-safe integer arithmetic
* without having to manually ensure that you have all the required bounds checks
* directly in your code.
*
* There are two modes of operation:
* - The default is Checked<T, CrashOnOverflow>, and crashes at the point
* and overflow has occurred.
* - The alternative is Checked<T, RecordOverflow>, which uses an additional
* byte of storage to track whether an overflow has occurred, subsequent
* unchecked operations will crash if an overflow has occured
*
* It is possible to provide a custom overflow handler, in which case you need
* to support these functions:
* - void overflowed();
* This function is called when an operation has produced an overflow.
* - bool hasOverflowed();
* This function must return true if overflowed() has been called on an
* instance and false if it has not.
* - void clearOverflow();
* Used to reset overflow tracking when a value is being overwritten with
* a new value.
*
* Checked<T> works for all integer types, with the following caveats:
* - Mixing signedness of operands is only supported for types narrower than
* 64bits.
* - It does have a performance impact, so tight loops may want to be careful
* when using it.
*
*/
namespace WTF {
enum class CheckedState {
DidOverflow,
DidNotOverflow
};
class CrashOnOverflow {
public:
static NO_RETURN_DUE_TO_CRASH void overflowed()
{
crash();
}
void clearOverflow() { }
static NO_RETURN_DUE_TO_CRASH void crash()
{
CRASH();
}
public:
bool hasOverflowed() const { return false; }
};
class RecordOverflow {
protected:
RecordOverflow()
: m_overflowed(false)
{
}
void overflowed()
{
m_overflowed = true;
}
void clearOverflow()
{
m_overflowed = false;
}
static NO_RETURN_DUE_TO_CRASH void crash()
{
CRASH();
}
public:
bool hasOverflowed() const { return m_overflowed; }
private:
unsigned char m_overflowed;
};
template <typename T, class OverflowHandler = CrashOnOverflow> class Checked;
template <typename T> struct RemoveChecked;
template <typename T> struct RemoveChecked<Checked<T>>;
template <typename Target, typename Source, bool isTargetBigger = sizeof(Target) >= sizeof(Source), bool targetSigned = std::numeric_limits<Target>::is_signed, bool sourceSigned = std::numeric_limits<Source>::is_signed> struct BoundsChecker;
template <typename Target, typename Source> struct BoundsChecker<Target, Source, false, false, false> {
static bool inBounds(Source value)
{
// Same signedness so implicit type conversion will always increase precision to widest type.
return value <= std::numeric_limits<Target>::max();
}
};
template <typename Target, typename Source> struct BoundsChecker<Target, Source, false, true, true> {
static bool inBounds(Source value)
{
// Same signedness so implicit type conversion will always increase precision to widest type.
return std::numeric_limits<Target>::min() <= value && value <= std::numeric_limits<Target>::max();
}
};
template <typename Target, typename Source> struct BoundsChecker<Target, Source, false, false, true> {
static bool inBounds(Source value)
{
// When converting value to unsigned Source, value will become a big value if value is negative.
// Casted value will become bigger than Target::max as Source is bigger than Target.
return static_cast<typename std::make_unsigned<Source>::type>(value) <= std::numeric_limits<Target>::max();
}
};
template <typename Target, typename Source> struct BoundsChecker<Target, Source, false, true, false> {
static bool inBounds(Source value)
{
// The unsigned Source type has greater precision than the target so max(Target) -> Source will widen.
return value <= static_cast<Source>(std::numeric_limits<Target>::max());
}
};
template <typename Target, typename Source> struct BoundsChecker<Target, Source, true, false, false> {
static bool inBounds(Source)
{
// Same sign, greater or same precision.
return true;
}
};
template <typename Target, typename Source> struct BoundsChecker<Target, Source, true, true, true> {
static bool inBounds(Source)
{
// Same sign, greater or same precision.
return true;
}
};
template <typename Target, typename Source> struct BoundsChecker<Target, Source, true, true, false> {
static bool inBounds(Source value)
{
// Target is signed with greater or same precision. If strictly greater, it is always safe.
if (sizeof(Target) > sizeof(Source))
return true;
return value <= static_cast<Source>(std::numeric_limits<Target>::max());
}
};
template <typename Target, typename Source> struct BoundsChecker<Target, Source, true, false, true> {
static bool inBounds(Source value)
{
// Target is unsigned with greater precision.
return value >= 0;
}
};
template <typename Target, typename Source> static inline bool isInBounds(Source value)
{
return BoundsChecker<Target, Source>::inBounds(value);
}
template <typename Target, typename Source> static inline bool convertSafely(Source input, Target& output)
{
if (!isInBounds<Target>(input))
return false;
output = static_cast<Target>(input);
return true;
}
template <typename T> struct RemoveChecked {
typedef T CleanType;
static const CleanType DefaultValue = 0;
};
template <typename T> struct RemoveChecked<Checked<T, CrashOnOverflow>> {
typedef typename RemoveChecked<T>::CleanType CleanType;
static const CleanType DefaultValue = 0;
};
template <typename T> struct RemoveChecked<Checked<T, RecordOverflow>> {
typedef typename RemoveChecked<T>::CleanType CleanType;
static const CleanType DefaultValue = 0;
};
// The ResultBase and SignednessSelector are used to workaround typeof not being
// available in MSVC
template <typename U, typename V, bool uIsBigger = (sizeof(U) > sizeof(V)), bool sameSize = (sizeof(U) == sizeof(V))> struct ResultBase;
template <typename U, typename V> struct ResultBase<U, V, true, false> {
typedef U ResultType;
};
template <typename U, typename V> struct ResultBase<U, V, false, false> {
typedef V ResultType;
};
template <typename U> struct ResultBase<U, U, false, true> {
typedef U ResultType;
};
template <typename U, typename V, bool uIsSigned = std::numeric_limits<U>::is_signed, bool vIsSigned = std::numeric_limits<V>::is_signed> struct SignednessSelector;
template <typename U, typename V> struct SignednessSelector<U, V, true, true> {
typedef U ResultType;
};
template <typename U, typename V> struct SignednessSelector<U, V, false, false> {
typedef U ResultType;
};
template <typename U, typename V> struct SignednessSelector<U, V, true, false> {
typedef V ResultType;
};
template <typename U, typename V> struct SignednessSelector<U, V, false, true> {
typedef U ResultType;
};
template <typename U, typename V> struct ResultBase<U, V, false, true> {
typedef typename SignednessSelector<U, V>::ResultType ResultType;
};
template <typename U, typename V> struct Result : ResultBase<typename RemoveChecked<U>::CleanType, typename RemoveChecked<V>::CleanType> {
};
template <typename LHS, typename RHS, typename ResultType = typename Result<LHS, RHS>::ResultType,
bool lhsSigned = std::numeric_limits<LHS>::is_signed, bool rhsSigned = std::numeric_limits<RHS>::is_signed> struct ArithmeticOperations;
template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOperations<LHS, RHS, ResultType, true, true> {
// LHS and RHS are signed types
// Helper function
static inline bool signsMatch(LHS lhs, RHS rhs)
{
return (lhs ^ rhs) >= 0;
}
static inline bool add(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
{
if (signsMatch(lhs, rhs)) {
if (lhs >= 0) {
if ((std::numeric_limits<ResultType>::max() - rhs) < lhs)
return false;
} else {
ResultType temp = lhs - std::numeric_limits<ResultType>::min();
if (rhs < -temp)
return false;
}
} // if the signs do not match this operation can't overflow
result = lhs + rhs;
return true;
}
static inline bool sub(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
{
if (!signsMatch(lhs, rhs)) {
if (lhs >= 0) {
if (lhs > std::numeric_limits<ResultType>::max() + rhs)
return false;
} else {
if (rhs > std::numeric_limits<ResultType>::max() + lhs)
return false;
}
} // if the signs match this operation can't overflow
result = lhs - rhs;
return true;
}
static inline bool multiply(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
{
if (signsMatch(lhs, rhs)) {
if (lhs >= 0) {
if (lhs && (std::numeric_limits<ResultType>::max() / lhs) < rhs)
return false;
} else {
if (static_cast<ResultType>(lhs) == std::numeric_limits<ResultType>::min() || static_cast<ResultType>(rhs) == std::numeric_limits<ResultType>::min())
return false;
if ((std::numeric_limits<ResultType>::max() / -lhs) < -rhs)
return false;
}
} else {
if (lhs < 0) {
if (rhs && lhs < (std::numeric_limits<ResultType>::min() / rhs))
return false;
} else {
if (lhs && rhs < (std::numeric_limits<ResultType>::min() / lhs))
return false;
}
}
result = lhs * rhs;
return true;
}
static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; }
};
template <typename LHS, typename RHS, typename ResultType> struct ArithmeticOperations<LHS, RHS, ResultType, false, false> {
// LHS and RHS are unsigned types so bounds checks are nice and easy
static inline bool add(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
{
ResultType temp = lhs + rhs;
if (temp < lhs)
return false;
result = temp;
return true;
}
static inline bool sub(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
{
ResultType temp = lhs - rhs;
if (temp > lhs)
return false;
result = temp;
return true;
}
static inline bool multiply(LHS lhs, RHS rhs, ResultType& result) WARN_UNUSED_RETURN
{
if (!lhs || !rhs) {
result = 0;
return true;
}
if (std::numeric_limits<ResultType>::max() / lhs < rhs)
return false;
result = lhs * rhs;
return true;
}
static inline bool equals(LHS lhs, RHS rhs) { return lhs == rhs; }
};
template <typename ResultType> struct ArithmeticOperations<int, unsigned, ResultType, true, false> {
static inline bool add(int64_t lhs, int64_t rhs, ResultType& result)
{
int64_t temp = lhs + rhs;
if (temp < std::numeric_limits<ResultType>::min())
return false;
if (temp > std::numeric_limits<ResultType>::max())
return false;
result = static_cast<ResultType>(temp);
return true;
}
static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result)
{
int64_t temp = lhs - rhs;
if (temp < std::numeric_limits<ResultType>::min())
return false;
if (temp > std::numeric_limits<ResultType>::max())
return false;
result = static_cast<ResultType>(temp);
return true;
}
static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result)
{
int64_t temp = lhs * rhs;
if (temp < std::numeric_limits<ResultType>::min())
return false;
if (temp > std::numeric_limits<ResultType>::max())
return false;
result = static_cast<ResultType>(temp);
return true;
}
static inline bool equals(int lhs, unsigned rhs)
{
return static_cast<int64_t>(lhs) == static_cast<int64_t>(rhs);
}
};
template <typename ResultType> struct ArithmeticOperations<unsigned, int, ResultType, false, true> {
static inline bool add(int64_t lhs, int64_t rhs, ResultType& result)
{
return ArithmeticOperations<int, unsigned, ResultType>::add(rhs, lhs, result);
}
static inline bool sub(int64_t lhs, int64_t rhs, ResultType& result)
{
return ArithmeticOperations<int, unsigned, ResultType>::sub(lhs, rhs, result);
}
static inline bool multiply(int64_t lhs, int64_t rhs, ResultType& result)
{
return ArithmeticOperations<int, unsigned, ResultType>::multiply(rhs, lhs, result);
}
static inline bool equals(unsigned lhs, int rhs)
{
return ArithmeticOperations<int, unsigned, ResultType>::equals(rhs, lhs);
}
};
template <typename U, typename V, typename R> static inline bool safeAdd(U lhs, V rhs, R& result)
{
return ArithmeticOperations<U, V, R>::add(lhs, rhs, result);
}
template <typename U, typename V, typename R> static inline bool safeSub(U lhs, V rhs, R& result)
{
return ArithmeticOperations<U, V, R>::sub(lhs, rhs, result);
}
template <typename U, typename V, typename R> static inline bool safeMultiply(U lhs, V rhs, R& result)
{
return ArithmeticOperations<U, V, R>::multiply(lhs, rhs, result);
}
template <typename U, typename V> static inline bool safeEquals(U lhs, V rhs)
{
return ArithmeticOperations<U, V>::equals(lhs, rhs);
}
enum ResultOverflowedTag { ResultOverflowed };
template <typename T, class OverflowHandler> class Checked : public OverflowHandler {
public:
template <typename _T, class _OverflowHandler> friend class Checked;
Checked()
: m_value(0)
{
}
Checked(ResultOverflowedTag)
: m_value(0)
{
this->overflowed();
}
template <typename U> Checked(U value)
{
if (!isInBounds<T>(value))
this->overflowed();
m_value = static_cast<T>(value);
}
template <typename V> Checked(const Checked<T, V>& rhs)
: m_value(rhs.m_value)
{
if (rhs.hasOverflowed())
this->overflowed();
}
template <typename U> Checked(const Checked<U, OverflowHandler>& rhs)
: OverflowHandler(rhs)
{
if (!isInBounds<T>(rhs.m_value))
this->overflowed();
m_value = static_cast<T>(rhs.m_value);
}
template <typename U, typename V> Checked(const Checked<U, V>& rhs)
{
if (rhs.hasOverflowed())
this->overflowed();
if (!isInBounds<T>(rhs.m_value))
this->overflowed();
m_value = static_cast<T>(rhs.m_value);
}
const Checked& operator=(Checked rhs)
{
this->clearOverflow();
if (rhs.hasOverflowed())
this->overflowed();
m_value = static_cast<T>(rhs.m_value);
return *this;
}
template <typename U> const Checked& operator=(U value)
{
return *this = Checked(value);
}
template <typename U, typename V> const Checked& operator=(const Checked<U, V>& rhs)
{
return *this = Checked(rhs);
}
// prefix
const Checked& operator++()
{
if (m_value == std::numeric_limits<T>::max())
this->overflowed();
m_value++;
return *this;
}
const Checked& operator--()
{
if (m_value == std::numeric_limits<T>::min())
this->overflowed();
m_value--;
return *this;
}
// postfix operators
const Checked operator++(int)
{
if (m_value == std::numeric_limits<T>::max())
this->overflowed();
return Checked(m_value++);
}
const Checked operator--(int)
{
if (m_value == std::numeric_limits<T>::min())
this->overflowed();
return Checked(m_value--);
}
// Boolean operators
bool operator!() const
{
if (this->hasOverflowed())
this->crash();
return !m_value;
}
explicit operator bool() const
{
if (this->hasOverflowed())
this->crash();
return m_value;
}
// Value accessors. unsafeGet() will crash if there's been an overflow.
T unsafeGet() const
{
if (this->hasOverflowed())
this->crash();
return m_value;
}
inline CheckedState safeGet(T& value) const WARN_UNUSED_RETURN
{
value = m_value;
if (this->hasOverflowed())
return CheckedState::DidOverflow;
return CheckedState::DidNotOverflow;
}
// Mutating assignment
template <typename U> const Checked operator+=(U rhs)
{
if (!safeAdd(m_value, rhs, m_value))
this->overflowed();
return *this;
}
template <typename U> const Checked operator-=(U rhs)
{
if (!safeSub(m_value, rhs, m_value))
this->overflowed();
return *this;
}
template <typename U> const Checked operator*=(U rhs)
{
if (!safeMultiply(m_value, rhs, m_value))
this->overflowed();
return *this;
}
const Checked operator*=(double rhs)
{
double result = rhs * m_value;
// Handle +/- infinity and NaN
if (!(std::numeric_limits<T>::min() <= result && std::numeric_limits<T>::max() >= result))
this->overflowed();
m_value = (T)result;
return *this;
}
const Checked operator*=(float rhs)
{
return *this *= (double)rhs;
}
template <typename U, typename V> const Checked operator+=(Checked<U, V> rhs)
{
if (rhs.hasOverflowed())
this->overflowed();
return *this += rhs.m_value;
}
template <typename U, typename V> const Checked operator-=(Checked<U, V> rhs)
{
if (rhs.hasOverflowed())
this->overflowed();
return *this -= rhs.m_value;
}
template <typename U, typename V> const Checked operator*=(Checked<U, V> rhs)
{
if (rhs.hasOverflowed())
this->overflowed();
return *this *= rhs.m_value;
}
// Equality comparisons
template <typename V> bool operator==(Checked<T, V> rhs)
{
return unsafeGet() == rhs.unsafeGet();
}
template <typename U> bool operator==(U rhs)
{
if (this->hasOverflowed())
this->crash();
return safeEquals(m_value, rhs);
}
template <typename U, typename V> const Checked operator==(Checked<U, V> rhs)
{
return unsafeGet() == Checked(rhs.unsafeGet());
}
template <typename U> bool operator!=(U rhs)
{
return !(*this == rhs);
}
// Other comparisons
template <typename V> bool operator<(Checked<T, V> rhs) const
{
return unsafeGet() < rhs.unsafeGet();
}
bool operator<(T rhs) const
{
return unsafeGet() < rhs;
}
template <typename V> bool operator<=(Checked<T, V> rhs) const
{
return unsafeGet() <= rhs.unsafeGet();
}
bool operator<=(T rhs) const
{
return unsafeGet() <= rhs;
}
template <typename V> bool operator>(Checked<T, V> rhs) const
{
return unsafeGet() > rhs.unsafeGet();
}
bool operator>(T rhs) const
{
return unsafeGet() > rhs;
}
template <typename V> bool operator>=(Checked<T, V> rhs) const
{
return unsafeGet() >= rhs.unsafeGet();
}
bool operator>=(T rhs) const
{
return unsafeGet() >= rhs;
}
private:
// Disallow implicit conversion of floating point to integer types
Checked(float);
Checked(double);
void operator=(float);
void operator=(double);
void operator+=(float);
void operator+=(double);
void operator-=(float);
void operator-=(double);
T m_value;
};
template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs)
{
U x = 0;
V y = 0;
bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow || rhs.safeGet(y) == CheckedState::DidOverflow;
typename Result<U, V>::ResultType result = 0;
overflowed |= !safeAdd(x, y, result);
if (overflowed)
return ResultOverflowed;
return result;
}
template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs)
{
U x = 0;
V y = 0;
bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow || rhs.safeGet(y) == CheckedState::DidOverflow;
typename Result<U, V>::ResultType result = 0;
overflowed |= !safeSub(x, y, result);
if (overflowed)
return ResultOverflowed;
return result;
}
template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(Checked<U, OverflowHandler> lhs, Checked<V, OverflowHandler> rhs)
{
U x = 0;
V y = 0;
bool overflowed = lhs.safeGet(x) == CheckedState::DidOverflow || rhs.safeGet(y) == CheckedState::DidOverflow;
typename Result<U, V>::ResultType result = 0;
overflowed |= !safeMultiply(x, y, result);
if (overflowed)
return ResultOverflowed;
return result;
}
template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(Checked<U, OverflowHandler> lhs, V rhs)
{
return lhs + Checked<V, OverflowHandler>(rhs);
}
template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(Checked<U, OverflowHandler> lhs, V rhs)
{
return lhs - Checked<V, OverflowHandler>(rhs);
}
template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(Checked<U, OverflowHandler> lhs, V rhs)
{
return lhs * Checked<V, OverflowHandler>(rhs);
}
template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator+(U lhs, Checked<V, OverflowHandler> rhs)
{
return Checked<U, OverflowHandler>(lhs) + rhs;
}
template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator-(U lhs, Checked<V, OverflowHandler> rhs)
{
return Checked<U, OverflowHandler>(lhs) - rhs;
}
template <typename U, typename V, typename OverflowHandler> static inline Checked<typename Result<U, V>::ResultType, OverflowHandler> operator*(U lhs, Checked<V, OverflowHandler> rhs)
{
return Checked<U, OverflowHandler>(lhs) * rhs;
}
// Convenience typedefs.
typedef Checked<int8_t, RecordOverflow> CheckedInt8;
typedef Checked<uint8_t, RecordOverflow> CheckedUint8;
typedef Checked<int16_t, RecordOverflow> CheckedInt16;
typedef Checked<uint16_t, RecordOverflow> CheckedUint16;
typedef Checked<int32_t, RecordOverflow> CheckedInt32;
typedef Checked<uint32_t, RecordOverflow> CheckedUint32;
typedef Checked<int64_t, RecordOverflow> CheckedInt64;
typedef Checked<uint64_t, RecordOverflow> CheckedUint64;
typedef Checked<size_t, RecordOverflow> CheckedSize;
template<typename T, typename U>
Checked<T, RecordOverflow> checkedSum(U value)
{
return Checked<T, RecordOverflow>(value);
}
template<typename T, typename U, typename... Args>
Checked<T, RecordOverflow> checkedSum(U value, Args... args)
{
return Checked<T, RecordOverflow>(value) + checkedSum<T>(args...);
}
// Sometimes, you just want to check if some math would overflow - the code to do the math is
// already in place, and you want to guard it.
template<typename T, typename... Args> bool sumOverflows(Args... args)
{
return checkedSum<T>(args...).hasOverflowed();
}
template<typename T, typename U> bool differenceOverflows(U left, U right)
{
return (Checked<T, RecordOverflow>(left) - Checked<T, RecordOverflow>(right)).hasOverflowed();
}
template<typename T, typename U>
Checked<T, RecordOverflow> checkedProduct(U value)
{
return Checked<T, RecordOverflow>(value);
}
template<typename T, typename U, typename... Args>
Checked<T, RecordOverflow> checkedProduct(U value, Args... args)
{
return Checked<T, RecordOverflow>(value) * checkedProduct<T>(args...);
}
// Sometimes, you just want to check if some math would overflow - the code to do the math is
// already in place, and you want to guard it.
template<typename T, typename... Args> bool productOverflows(Args... args)
{
return checkedProduct<T>(args...).hasOverflowed();
}
}
using WTF::Checked;
using WTF::CheckedState;
using WTF::RecordOverflow;
using WTF::CheckedInt8;
using WTF::CheckedUint8;
using WTF::CheckedInt16;
using WTF::CheckedUint16;
using WTF::CheckedInt32;
using WTF::CheckedUint32;
using WTF::CheckedInt64;
using WTF::CheckedUint64;
using WTF::CheckedSize;
using WTF::checkedSum;
using WTF::differenceOverflows;
using WTF::productOverflows;
using WTF::sumOverflows;
#endif

70
include/CheckedBoolean.h Normal file
View File

@ -0,0 +1,70 @@
/*
* Copyright (C) 2011 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. ``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
* 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.
*/
#ifndef CheckedBoolean_h
#define CheckedBoolean_h
#include <wtf/Assertions.h>
class CheckedBoolean {
public:
#if !ASSERT_DISABLED
CheckedBoolean(const CheckedBoolean& other)
: m_value(other.m_value)
, m_checked(false)
{
other.m_checked = true;
}
#endif
CheckedBoolean(bool value)
: m_value(value)
#if !ASSERT_DISABLED
, m_checked(false)
#endif
{
}
~CheckedBoolean()
{
ASSERT(m_checked);
}
operator bool()
{
#if !ASSERT_DISABLED
m_checked = true;
#endif
return m_value;
}
private:
bool m_value;
#if !ASSERT_DISABLED
mutable bool m_checked;
#endif
};
#endif

44
include/ClockType.h Normal file
View File

@ -0,0 +1,44 @@
/*
* 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. ``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
* 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.
*/
#ifndef WTF_ClockType_h
#define WTF_ClockType_h
namespace WTF {
class PrintStream;
enum class ClockType {
Wall,
Monotonic
};
WTF_EXPORT_PRIVATE void printInternal(PrintStream&, ClockType);
} // namespace WTF
using WTF::ClockType;
#endif // WTF_ClockType_h

66
include/CommaPrinter.h Normal file
View File

@ -0,0 +1,66 @@
/*
* Copyright (C) 2013, 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. ``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
* 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.
*/
#ifndef CommaPrinter_h
#define CommaPrinter_h
#include "PrintStream.h"
namespace WTF {
class CommaPrinter {
public:
CommaPrinter(const char* comma = ", ", const char* start = "")
: m_comma(comma)
, m_start(start)
, m_didPrint(false)
{
}
void dump(PrintStream& out) const
{
if (!m_didPrint) {
out.print(m_start);
m_didPrint = true;
return;
}
out.print(m_comma);
}
bool didPrint() const { return m_didPrint; }
private:
const char* m_comma;
const char* m_start;
mutable bool m_didPrint;
};
} // namespace WTF
using WTF::CommaPrinter;
#endif // CommaPrinter_h

View File

@ -0,0 +1,59 @@
/*
* Copyright (C) 2013 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. ``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
* 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.
*/
#ifndef CompilationThread_h
#define CompilationThread_h
namespace WTF {
WTF_EXPORT_PRIVATE bool exchangeIsCompilationThread(bool newValue);
class CompilationScope {
public:
CompilationScope()
: m_oldValue(exchangeIsCompilationThread(true))
{
}
~CompilationScope()
{
exchangeIsCompilationThread(m_oldValue);
}
void leaveEarly()
{
exchangeIsCompilationThread(m_oldValue);
}
private:
bool m_oldValue;
};
} // namespace WTF
using WTF::CompilationScope;
using WTF::exchangeIsCompilationThread;
#endif // CompilationThread_h

377
include/Compiler.h Normal file
View File

@ -0,0 +1,377 @@
/*
* Copyright (C) 2011, 2012, 2014 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. ``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
* 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.
*/
#ifndef WTF_Compiler_h
#define WTF_Compiler_h
/* COMPILER() - the compiler being used to build the project */
#define COMPILER(WTF_FEATURE) (defined WTF_COMPILER_##WTF_FEATURE && WTF_COMPILER_##WTF_FEATURE)
/* COMPILER_SUPPORTS() - whether the compiler being used to build the project supports the given feature. */
#define COMPILER_SUPPORTS(WTF_COMPILER_FEATURE) (defined WTF_COMPILER_SUPPORTS_##WTF_COMPILER_FEATURE && WTF_COMPILER_SUPPORTS_##WTF_COMPILER_FEATURE)
/* COMPILER_QUIRK() - whether the compiler being used to build the project requires a given quirk. */
#define COMPILER_QUIRK(WTF_COMPILER_QUIRK) (defined WTF_COMPILER_QUIRK_##WTF_COMPILER_QUIRK && WTF_COMPILER_QUIRK_##WTF_COMPILER_QUIRK)
/* COMPILER_HAS_CLANG_BUILTIN() - whether the compiler supports a particular clang builtin. */
#ifdef __has_builtin
#define COMPILER_HAS_CLANG_BUILTIN(x) __has_builtin(x)
#else
#define COMPILER_HAS_CLANG_BUILTIN(x) 0
#endif
/* COMPILER_HAS_CLANG_HEATURE() - whether the compiler supports a particular language or library feature. */
/* http://clang.llvm.org/docs/LanguageExtensions.html#has-feature-and-has-extension */
#ifdef __has_feature
#define COMPILER_HAS_CLANG_FEATURE(x) __has_feature(x)
#else
#define COMPILER_HAS_CLANG_FEATURE(x) 0
#endif
/* COMPILER_HAS_CLANG_DECLSPEC() - whether the compiler supports a Microsoft style __declspec attribute. */
/* https://clang.llvm.org/docs/LanguageExtensions.html#has-declspec-attribute */
#ifdef __has_declspec_attribute
#define COMPILER_HAS_CLANG_DECLSPEC(x) __has_declspec_attribute(x)
#else
#define COMPILER_HAS_CLANG_DECLSPEC(x) 0
#endif
/* ==== COMPILER() - primary detection of the compiler being used to build the project, in alphabetical order ==== */
/* COMPILER(CLANG) - Clang */
#if defined(__clang__)
#define WTF_COMPILER_CLANG 1
#define WTF_COMPILER_SUPPORTS_BLOCKS COMPILER_HAS_CLANG_FEATURE(blocks)
#define WTF_COMPILER_SUPPORTS_C_STATIC_ASSERT COMPILER_HAS_CLANG_FEATURE(c_static_assert)
#define WTF_COMPILER_SUPPORTS_CXX_REFERENCE_QUALIFIED_FUNCTIONS COMPILER_HAS_CLANG_FEATURE(cxx_reference_qualified_functions)
#define WTF_COMPILER_SUPPORTS_CXX_EXCEPTIONS COMPILER_HAS_CLANG_FEATURE(cxx_exceptions)
#define WTF_COMPILER_SUPPORTS_BUILTIN_IS_TRIVIALLY_COPYABLE COMPILER_HAS_CLANG_FEATURE(is_trivially_copyable)
#ifdef __cplusplus
#if __cplusplus <= 201103L
#define WTF_CPP_STD_VER 11
#elif __cplusplus <= 201402L
#define WTF_CPP_STD_VER 14
#endif
#endif
#endif // defined(__clang__)
/* COMPILER(GCC_OR_CLANG) - GNU Compiler Collection or Clang */
#if defined(__GNUC__)
#define WTF_COMPILER_GCC_OR_CLANG 1
#endif
/* COMPILER(GCC) - GNU Compiler Collection */
/* Note: This section must come after the Clang section since we check !COMPILER(CLANG) here. */
#if COMPILER(GCC_OR_CLANG) && !COMPILER(CLANG)
#define WTF_COMPILER_GCC 1
#define WTF_COMPILER_SUPPORTS_CXX_REFERENCE_QUALIFIED_FUNCTIONS 1
#define GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
#define GCC_VERSION_AT_LEAST(major, minor, patch) (GCC_VERSION >= (major * 10000 + minor * 100 + patch))
#if !GCC_VERSION_AT_LEAST(5, 0, 0)
#error "Please use a newer version of GCC. WebKit requires GCC 5.0.0 or newer to compile."
#endif
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
#define WTF_COMPILER_SUPPORTS_C_STATIC_ASSERT 1
#endif
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
#endif /* COMPILER(GCC) */
/* COMPILER(MINGW) - MinGW GCC */
#if defined(__MINGW32__)
#define WTF_COMPILER_MINGW 1
#include <_mingw.h>
#endif
/* COMPILER(MINGW64) - mingw-w64 GCC - used as additional check to exclude mingw.org specific functions */
/* Note: This section must come after the MinGW section since we check COMPILER(MINGW) here. */
#if COMPILER(MINGW) && defined(__MINGW64_VERSION_MAJOR) /* best way to check for mingw-w64 vs mingw.org */
#define WTF_COMPILER_MINGW64 1
#endif
/* COMPILER(MSVC) - Microsoft Visual C++ */
#if defined(_MSC_VER)
#define WTF_COMPILER_MSVC 1
#define WTF_COMPILER_SUPPORTS_CXX_REFERENCE_QUALIFIED_FUNCTIONS 1
#if _MSC_VER < 1900
#error "Please use a newer version of Visual Studio. WebKit requires VS2015 or newer to compile."
#endif
#endif
/* COMPILER(SUNCC) */
#if defined(__SUNPRO_CC) || defined(__SUNPRO_C)
#define WTF_COMPILER_SUNCC 1
#endif
#if !COMPILER(CLANG) && !COMPILER(MSVC)
#define WTF_COMPILER_QUIRK_CONSIDERS_UNREACHABLE_CODE 1
#endif
/* ==== COMPILER_SUPPORTS - additional compiler feature detection, in alphabetical order ==== */
/* COMPILER_SUPPORTS(EABI) */
#if defined(__ARM_EABI__) || defined(__EABI__)
#define WTF_COMPILER_SUPPORTS_EABI 1
#endif
/* RELAXED_CONSTEXPR */
#if defined(__cpp_constexpr) && __cpp_constexpr >= 201304
#define WTF_COMPILER_SUPPORTS_RELAXED_CONSTEXPR 1
#endif
#if !defined(RELAXED_CONSTEXPR)
#if COMPILER_SUPPORTS(RELAXED_CONSTEXPR)
#define RELAXED_CONSTEXPR constexpr
#else
#define RELAXED_CONSTEXPR
#endif
#endif
#define ASAN_ENABLED COMPILER_HAS_CLANG_FEATURE(address_sanitizer)
#if ASAN_ENABLED
#define SUPPRESS_ASAN __attribute__((no_sanitize_address))
#else
#define SUPPRESS_ASAN
#endif
/* ==== Compiler-independent macros for various compiler features, in alphabetical order ==== */
/* ALWAYS_INLINE */
#if !defined(ALWAYS_INLINE) && COMPILER(GCC_OR_CLANG) && defined(NDEBUG) && !COMPILER(MINGW)
#define ALWAYS_INLINE inline __attribute__((__always_inline__))
#endif
#if !defined(ALWAYS_INLINE) && COMPILER(MSVC) && defined(NDEBUG)
#define ALWAYS_INLINE __forceinline
#endif
#if !defined(ALWAYS_INLINE)
#define ALWAYS_INLINE inline
#endif
/* WTF_EXTERN_C_{BEGIN, END} */
#ifdef __cplusplus
#define WTF_EXTERN_C_BEGIN extern "C" {
#define WTF_EXTERN_C_END }
#else
#define WTF_EXTERN_C_BEGIN
#define WTF_EXTERN_C_END
#endif
/* FALLTHROUGH */
#if !defined(FALLTHROUGH) && defined(__cplusplus) && defined(__has_cpp_attribute)
#if __has_cpp_attribute(fallthrough)
#define FALLTHROUGH [[fallthrough]]
#elif __has_cpp_attribute(clang::fallthrough)
#define FALLTHROUGH [[clang::fallthrough]]
#elif __has_cpp_attribute(gnu::fallthrough)
#define FALLTHROUGH [[gnu::fallthrough]]
#endif
#endif // !defined(FALLTHROUGH) && defined(__cplusplus) && defined(__has_cpp_attribute)
#if !defined(FALLTHROUGH)
#define FALLTHROUGH
#endif
/* LIKELY */
#if !defined(LIKELY) && COMPILER(GCC_OR_CLANG)
#define LIKELY(x) __builtin_expect(!!(x), 1)
#endif
#if !defined(LIKELY)
#define LIKELY(x) (x)
#endif
/* NEVER_INLINE */
#if !defined(NEVER_INLINE) && COMPILER(GCC_OR_CLANG)
#define NEVER_INLINE __attribute__((__noinline__))
#endif
#if !defined(NEVER_INLINE) && COMPILER(MSVC)
#define NEVER_INLINE __declspec(noinline)
#endif
#if !defined(NEVER_INLINE)
#define NEVER_INLINE
#endif
/* NO_RETURN */
#if !defined(NO_RETURN) && COMPILER(GCC_OR_CLANG)
#define NO_RETURN __attribute((__noreturn__))
#endif
#if !defined(NO_RETURN) && COMPILER(MSVC)
#define NO_RETURN __declspec(noreturn)
#endif
#if !defined(NO_RETURN)
#define NO_RETURN
#endif
/* NOT_TAIL_CALLED */
#if !defined(NOT_TAIL_CALLED) && defined(__has_attribute)
#if __has_attribute(not_tail_called)
#define NOT_TAIL_CALLED __attribute__((not_tail_called))
#endif
#endif
#if !defined(NOT_TAIL_CALLED)
#define NOT_TAIL_CALLED
#endif
/* RETURNS_NONNULL */
#if !defined(RETURNS_NONNULL) && COMPILER(GCC_OR_CLANG)
#define RETURNS_NONNULL __attribute__((returns_nonnull))
#endif
#if !defined(RETURNS_NONNULL)
#define RETURNS_NONNULL
#endif
/* NO_RETURN_WITH_VALUE */
#if !defined(NO_RETURN_WITH_VALUE) && !COMPILER(MSVC)
#define NO_RETURN_WITH_VALUE NO_RETURN
#endif
#if !defined(NO_RETURN_WITH_VALUE)
#define NO_RETURN_WITH_VALUE
#endif
/* OBJC_CLASS */
#if !defined(OBJC_CLASS) && defined(__OBJC__)
#define OBJC_CLASS @class
#endif
#if !defined(OBJC_CLASS)
#define OBJC_CLASS class
#endif
/* PURE_FUNCTION */
#if !defined(PURE_FUNCTION) && COMPILER(GCC_OR_CLANG)
#define PURE_FUNCTION __attribute__((__pure__))
#endif
#if !defined(PURE_FUNCTION)
#define PURE_FUNCTION
#endif
/* UNUSED_FUNCTION */
#if !defined(UNUSED_FUNCTION) && COMPILER(GCC_OR_CLANG)
#define UNUSED_FUNCTION __attribute__((unused))
#endif
#if !defined(UNUSED_FUNCTION)
#define UNUSED_FUNCTION
#endif
/* REFERENCED_FROM_ASM */
#if !defined(REFERENCED_FROM_ASM) && COMPILER(GCC_OR_CLANG)
#define REFERENCED_FROM_ASM __attribute__((__used__))
#endif
#if !defined(REFERENCED_FROM_ASM)
#define REFERENCED_FROM_ASM
#endif
/* UNLIKELY */
#if !defined(UNLIKELY) && COMPILER(GCC_OR_CLANG)
#define UNLIKELY(x) __builtin_expect(!!(x), 0)
#endif
#if !defined(UNLIKELY)
#define UNLIKELY(x) (x)
#endif
/* UNUSED_LABEL */
/* Keep the compiler from complaining for a local label that is defined but not referenced. */
/* Helpful when mixing hand-written and autogenerated code. */
#if !defined(UNUSED_LABEL) && COMPILER(MSVC)
#define UNUSED_LABEL(label) if (false) goto label
#endif
#if !defined(UNUSED_LABEL)
#define UNUSED_LABEL(label) UNUSED_PARAM(&& label)
#endif
/* UNUSED_PARAM */
#if !defined(UNUSED_PARAM) && COMPILER(MSVC)
#define UNUSED_PARAM(variable) (void)&variable
#endif
#if !defined(UNUSED_PARAM)
#define UNUSED_PARAM(variable) (void)variable
#endif
/* WARN_UNUSED_RETURN */
#if !defined(WARN_UNUSED_RETURN) && COMPILER(GCC_OR_CLANG)
#define WARN_UNUSED_RETURN __attribute__((__warn_unused_result__))
#endif
#if !defined(WARN_UNUSED_RETURN)
#define WARN_UNUSED_RETURN
#endif
#if !defined(__has_include) && COMPILER(MSVC)
#define __has_include(path) 0
#endif
#endif /* WTF_Compiler_h */

192
include/Condition.h Normal file
View File

@ -0,0 +1,192 @@
/*
* Copyright (C) 2015-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. ``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
* 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.
*/
#ifndef WTF_Condition_h
#define WTF_Condition_h
#include <wtf/CurrentTime.h>
#include <wtf/Noncopyable.h>
#include <wtf/ParkingLot.h>
#include <wtf/TimeWithDynamicClockType.h>
namespace WTF {
// This is a condition variable that is suitable for use with any lock-like object, including
// our own WTF::Lock. It features standard wait()/notifyOne()/notifyAll() methods in addition to
// a variety of wait-with-timeout methods. This includes methods that use WTF's own notion of
// time, like wall-clock time (i.e. currentTime()) and monotonic time (i.e.
// monotonicallyIncreasingTime()). This is a very efficient condition variable. It only requires
// one byte of memory. notifyOne() and notifyAll() require just a load and branch for the fast
// case where no thread is waiting. This condition variable, when used with WTF::Lock, can
// outperform a system condition variable and lock by up to 58x.
// This is a struct without a constructor or destructor so that it can be statically initialized.
// Use Lock in instance variables.
struct ConditionBase {
// Condition will accept any kind of time and convert it internally, but this typedef tells
// you what kind of time Condition would be able to use without conversions. However, if you
// are unlikely to be affected by the cost of conversions, it is better to use MonotonicTime.
typedef ParkingLot::Time Time;
// Wait on a parking queue while releasing the given lock. It will unlock the lock just before
// parking, and relock it upon wakeup. Returns true if we woke up due to some call to
// notifyOne() or notifyAll(). Returns false if we woke up due to a timeout. Note that this form
// of waitUntil() has some quirks:
//
// No spurious wake-up: in order for this to return before the timeout, some notifyOne() or
// notifyAll() call must have happened. No scenario other than timeout or notify can lead to this
// method returning. This means, for example, that you can't use pthread cancelation or signals to
// cause early return.
//
// Past timeout: it's possible for waitUntil() to be called with a timeout in the past. In that
// case, waitUntil() will still release the lock and reacquire it. waitUntil() will always return
// false in that case. This is subtly different from some pthread_cond_timedwait() implementations,
// which may not release the lock for past timeout. But, this behavior is consistent with OpenGroup
// documentation for timedwait().
template<typename LockType>
bool waitUntil(LockType& lock, const TimeWithDynamicClockType& timeout)
{
bool result;
if (timeout < timeout.nowWithSameClock()) {
lock.unlock();
result = false;
} else {
result = ParkingLot::parkConditionally(
&m_hasWaiters,
[this] () -> bool {
// Let everyone know that we will be waiting. Do this while we hold the queue lock,
// to prevent races with notifyOne().
m_hasWaiters.store(true);
return true;
},
[&lock] () { lock.unlock(); },
timeout).wasUnparked;
}
lock.lock();
return result;
}
// Wait until the given predicate is satisfied. Returns true if it is satisfied in the end.
// May return early due to timeout.
template<typename LockType, typename Functor>
bool waitUntil(
LockType& lock, const TimeWithDynamicClockType& timeout, const Functor& predicate)
{
while (!predicate()) {
if (!waitUntil(lock, timeout))
return predicate();
}
return true;
}
// Wait until the given predicate is satisfied. Returns true if it is satisfied in the end.
// May return early due to timeout.
template<typename LockType, typename Functor>
bool waitFor(
LockType& lock, Seconds relativeTimeout, const Functor& predicate)
{
return waitUntil(lock, MonotonicTime::now() + relativeTimeout, predicate);
}
template<typename LockType>
bool waitFor(LockType& lock, Seconds relativeTimeout)
{
return waitUntil(lock, MonotonicTime::now() + relativeTimeout);
}
template<typename LockType>
void wait(LockType& lock)
{
waitUntil(lock, Time::infinity());
}
template<typename LockType, typename Functor>
void wait(LockType& lock, const Functor& predicate)
{
while (!predicate())
wait(lock);
}
// Note that this method is extremely fast when nobody is waiting. It is not necessary to try to
// avoid calling this method. This returns true if someone was actually woken up.
bool notifyOne()
{
if (!m_hasWaiters.load()) {
// At this exact instant, there is nobody waiting on this condition. The way to visualize
// this is that if unparkOne() ran to completion without obstructions at this moment, it
// wouldn't wake anyone up. Hence, we have nothing to do!
return false;
}
bool didNotifyThread = false;
ParkingLot::unparkOne(
&m_hasWaiters,
[&] (ParkingLot::UnparkResult result) -> intptr_t {
if (!result.mayHaveMoreThreads)
m_hasWaiters.store(false);
didNotifyThread = result.didUnparkThread;
return 0;
});
return didNotifyThread;
}
void notifyAll()
{
if (!m_hasWaiters.load()) {
// See above.
return;
}
// It's totally safe for us to set this to false without any locking, because this thread is
// guaranteed to then unparkAll() anyway. So, if there is a race with some thread calling
// wait() just before this store happens, that thread is guaranteed to be awoken by the call to
// unparkAll(), below.
m_hasWaiters.store(false);
ParkingLot::unparkAll(&m_hasWaiters);
}
protected:
Atomic<bool> m_hasWaiters;
};
class Condition : public ConditionBase {
WTF_MAKE_NONCOPYABLE(Condition);
public:
Condition()
{
m_hasWaiters.store(false);
}
};
typedef ConditionBase StaticCondition;
} // namespace WTF
using WTF::Condition;
using WTF::StaticCondition;
#endif // WTF_Condition_h

146
include/CrossThreadCopier.h Normal file
View File

@ -0,0 +1,146 @@
/*
* Copyright (C) 2009, 2010 Google Inc. All rights reserved.
* Copyright (C) 2014-2017 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:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
* OWNER OR 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 <wtf/Assertions.h>
#include <wtf/Forward.h>
#include <wtf/HashSet.h>
#include <wtf/RefPtr.h>
#include <wtf/text/WTFString.h>
namespace WTF {
struct CrossThreadCopierBaseHelper {
template<typename T> struct RemovePointer {
typedef T Type;
};
template<typename T> struct RemovePointer<T*> {
typedef T Type;
};
template<typename T> struct RemovePointer<RefPtr<T>> {
typedef T Type;
};
template<typename T> struct IsEnumOrConvertibleToInteger {
static const bool value = std::is_integral<T>::value || std::is_enum<T>::value || std::is_convertible<T, long double>::value;
};
template<typename T> struct IsThreadSafeRefCountedPointer {
static const bool value = std::is_convertible<typename RemovePointer<T>::Type*, ThreadSafeRefCounted<typename RemovePointer<T>::Type>*>::value;
};
};
template<typename T> struct CrossThreadCopierPassThrough {
typedef T Type;
static Type copy(const T& parameter)
{
return parameter;
}
};
template<bool isEnumOrConvertibleToInteger, bool isThreadSafeRefCounted, typename T> struct CrossThreadCopierBase;
// Integers get passed through without any changes.
template<typename T> struct CrossThreadCopierBase<true, false, T> : public CrossThreadCopierPassThrough<T> {
};
// Classes that have an isolatedCopy() method get a default specialization.
template<class T> struct CrossThreadCopierBase<false, false, T> {
static T copy(const T& value)
{
return value.isolatedCopy();
}
};
// Custom copy methods.
template<typename T> struct CrossThreadCopierBase<false, true, T> {
typedef typename CrossThreadCopierBaseHelper::RemovePointer<T>::Type RefCountedType;
static_assert(std::is_convertible<RefCountedType*, ThreadSafeRefCounted<RefCountedType>*>::value, "T is not convertible to ThreadSafeRefCounted!");
typedef RefPtr<RefCountedType> Type;
static Type copy(const T& refPtr)
{
return refPtr;
}
};
template<> struct CrossThreadCopierBase<false, false, std::chrono::system_clock::time_point> {
typedef std::chrono::system_clock::time_point Type;
static Type copy(const Type& source)
{
return source;
}
};
template<> struct CrossThreadCopierBase<false, false, WTF::ASCIILiteral> {
typedef WTF::ASCIILiteral Type;
static Type copy(const Type& source)
{
return source;
}
};
template<typename T>
struct CrossThreadCopier : public CrossThreadCopierBase<CrossThreadCopierBaseHelper::IsEnumOrConvertibleToInteger<T>::value, CrossThreadCopierBaseHelper::IsThreadSafeRefCountedPointer<T>::value, T> {
};
// Default specialization for Vectors of CrossThreadCopyable classes.
template<typename T> struct CrossThreadCopierBase<false, false, Vector<T>> {
typedef Vector<T> Type;
static Type copy(const Type& source)
{
Type destination;
destination.reserveInitialCapacity(source.size());
for (auto& object : source)
destination.uncheckedAppend(CrossThreadCopier<T>::copy(object));
return destination;
}
};
// Default specialization for HashSets of CrossThreadCopyable classes
template<typename T> struct CrossThreadCopierBase<false, false, HashSet<T> > {
typedef HashSet<T> Type;
static Type copy(const Type& source)
{
Type destination;
for (auto& object : source)
destination.add(CrossThreadCopier<T>::copy(object));
return destination;
}
};
} // namespace WTF
using WTF::CrossThreadCopierBaseHelper;
using WTF::CrossThreadCopierBase;
using WTF::CrossThreadCopier;

121
include/CrossThreadQueue.h Normal file
View File

@ -0,0 +1,121 @@
/*
* 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 <limits>
#include <wtf/Assertions.h>
#include <wtf/Condition.h>
#include <wtf/Deque.h>
#include <wtf/Lock.h>
#include <wtf/Noncopyable.h>
#include <wtf/Optional.h>
namespace WTF {
template<typename DataType>
class CrossThreadQueue {
WTF_MAKE_NONCOPYABLE(CrossThreadQueue);
public:
CrossThreadQueue() = default;
void append(DataType&&);
DataType waitForMessage();
std::optional<DataType> tryGetMessage();
void kill();
bool isKilled() const;
bool isEmpty() const;
private:
mutable Lock m_lock;
Condition m_condition;
Deque<DataType> m_queue;
bool m_killed { false };
};
template<typename DataType>
void CrossThreadQueue<DataType>::append(DataType&& message)
{
LockHolder lock(m_lock);
ASSERT(!m_killed);
m_queue.append(WTFMove(message));
m_condition.notifyOne();
}
template<typename DataType>
DataType CrossThreadQueue<DataType>::waitForMessage()
{
LockHolder lock(m_lock);
auto found = m_queue.end();
while (found == m_queue.end()) {
found = m_queue.begin();
if (found != m_queue.end())
break;
m_condition.wait(m_lock);
}
return m_queue.takeFirst();
}
template<typename DataType>
std::optional<DataType> CrossThreadQueue<DataType>::tryGetMessage()
{
LockHolder lock(m_lock);
if (m_queue.isEmpty())
return { };
return m_queue.takeFirst();
}
template<typename DataType>
void CrossThreadQueue<DataType>::kill()
{
LockHolder lock(m_lock);
m_killed = true;
m_condition.notifyAll();
}
template<typename DataType>
bool CrossThreadQueue<DataType>::isKilled() const
{
LockHolder lock(m_lock);
return m_killed;
}
template<typename DataType>
bool CrossThreadQueue<DataType>::isEmpty() const
{
LockHolder lock(m_lock);
return m_queue.isEmpty();
}
} // namespace WTF
using WTF::CrossThreadQueue;

102
include/CrossThreadTask.h Normal file
View File

@ -0,0 +1,102 @@
/*
* Copyright (C) 2013, 2015, 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 <wtf/CrossThreadCopier.h>
#include <wtf/Function.h>
#include <wtf/StdLibExtras.h>
namespace WTF {
class CrossThreadTask {
public:
CrossThreadTask() = default;
CrossThreadTask(Function<void ()>&& taskFunction)
: m_taskFunction(WTFMove(taskFunction))
{
ASSERT(m_taskFunction);
}
void performTask()
{
m_taskFunction();
}
protected:
Function<void ()> m_taskFunction;
};
template <typename T>
T crossThreadCopy(const T& t)
{
return CrossThreadCopier<T>::copy(t);
}
template <typename F, typename ArgsTuple, size_t... ArgsIndex>
void callFunctionForCrossThreadTaskImpl(F function, ArgsTuple&& args, std::index_sequence<ArgsIndex...>)
{
function(std::get<ArgsIndex>(std::forward<ArgsTuple>(args))...);
}
template <typename F, typename ArgsTuple, typename ArgsIndices = std::make_index_sequence<std::tuple_size<ArgsTuple>::value>>
void callFunctionForCrossThreadTask(F function, ArgsTuple&& args)
{
callFunctionForCrossThreadTaskImpl(function, std::forward<ArgsTuple>(args), ArgsIndices());
}
template<typename... Parameters, typename... Arguments>
CrossThreadTask createCrossThreadTask(void (*method)(Parameters...), const Arguments&... arguments)
{
return CrossThreadTask([method, arguments = std::make_tuple(crossThreadCopy<Arguments>(arguments)...)]() mutable {
callFunctionForCrossThreadTask(method, WTFMove(arguments));
});
}
template <typename C, typename MF, typename ArgsTuple, size_t... ArgsIndex>
void callMemberFunctionForCrossThreadTaskImpl(C* object, MF function, ArgsTuple&& args, std::index_sequence<ArgsIndex...>)
{
(object->*function)(std::get<ArgsIndex>(std::forward<ArgsTuple>(args))...);
}
template <typename C, typename MF, typename ArgsTuple, typename ArgsIndicies = std::make_index_sequence<std::tuple_size<ArgsTuple>::value>>
void callMemberFunctionForCrossThreadTask(C* object, MF function, ArgsTuple&& args)
{
callMemberFunctionForCrossThreadTaskImpl(object, function, std::forward<ArgsTuple>(args), ArgsIndicies());
}
template<typename T, typename... Parameters, typename... Arguments>
CrossThreadTask createCrossThreadTask(T& callee, void (T::*method)(Parameters...), const Arguments&... arguments)
{
return CrossThreadTask([callee = &callee, method, arguments = std::make_tuple(crossThreadCopy<Arguments>(arguments)...)]() mutable {
callMemberFunctionForCrossThreadTask(callee, method, WTFMove(arguments));
});
}
} // namespace WTF
using WTF::CrossThreadTask;
using WTF::createCrossThreadTask;

View File

@ -0,0 +1,38 @@
/*
* Copyright (C) 2014 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. ``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
* 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.
*/
#ifndef WTF_CryptographicUtilities_h
#define WTF_CryptographicUtilities_h
namespace WTF {
// Returns zero if arrays are equal, and non-zero otherwise. Execution time does not depend on array contents.
WTF_EXPORT_PRIVATE int constantTimeMemcmp(const void*, const void*, size_t length);
}
using WTF::constantTimeMemcmp;
#endif

View File

@ -0,0 +1,41 @@
/*
* Copyright (C) 2008 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
*
* 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. ``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
* 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.
*/
#ifndef WTF_CryptographicallyRandomNumber_h
#define WTF_CryptographicallyRandomNumber_h
#include <stdint.h>
namespace WTF {
WTF_EXPORT_PRIVATE uint32_t cryptographicallyRandomNumber();
WTF_EXPORT_PRIVATE void cryptographicallyRandomValues(void* buffer, size_t length);
}
using WTF::cryptographicallyRandomNumber;
using WTF::cryptographicallyRandomValues;
#endif

86
include/CurrentTime.h Normal file
View File

@ -0,0 +1,86 @@
/*
* Copyright (C) 2006 Apple Inc. All rights reserved.
* Copyright (C) 2008 Google 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:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
* OWNER OR 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.
*/
#ifndef CurrentTime_h
#define CurrentTime_h
#include <chrono>
#include <time.h>
namespace WTF {
// Returns the current UTC time in seconds, counted from January 1, 1970.
// Precision varies depending on platform but is usually as good or better
// than a millisecond.
// Use this function only if wall clock time is needed. For elapsed time
// measurement use monotonicallyIncreasingTime() instead.
WTF_EXPORT_PRIVATE double currentTime();
// Same thing, in milliseconds.
inline double currentTimeMS()
{
return currentTime() * 1000.0;
}
// Provides a monotonically increasing time in seconds since an arbitrary point in the past.
// On unsupported platforms, this function only guarantees the result will be non-decreasing.
// Result of this function increases monotonically even when clock time goes back due to
// NTP or manual adjustments, so it is better suited for elapsed time measurement.
WTF_EXPORT_PRIVATE double monotonicallyIncreasingTime();
inline double monotonicallyIncreasingTimeMS()
{
return monotonicallyIncreasingTime() * 1000.0;
}
// Returns the current CPU time of the current thread.
// Precision varies depending on platform but is usually as good or better
// than a millisecond.
WTF_EXPORT_PRIVATE std::chrono::microseconds currentCPUTime();
WTF_EXPORT_PRIVATE void sleep(double);
inline void sleepMS(double value)
{
sleep(value / 1000.0);
}
} // namespace WTF
using WTF::currentCPUTime;
using WTF::currentTime;
using WTF::currentTimeMS;
using WTF::monotonicallyIncreasingTime;
using WTF::monotonicallyIncreasingTimeMS;
using WTF::sleep;
using WTF::sleepMS;
#endif // CurrentTime_h

79
include/DataLog.h Normal file
View File

@ -0,0 +1,79 @@
/*
* Copyright (C) 2012 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. ``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
* 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.
*/
#ifndef DataLog_h
#define DataLog_h
#include <stdarg.h>
#include <stdio.h>
#include <wtf/PrintStream.h>
#include <wtf/StdLibExtras.h>
namespace WTF {
WTF_EXPORT_PRIVATE PrintStream& dataFile();
WTF_EXPORT_PRIVATE void setDataFile(const char* path);
WTF_EXPORT_PRIVATE void dataLogFV(const char* format, va_list) WTF_ATTRIBUTE_PRINTF(1, 0);
WTF_EXPORT_PRIVATE void dataLogF(const char* format, ...) WTF_ATTRIBUTE_PRINTF(1, 2);
WTF_EXPORT_PRIVATE void dataLogFString(const char*);
template<typename... Types>
void dataLog(const Types&... values)
{
dataFile().print(values...);
}
template<typename... Types>
void dataLogLn(const Types&... values)
{
dataLog(values..., "\n");
}
template<typename... Types>
void dataLogIf(bool shouldLog, const Types&... values)
{
if (shouldLog)
dataLog(values...);
}
template<typename... Types>
void dataLogLnIf(bool shouldLog, const Types&... values)
{
if (shouldLog)
dataLogLn(values...);
}
} // namespace WTF
using WTF::dataLog;
using WTF::dataLogLn;
using WTF::dataLogIf;
using WTF::dataLogLnIf;
using WTF::dataLogF;
using WTF::dataLogFString;
#endif // DataLog_h

158
include/DateMath.h Normal file
View File

@ -0,0 +1,158 @@
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
* Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
* Copyright (C) 2009 Google Inc. All rights reserved.
* Copyright (C) 2010 Research In Motion Limited. All rights reserved.
*
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla Communicator client code, released
* March 31, 1998.
*
* The Initial Developer of the Original Code is
* Netscape Communications Corporation.
* Portions created by the Initial Developer are Copyright (C) 1998
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
*/
#ifndef DateMath_h
#define DateMath_h
#include <math.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <wtf/CurrentTime.h>
#include <wtf/text/WTFString.h>
namespace WTF {
enum TimeType {
UTCTime = 0,
LocalTime
};
struct LocalTimeOffset {
LocalTimeOffset()
: isDST(false)
, offset(0)
{
}
LocalTimeOffset(bool isDST, int offset)
: isDST(isDST)
, offset(offset)
{
}
bool operator==(const LocalTimeOffset& other)
{
return isDST == other.isDST && offset == other.offset;
}
bool operator!=(const LocalTimeOffset& other)
{
return isDST != other.isDST || offset != other.offset;
}
bool isDST;
int offset;
};
void initializeDates();
int equivalentYearForDST(int year);
// Not really math related, but this is currently the only shared place to put these.
WTF_EXPORT_PRIVATE double parseES5DateFromNullTerminatedCharacters(const char* dateString);
WTF_EXPORT_PRIVATE double parseDateFromNullTerminatedCharacters(const char* dateString);
WTF_EXPORT_PRIVATE double parseDateFromNullTerminatedCharacters(const char* dateString, bool& haveTZ, int& offset);
WTF_EXPORT_PRIVATE double timeClip(double);
// dayOfWeek: [0, 6] 0 being Monday, day: [1, 31], month: [0, 11], year: ex: 2011, hours: [0, 23], minutes: [0, 59], seconds: [0, 59], utcOffset: [-720,720].
String makeRFC2822DateString(unsigned dayOfWeek, unsigned day, unsigned month, unsigned year, unsigned hours, unsigned minutes, unsigned seconds, int utcOffset);
inline double jsCurrentTime()
{
// JavaScript doesn't recognize fractions of a millisecond.
return floor(WTF::currentTimeMS());
}
const char* const weekdayName[7] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
const char* const monthName[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
const char* const monthFullName[12] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" };
const double hoursPerDay = 24.0;
const double minutesPerHour = 60.0;
const double secondsPerMinute = 60.0;
const double msPerSecond = 1000.0;
const double msPerMonth = 2592000000.0;
const double secondsPerHour = secondsPerMinute * minutesPerHour;
const double secondsPerDay = secondsPerHour * hoursPerDay;
const double msPerMinute = msPerSecond * secondsPerMinute;
const double msPerHour = msPerSecond * secondsPerHour;
const double msPerDay = msPerSecond * secondsPerDay;
WTF_EXPORT_PRIVATE bool isLeapYear(int year);
// Returns the number of days from 1970-01-01 to the specified date.
WTF_EXPORT_PRIVATE double dateToDaysFrom1970(int year, int month, int day);
WTF_EXPORT_PRIVATE int msToYear(double ms);
WTF_EXPORT_PRIVATE double msToDays(double ms);
WTF_EXPORT_PRIVATE int msToMinutes(double ms);
WTF_EXPORT_PRIVATE int msToHours(double ms);
WTF_EXPORT_PRIVATE int dayInYear(int year, int month, int day);
WTF_EXPORT_PRIVATE int dayInYear(double ms, int year);
WTF_EXPORT_PRIVATE int monthFromDayInYear(int dayInYear, bool leapYear);
WTF_EXPORT_PRIVATE int dayInMonthFromDayInYear(int dayInYear, bool leapYear);
// Returns combined offset in millisecond (UTC + DST).
WTF_EXPORT_PRIVATE LocalTimeOffset calculateLocalTimeOffset(double utcInMilliseconds, TimeType = UTCTime);
} // namespace WTF
using WTF::isLeapYear;
using WTF::dateToDaysFrom1970;
using WTF::dayInMonthFromDayInYear;
using WTF::dayInYear;
using WTF::minutesPerHour;
using WTF::monthFromDayInYear;
using WTF::msPerDay;
using WTF::msPerHour;
using WTF::msPerMinute;
using WTF::msPerSecond;
using WTF::msToYear;
using WTF::msToDays;
using WTF::msToMinutes;
using WTF::msToHours;
using WTF::secondsPerDay;
using WTF::secondsPerMinute;
using WTF::parseDateFromNullTerminatedCharacters;
using WTF::makeRFC2822DateString;
using WTF::LocalTimeOffset;
using WTF::calculateLocalTimeOffset;
#endif // DateMath_h

41
include/DebugUtilities.h Normal file
View File

@ -0,0 +1,41 @@
/*
* Copyright (C) 2017 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. ``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
* 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.
*/
#ifndef WTF_DebugUtilities_h
#define WTF_DebugUtilities_h
#include <wtf/Assertions.h>
#define SLEEP_THREAD_FOR_DEBUGGER() \
do { \
do { \
sleep(1); \
if (WTFIsDebuggerAttached()) \
break; \
} while (1); \
WTFBreakpointTrap(); \
} while (0)
#endif /* WTF_DebugUtilities_h */

108
include/DecimalNumber.h Normal file
View File

@ -0,0 +1,108 @@
/*
* Copyright (C) 2010 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. ``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
* 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.
*/
#ifndef DecimalNumber_h
#define DecimalNumber_h
#include <math.h>
#include <wtf/dtoa.h>
#include <wtf/MathExtras.h>
#include <wtf/text/WTFString.h>
namespace WTF {
enum RoundingSignificantFiguresType { RoundingSignificantFigures };
enum RoundingDecimalPlacesType { RoundingDecimalPlaces };
class DecimalNumber {
public:
DecimalNumber(double d)
{
ASSERT(std::isfinite(d));
dtoa(m_significand, d, m_sign, m_exponent, m_precision);
ASSERT(m_precision);
// Zero should always have exponent 0.
ASSERT(m_significand[0] != '0' || !m_exponent);
// No values other than zero should have a leading zero.
ASSERT(m_significand[0] != '0' || m_precision == 1);
// No values other than zero should have trailing zeros.
ASSERT(m_significand[0] == '0' || m_significand[m_precision - 1] != '0');
}
DecimalNumber(double d, RoundingSignificantFiguresType, unsigned significantFigures)
{
ASSERT(std::isfinite(d));
dtoaRoundSF(m_significand, d, significantFigures, m_sign, m_exponent, m_precision);
ASSERT_WITH_SECURITY_IMPLICATION(significantFigures && significantFigures <= sizeof(DtoaBuffer));
while (m_precision < significantFigures)
m_significand[m_precision++] = '0';
ASSERT(m_precision);
// Zero should always have exponent 0.
ASSERT(m_significand[0] != '0' || !m_exponent);
}
DecimalNumber(double d, RoundingDecimalPlacesType, unsigned decimalPlaces)
{
ASSERT(std::isfinite(d));
dtoaRoundDP(m_significand, d, decimalPlaces, m_sign, m_exponent, m_precision);
unsigned significantFigures = 1 + m_exponent + decimalPlaces;
ASSERT_WITH_SECURITY_IMPLICATION(significantFigures && significantFigures <= sizeof(DtoaBuffer));
while (m_precision < significantFigures)
m_significand[m_precision++] = '0';
ASSERT(m_precision);
// Zero should always have exponent 0.
ASSERT(m_significand[0] != '0' || !m_exponent);
}
WTF_EXPORT_PRIVATE unsigned bufferLengthForStringDecimal() const;
WTF_EXPORT_PRIVATE unsigned bufferLengthForStringExponential() const;
WTF_EXPORT_PRIVATE unsigned toStringDecimal(LChar* buffer, unsigned bufferLength) const;
WTF_EXPORT_PRIVATE unsigned toStringExponential(LChar* buffer, unsigned bufferLength) const;
bool sign() const { return m_sign; }
int exponent() const { return m_exponent; }
const char* significand() const { return m_significand; } // significand contains precision characters, is not null-terminated.
unsigned precision() const { return m_precision; }
private:
bool m_sign;
int m_exponent;
DtoaBuffer m_significand;
unsigned m_precision;
};
} // namespace WTF
using WTF::DecimalNumber;
using WTF::RoundingSignificantFigures;
using WTF::RoundingDecimalPlaces;
#endif // DecimalNumber_h

View File

@ -0,0 +1,120 @@
/*
* Copyright (C) 2013 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. ``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
* 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 <wtf/Assertions.h>
#include <wtf/FastMalloc.h>
#include <wtf/Noncopyable.h>
namespace WTF {
// A variant of RefCounted that allows reference counting to be deferred,
// and can tell you if that has happened. You can think of a deferral as
// just being an additional "ref", except that you can detect if it has
// specifically happened - this can be useful either for debugging, or
// sometimes even for some additional functionality.
class DeferrableRefCountedBase {
static const unsigned deferredFlag = 1;
static const unsigned normalIncrement = 2;
public:
void ref() const
{
m_refCount += normalIncrement;
}
bool hasOneRef() const
{
return refCount() == 1;
}
unsigned refCount() const
{
return m_refCount / normalIncrement;
}
bool isDeferred() const
{
return !!(m_refCount & deferredFlag);
}
protected:
DeferrableRefCountedBase()
: m_refCount(normalIncrement)
{
}
~DeferrableRefCountedBase()
{
}
bool derefBase() const
{
m_refCount -= normalIncrement;
return !m_refCount;
}
bool setIsDeferredBase(bool value)
{
if (value) {
m_refCount |= deferredFlag;
return false;
}
m_refCount &= ~deferredFlag;
return !m_refCount;
}
private:
mutable unsigned m_refCount;
};
template<typename T>
class DeferrableRefCounted : public DeferrableRefCountedBase {
WTF_MAKE_NONCOPYABLE(DeferrableRefCounted); WTF_MAKE_FAST_ALLOCATED;
public:
void deref() const
{
if (derefBase())
delete static_cast<const T*>(this);
}
bool setIsDeferred(bool value)
{
if (!setIsDeferredBase(value))
return false;
delete static_cast<T*>(this);
return true;
}
protected:
DeferrableRefCounted() { }
~DeferrableRefCounted() { }
};
} // namespace WTF
using WTF::DeferrableRefCounted;

View File

@ -0,0 +1,51 @@
/*
* Copyright (C) 2014, 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.
*/
// This file contains a deprecated version of WTF::Optional which a released
// version of Safari uses. Once Safari stops using this, we can remove this.
// New code should use std::optional.
#pragma once
#include <type_traits>
namespace WTF {
template<typename T>
class Optional {
public:
explicit operator bool() const { return m_isEngaged; }
T& value() { return *asPtr(); }
private:
T* asPtr() { return reinterpret_cast<T*>(&m_value); }
bool m_isEngaged;
typename std::aligned_storage<sizeof(T), std::alignment_of<T>::value>::type m_value;
};
template<typename T> using DeprecatedOptional = WTF::Optional<T>;
} // namespace WTF

752
include/Deque.h Normal file
View File

@ -0,0 +1,752 @@
/*
* Copyright (C) 2007-2017 Apple Inc. All rights reserved.
* Copyright (C) 2009 Google 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.
* 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE 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 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.
*/
#ifndef WTF_Deque_h
#define WTF_Deque_h
// FIXME: Could move what Vector and Deque share into a separate file.
// Deque doesn't actually use Vector.
#include <iterator>
#include <wtf/Vector.h>
namespace WTF {
template<typename T, size_t inlineCapacity> class DequeIteratorBase;
template<typename T, size_t inlineCapacity> class DequeIterator;
template<typename T, size_t inlineCapacity> class DequeConstIterator;
template<typename T, size_t inlineCapacity = 0>
class Deque {
WTF_MAKE_FAST_ALLOCATED;
public:
typedef T ValueType;
typedef DequeIterator<T, inlineCapacity> iterator;
typedef DequeConstIterator<T, inlineCapacity> const_iterator;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
Deque();
Deque(std::initializer_list<T>);
Deque(const Deque&);
Deque(Deque&&);
~Deque();
Deque& operator=(const Deque&);
Deque& operator=(Deque&&);
void swap(Deque&);
size_t size() const { return m_start <= m_end ? m_end - m_start : m_end + m_buffer.capacity() - m_start; }
bool isEmpty() const { return m_start == m_end; }
iterator begin() { return iterator(this, m_start); }
iterator end() { return iterator(this, m_end); }
const_iterator begin() const { return const_iterator(this, m_start); }
const_iterator end() const { return const_iterator(this, m_end); }
reverse_iterator rbegin() { return reverse_iterator(end()); }
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
T& first() { ASSERT(m_start != m_end); return m_buffer.buffer()[m_start]; }
const T& first() const { ASSERT(m_start != m_end); return m_buffer.buffer()[m_start]; }
T takeFirst();
T& last() { ASSERT(m_start != m_end); return *(--end()); }
const T& last() const { ASSERT(m_start != m_end); return *(--end()); }
T takeLast();
void append(T&& value) { append<T>(std::forward<T>(value)); }
template<typename U> void append(U&&);
template<typename U> void prepend(U&&);
void removeFirst();
void removeLast();
void remove(iterator&);
void remove(const_iterator&);
template<typename Func> void removeAllMatching(const Func&);
// This is a priority enqueue. The callback is given a value, and if it returns true, then this
// will put the appended value before that value. It will keep bubbling until the callback returns
// false or the value ends up at the head of the queue.
template<typename U, typename Func>
void appendAndBubble(U&&, const Func&);
// Remove and return the last element for which the callback returns true. Returns a null version of
// T if it the callback always returns false.
template<typename Func>
T takeLast(const Func&);
void clear();
template<typename Predicate>
iterator findIf(Predicate&&);
private:
friend class DequeIteratorBase<T, inlineCapacity>;
typedef VectorBuffer<T, inlineCapacity> Buffer;
typedef VectorTypeOperations<T> TypeOperations;
typedef DequeIteratorBase<T, inlineCapacity> IteratorBase;
void remove(size_t position);
void invalidateIterators();
void destroyAll();
void checkValidity() const;
void checkIndexValidity(size_t) const;
void expandCapacityIfNeeded();
void expandCapacity();
size_t m_start;
size_t m_end;
Buffer m_buffer;
#ifndef NDEBUG
mutable IteratorBase* m_iterators;
#endif
};
template<typename T, size_t inlineCapacity = 0>
class DequeIteratorBase {
protected:
DequeIteratorBase();
DequeIteratorBase(const Deque<T, inlineCapacity>*, size_t);
DequeIteratorBase(const DequeIteratorBase&);
DequeIteratorBase& operator=(const DequeIteratorBase&);
~DequeIteratorBase();
void assign(const DequeIteratorBase& other) { *this = other; }
void increment();
void decrement();
T* before() const;
T* after() const;
bool isEqual(const DequeIteratorBase&) const;
private:
void addToIteratorsList();
void removeFromIteratorsList();
void checkValidity() const;
void checkValidity(const DequeIteratorBase&) const;
Deque<T, inlineCapacity>* m_deque;
size_t m_index;
friend class Deque<T, inlineCapacity>;
#ifndef NDEBUG
mutable DequeIteratorBase* m_next;
mutable DequeIteratorBase* m_previous;
#endif
};
template<typename T, size_t inlineCapacity = 0>
class DequeIterator : public DequeIteratorBase<T, inlineCapacity> {
private:
typedef DequeIteratorBase<T, inlineCapacity> Base;
typedef DequeIterator<T, inlineCapacity> Iterator;
public:
typedef ptrdiff_t difference_type;
typedef T value_type;
typedef T* pointer;
typedef T& reference;
typedef std::bidirectional_iterator_tag iterator_category;
DequeIterator(Deque<T, inlineCapacity>* deque, size_t index)
: Base(deque, index) { }
DequeIterator(const Iterator& other) : Base(other) { }
DequeIterator& operator=(const Iterator& other) { Base::assign(other); return *this; }
T& operator*() const { return *Base::after(); }
T* operator->() const { return Base::after(); }
bool operator==(const Iterator& other) const { return Base::isEqual(other); }
bool operator!=(const Iterator& other) const { return !Base::isEqual(other); }
Iterator& operator++() { Base::increment(); return *this; }
// postfix ++ intentionally omitted
Iterator& operator--() { Base::decrement(); return *this; }
// postfix -- intentionally omitted
};
template<typename T, size_t inlineCapacity = 0>
class DequeConstIterator : public DequeIteratorBase<T, inlineCapacity> {
private:
typedef DequeIteratorBase<T, inlineCapacity> Base;
typedef DequeConstIterator<T, inlineCapacity> Iterator;
typedef DequeIterator<T, inlineCapacity> NonConstIterator;
public:
typedef ptrdiff_t difference_type;
typedef T value_type;
typedef const T* pointer;
typedef const T& reference;
typedef std::bidirectional_iterator_tag iterator_category;
DequeConstIterator(const Deque<T, inlineCapacity>* deque, size_t index)
: Base(deque, index) { }
DequeConstIterator(const Iterator& other) : Base(other) { }
DequeConstIterator(const NonConstIterator& other) : Base(other) { }
DequeConstIterator& operator=(const Iterator& other) { Base::assign(other); return *this; }
DequeConstIterator& operator=(const NonConstIterator& other) { Base::assign(other); return *this; }
const T& operator*() const { return *Base::after(); }
const T* operator->() const { return Base::after(); }
bool operator==(const Iterator& other) const { return Base::isEqual(other); }
bool operator!=(const Iterator& other) const { return !Base::isEqual(other); }
Iterator& operator++() { Base::increment(); return *this; }
// postfix ++ intentionally omitted
Iterator& operator--() { Base::decrement(); return *this; }
// postfix -- intentionally omitted
};
#ifdef NDEBUG
template<typename T, size_t inlineCapacity> inline void Deque<T, inlineCapacity>::checkValidity() const { }
template<typename T, size_t inlineCapacity> inline void Deque<T, inlineCapacity>::checkIndexValidity(size_t) const { }
template<typename T, size_t inlineCapacity> inline void Deque<T, inlineCapacity>::invalidateIterators() { }
#else
template<typename T, size_t inlineCapacity>
void Deque<T, inlineCapacity>::checkValidity() const
{
// In this implementation a capacity of 1 would confuse append() and
// other places that assume the index after capacity - 1 is 0.
ASSERT(m_buffer.capacity() != 1);
if (!m_buffer.capacity()) {
ASSERT(!m_start);
ASSERT(!m_end);
} else {
ASSERT(m_start < m_buffer.capacity());
ASSERT(m_end < m_buffer.capacity());
}
}
template<typename T, size_t inlineCapacity>
void Deque<T, inlineCapacity>::checkIndexValidity(size_t index) const
{
ASSERT_UNUSED(index, index <= m_buffer.capacity());
if (m_start <= m_end) {
ASSERT(index >= m_start);
ASSERT(index <= m_end);
} else {
ASSERT(index >= m_start || index <= m_end);
}
}
template<typename T, size_t inlineCapacity>
void Deque<T, inlineCapacity>::invalidateIterators()
{
IteratorBase* next;
for (IteratorBase* p = m_iterators; p; p = next) {
next = p->m_next;
p->m_deque = 0;
p->m_next = 0;
p->m_previous = 0;
}
m_iterators = 0;
}
#endif
template<typename T, size_t inlineCapacity>
inline Deque<T, inlineCapacity>::Deque()
: m_start(0)
, m_end(0)
#ifndef NDEBUG
, m_iterators(0)
#endif
{
checkValidity();
}
template<typename T, size_t inlineCapacity>
inline Deque<T, inlineCapacity>::Deque(std::initializer_list<T> initializerList)
: Deque()
{
for (auto& element : initializerList)
append(element);
}
template<typename T, size_t inlineCapacity>
inline Deque<T, inlineCapacity>::Deque(const Deque& other)
: m_start(other.m_start)
, m_end(other.m_end)
, m_buffer(other.m_buffer.capacity())
#ifndef NDEBUG
, m_iterators(0)
#endif
{
const T* otherBuffer = other.m_buffer.buffer();
if (m_start <= m_end)
TypeOperations::uninitializedCopy(otherBuffer + m_start, otherBuffer + m_end, m_buffer.buffer() + m_start);
else {
TypeOperations::uninitializedCopy(otherBuffer, otherBuffer + m_end, m_buffer.buffer());
TypeOperations::uninitializedCopy(otherBuffer + m_start, otherBuffer + m_buffer.capacity(), m_buffer.buffer() + m_start);
}
}
template<typename T, size_t inlineCapacity>
inline Deque<T, inlineCapacity>::Deque(Deque&& other)
: Deque()
{
swap(other);
}
template<typename T, size_t inlineCapacity>
inline auto Deque<T, inlineCapacity>::operator=(const Deque& other) -> Deque&
{
// FIXME: This is inefficient if we're using an inline buffer and T is
// expensive to copy since it will copy the buffer twice instead of once.
Deque<T, inlineCapacity> copy(other);
swap(copy);
return *this;
}
template<typename T, size_t inlineCapacity>
inline auto Deque<T, inlineCapacity>::operator=(Deque&& other) -> Deque&
{
swap(other);
return *this;
}
template<typename T, size_t inlineCapacity>
inline void Deque<T, inlineCapacity>::destroyAll()
{
if (m_start <= m_end)
TypeOperations::destruct(m_buffer.buffer() + m_start, m_buffer.buffer() + m_end);
else {
TypeOperations::destruct(m_buffer.buffer(), m_buffer.buffer() + m_end);
TypeOperations::destruct(m_buffer.buffer() + m_start, m_buffer.buffer() + m_buffer.capacity());
}
}
template<typename T, size_t inlineCapacity>
inline Deque<T, inlineCapacity>::~Deque()
{
checkValidity();
invalidateIterators();
destroyAll();
}
template<typename T, size_t inlineCapacity>
inline void Deque<T, inlineCapacity>::swap(Deque<T, inlineCapacity>& other)
{
checkValidity();
other.checkValidity();
invalidateIterators();
std::swap(m_start, other.m_start);
std::swap(m_end, other.m_end);
m_buffer.swap(other.m_buffer, 0, 0);
checkValidity();
other.checkValidity();
}
template<typename T, size_t inlineCapacity>
inline void Deque<T, inlineCapacity>::clear()
{
checkValidity();
invalidateIterators();
destroyAll();
m_start = 0;
m_end = 0;
m_buffer.deallocateBuffer(m_buffer.buffer());
checkValidity();
}
template<typename T, size_t inlineCapacity>
template<typename Predicate>
inline auto Deque<T, inlineCapacity>::findIf(Predicate&& predicate) -> iterator
{
iterator end_iterator = end();
for (iterator it = begin(); it != end_iterator; ++it) {
if (predicate(*it))
return it;
}
return end_iterator;
}
template<typename T, size_t inlineCapacity>
inline void Deque<T, inlineCapacity>::expandCapacityIfNeeded()
{
if (m_start) {
if (m_end + 1 != m_start)
return;
} else if (m_end) {
if (m_end != m_buffer.capacity() - 1)
return;
} else if (m_buffer.capacity())
return;
expandCapacity();
}
template<typename T, size_t inlineCapacity>
void Deque<T, inlineCapacity>::expandCapacity()
{
checkValidity();
size_t oldCapacity = m_buffer.capacity();
T* oldBuffer = m_buffer.buffer();
m_buffer.allocateBuffer(std::max(static_cast<size_t>(16), oldCapacity + oldCapacity / 4 + 1));
if (m_start <= m_end)
TypeOperations::move(oldBuffer + m_start, oldBuffer + m_end, m_buffer.buffer() + m_start);
else {
TypeOperations::move(oldBuffer, oldBuffer + m_end, m_buffer.buffer());
size_t newStart = m_buffer.capacity() - (oldCapacity - m_start);
TypeOperations::move(oldBuffer + m_start, oldBuffer + oldCapacity, m_buffer.buffer() + newStart);
m_start = newStart;
}
m_buffer.deallocateBuffer(oldBuffer);
checkValidity();
}
template<typename T, size_t inlineCapacity>
inline auto Deque<T, inlineCapacity>::takeFirst() -> T
{
T oldFirst = WTFMove(first());
removeFirst();
return oldFirst;
}
template<typename T, size_t inlineCapacity>
inline auto Deque<T, inlineCapacity>::takeLast() -> T
{
T oldLast = WTFMove(last());
removeLast();
return oldLast;
}
template<typename T, size_t inlineCapacity> template<typename U>
inline void Deque<T, inlineCapacity>::append(U&& value)
{
checkValidity();
expandCapacityIfNeeded();
new (NotNull, std::addressof(m_buffer.buffer()[m_end])) T(std::forward<U>(value));
if (m_end == m_buffer.capacity() - 1)
m_end = 0;
else
++m_end;
checkValidity();
}
template<typename T, size_t inlineCapacity> template<typename U>
inline void Deque<T, inlineCapacity>::prepend(U&& value)
{
checkValidity();
expandCapacityIfNeeded();
if (!m_start)
m_start = m_buffer.capacity() - 1;
else
--m_start;
new (NotNull, std::addressof(m_buffer.buffer()[m_start])) T(std::forward<U>(value));
checkValidity();
}
template<typename T, size_t inlineCapacity>
inline void Deque<T, inlineCapacity>::removeFirst()
{
checkValidity();
invalidateIterators();
ASSERT(!isEmpty());
TypeOperations::destruct(std::addressof(m_buffer.buffer()[m_start]), std::addressof(m_buffer.buffer()[m_start + 1]));
if (m_start == m_buffer.capacity() - 1)
m_start = 0;
else
++m_start;
checkValidity();
}
template<typename T, size_t inlineCapacity>
inline void Deque<T, inlineCapacity>::removeLast()
{
checkValidity();
invalidateIterators();
ASSERT(!isEmpty());
if (!m_end)
m_end = m_buffer.capacity() - 1;
else
--m_end;
TypeOperations::destruct(std::addressof(m_buffer.buffer()[m_end]), std::addressof(m_buffer.buffer()[m_end + 1]));
checkValidity();
}
template<typename T, size_t inlineCapacity>
inline void Deque<T, inlineCapacity>::remove(iterator& it)
{
it.checkValidity();
remove(it.m_index);
}
template<typename T, size_t inlineCapacity>
inline void Deque<T, inlineCapacity>::remove(const_iterator& it)
{
it.checkValidity();
remove(it.m_index);
}
template<typename T, size_t inlineCapacity>
inline void Deque<T, inlineCapacity>::remove(size_t position)
{
if (position == m_end)
return;
checkValidity();
invalidateIterators();
T* buffer = m_buffer.buffer();
TypeOperations::destruct(std::addressof(buffer[position]), std::addressof(buffer[position + 1]));
// Find which segment of the circular buffer contained the remove element, and only move elements in that part.
if (position >= m_start) {
TypeOperations::moveOverlapping(buffer + m_start, buffer + position, buffer + m_start + 1);
m_start = (m_start + 1) % m_buffer.capacity();
} else {
TypeOperations::moveOverlapping(buffer + position + 1, buffer + m_end, buffer + position);
m_end = (m_end - 1 + m_buffer.capacity()) % m_buffer.capacity();
}
checkValidity();
}
template<typename T, size_t inlineCapacity>
template<typename Func>
inline void Deque<T, inlineCapacity>::removeAllMatching(const Func& func)
{
size_t count = size();
while (count--) {
T value = takeFirst();
if (!func(value))
append(WTFMove(value));
}
}
template<typename T, size_t inlineCapacity>
template<typename U, typename Func>
inline void Deque<T, inlineCapacity>::appendAndBubble(U&& value, const Func& func)
{
append(WTFMove(value));
iterator begin = this->begin();
iterator iter = end();
--iter;
while (iter != begin) {
iterator prev = iter;
--prev;
if (!func(*prev))
return;
std::swap(*prev, *iter);
iter = prev;
}
}
template<typename T, size_t inlineCapacity>
template<typename Func>
inline T Deque<T, inlineCapacity>::takeLast(const Func& func)
{
unsigned count = 0;
unsigned size = this->size();
while (count < size) {
T candidate = takeLast();
if (func(candidate)) {
while (count--)
append(takeFirst());
return candidate;
}
count++;
prepend(WTFMove(candidate));
}
return T();
}
#ifdef NDEBUG
template<typename T, size_t inlineCapacity> inline void DequeIteratorBase<T, inlineCapacity>::checkValidity() const { }
template<typename T, size_t inlineCapacity> inline void DequeIteratorBase<T, inlineCapacity>::checkValidity(const DequeIteratorBase<T, inlineCapacity>&) const { }
template<typename T, size_t inlineCapacity> inline void DequeIteratorBase<T, inlineCapacity>::addToIteratorsList() { }
template<typename T, size_t inlineCapacity> inline void DequeIteratorBase<T, inlineCapacity>::removeFromIteratorsList() { }
#else
template<typename T, size_t inlineCapacity>
void DequeIteratorBase<T, inlineCapacity>::checkValidity() const
{
ASSERT(m_deque);
m_deque->checkIndexValidity(m_index);
}
template<typename T, size_t inlineCapacity>
void DequeIteratorBase<T, inlineCapacity>::checkValidity(const DequeIteratorBase& other) const
{
checkValidity();
other.checkValidity();
ASSERT(m_deque == other.m_deque);
}
template<typename T, size_t inlineCapacity>
void DequeIteratorBase<T, inlineCapacity>::addToIteratorsList()
{
if (!m_deque)
m_next = 0;
else {
m_next = m_deque->m_iterators;
m_deque->m_iterators = this;
if (m_next)
m_next->m_previous = this;
}
m_previous = 0;
}
template<typename T, size_t inlineCapacity>
void DequeIteratorBase<T, inlineCapacity>::removeFromIteratorsList()
{
if (!m_deque) {
ASSERT(!m_next);
ASSERT(!m_previous);
} else {
if (m_next) {
ASSERT(m_next->m_previous == this);
m_next->m_previous = m_previous;
}
if (m_previous) {
ASSERT(m_deque->m_iterators != this);
ASSERT(m_previous->m_next == this);
m_previous->m_next = m_next;
} else {
ASSERT(m_deque->m_iterators == this);
m_deque->m_iterators = m_next;
}
}
m_next = 0;
m_previous = 0;
}
#endif
template<typename T, size_t inlineCapacity>
inline DequeIteratorBase<T, inlineCapacity>::DequeIteratorBase()
: m_deque(0)
{
}
template<typename T, size_t inlineCapacity>
inline DequeIteratorBase<T, inlineCapacity>::DequeIteratorBase(const Deque<T, inlineCapacity>* deque, size_t index)
: m_deque(const_cast<Deque<T, inlineCapacity>*>(deque))
, m_index(index)
{
addToIteratorsList();
checkValidity();
}
template<typename T, size_t inlineCapacity>
inline DequeIteratorBase<T, inlineCapacity>::DequeIteratorBase(const DequeIteratorBase& other)
: m_deque(other.m_deque)
, m_index(other.m_index)
{
addToIteratorsList();
checkValidity();
}
template<typename T, size_t inlineCapacity>
inline DequeIteratorBase<T, inlineCapacity>& DequeIteratorBase<T, inlineCapacity>::operator=(const DequeIteratorBase& other)
{
other.checkValidity();
removeFromIteratorsList();
m_deque = other.m_deque;
m_index = other.m_index;
addToIteratorsList();
checkValidity();
return *this;
}
template<typename T, size_t inlineCapacity>
inline DequeIteratorBase<T, inlineCapacity>::~DequeIteratorBase()
{
#ifndef NDEBUG
removeFromIteratorsList();
m_deque = 0;
#endif
}
template<typename T, size_t inlineCapacity>
inline bool DequeIteratorBase<T, inlineCapacity>::isEqual(const DequeIteratorBase& other) const
{
checkValidity(other);
return m_index == other.m_index;
}
template<typename T, size_t inlineCapacity>
inline void DequeIteratorBase<T, inlineCapacity>::increment()
{
checkValidity();
ASSERT(m_index != m_deque->m_end);
ASSERT(m_deque->m_buffer.capacity());
if (m_index == m_deque->m_buffer.capacity() - 1)
m_index = 0;
else
++m_index;
checkValidity();
}
template<typename T, size_t inlineCapacity>
inline void DequeIteratorBase<T, inlineCapacity>::decrement()
{
checkValidity();
ASSERT(m_index != m_deque->m_start);
ASSERT(m_deque->m_buffer.capacity());
if (!m_index)
m_index = m_deque->m_buffer.capacity() - 1;
else
--m_index;
checkValidity();
}
template<typename T, size_t inlineCapacity>
inline T* DequeIteratorBase<T, inlineCapacity>::after() const
{
checkValidity();
ASSERT(m_index != m_deque->m_end);
return std::addressof(m_deque->m_buffer.buffer()[m_index]);
}
template<typename T, size_t inlineCapacity>
inline T* DequeIteratorBase<T, inlineCapacity>::before() const
{
checkValidity();
ASSERT(m_index != m_deque->m_start);
if (!m_index)
return std::addressof(m_deque->m_buffer.buffer()[m_deque->m_buffer.capacity() - 1]);
return std::addressof(m_deque->m_buffer.buffer()[m_index - 1]);
}
} // namespace WTF
using WTF::Deque;
#endif // WTF_Deque_h

83
include/DisallowCType.h Normal file
View File

@ -0,0 +1,83 @@
/*
* Copyright (C) 2007 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.
* 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE 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 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.
*/
#ifndef WTF_DisallowCType_h
#define WTF_DisallowCType_h
// The behavior of many of the functions in the <ctype.h> header is dependent
// on the current locale. But almost all uses of these functions are for
// locale-independent, ASCII-specific purposes. In WebKit code we use our own
// ASCII-specific functions instead. This header makes sure we get a compile-time
// error if we use one of the <ctype.h> functions by accident.
// this breaks compilation of <QFontDatabase>, at least, so turn it off for now
// Also generates errors on wx on Windows, presumably because these functions
// are used from wx headers. On GTK+ for Mac many GTK+ files include <libintl.h>
// or <glib/gi18n-lib.h>, which in turn include <xlocale/_ctype.h> which uses
// isacii().
#if !(OS(DARWIN) && PLATFORM(GTK)) && !defined(_LIBCPP_VERSION) && defined(__GLIBC__)
#include <ctype.h>
#undef isalnum
#undef isalpha
#undef isascii
#undef isblank
#undef iscntrl
#undef isdigit
#undef isgraph
#undef islower
#undef isprint
#undef ispunct
#undef isspace
#undef isupper
#undef isxdigit
#undef toascii
#undef tolower
#undef toupper
#define isalnum isalnum_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
#define isalpha isalpha_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
#define isascii isascii_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
#define isblank isblank_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
#define iscntrl iscntrl_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
#define isdigit isdigit_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
#define isgraph isgraph_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
#define islower islower_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
#define isprint isprint_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
#define ispunct ispunct_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
#define isspace isspace_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
#define isupper isupper_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
#define isxdigit isxdigit_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
#define toascii toascii_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
#define tolower tolower_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
#define toupper toupper_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h
#endif
#endif

103
include/DispatchPtr.h Normal file
View File

@ -0,0 +1,103 @@
/*
* Copyright (C) 2015-2017 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
#if PLATFORM(COCOA)
#include <wtf/Assertions.h>
#include <wtf/StdLibExtras.h>
namespace WTF {
template <typename T> class DispatchPtr;
template <typename T> DispatchPtr<T> adoptDispatch(T dispatchObject);
// FIXME: Use OSObjectPtr instead when it works with dispatch_data_t on all platforms.
template<typename T> class DispatchPtr {
public:
DispatchPtr()
: m_ptr(nullptr)
{
}
explicit DispatchPtr(T ptr)
: m_ptr(ptr)
{
if (m_ptr)
dispatch_retain(m_ptr);
}
DispatchPtr(const DispatchPtr& other)
: m_ptr(other.m_ptr)
{
if (m_ptr)
dispatch_retain(m_ptr);
}
~DispatchPtr()
{
if (m_ptr)
dispatch_release(m_ptr);
}
DispatchPtr& operator=(const DispatchPtr& other)
{
auto copy = other;
std::swap(m_ptr, copy.m_ptr);
return *this;
}
DispatchPtr& operator=(std::nullptr_t)
{
auto ptr = std::exchange(m_ptr, nullptr);
if (LIKELY(ptr != nullptr))
dispatch_release(ptr);
return *this;
}
T get() const { return m_ptr; }
explicit operator bool() const { return m_ptr; }
friend DispatchPtr adoptDispatch<T>(T);
private:
struct Adopt { };
DispatchPtr(Adopt, T data)
: m_ptr(data)
{
}
T m_ptr;
};
template <typename T> DispatchPtr<T> adoptDispatch(T dispatchObject)
{
return DispatchPtr<T>(typename DispatchPtr<T>::Adopt { }, dispatchObject);
}
} // namespace WTF
using WTF::DispatchPtr;
using WTF::adoptDispatch;
#endif

752
include/Dominators.h Normal file
View File

@ -0,0 +1,752 @@
/*
* Copyright (C) 2011, 2014-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. ``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
* 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.
*/
#ifndef WTFDominators_h
#define WTFDominators_h
#include <wtf/FastBitVector.h>
#include <wtf/GraphNodeWorklist.h>
namespace WTF {
// This is a utility for finding the dominators of a graph. Dominators are almost universally used
// for control flow graph analysis, so this code will refer to the graph's "nodes" as "blocks". In
// that regard this code is kind of specialized for the various JSC compilers, but you could use it
// for non-compiler things if you are OK with referring to your "nodes" as "blocks".
template<typename Graph>
class Dominators {
public:
Dominators(Graph& graph, bool selfCheck = false)
: m_graph(graph)
, m_data(graph.template newMap<BlockData>())
{
LengauerTarjan lengauerTarjan(m_graph);
lengauerTarjan.compute();
m_data = m_graph.template newMap<BlockData>();
// From here we want to build a spanning tree with both upward and downward links and we want
// to do a search over this tree to compute pre and post numbers that can be used for dominance
// tests.
for (unsigned blockIndex = m_graph.numNodes(); blockIndex--;) {
typename Graph::Node block = m_graph.node(blockIndex);
if (!block)
continue;
typename Graph::Node idomBlock = lengauerTarjan.immediateDominator(block);
m_data[block].idomParent = idomBlock;
if (idomBlock)
m_data[idomBlock].idomKids.append(block);
}
unsigned nextPreNumber = 0;
unsigned nextPostNumber = 0;
// Plain stack-based worklist because we are guaranteed to see each block exactly once anyway.
Vector<GraphNodeWithOrder<typename Graph::Node>> worklist;
worklist.append(GraphNodeWithOrder<typename Graph::Node>(m_graph.root(), GraphVisitOrder::Pre));
while (!worklist.isEmpty()) {
GraphNodeWithOrder<typename Graph::Node> item = worklist.takeLast();
switch (item.order) {
case GraphVisitOrder::Pre:
m_data[item.node].preNumber = nextPreNumber++;
worklist.append(GraphNodeWithOrder<typename Graph::Node>(item.node, GraphVisitOrder::Post));
for (typename Graph::Node kid : m_data[item.node].idomKids)
worklist.append(GraphNodeWithOrder<typename Graph::Node>(kid, GraphVisitOrder::Pre));
break;
case GraphVisitOrder::Post:
m_data[item.node].postNumber = nextPostNumber++;
break;
}
}
if (selfCheck) {
// Check our dominator calculation:
// 1) Check that our range-based ancestry test is the same as a naive ancestry test.
// 2) Check that our notion of who dominates whom is identical to a naive (not
// Lengauer-Tarjan) dominator calculation.
ValidationContext context(m_graph, *this);
for (unsigned fromBlockIndex = m_graph.numNodes(); fromBlockIndex--;) {
typename Graph::Node fromBlock = m_graph.node(fromBlockIndex);
if (!fromBlock || m_data[fromBlock].preNumber == UINT_MAX)
continue;
for (unsigned toBlockIndex = m_graph.numNodes(); toBlockIndex--;) {
typename Graph::Node toBlock = m_graph.node(toBlockIndex);
if (!toBlock || m_data[toBlock].preNumber == UINT_MAX)
continue;
if (dominates(fromBlock, toBlock) != naiveDominates(fromBlock, toBlock))
context.reportError(fromBlock, toBlock, "Range-based domination check is broken");
if (dominates(fromBlock, toBlock) != context.naiveDominators.dominates(fromBlock, toBlock))
context.reportError(fromBlock, toBlock, "Lengauer-Tarjan domination is broken");
}
}
context.handleErrors();
}
}
bool strictlyDominates(typename Graph::Node from, typename Graph::Node to) const
{
return m_data[to].preNumber > m_data[from].preNumber
&& m_data[to].postNumber < m_data[from].postNumber;
}
bool dominates(typename Graph::Node from, typename Graph::Node to) const
{
return from == to || strictlyDominates(from, to);
}
// Returns the immediate dominator of this block. Returns null for the root block.
typename Graph::Node idom(typename Graph::Node block) const
{
return m_data[block].idomParent;
}
template<typename Functor>
void forAllStrictDominatorsOf(typename Graph::Node to, const Functor& functor) const
{
for (typename Graph::Node block = m_data[to].idomParent; block; block = m_data[block].idomParent)
functor(block);
}
// Note: This will visit the dominators starting with the 'to' node and moving up the idom tree
// until it gets to the root. Some clients of this function, like B3::moveConstants(), rely on this
// order.
template<typename Functor>
void forAllDominatorsOf(typename Graph::Node to, const Functor& functor) const
{
for (typename Graph::Node block = to; block; block = m_data[block].idomParent)
functor(block);
}
template<typename Functor>
void forAllBlocksStrictlyDominatedBy(typename Graph::Node from, const Functor& functor) const
{
Vector<typename Graph::Node, 16> worklist;
worklist.appendVector(m_data[from].idomKids);
while (!worklist.isEmpty()) {
typename Graph::Node block = worklist.takeLast();
functor(block);
worklist.appendVector(m_data[block].idomKids);
}
}
template<typename Functor>
void forAllBlocksDominatedBy(typename Graph::Node from, const Functor& functor) const
{
Vector<typename Graph::Node, 16> worklist;
worklist.append(from);
while (!worklist.isEmpty()) {
typename Graph::Node block = worklist.takeLast();
functor(block);
worklist.appendVector(m_data[block].idomKids);
}
}
typename Graph::Set strictDominatorsOf(typename Graph::Node to) const
{
typename Graph::Set result;
forAllStrictDominatorsOf(
to,
[&] (typename Graph::Node node) {
result.add(node);
});
return result;
}
typename Graph::Set dominatorsOf(typename Graph::Node to) const
{
typename Graph::Set result;
forAllDominatorsOf(
to,
[&] (typename Graph::Node node) {
result.add(node);
});
return result;
}
typename Graph::Set blocksStrictlyDominatedBy(typename Graph::Node from) const
{
typename Graph::Set result;
forAllBlocksStrictlyDominatedBy(
from,
[&] (typename Graph::Node node) {
result.add(node);
});
return result;
}
typename Graph::Set blocksDominatedBy(typename Graph::Node from) const
{
typename Graph::Set result;
forAllBlocksDominatedBy(
from,
[&] (typename Graph::Node node) {
result.add(node);
});
return result;
}
template<typename Functor>
void forAllBlocksInDominanceFrontierOf(
typename Graph::Node from, const Functor& functor) const
{
typename Graph::Set set;
forAllBlocksInDominanceFrontierOfImpl(
from,
[&] (typename Graph::Node block) {
if (set.add(block))
functor(block);
});
}
typename Graph::Set dominanceFrontierOf(typename Graph::Node from) const
{
typename Graph::Set result;
forAllBlocksInDominanceFrontierOf(
from,
[&] (typename Graph::Node node) {
result.add(node);
});
return result;
}
template<typename Functor>
void forAllBlocksInIteratedDominanceFrontierOf(const typename Graph::List& from, const Functor& functor)
{
forAllBlocksInPrunedIteratedDominanceFrontierOf(
from,
[&] (typename Graph::Node block) -> bool {
functor(block);
return true;
});
}
// This is a close relative of forAllBlocksInIteratedDominanceFrontierOf(), which allows the
// given functor to return false to indicate that we don't wish to consider the given block.
// Useful for computing pruned SSA form.
template<typename Functor>
void forAllBlocksInPrunedIteratedDominanceFrontierOf(
const typename Graph::List& from, const Functor& functor)
{
typename Graph::Set set;
forAllBlocksInIteratedDominanceFrontierOfImpl(
from,
[&] (typename Graph::Node block) -> bool {
if (!set.add(block))
return false;
return functor(block);
});
}
typename Graph::Set iteratedDominanceFrontierOf(const typename Graph::List& from) const
{
typename Graph::Set result;
forAllBlocksInIteratedDominanceFrontierOfImpl(
from,
[&] (typename Graph::Node node) -> bool {
return result.add(node);
});
return result;
}
void dump(PrintStream& out) const
{
for (unsigned blockIndex = 0; blockIndex < m_data.size(); ++blockIndex) {
if (m_data[blockIndex].preNumber == UINT_MAX)
continue;
out.print(" Block #", blockIndex, ": idom = ", m_graph.dump(m_data[blockIndex].idomParent), ", idomKids = [");
CommaPrinter comma;
for (unsigned i = 0; i < m_data[blockIndex].idomKids.size(); ++i)
out.print(comma, m_graph.dump(m_data[blockIndex].idomKids[i]));
out.print("], pre/post = ", m_data[blockIndex].preNumber, "/", m_data[blockIndex].postNumber, "\n");
}
}
private:
// This implements Lengauer and Tarjan's "A Fast Algorithm for Finding Dominators in a Flowgraph"
// (TOPLAS 1979). It uses the "simple" implementation of LINK and EVAL, which yields an O(n log n)
// solution. The full paper is linked below; this code attempts to closely follow the algorithm as
// it is presented in the paper; in particular sections 3 and 4 as well as appendix B.
// https://www.cs.princeton.edu/courses/archive/fall03/cs528/handouts/a%20fast%20algorithm%20for%20finding.pdf
//
// This code is very subtle. The Lengauer-Tarjan algorithm is incredibly deep to begin with. The
// goal of this code is to follow the code in the paper, however our implementation must deviate
// from the paper when it comes to recursion. The authors had used recursion to implement DFS, and
// also to implement the "simple" EVAL. We convert both of those into worklist-based solutions.
// Finally, once the algorithm gives us immediate dominators, we implement dominance tests by
// walking the dominator tree and computing pre and post numbers. We then use the range inclusion
// check trick that was first discovered by Paul F. Dietz in 1982 in "Maintaining order in a linked
// list" (see http://dl.acm.org/citation.cfm?id=802184).
class LengauerTarjan {
public:
LengauerTarjan(Graph& graph)
: m_graph(graph)
, m_data(graph.template newMap<BlockData>())
{
for (unsigned blockIndex = m_graph.numNodes(); blockIndex--;) {
typename Graph::Node block = m_graph.node(blockIndex);
if (!block)
continue;
m_data[block].label = block;
}
}
void compute()
{
computeDepthFirstPreNumbering(); // Step 1.
computeSemiDominatorsAndImplicitImmediateDominators(); // Steps 2 and 3.
computeExplicitImmediateDominators(); // Step 4.
}
typename Graph::Node immediateDominator(typename Graph::Node block)
{
return m_data[block].dom;
}
private:
void computeDepthFirstPreNumbering()
{
// Use a block worklist that also tracks the index inside the successor list. This is
// necessary for ensuring that we don't attempt to visit a successor until the previous
// successors that we had visited are fully processed. This ends up being revealed in the
// output of this method because the first time we see an edge to a block, we set the
// block's parent. So, if we have:
//
// A -> B
// A -> C
// B -> C
//
// And we're processing A, then we want to ensure that if we see A->B first (and hence set
// B's prenumber before we set C's) then we also end up setting C's parent to B by virtue
// of not noticing A->C until we're done processing B.
ExtendedGraphNodeWorklist<typename Graph::Node, unsigned, typename Graph::Set> worklist;
worklist.push(m_graph.root(), 0);
while (GraphNodeWith<typename Graph::Node, unsigned> item = worklist.pop()) {
typename Graph::Node block = item.node;
unsigned successorIndex = item.data;
// We initially push with successorIndex = 0 regardless of whether or not we have any
// successors. This is so that we can assign our prenumber. Subsequently we get pushed
// with higher successorIndex values, but only if they are in range.
ASSERT(!successorIndex || successorIndex < m_graph.successors(block).size());
if (!successorIndex) {
m_data[block].semiNumber = m_blockByPreNumber.size();
m_blockByPreNumber.append(block);
}
if (successorIndex < m_graph.successors(block).size()) {
unsigned nextSuccessorIndex = successorIndex + 1;
if (nextSuccessorIndex < m_graph.successors(block).size())
worklist.forcePush(block, nextSuccessorIndex);
typename Graph::Node successorBlock = m_graph.successors(block)[successorIndex];
if (worklist.push(successorBlock, 0))
m_data[successorBlock].parent = block;
}
}
}
void computeSemiDominatorsAndImplicitImmediateDominators()
{
for (unsigned currentPreNumber = m_blockByPreNumber.size(); currentPreNumber-- > 1;) {
typename Graph::Node block = m_blockByPreNumber[currentPreNumber];
BlockData& blockData = m_data[block];
// Step 2:
for (typename Graph::Node predecessorBlock : m_graph.predecessors(block)) {
typename Graph::Node intermediateBlock = eval(predecessorBlock);
blockData.semiNumber = std::min(
m_data[intermediateBlock].semiNumber, blockData.semiNumber);
}
unsigned bucketPreNumber = blockData.semiNumber;
ASSERT(bucketPreNumber <= currentPreNumber);
m_data[m_blockByPreNumber[bucketPreNumber]].bucket.append(block);
link(blockData.parent, block);
// Step 3:
for (typename Graph::Node semiDominee : m_data[blockData.parent].bucket) {
typename Graph::Node possibleDominator = eval(semiDominee);
BlockData& semiDomineeData = m_data[semiDominee];
ASSERT(m_blockByPreNumber[semiDomineeData.semiNumber] == blockData.parent);
BlockData& possibleDominatorData = m_data[possibleDominator];
if (possibleDominatorData.semiNumber < semiDomineeData.semiNumber)
semiDomineeData.dom = possibleDominator;
else
semiDomineeData.dom = blockData.parent;
}
m_data[blockData.parent].bucket.clear();
}
}
void computeExplicitImmediateDominators()
{
for (unsigned currentPreNumber = 1; currentPreNumber < m_blockByPreNumber.size(); ++currentPreNumber) {
typename Graph::Node block = m_blockByPreNumber[currentPreNumber];
BlockData& blockData = m_data[block];
if (blockData.dom != m_blockByPreNumber[blockData.semiNumber])
blockData.dom = m_data[blockData.dom].dom;
}
}
void link(typename Graph::Node from, typename Graph::Node to)
{
m_data[to].ancestor = from;
}
typename Graph::Node eval(typename Graph::Node block)
{
if (!m_data[block].ancestor)
return block;
compress(block);
return m_data[block].label;
}
void compress(typename Graph::Node initialBlock)
{
// This was meant to be a recursive function, but we don't like recursion because we don't
// want to blow the stack. The original function will call compress() recursively on the
// ancestor of anything that has an ancestor. So, we populate our worklist with the
// recursive ancestors of initialBlock. Then we process the list starting from the block
// that is furthest up the ancestor chain.
typename Graph::Node ancestor = m_data[initialBlock].ancestor;
ASSERT(ancestor);
if (!m_data[ancestor].ancestor)
return;
Vector<typename Graph::Node, 16> stack;
for (typename Graph::Node block = initialBlock; block; block = m_data[block].ancestor)
stack.append(block);
// We only care about blocks that have an ancestor that has an ancestor. The last two
// elements in the stack won't satisfy this property.
ASSERT(stack.size() >= 2);
ASSERT(!m_data[stack[stack.size() - 1]].ancestor);
ASSERT(!m_data[m_data[stack[stack.size() - 2]].ancestor].ancestor);
for (unsigned i = stack.size() - 2; i--;) {
typename Graph::Node block = stack[i];
typename Graph::Node& labelOfBlock = m_data[block].label;
typename Graph::Node& ancestorOfBlock = m_data[block].ancestor;
ASSERT(ancestorOfBlock);
ASSERT(m_data[ancestorOfBlock].ancestor);
typename Graph::Node labelOfAncestorOfBlock = m_data[ancestorOfBlock].label;
if (m_data[labelOfAncestorOfBlock].semiNumber < m_data[labelOfBlock].semiNumber)
labelOfBlock = labelOfAncestorOfBlock;
ancestorOfBlock = m_data[ancestorOfBlock].ancestor;
}
}
struct BlockData {
BlockData()
: parent(nullptr)
, preNumber(UINT_MAX)
, semiNumber(UINT_MAX)
, ancestor(nullptr)
, label(nullptr)
, dom(nullptr)
{
}
typename Graph::Node parent;
unsigned preNumber;
unsigned semiNumber;
typename Graph::Node ancestor;
typename Graph::Node label;
Vector<typename Graph::Node> bucket;
typename Graph::Node dom;
};
Graph& m_graph;
typename Graph::template Map<BlockData> m_data;
Vector<typename Graph::Node> m_blockByPreNumber;
};
class NaiveDominators {
public:
NaiveDominators(Graph& graph)
: m_graph(graph)
{
// This implements a naive dominator solver.
ASSERT(!graph.predecessors(graph.root()).size());
unsigned numBlocks = graph.numNodes();
// Allocate storage for the dense dominance matrix.
m_results.grow(numBlocks);
for (unsigned i = numBlocks; i--;)
m_results[i].resize(numBlocks);
m_scratch.resize(numBlocks);
// We know that the entry block is only dominated by itself.
m_results[0].clearAll();
m_results[0][0] = true;
// Find all of the valid blocks.
m_scratch.clearAll();
for (unsigned i = numBlocks; i--;) {
if (!graph.node(i))
continue;
m_scratch[i] = true;
}
// Mark all nodes as dominated by everything.
for (unsigned i = numBlocks; i-- > 1;) {
if (!graph.node(i) || !graph.predecessors(graph.node(i)).size())
m_results[i].clearAll();
else
m_results[i] = m_scratch;
}
// Iteratively eliminate nodes that are not dominator.
bool changed;
do {
changed = false;
// Prune dominators in all non entry blocks: forward scan.
for (unsigned i = 1; i < numBlocks; ++i)
changed |= pruneDominators(i);
if (!changed)
break;
// Prune dominators in all non entry blocks: backward scan.
changed = false;
for (unsigned i = numBlocks; i-- > 1;)
changed |= pruneDominators(i);
} while (changed);
}
bool dominates(unsigned from, unsigned to) const
{
return m_results[to][from];
}
bool dominates(typename Graph::Node from, typename Graph::Node to) const
{
return dominates(m_graph.index(from), m_graph.index(to));
}
void dump(PrintStream& out) const
{
for (unsigned blockIndex = 0; blockIndex < m_graph.numNodes(); ++blockIndex) {
typename Graph::Node block = m_graph.node(blockIndex);
if (!block)
continue;
out.print(" Block ", m_graph.dump(block), ":");
for (unsigned otherIndex = 0; otherIndex < m_graph.numNodes(); ++otherIndex) {
if (!dominates(m_graph.index(block), otherIndex))
continue;
out.print(" ", m_graph.dump(m_graph.node(otherIndex)));
}
out.print("\n");
}
}
private:
bool pruneDominators(unsigned idx)
{
typename Graph::Node block = m_graph.node(idx);
if (!block || !m_graph.predecessors(block).size())
return false;
// Find the intersection of dom(preds).
m_scratch = m_results[m_graph.index(m_graph.predecessors(block)[0])];
for (unsigned j = m_graph.predecessors(block).size(); j-- > 1;)
m_scratch &= m_results[m_graph.index(m_graph.predecessors(block)[j])];
// The block is also dominated by itself.
m_scratch[idx] = true;
return m_results[idx].setAndCheck(m_scratch);
}
Graph& m_graph;
Vector<FastBitVector> m_results; // For each block, the bitvector of blocks that dominate it.
FastBitVector m_scratch; // A temporary bitvector with bit for each block. We recycle this to save new/deletes.
};
struct ValidationContext {
ValidationContext(Graph& graph, Dominators& dominators)
: graph(graph)
, dominators(dominators)
, naiveDominators(graph)
{
}
void reportError(typename Graph::Node from, typename Graph::Node to, const char* message)
{
Error error;
error.from = from;
error.to = to;
error.message = message;
errors.append(error);
}
void handleErrors()
{
if (errors.isEmpty())
return;
dataLog("DFG DOMINATOR VALIDATION FAILED:\n");
dataLog("\n");
dataLog("For block domination relationships:\n");
for (unsigned i = 0; i < errors.size(); ++i) {
dataLog(
" ", graph.dump(errors[i].from), " -> ", graph.dump(errors[i].to),
" (", errors[i].message, ")\n");
}
dataLog("\n");
dataLog("Control flow graph:\n");
for (unsigned blockIndex = 0; blockIndex < graph.numNodes(); ++blockIndex) {
typename Graph::Node block = graph.node(blockIndex);
if (!block)
continue;
dataLog(" Block ", graph.dump(graph.node(blockIndex)), ": successors = [");
CommaPrinter comma;
for (auto successor : graph.successors(block))
dataLog(comma, graph.dump(successor));
dataLog("], predecessors = [");
comma = CommaPrinter();
for (auto predecessor : graph.predecessors(block))
dataLog(comma, graph.dump(predecessor));
dataLog("]\n");
}
dataLog("\n");
dataLog("Lengauer-Tarjan Dominators:\n");
dataLog(dominators);
dataLog("\n");
dataLog("Naive Dominators:\n");
naiveDominators.dump(WTF::dataFile());
dataLog("\n");
dataLog("Graph at time of failure:\n");
dataLog(graph);
dataLog("\n");
dataLog("DFG DOMINATOR VALIDATION FAILIED!\n");
CRASH();
}
Graph& graph;
Dominators& dominators;
NaiveDominators naiveDominators;
struct Error {
typename Graph::Node from;
typename Graph::Node to;
const char* message;
};
Vector<Error> errors;
};
bool naiveDominates(typename Graph::Node from, typename Graph::Node to) const
{
for (typename Graph::Node block = to; block; block = m_data[block].idomParent) {
if (block == from)
return true;
}
return false;
}
template<typename Functor>
void forAllBlocksInDominanceFrontierOfImpl(
typename Graph::Node from, const Functor& functor) const
{
// Paraphrasing from http://en.wikipedia.org/wiki/Dominator_(graph_theory):
// "The dominance frontier of a block 'from' is the set of all blocks 'to' such that
// 'from' dominates an immediate predecessor of 'to', but 'from' does not strictly
// dominate 'to'."
//
// A useful corner case to remember: a block may be in its own dominance frontier if it has
// a loop edge to itself, since it dominates itself and so it dominates its own immediate
// predecessor, and a block never strictly dominates itself.
forAllBlocksDominatedBy(
from,
[&] (typename Graph::Node block) {
for (typename Graph::Node to : m_graph.successors(block)) {
if (!strictlyDominates(from, to))
functor(to);
}
});
}
template<typename Functor>
void forAllBlocksInIteratedDominanceFrontierOfImpl(
const typename Graph::List& from, const Functor& functor) const
{
typename Graph::List worklist = from;
while (!worklist.isEmpty()) {
typename Graph::Node block = worklist.takeLast();
forAllBlocksInDominanceFrontierOfImpl(
block,
[&] (typename Graph::Node otherBlock) {
if (functor(otherBlock))
worklist.append(otherBlock);
});
}
}
struct BlockData {
BlockData()
: idomParent(nullptr)
, preNumber(UINT_MAX)
, postNumber(UINT_MAX)
{
}
Vector<typename Graph::Node> idomKids;
typename Graph::Node idomParent;
unsigned preNumber;
unsigned postNumber;
};
Graph& m_graph;
typename Graph::template Map<BlockData> m_data;
};
} // namespace WTF
using WTF::Dominators;
#endif // WTFDominators_h

220
include/DoublyLinkedList.h Normal file
View File

@ -0,0 +1,220 @@
/*
* Copyright (C) 2011 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.
*/
#ifndef DoublyLinkedList_h
#define DoublyLinkedList_h
namespace WTF {
// This class allows nodes to share code without dictating data member layout.
template<typename T> class DoublyLinkedListNode {
public:
DoublyLinkedListNode();
void setPrev(T*);
void setNext(T*);
T* prev() const;
T* next() const;
};
template<typename T> inline DoublyLinkedListNode<T>::DoublyLinkedListNode()
{
setPrev(0);
setNext(0);
}
template<typename T> inline void DoublyLinkedListNode<T>::setPrev(T* prev)
{
static_cast<T*>(this)->m_prev = prev;
}
template<typename T> inline void DoublyLinkedListNode<T>::setNext(T* next)
{
static_cast<T*>(this)->m_next = next;
}
template<typename T> inline T* DoublyLinkedListNode<T>::prev() const
{
return static_cast<const T*>(this)->m_prev;
}
template<typename T> inline T* DoublyLinkedListNode<T>::next() const
{
return static_cast<const T*>(this)->m_next;
}
template<typename T> class DoublyLinkedList {
public:
DoublyLinkedList();
bool isEmpty() const;
size_t size() const; // This is O(n).
void clear();
T* head() const;
T* removeHead();
T* tail() const;
void push(T*);
void append(T*);
void remove(T*);
void append(DoublyLinkedList<T>&);
private:
T* m_head;
T* m_tail;
};
template<typename T> inline DoublyLinkedList<T>::DoublyLinkedList()
: m_head(0)
, m_tail(0)
{
}
template<typename T> inline bool DoublyLinkedList<T>::isEmpty() const
{
return !m_head;
}
template<typename T> inline size_t DoublyLinkedList<T>::size() const
{
size_t size = 0;
for (T* node = m_head; node; node = node->next())
++size;
return size;
}
template<typename T> inline void DoublyLinkedList<T>::clear()
{
m_head = 0;
m_tail = 0;
}
template<typename T> inline T* DoublyLinkedList<T>::head() const
{
return m_head;
}
template<typename T> inline T* DoublyLinkedList<T>::tail() const
{
return m_tail;
}
template<typename T> inline void DoublyLinkedList<T>::push(T* node)
{
if (!m_head) {
ASSERT(!m_tail);
m_head = node;
m_tail = node;
node->setPrev(0);
node->setNext(0);
return;
}
ASSERT(m_tail);
m_head->setPrev(node);
node->setNext(m_head);
node->setPrev(0);
m_head = node;
}
template<typename T> inline void DoublyLinkedList<T>::append(T* node)
{
if (!m_tail) {
ASSERT(!m_head);
m_head = node;
m_tail = node;
node->setPrev(0);
node->setNext(0);
return;
}
ASSERT(m_head);
m_tail->setNext(node);
node->setPrev(m_tail);
node->setNext(0);
m_tail = node;
}
template<typename T> inline void DoublyLinkedList<T>::remove(T* node)
{
if (node->prev()) {
ASSERT(node != m_head);
node->prev()->setNext(node->next());
} else {
ASSERT(node == m_head);
m_head = node->next();
}
if (node->next()) {
ASSERT(node != m_tail);
node->next()->setPrev(node->prev());
} else {
ASSERT(node == m_tail);
m_tail = node->prev();
}
}
template<typename T> inline T* DoublyLinkedList<T>::removeHead()
{
T* node = head();
if (node)
remove(node);
return node;
}
template<typename T> inline void DoublyLinkedList<T>::append(DoublyLinkedList<T>& other)
{
if (!other.head())
return;
if (!head()) {
m_head = other.head();
m_tail = other.tail();
other.clear();
return;
}
ASSERT(tail());
ASSERT(other.head());
T* otherHead = other.head();
T* otherTail = other.tail();
other.clear();
ASSERT(!m_tail->next());
m_tail->setNext(otherHead);
ASSERT(!otherHead->prev());
otherHead->setPrev(m_tail);
m_tail = otherTail;
}
} // namespace WTF
using WTF::DoublyLinkedListNode;
using WTF::DoublyLinkedList;
#endif

64
include/EnumTraits.h Normal file
View File

@ -0,0 +1,64 @@
/*
* 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 <type_traits>
namespace WTF {
template<typename> struct EnumTraits;
template<typename E, E...> struct EnumValues;
template<typename T, typename E> struct EnumValueChecker;
template<typename T, typename E, E e, E... es>
struct EnumValueChecker<T, EnumValues<E, e, es...>> {
static constexpr bool isValidEnum(T t)
{
return (static_cast<T>(e) == t) ? true : EnumValueChecker<T, EnumValues<E, es...>>::isValidEnum(t);
}
};
template<typename T, typename E>
struct EnumValueChecker<T, EnumValues<E>> {
static constexpr bool isValidEnum(T)
{
return false;
}
};
template<typename E, typename T>
constexpr auto isValidEnum(T t) -> std::enable_if_t<std::is_enum<E>::value, bool>
{
static_assert(sizeof(T) >= std::underlying_type_t<E>(), "Integral type must be at least the size of the underlying enum type");
return EnumValueChecker<T, typename EnumTraits<E>::values>::isValidEnum(t);
}
}
using WTF::isValidEnum;

454
include/Expected.h Normal file
View File

@ -0,0 +1,454 @@
/*
* 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.
*/
// WTF::Expected is based on std::expected, as described here: http://wg21.link/p0323r1
// The specification expects to throw. This implementation doesn't support exceptions, uses RELEASE_ASSERT instead.
#pragma once
#include <cstdlib>
#include <initializer_list>
#include <type_traits>
#include <utility>
#include <wtf/Assertions.h>
#include <wtf/Optional.h>
#include <wtf/StdLibExtras.h>
namespace WTF {
template <class E>
class UnexpectedType {
public:
UnexpectedType() = delete;
constexpr explicit UnexpectedType(const E& e) : val(e) { }
constexpr explicit UnexpectedType(E&& e) : val(std::forward<E>(e)) { }
constexpr const E& value() const& { return val; }
RELAXED_CONSTEXPR E& value() & { return val; }
RELAXED_CONSTEXPR E&& value() && { return WTFMove(val); }
private:
E val;
};
template <class E> constexpr bool operator==(const UnexpectedType<E>& lhs, const UnexpectedType<E>& rhs) { return lhs.value() == rhs.value(); }
template <class E> constexpr bool operator!=(const UnexpectedType<E>& lhs, const UnexpectedType<E>& rhs) { return lhs.value() != rhs.value(); }
template <class E> constexpr bool operator<(const UnexpectedType<E>& lhs, const UnexpectedType<E>& rhs) { return lhs.value() < rhs.value(); }
template <class E> constexpr bool operator>(const UnexpectedType<E>& lhs, const UnexpectedType<E>& rhs) { return lhs.value() > rhs.value(); }
template <class E> constexpr bool operator<=(const UnexpectedType<E>& lhs, const UnexpectedType<E>& rhs) { return lhs.value() <= rhs.value(); }
template <class E> constexpr bool operator>=(const UnexpectedType<E>& lhs, const UnexpectedType<E>& rhs) { return lhs.value() >= rhs.value(); }
template <class E> constexpr UnexpectedType<std::decay_t<E>> makeUnexpected(E&& v) { return UnexpectedType<typename std::decay<E>::type>(std::forward<E>(v)); }
struct UnexpectTag {
UnexpectTag() = delete;
};
constexpr UnexpectTag Unexpect { };
namespace ExpectedDetail {
// Invoked where std::Expected would instead throw.
inline NO_RETURN_DUE_TO_CRASH void Throw() { RELEASE_ASSERT_NOT_REACHED(); }
static constexpr enum class ValueTagType { } ValueTag { };
static constexpr enum class ErrorTagType { } ErrorTag { };
template<class T, std::enable_if_t<std::is_trivially_destructible<T>::value>* = nullptr> void destroy(T&) { }
template<class T, std::enable_if_t<!std::is_trivially_destructible<T>::value && (std::is_class<T>::value || std::is_union<T>::value)>* = nullptr> void destroy(T& t) { t.~T(); }
template <class T, class E>
union ConstexprStorage {
typedef T ValueType;
typedef E ErrorType;
char dummy;
ValueType val;
ErrorType err;
constexpr ConstexprStorage() : dummy() { }
constexpr ConstexprStorage(ValueTagType) : val() { }
constexpr ConstexprStorage(ErrorTagType) : err() { }
constexpr ConstexprStorage(ValueTagType, const ValueType& v) : val(v) { }
constexpr ConstexprStorage(ErrorTagType, const ErrorType& e) : err(e) { }
~ConstexprStorage() = default;
};
template <class T, class E>
union Storage {
typedef T ValueType;
typedef E ErrorType;
char dummy;
ValueType val;
ErrorType err;
constexpr Storage() : dummy() { }
constexpr Storage(ValueTagType) : val() { }
constexpr Storage(ErrorTagType) : err() { }
constexpr Storage(ValueTagType, const ValueType& val) : val(val) { }
constexpr Storage(ValueTagType, ValueType&& val) : val(std::forward<ValueType>(val)) { }
constexpr Storage(ErrorTagType, const ErrorType& err) : err(err) { }
constexpr Storage(ErrorTagType, ErrorType&& err) : err(std::forward<ErrorType>(err)) { }
~Storage() { }
};
template <class E>
union ConstexprStorage<void, E> {
typedef void ValueType;
typedef E ErrorType;
char dummy;
ErrorType err;
constexpr ConstexprStorage() : dummy() { }
constexpr ConstexprStorage(ValueTagType) : dummy() { }
constexpr ConstexprStorage(ErrorTagType) : err() { }
constexpr ConstexprStorage(ErrorTagType, const ErrorType& e) : err(e) { }
~ConstexprStorage() = default;
};
template <class E>
union Storage<void, E> {
typedef void ValueType;
typedef E ErrorType;
char dummy;
ErrorType err;
constexpr Storage() : dummy() { }
constexpr Storage(ValueTagType) : dummy() { }
constexpr Storage(ErrorTagType) : err() { }
constexpr Storage(ErrorTagType, const ErrorType& err) : err(err) { }
constexpr Storage(ErrorTagType, ErrorType&& err) : err(std::forward<ErrorType>(err)) { }
~Storage() { }
};
template <class T, class E>
struct ConstexprBase {
typedef T ValueType;
typedef E ErrorType;
ConstexprStorage<ValueType, ErrorType> s;
bool has;
constexpr ConstexprBase() : s(), has(true) { }
constexpr ConstexprBase(ValueTagType tag) : s(tag), has(true) { }
constexpr ConstexprBase(ErrorTagType tag) : s(tag), has(false) { }
constexpr ConstexprBase(ValueTagType tag, const ValueType& val) : s(tag, val), has(true) { }
constexpr ConstexprBase(ErrorTagType tag, const ErrorType& err) : s(tag, err), has(false) { }
~ConstexprBase() = default;
};
template <class T, class E>
struct Base {
typedef T ValueType;
typedef E ErrorType;
Storage<ValueType, ErrorType> s;
bool has;
constexpr Base() : s(), has(true) { }
constexpr Base(ValueTagType tag) : s(tag), has(true) { }
constexpr Base(ErrorTagType tag) : s(tag), has(false) { }
constexpr Base(ValueTagType tag, const ValueType& val) : s(tag, val), has(true) { }
constexpr Base(ValueTagType tag, ValueType&& val) : s(tag, std::forward<ValueType>(val)), has(true) { }
constexpr Base(ErrorTagType tag, const ErrorType& err) : s(tag, err), has(false) { }
constexpr Base(ErrorTagType tag, ErrorType&& err) : s(tag, std::forward<ErrorType>(err)), has(false) { }
Base(const Base& o)
: has(o.has)
{
if (has)
::new (&s.val) ValueType(o.s.val);
else
::new (&s.err) ErrorType(o.s.err);
}
Base(Base&& o)
: has(o.has)
{
if (has)
::new (&s.val) ValueType(WTFMove(o.s.val));
else
::new (&s.err) ErrorType(WTFMove(o.s.err));
}
~Base()
{
if (has)
destroy(s.val);
else
destroy(s.err);
}
};
template <class E>
struct ConstexprBase<void, E> {
typedef void ValueType;
typedef E ErrorType;
ConstexprStorage<ValueType, ErrorType> s;
bool has;
constexpr ConstexprBase() : s(), has(true) { }
constexpr ConstexprBase(ValueTagType tag) : s(tag), has(true) { }
constexpr ConstexprBase(ErrorTagType tag) : s(tag), has(false) { }
constexpr ConstexprBase(ErrorTagType tag, const ErrorType& err) : s(tag, err), has(false) { }
constexpr ConstexprBase(ErrorTagType tag, ErrorType&& err) : s(tag, std::forward<ErrorType>(err)), has(false) { }
~ConstexprBase() = default;
};
template <class E>
struct Base<void, E> {
typedef void ValueType;
typedef E ErrorType;
Storage<ValueType, ErrorType> s;
bool has;
constexpr Base() : s(), has(true) { }
constexpr Base(ValueTagType tag) : s(tag), has(true) { }
constexpr Base(ErrorTagType tag) : s(tag), has(false) { }
constexpr Base(ErrorTagType tag, const ErrorType& err) : s(tag, err), has(false) { }
constexpr Base(ErrorTagType tag, ErrorType&& err) : s(tag, std::forward<ErrorType>(err)), has(false) { }
Base(const Base& o)
: has(o.has)
{
if (!has)
::new (&s.err) ErrorType(o.s.err);
}
Base(Base&& o)
: has(o.has)
{
if (!has)
::new (&s.err) ErrorType(WTFMove(o.s.err));
}
~Base()
{
if (!has)
destroy(s.err);
}
};
template <class T, class E>
using BaseSelect = typename std::conditional<
((std::is_void<T>::value || std::is_trivially_destructible<T>::value)
&& std::is_trivially_destructible<E>::value),
ConstexprBase<typename std::remove_const<T>::type, typename std::remove_const<E>::type>,
Base<typename std::remove_const<T>::type, typename std::remove_const<E>::type>
>::type;
} // namespace ExpectedDetail
template <class T, class E>
class Expected : private ExpectedDetail::BaseSelect<T, E> {
typedef ExpectedDetail::BaseSelect<T, E> base;
public:
typedef typename base::ValueType ValueType;
typedef typename base::ErrorType ErrorType;
private:
typedef Expected<ValueType, ErrorType> type;
public:
// template <class U> struct rebind { using type = Expected<U, ErrorType>; };
constexpr Expected() : base(ExpectedDetail::ValueTag) { }
Expected(const Expected&) = default;
Expected(Expected&&) = default;
constexpr Expected(const ValueType& e) : base(ExpectedDetail::ValueTag, e) { }
constexpr Expected(ValueType&& e) : base(ExpectedDetail::ValueTag, std::forward<ValueType>(e)) { }
// template <class... Args> constexpr explicit Expected(in_place_t, Args&&...);
// template <class U, class... Args> constexpr explicit Expected(in_place_t, std::initializer_list<U>, Args&&...);
constexpr Expected(UnexpectedType<ErrorType> const& u) : base(ExpectedDetail::ErrorTag, u.value()) { }
constexpr Expected(UnexpectedType<ErrorType>&& u) : base(ExpectedDetail::ErrorTag, std::forward<UnexpectedType<E>>(u).value()) { }
template <class Err> constexpr Expected(UnexpectedType<Err> const& u) : base(ExpectedDetail::ErrorTag, u.value()) { }
// template <class... Args> constexpr explicit Expected(UnexpectTag, Args&&...);
// template <class U, class... Args> constexpr explicit Expected(UnexpectTag, std::initializer_list<U>, Args&&...);
~Expected() = default;
Expected& operator=(const Expected& e) { type(e).swap(*this); return *this; }
Expected& operator=(Expected&& e) { type(WTFMove(e)).swap(*this); return *this; }
template <class U> Expected& operator=(U&& u) { type(WTFMove(u)).swap(*this); return *this; }
Expected& operator=(const UnexpectedType<ErrorType>& u) { type(u).swap(*this); return *this; }
Expected& operator=(UnexpectedType<ErrorType>&& u) { type(WTFMove(u)).swap(*this); return *this; }
// template <class... Args> void emplace(Args&&...);
// template <class U, class... Args> void emplace(std::initializer_list<U>, Args&&...);
void swap(Expected& o)
{
using std::swap;
if (base::has && o.has)
swap(base::s.val, o.s.val);
else if (base::has && !o.has) {
ErrorType e(WTFMove(o.s.err));
ExpectedDetail::destroy(o.s.err);
::new (&o.s.val) ValueType(WTFMove(base::s.val));
ExpectedDetail::destroy(base::s.val);
::new (&base::s.err) ErrorType(WTFMove(e));
swap(base::has, o.has);
} else if (!base::has && o.has) {
ValueType v(WTFMove(o.s.val));
ExpectedDetail::destroy(o.s.val);
::new (&o.s.err) ErrorType(WTFMove(base::s.err));
ExpectedDetail::destroy(base::s.err);
::new (&base::s.val) ValueType(WTFMove(v));
swap(base::has, o.has);
} else
swap(base::s.err, o.s.err);
}
constexpr const ValueType* operator->() const { return &base::s.val; }
ValueType* operator->() { return &base::s.val; }
constexpr const ValueType& operator*() const & { return base::s.val; }
ValueType& operator*() & { return base::s.val; }
constexpr const ValueType&& operator*() const && { return WTFMove(base::s.val); }
RELAXED_CONSTEXPR ValueType&& operator*() && { return WTFMove(base::s.val); }
constexpr explicit operator bool() const { return base::has; }
constexpr bool hasValue() const { return base::has; }
constexpr const ValueType& value() const & { return base::has ? base::s.val : (ExpectedDetail::Throw(), base::s.val); }
RELAXED_CONSTEXPR ValueType& value() & { return base::has ? base::s.val : (ExpectedDetail::Throw(), base::s.val); }
constexpr const ValueType&& value() const && { return base::has ? base::s.val : (ExpectedDetail::Throw(), base::s.val); }
RELAXED_CONSTEXPR ValueType&& value() && { return WTFMove(base::has ? base::s.val : (ExpectedDetail::Throw(), base::s.val)); }
constexpr const ErrorType& error() const & { return !base::has ? base::s.err : (ExpectedDetail::Throw(), base::s.err); }
ErrorType& error() & { return !base::has ? base::s.err : (ExpectedDetail::Throw(), base::s.err); }
RELAXED_CONSTEXPR ErrorType&& error() && { return !base::has ? base::s.err : (ExpectedDetail::Throw(), base::s.err); }
constexpr const ErrorType&& error() const && { return !base::has ? base::s.err : (ExpectedDetail::Throw(), base::s.err); }
constexpr UnexpectedType<ErrorType> getUnexpected() const { return UnexpectedType<ErrorType>(base::s.err); }
template <class U> constexpr ValueType valueOr(U&& u) const & { return base::has ? **this : static_cast<ValueType>(std::forward<U>(u)); }
template <class U> ValueType valueOr(U&& u) && { return base::has ? WTFMove(**this) : static_cast<ValueType>(std::forward<U>(u)); }
};
template <class E>
class Expected<void, E> : private ExpectedDetail::BaseSelect<void, E> {
typedef ExpectedDetail::BaseSelect<void, E> base;
public:
typedef typename base::ValueType ValueType;
typedef typename base::ErrorType ErrorType;
private:
typedef Expected<ValueType, ErrorType> type;
public:
// template <class U> struct rebind { typedef Expected<U, ErrorType> type; };
constexpr Expected() : base(ExpectedDetail::ValueTag) { }
Expected(const Expected&) = default;
Expected(Expected&&) = default;
// constexpr explicit Expected(in_place_t);
constexpr Expected(UnexpectedType<E> const& u) : base(ExpectedDetail::ErrorTag, u.value()) { }
constexpr Expected(UnexpectedType<E>&& u) : base(ExpectedDetail::ErrorTag, std::forward<UnexpectedType<E>>(u).value()) { }
template <class Err> constexpr Expected(UnexpectedType<Err> const& u) : base(ExpectedDetail::ErrorTag, u.value()) { }
~Expected() = default;
Expected& operator=(const Expected& e) { type(e).swap(*this); return *this; }
Expected& operator=(Expected&& e) { type(WTFMove(e)).swap(*this); return *this; }
Expected& operator=(const UnexpectedType<E>& u) { type(u).swap(*this); return *this; } // Not in the current paper.
Expected& operator=(UnexpectedType<E>&& u) { type(WTFMove(u)).swap(*this); return *this; } // Not in the current paper.
// void emplace();
void swap(Expected& o)
{
using std::swap;
if (base::has && o.has) {
// Do nothing.
} else if (base::has && !o.has) {
ErrorType e(WTFMove(o.s.err));
::new (&base::s.err) ErrorType(e);
swap(base::has, o.has);
} else if (!base::has && o.has) {
::new (&o.s.err) ErrorType(WTFMove(base::s.err));
swap(base::has, o.has);
} else
swap(base::s.err, o.s.err);
}
constexpr explicit operator bool() const { return base::has; }
constexpr bool hasValue() const { return base::has; }
void value() const { !base::has ? ExpectedDetail::Throw() : void(); }
constexpr const E& error() const & { return !base::has ? base::s.err : (ExpectedDetail::Throw(), base::s.err); }
E& error() & { return !base::has ? base::s.err : (ExpectedDetail::Throw(), base::s.err); } // Not in the current paper.
RELAXED_CONSTEXPR E&& error() && { return !base::has ? base::s.err : (ExpectedDetail::Throw(), base::s.err); }
constexpr const E&& error() const && { return !base::has ? base::s.err : (ExpectedDetail::Throw(), base::s.err); } // Not in the current paper.
// constexpr E& error() &;
constexpr UnexpectedType<E> getUnexpected() const { return UnexpectedType<E>(base::s.err); }
};
template <class T, class E> constexpr bool operator==(const Expected<T, E>& x, const Expected<T, E>& y) { return bool(x) == bool(y) && (x ? x.value() == y.value() : x.error() == y.error()); }
template <class T, class E> constexpr bool operator!=(const Expected<T, E>& x, const Expected<T, E>& y) { return !(x == y); }
template <class T, class E> constexpr bool operator<(const Expected<T, E>& x, const Expected<T, E>& y) { return (!bool(x) && bool(y)) ? false : ((bool(x) && !bool(y)) ? true : ((bool(x) && bool(y)) ? x.value() < y.value() : x.error() < y.error())); }
template <class T, class E> constexpr bool operator>(const Expected<T, E>& x, const Expected<T, E>& y) { return !(x == y) && !(x < y); }
template <class T, class E> constexpr bool operator<=(const Expected<T, E>& x, const Expected<T, E>& y) { return (x == y) || (x < y); }
template <class T, class E> constexpr bool operator>=(const Expected<T, E>& x, const Expected<T, E>& y) { return (x == y) || (x > y); }
template <class E> constexpr bool operator==(const Expected<void, E>& x, const Expected<void, E>& y) { return bool(x) == bool(y) && (x ? true : x.error() == y.error()); } // Not in the current paper.
template <class E> constexpr bool operator<(const Expected<void, E>& x, const Expected<void, E>& y) { return (!bool(x) && bool(y)) ? false : ((bool(x) && !bool(y)) ? true : ((bool(x) && bool(y)) ? false : x.error() < y.error())); } // Not in the current paper.
template <class T, class E> constexpr bool operator==(const Expected<T, E>& x, const T& y) { return x == Expected<T, E>(y); }
template <class T, class E> constexpr bool operator==(const T& x, const Expected<T, E>& y) { return Expected<T, E>(x) == y; }
template <class T, class E> constexpr bool operator!=(const Expected<T, E>& x, const T& y) { return x != Expected<T, E>(y); }
template <class T, class E> constexpr bool operator!=(const T& x, const Expected<T, E>& y) { return Expected<T, E>(x) != y; }
template <class T, class E> constexpr bool operator<(const Expected<T, E>& x, const T& y) { return x < Expected<T, E>(y); }
template <class T, class E> constexpr bool operator<(const T& x, const Expected<T, E>& y) { return Expected<T, E>(x) < y; }
template <class T, class E> constexpr bool operator<=(const Expected<T, E>& x, const T& y) { return x <= Expected<T, E>(y); }
template <class T, class E> constexpr bool operator<=(const T& x, const Expected<T, E>& y) { return Expected<T, E>(x) <= y; }
template <class T, class E> constexpr bool operator>(const Expected<T, E>& x, const T& y) { return x > Expected<T, E>(y); }
template <class T, class E> constexpr bool operator>(const T& x, const Expected<T, E>& y) { return Expected<T, E>(x) > y; }
template <class T, class E> constexpr bool operator>=(const Expected<T, E>& x, const T& y) { return x >= Expected<T, E>(y); }
template <class T, class E> constexpr bool operator>=(const T& x, const Expected<T, E>& y) { return Expected<T, E>(x) >= y; }
template <class T, class E> constexpr bool operator==(const Expected<T, E>& x, const UnexpectedType<E>& y) { return x == Expected<T, E>(y); }
template <class T, class E> constexpr bool operator==(const UnexpectedType<E>& x, const Expected<T, E>& y) { return Expected<T, E>(x) == y; }
template <class T, class E> constexpr bool operator!=(const Expected<T, E>& x, const UnexpectedType<E>& y) { return x != Expected<T, E>(y); }
template <class T, class E> constexpr bool operator!=(const UnexpectedType<E>& x, const Expected<T, E>& y) { return Expected<T, E>(x) != y; }
template <class T, class E> constexpr bool operator<(const Expected<T, E>& x, const UnexpectedType<E>& y) { return x < Expected<T, E>(y); }
template <class T, class E> constexpr bool operator<(const UnexpectedType<E>& x, const Expected<T, E>& y) { return Expected<T, E>(x) < y; }
template <class T, class E> constexpr bool operator<=(const Expected<T, E>& x, const UnexpectedType<E>& y) { return x <= Expected<T, E>(y); }
template <class T, class E> constexpr bool operator<=(const UnexpectedType<E>& x, const Expected<T, E>& y) { return Expected<T, E>(x) <= y; }
template <class T, class E> constexpr bool operator>(const Expected<T, E>& x, const UnexpectedType<E>& y) { return x > Expected<T, E>(y); }
template <class T, class E> constexpr bool operator>(const UnexpectedType<E>& x, const Expected<T, E>& y) { return Expected<T, E>(x) > y; }
template <class T, class E> constexpr bool operator>=(const Expected<T, E>& x, const UnexpectedType<E>& y) { return x >= Expected<T, E>(y); }
template <class T, class E> constexpr bool operator>=(const UnexpectedType<E>& x, const Expected<T, E>& y) { return Expected<T, E>(x) >= y; }
template <typename T, typename E> void swap(Expected<T, E>& x, Expected<T, E>& y) { x.swap(y); }
template <class T, class E = std::nullopt_t> constexpr Expected<std::decay_t<T>, E> makeExpected(T&& v)
{
return Expected<typename std::decay<T>::type, E>(std::forward<T>(v));
}
template <class T, class E> constexpr Expected<T, std::decay_t<E>> makeExpectedFromError(E&& e) { return Expected<T, std::decay_t<E>>(makeUnexpected(e)); }
template <class T, class E, class U> constexpr Expected<T, E> makeExpectedFromError(U&& u) { return Expected<T, E>(makeUnexpected(E { std::forward<U>(u) } )); }
// template <class F, class E = std::nullopt_t> constexpr Expected<typename std::result_of<F>::type, E> makeExpected_from_call(F f);
inline Expected<void, std::nullopt_t> makeExpected() { return Expected<void, std::nullopt_t>(); }
} // namespace WTF
namespace std {
template <class T, class E> struct hash<WTF::Expected<T, E>> {
typedef WTF::Expected<T, E> argument_type;
typedef std::size_t result_type;
result_type operator()(argument_type const& e) const { return e ? hash<typename argument_type::ValueType> { } (e.value()) : hash<typename argument_type::ErrorType> { } (e.error()); }
};
template <class E> struct hash<WTF::Expected<void, E>> {
typedef WTF::Expected<void, E> argument_type;
typedef std::size_t result_type;
result_type operator()(argument_type const& e) const { return e ? 0 : hash<typename argument_type::ErrorType> { } (e.error()); }
};
}
using WTF::UnexpectedType;
using WTF::makeUnexpected;
using WTF::Unexpect;
using WTF::Expected;
using WTF::makeExpected;
using WTF::makeExpectedFromError;

119
include/ExportMacros.h Normal file
View File

@ -0,0 +1,119 @@
/*
* Copyright (C) 2011 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. ``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
* 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.
*
* This file handles shared library symbol export decorations. It is recommended
* that all WebKit projects use these definitions so that symbol exports work
* properly on all platforms and compilers that WebKit builds under.
*/
#pragma once
#include <wtf/Platform.h>
// Different platforms have different defaults for symbol visibility. Usually
// the compiler and the linker just take care of it. However for references to
// runtime routines from JIT stubs, it matters to be able to declare a symbol as
// being local to the target being generated, and thus not subject to (e.g.) ELF
// symbol interposition rules.
#if USE(DECLSPEC_ATTRIBUTE)
#define HAVE_INTERNAL_VISIBILITY 1
#define WTF_INTERNAL
#elif USE(VISIBILITY_ATTRIBUTE)
#define HAVE_INTERNAL_VISIBILITY 1
#define WTF_INTERNAL __attribute__((visibility("hidden")))
#else
#define WTF_INTERNAL
#endif
#if USE(DECLSPEC_ATTRIBUTE)
#define WTF_EXPORT_DECLARATION __declspec(dllexport)
#define WTF_IMPORT_DECLARATION __declspec(dllimport)
#define WTF_HIDDEN_DECLARATION
#elif USE(VISIBILITY_ATTRIBUTE)
#define WTF_EXPORT_DECLARATION __attribute__((visibility("default")))
#define WTF_IMPORT_DECLARATION WTF_EXPORT_DECLARATION
#define WTF_HIDDEN_DECLARATION __attribute__((visibility("hidden")))
#else
#define WTF_EXPORT_DECLARATION
#define WTF_IMPORT_DECLARATION
#define WTF_HIDDEN_DECLARATION
#endif
#if defined(BUILDING_WTF) || defined(STATICALLY_LINKED_WITH_WTF)
#define WTF_IS_LINKED_IN_SAME_BINARY 1
#endif
// See note in wtf/Platform.h for more info on EXPORT_MACROS.
#if USE(EXPORT_MACROS)
#define WTF_EXPORT WTF_EXPORT_DECLARATION
#define WTF_IMPORT WTF_IMPORT_DECLARATION
#define WTF_HIDDEN WTF_IMPORT_DECLARATION
// FIXME: When all ports are using the export macros, we should replace
// WTF_EXPORTDATA with WTF_EXPORT_PRIVATE macros.
#if defined(WTF_IS_LINKED_IN_SAME_BINARY)
#define WTF_EXPORTDATA WTF_EXPORT
#else
#define WTF_EXPORTDATA WTF_IMPORT
#endif
#else // !USE(EXPORT_MACROS)
#if USE(DECLSPEC_ATTRIBUTE)
#if defined(BUILDING_WTF) || defined(STATICALLY_LINKED_WITH_WTF)
#define WTF_EXPORTDATA __declspec(dllexport)
#else
#define WTF_EXPORTDATA __declspec(dllimport)
#endif
#else // !OS(WINDOWS) || COMPILER(GCC_OR_CLANG)
#define WTF_EXPORTDATA
#endif
#define WTF_EXPORTCLASS WTF_EXPORTDATA
#define WTF_EXPORT
#define WTF_IMPORT
#define WTF_HIDDEN
#endif // USE(EXPORT_MACROS)
#if defined(WTF_IS_LINKED_IN_SAME_BINARY)
#define WTF_EXPORT_PRIVATE WTF_EXPORT
#else
#define WTF_EXPORT_PRIVATE WTF_IMPORT
#endif
#define WTF_EXPORT_STRING_API WTF_EXPORT_PRIVATE
#define WTF_EXPORT_HIDDEN WTF_HIDDEN
#define HIDDEN_INLINE WTF_EXPORT_HIDDEN inline

580
include/FastBitVector.h Normal file
View File

@ -0,0 +1,580 @@
/*
* Copyright (C) 2012, 2013, 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. ``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
* 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 <string.h>
#include <wtf/Atomics.h>
#include <wtf/FastMalloc.h>
#include <wtf/PrintStream.h>
#include <wtf/StdLibExtras.h>
namespace WTF {
class PrintStream;
inline size_t fastBitVectorArrayLength(size_t numBits) { return (numBits + 31) / 32; }
class FastBitVectorWordView {
public:
typedef FastBitVectorWordView ViewType;
FastBitVectorWordView() { }
FastBitVectorWordView(const uint32_t* array, size_t numBits)
: m_words(array)
, m_numBits(numBits)
{
}
size_t numBits() const
{
return m_numBits;
}
uint32_t word(size_t index) const
{
ASSERT_WITH_SECURITY_IMPLICATION(index < fastBitVectorArrayLength(numBits()));
return m_words[index];
}
private:
const uint32_t* m_words { nullptr };
size_t m_numBits { 0 };
};
class FastBitVectorWordOwner {
public:
typedef FastBitVectorWordView ViewType;
FastBitVectorWordOwner() = default;
FastBitVectorWordOwner(FastBitVectorWordOwner&& other)
: m_words(std::exchange(other.m_words, nullptr))
, m_numBits(std::exchange(other.m_numBits, 0))
{
}
FastBitVectorWordOwner(const FastBitVectorWordOwner& other)
{
*this = other;
}
~FastBitVectorWordOwner()
{
if (m_words)
fastFree(m_words);
}
FastBitVectorWordView view() const { return FastBitVectorWordView(m_words, m_numBits); }
FastBitVectorWordOwner& operator=(const FastBitVectorWordOwner& other)
{
if (arrayLength() != other.arrayLength())
setEqualsSlow(other);
else {
memcpy(m_words, other.m_words, arrayLength() * sizeof(uint32_t));
m_numBits = other.m_numBits;
}
return *this;
}
FastBitVectorWordOwner& operator=(FastBitVectorWordOwner&& other)
{
std::swap(m_words, other.m_words);
std::swap(m_numBits, other.m_numBits);
return *this;
}
void setAll()
{
memset(m_words, 255, arrayLength() * sizeof(uint32_t));
}
void clearAll()
{
memset(m_words, 0, arrayLength() * sizeof(uint32_t));
}
void set(const FastBitVectorWordOwner& other)
{
ASSERT_WITH_SECURITY_IMPLICATION(m_numBits == other.m_numBits);
memcpy(m_words, other.m_words, arrayLength() * sizeof(uint32_t));
}
size_t numBits() const
{
return m_numBits;
}
size_t arrayLength() const
{
return fastBitVectorArrayLength(numBits());
}
void resize(size_t numBits)
{
if (arrayLength() != fastBitVectorArrayLength(numBits))
resizeSlow(numBits);
m_numBits = numBits;
}
uint32_t word(size_t index) const
{
ASSERT_WITH_SECURITY_IMPLICATION(index < arrayLength());
return m_words[index];
}
uint32_t& word(size_t index)
{
ASSERT_WITH_SECURITY_IMPLICATION(index < arrayLength());
return m_words[index];
}
const uint32_t* words() const { return m_words; }
uint32_t* words() { return m_words; }
private:
WTF_EXPORT_PRIVATE void setEqualsSlow(const FastBitVectorWordOwner& other);
WTF_EXPORT_PRIVATE void resizeSlow(size_t numBits);
uint32_t* m_words { nullptr };
size_t m_numBits { 0 };
};
template<typename Left, typename Right>
class FastBitVectorAndWords {
public:
typedef FastBitVectorAndWords ViewType;
FastBitVectorAndWords(const Left& left, const Right& right)
: m_left(left)
, m_right(right)
{
ASSERT_WITH_SECURITY_IMPLICATION(m_left.numBits() == m_right.numBits());
}
FastBitVectorAndWords view() const { return *this; }
size_t numBits() const
{
return m_left.numBits();
}
uint32_t word(size_t index) const
{
return m_left.word(index) & m_right.word(index);
}
private:
Left m_left;
Right m_right;
};
template<typename Left, typename Right>
class FastBitVectorOrWords {
public:
typedef FastBitVectorOrWords ViewType;
FastBitVectorOrWords(const Left& left, const Right& right)
: m_left(left)
, m_right(right)
{
ASSERT_WITH_SECURITY_IMPLICATION(m_left.numBits() == m_right.numBits());
}
FastBitVectorOrWords view() const { return *this; }
size_t numBits() const
{
return m_left.numBits();
}
uint32_t word(size_t index) const
{
return m_left.word(index) | m_right.word(index);
}
private:
Left m_left;
Right m_right;
};
template<typename View>
class FastBitVectorNotWords {
public:
typedef FastBitVectorNotWords ViewType;
FastBitVectorNotWords(const View& view)
: m_view(view)
{
}
FastBitVectorNotWords view() const { return *this; }
size_t numBits() const
{
return m_view.numBits();
}
uint32_t word(size_t index) const
{
return ~m_view.word(index);
}
private:
View m_view;
};
class FastBitVector;
template<typename Words>
class FastBitVectorImpl {
public:
FastBitVectorImpl()
: m_words()
{
}
FastBitVectorImpl(const Words& words)
: m_words(words)
{
}
FastBitVectorImpl(Words&& words)
: m_words(WTFMove(words))
{
}
size_t numBits() const { return m_words.numBits(); }
size_t size() const { return numBits(); }
size_t arrayLength() const { return fastBitVectorArrayLength(numBits()); }
template<typename Other>
bool operator==(const Other& other) const
{
if (numBits() != other.numBits())
return false;
for (size_t i = arrayLength(); i--;) {
if (m_words.word(i) != other.m_words.word(i))
return false;
}
return true;
}
template<typename Other>
bool operator!=(const Other& other) const
{
return !(*this == other);
}
bool at(size_t index) const
{
return atImpl(index);
}
bool operator[](size_t index) const
{
return atImpl(index);
}
size_t bitCount() const
{
size_t result = 0;
for (size_t index = arrayLength(); index--;)
result += WTF::bitCount(m_words.word(index));
return result;
}
bool isEmpty() const
{
for (size_t index = arrayLength(); index--;) {
if (m_words.word(index))
return false;
}
return true;
}
template<typename OtherWords>
FastBitVectorImpl<FastBitVectorAndWords<typename Words::ViewType, typename OtherWords::ViewType>> operator&(const FastBitVectorImpl<OtherWords>& other) const
{
return FastBitVectorImpl<FastBitVectorAndWords<typename Words::ViewType, typename OtherWords::ViewType>>(FastBitVectorAndWords<typename Words::ViewType, typename OtherWords::ViewType>(wordView(), other.wordView()));
}
template<typename OtherWords>
FastBitVectorImpl<FastBitVectorOrWords<typename Words::ViewType, typename OtherWords::ViewType>> operator|(const FastBitVectorImpl<OtherWords>& other) const
{
return FastBitVectorImpl<FastBitVectorOrWords<typename Words::ViewType, typename OtherWords::ViewType>>(FastBitVectorOrWords<typename Words::ViewType, typename OtherWords::ViewType>(wordView(), other.wordView()));
}
FastBitVectorImpl<FastBitVectorNotWords<typename Words::ViewType>> operator~() const
{
return FastBitVectorImpl<FastBitVectorNotWords<typename Words::ViewType>>(FastBitVectorNotWords<typename Words::ViewType>(wordView()));
}
template<typename Func>
ALWAYS_INLINE void forEachSetBit(const Func& func) const
{
size_t n = arrayLength();
for (size_t i = 0; i < n; ++i) {
uint32_t word = m_words.word(i);
size_t j = i * 32;
while (word) {
if (word & 1)
func(j);
word >>= 1;
j++;
}
}
}
template<typename Func>
ALWAYS_INLINE void forEachClearBit(const Func& func) const
{
(~*this).forEachSetBit(func);
}
template<typename Func>
void forEachBit(bool value, const Func& func) const
{
if (value)
forEachSetBit(func);
else
forEachClearBit(func);
}
// Starts looking for bits at the index you pass. If that index contains the value you want,
// then it will return that index. Returns numBits when we get to the end. For example, you
// can write a loop to iterate over all set bits like this:
//
// for (size_t i = 0; i < bits.numBits(); i = bits.findBit(i + 1, true))
// ...
ALWAYS_INLINE size_t findBit(size_t startIndex, bool value) const
{
// If value is true, this produces 0. If value is false, this produces UINT_MAX. It's
// written this way so that it performs well regardless of whether value is a constant.
uint32_t skipValue = -(static_cast<uint32_t>(value) ^ 1);
size_t numWords = fastBitVectorArrayLength(m_words.numBits());
size_t wordIndex = startIndex / 32;
size_t startIndexInWord = startIndex - wordIndex * 32;
while (wordIndex < numWords) {
uint32_t word = m_words.word(wordIndex);
if (word != skipValue) {
size_t index = startIndexInWord;
if (findBitInWord(word, index, 32, value))
return wordIndex * 32 + index;
}
wordIndex++;
startIndexInWord = 0;
}
return numBits();
}
ALWAYS_INLINE size_t findSetBit(size_t index) const
{
return findBit(index, true);
}
ALWAYS_INLINE size_t findClearBit(size_t index) const
{
return findBit(index, false);
}
void dump(PrintStream& out) const
{
for (size_t i = 0; i < numBits(); ++i)
out.print((*this)[i] ? "1" : "-");
}
typename Words::ViewType wordView() const { return m_words.view(); }
private:
// You'd think that we could remove this friend if we used protected, but you'd be wrong,
// because templates.
friend class FastBitVector;
bool atImpl(size_t index) const
{
ASSERT_WITH_SECURITY_IMPLICATION(index < numBits());
return !!(m_words.word(index >> 5) & (1 << (index & 31)));
}
Words m_words;
};
class FastBitVector : public FastBitVectorImpl<FastBitVectorWordOwner> {
public:
FastBitVector() { }
FastBitVector(const FastBitVector&) = default;
FastBitVector& operator=(const FastBitVector&) = default;
template<typename OtherWords>
FastBitVector(const FastBitVectorImpl<OtherWords>& other)
{
*this = other;
}
template<typename OtherWords>
FastBitVector& operator=(const FastBitVectorImpl<OtherWords>& other)
{
if (UNLIKELY(numBits() != other.numBits()))
resize(other.numBits());
for (unsigned i = arrayLength(); i--;)
m_words.word(i) = other.m_words.word(i);
return *this;
}
void resize(size_t numBits)
{
m_words.resize(numBits);
}
void setAll()
{
m_words.setAll();
}
void clearAll()
{
m_words.clearAll();
}
WTF_EXPORT_PRIVATE void clearRange(size_t begin, size_t end);
// Returns true if the contents of this bitvector changed.
template<typename OtherWords>
bool setAndCheck(const FastBitVectorImpl<OtherWords>& other)
{
bool changed = false;
ASSERT_WITH_SECURITY_IMPLICATION(numBits() == other.numBits());
for (unsigned i = arrayLength(); i--;) {
changed |= m_words.word(i) != other.m_words.word(i);
m_words.word(i) = other.m_words.word(i);
}
return changed;
}
template<typename OtherWords>
FastBitVector& operator|=(const FastBitVectorImpl<OtherWords>& other)
{
ASSERT_WITH_SECURITY_IMPLICATION(numBits() == other.numBits());
for (unsigned i = arrayLength(); i--;)
m_words.word(i) |= other.m_words.word(i);
return *this;
}
template<typename OtherWords>
FastBitVector& operator&=(const FastBitVectorImpl<OtherWords>& other)
{
ASSERT_WITH_SECURITY_IMPLICATION(numBits() == other.numBits());
for (unsigned i = arrayLength(); i--;)
m_words.word(i) &= other.m_words.word(i);
return *this;
}
bool at(size_t index) const
{
return atImpl(index);
}
bool operator[](size_t index) const
{
return atImpl(index);
}
class BitReference {
public:
BitReference() { }
BitReference(uint32_t* word, uint32_t mask)
: m_word(word)
, m_mask(mask)
{
}
explicit operator bool() const
{
return !!(*m_word & m_mask);
}
BitReference& operator=(bool value)
{
if (value)
*m_word |= m_mask;
else
*m_word &= ~m_mask;
return *this;
}
private:
uint32_t* m_word { nullptr };
uint32_t m_mask { 0 };
};
BitReference at(size_t index)
{
ASSERT_WITH_SECURITY_IMPLICATION(index < numBits());
return BitReference(&m_words.word(index >> 5), 1 << (index & 31));
}
BitReference operator[](size_t index)
{
return at(index);
}
// Returns true if the contents changed.
ALWAYS_INLINE bool atomicSetAndCheck(size_t index, bool value)
{
uint32_t* pointer = &m_words.word(index >> 5);
uint32_t mask = 1 << (index & 31);
for (;;) {
uint32_t oldValue = *pointer;
uint32_t newValue;
if (value) {
if (oldValue & mask)
return false;
newValue = oldValue | mask;
} else {
if (!(oldValue & mask))
return false;
newValue = oldValue & ~mask;
}
if (atomicCompareExchangeWeakRelaxed(pointer, oldValue, newValue))
return true;
}
}
};
} // namespace WTF
using WTF::FastBitVector;

198
include/FastMalloc.h Normal file
View File

@ -0,0 +1,198 @@
/*
* Copyright (C) 2005-2009, 2015-2016 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef WTF_FastMalloc_h
#define WTF_FastMalloc_h
#include <new>
#include <stdlib.h>
#include <wtf/StdLibExtras.h>
namespace WTF {
#if !defined(NDEBUG)
WTF_EXPORT_PRIVATE void fastSetMaxSingleAllocationSize(size_t);
#endif
class TryMallocReturnValue {
public:
TryMallocReturnValue(void*);
TryMallocReturnValue(TryMallocReturnValue&&);
~TryMallocReturnValue();
template<typename T> bool getValue(T*&) WARN_UNUSED_RETURN;
private:
void operator=(TryMallocReturnValue&&) = delete;
mutable void* m_data;
};
WTF_EXPORT_PRIVATE bool isFastMallocEnabled();
// These functions call CRASH() if an allocation fails.
WTF_EXPORT_PRIVATE void* fastMalloc(size_t) RETURNS_NONNULL;
WTF_EXPORT_PRIVATE void* fastZeroedMalloc(size_t) RETURNS_NONNULL;
WTF_EXPORT_PRIVATE void* fastCalloc(size_t numElements, size_t elementSize) RETURNS_NONNULL;
WTF_EXPORT_PRIVATE void* fastRealloc(void*, size_t) RETURNS_NONNULL;
WTF_EXPORT_PRIVATE char* fastStrDup(const char*) RETURNS_NONNULL;
WTF_EXPORT_PRIVATE TryMallocReturnValue tryFastMalloc(size_t);
TryMallocReturnValue tryFastZeroedMalloc(size_t);
WTF_EXPORT_PRIVATE TryMallocReturnValue tryFastCalloc(size_t numElements, size_t elementSize);
WTF_EXPORT_PRIVATE void fastFree(void*);
// Allocations from fastAlignedMalloc() must be freed using fastAlignedFree().
WTF_EXPORT_PRIVATE void* fastAlignedMalloc(size_t alignment, size_t) RETURNS_NONNULL;
WTF_EXPORT_PRIVATE void* tryFastAlignedMalloc(size_t alignment, size_t);
WTF_EXPORT_PRIVATE void fastAlignedFree(void*);
WTF_EXPORT_PRIVATE size_t fastMallocSize(const void*);
// FIXME: This is non-helpful; fastMallocGoodSize will be removed soon.
WTF_EXPORT_PRIVATE size_t fastMallocGoodSize(size_t);
WTF_EXPORT_PRIVATE void releaseFastMallocFreeMemory();
WTF_EXPORT_PRIVATE void releaseFastMallocFreeMemoryForThisThread();
struct FastMallocStatistics {
size_t reservedVMBytes;
size_t committedVMBytes;
size_t freeListBytes;
};
WTF_EXPORT_PRIVATE FastMallocStatistics fastMallocStatistics();
// This defines a type which holds an unsigned integer and is the same
// size as the minimally aligned memory allocation.
typedef unsigned long long AllocAlignmentInteger;
inline TryMallocReturnValue::TryMallocReturnValue(void* data)
: m_data(data)
{
}
inline TryMallocReturnValue::TryMallocReturnValue(TryMallocReturnValue&& source)
: m_data(source.m_data)
{
source.m_data = nullptr;
}
inline TryMallocReturnValue::~TryMallocReturnValue()
{
ASSERT(!m_data);
}
template<typename T> inline bool TryMallocReturnValue::getValue(T*& data)
{
data = static_cast<T*>(m_data);
m_data = nullptr;
return data;
}
// C++ STL allocator implementation. You can integrate fastMalloc into STL containers.
// e.g. std::unordered_map<Key, Value, std::hash<Key>, std::equal_to<Key>, FastAllocator<std::pair<const Key, Value>>>.
template<typename T>
class FastAllocator {
public:
using value_type = T;
FastAllocator() = default;
template<typename U> FastAllocator(const FastAllocator<U>&) { }
T* allocate(size_t count)
{
return reinterpret_cast<T*>(fastMalloc(sizeof(T) * count));
}
void deallocate(T* pointer, size_t)
{
fastFree(pointer);
}
};
template<typename T, typename U> inline bool operator==(const FastAllocator<T>&, const FastAllocator<U>&) { return true; }
template<typename T, typename U> inline bool operator!=(const FastAllocator<T>&, const FastAllocator<U>&) { return false; }
} // namespace WTF
#if !defined(NDEBUG)
using WTF::fastSetMaxSingleAllocationSize;
#endif
using WTF::isFastMallocEnabled;
using WTF::fastCalloc;
using WTF::fastFree;
using WTF::fastMalloc;
using WTF::fastMallocGoodSize;
using WTF::fastMallocSize;
using WTF::fastRealloc;
using WTF::fastStrDup;
using WTF::fastZeroedMalloc;
using WTF::tryFastAlignedMalloc;
using WTF::tryFastCalloc;
using WTF::tryFastMalloc;
using WTF::tryFastZeroedMalloc;
using WTF::fastAlignedMalloc;
using WTF::fastAlignedFree;
using WTF::FastAllocator;
#if COMPILER(GCC_OR_CLANG) && OS(DARWIN)
#define WTF_PRIVATE_INLINE __private_extern__ inline __attribute__((always_inline))
#elif COMPILER(GCC_OR_CLANG)
#define WTF_PRIVATE_INLINE inline __attribute__((always_inline))
#elif COMPILER(MSVC)
#define WTF_PRIVATE_INLINE __forceinline
#else
#define WTF_PRIVATE_INLINE inline
#endif
#define WTF_MAKE_FAST_ALLOCATED \
public: \
void* operator new(size_t, void* p) { return p; } \
void* operator new[](size_t, void* p) { return p; } \
\
void* operator new(size_t size) \
{ \
return ::WTF::fastMalloc(size); \
} \
\
void operator delete(void* p) \
{ \
::WTF::fastFree(p); \
} \
\
void* operator new[](size_t size) \
{ \
return ::WTF::fastMalloc(size); \
} \
\
void operator delete[](void* p) \
{ \
::WTF::fastFree(p); \
} \
void* operator new(size_t, NotNullTag, void* location) \
{ \
ASSERT(location); \
return location; \
} \
private: \
typedef int __thisIsHereToForceASemicolonAfterThisMacro
#endif /* WTF_FastMalloc_h */

65
include/FastTLS.h Normal file
View File

@ -0,0 +1,65 @@
/*
* Copyright (C) 2017 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. ``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
* 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
#if HAVE(FAST_TLS)
#include <pthread.h>
#include <System/pthread_machdep.h>
#include <wtf/Platform.h>
namespace WTF {
// __PTK_FRAMEWORK_JAVASCRIPTCORE_KEY0 is taken by bmalloc, so WTF's KEY0 maps to the
// system's KEY1.
#define WTF_FAST_TLS_KEY0 __PTK_FRAMEWORK_JAVASCRIPTCORE_KEY1
#define WTF_FAST_TLS_KEY1 __PTK_FRAMEWORK_JAVASCRIPTCORE_KEY2
#define WTF_FAST_TLS_KEY2 __PTK_FRAMEWORK_JAVASCRIPTCORE_KEY3
#define WTF_FAST_TLS_KEY3 __PTK_FRAMEWORK_JAVASCRIPTCORE_KEY4
// NOTE: We should manage our use of these keys here. If you want to use a key for something,
// put a #define in here to give your key a symbolic name. This ensures that we don't
// accidentally use the same key for more than one thing.
#define WTF_THREAD_DATA_KEY WTF_FAST_TLS_KEY0
#define WTF_WASM_CONTEXT_KEY WTF_FAST_TLS_KEY1
#define WTF_TESTING_KEY WTF_FAST_TLS_KEY3
#if ENABLE(FAST_TLS_JIT)
inline unsigned fastTLSOffsetForKey(unsigned long slot)
{
return slot * sizeof(void*);
}
#endif
} // namespace WTF
#if ENABLE(FAST_TLS_JIT)
using WTF::fastTLSOffsetForKey;
#endif
#endif // HAVE(FAST_TLS)

765
include/FeatureDefines.h Normal file
View File

@ -0,0 +1,765 @@
/*
* Copyright (C) 2006, 2007, 2008, 2009, 2013 Apple Inc. All rights reserved.
* Copyright (C) 2007-2009 Torch Mobile, Inc.
* Copyright (C) 2010, 2011 Research In Motion Limited. All rights reserved.
* Copyright (C) 2013 Samsung Electronics. 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. ``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
* 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.
*/
#ifndef WTF_FeatureDefines_h
#define WTF_FeatureDefines_h
/* Use this file to list _all_ ENABLE() macros. Define the macros to be one of the following values:
* - "0" disables the feature by default. The feature can still be enabled for a specific port or environment.
* - "1" enables the feature by default. The feature can still be disabled for a specific port or environment.
*
* The feature defaults in this file are only taken into account if the (port specific) build system
* has not enabled or disabled a particular feature.
*
* Use this file to define ENABLE() macros only. Do not use this file to define USE() or macros !
*
* Only define a macro if it was not defined before - always check for !defined first.
*
* Keep the file sorted by the name of the defines. As an exception you can change the order
* to allow interdependencies between the default values.
*
* Below are a few potential commands to take advantage of this file running from the Source/WTF directory
*
* Get the list of feature defines: grep -o "ENABLE_\(\w\+\)" wtf/FeatureDefines.h | sort | uniq
* Get the list of features enabled by default for a PLATFORM(XXX): gcc -E -dM -I. -DWTF_PLATFORM_XXX "wtf/Platform.h" | grep "ENABLE_\w\+ 1" | cut -d' ' -f2 | sort
*/
/* FIXME: Move out the PLATFORM specific rules into platform specific files. */
/* --------- Apple IOS (but not MAC) port --------- */
#if PLATFORM(IOS)
#if !defined(ENABLE_ASYNC_SCROLLING)
#define ENABLE_ASYNC_SCROLLING 1
#endif
#if !defined(ENABLE_CONTENT_EXTENSIONS)
#define ENABLE_CONTENT_EXTENSIONS 1
#endif
#if !defined(ENABLE_CONTEXT_MENUS)
#define ENABLE_CONTEXT_MENUS 0
#endif
#if !defined(ENABLE_CURSOR_SUPPORT)
#define ENABLE_CURSOR_SUPPORT 0
#endif
#if !defined(ENABLE_DRAG_SUPPORT)
#define ENABLE_DRAG_SUPPORT 0
#endif
#if !defined(ENABLE_GEOLOCATION)
#define ENABLE_GEOLOCATION 1
#endif
#if !defined(ENABLE_ICONDATABASE)
#define ENABLE_ICONDATABASE 0
#endif
#if !defined(ENABLE_INSPECTOR_ALTERNATE_DISPATCHERS)
#define ENABLE_INSPECTOR_ALTERNATE_DISPATCHERS 1
#endif
#if !defined(ENABLE_LETTERPRESS)
#define ENABLE_LETTERPRESS 1
#endif
#if !defined(ENABLE_IOS_AUTOCORRECT_AND_AUTOCAPITALIZE)
#define ENABLE_IOS_AUTOCORRECT_AND_AUTOCAPITALIZE 1
#endif
#if !defined(ENABLE_IOS_GESTURE_EVENTS) && USE(APPLE_INTERNAL_SDK)
#define ENABLE_IOS_GESTURE_EVENTS 1
#endif
#if !defined(ENABLE_TEXT_AUTOSIZING)
#define ENABLE_TEXT_AUTOSIZING 1
#endif
#if !defined(ENABLE_IOS_TOUCH_EVENTS) && USE(APPLE_INTERNAL_SDK)
#define ENABLE_IOS_TOUCH_EVENTS 1
#endif
#if !defined(ENABLE_METER_ELEMENT)
#define ENABLE_METER_ELEMENT 0
#endif
#if !defined(ENABLE_NETSCAPE_PLUGIN_API)
#define ENABLE_NETSCAPE_PLUGIN_API 0
#endif
#if !defined(ENABLE_ORIENTATION_EVENTS)
#define ENABLE_ORIENTATION_EVENTS 1
#endif
#if !defined(ENABLE_POINTER_LOCK)
#define ENABLE_POINTER_LOCK 0
#endif
#if !defined(ENABLE_REMOTE_INSPECTOR)
#define ENABLE_REMOTE_INSPECTOR 1
#endif
#if !defined(ENABLE_RESPECT_EXIF_ORIENTATION)
#define ENABLE_RESPECT_EXIF_ORIENTATION 1
#endif
#if !defined(ENABLE_TEXT_CARET)
#define ENABLE_TEXT_CARET 0
#endif
#if !defined(ENABLE_TEXT_SELECTION)
#define ENABLE_TEXT_SELECTION 0
#endif
/* FIXME: Remove the USE(APPLE_INTERNAL_SDK) conjunct once we support touch events when building against
the public iOS SDK. We will also need to update the FeatureDefines.xcconfig files. */
#if !defined(ENABLE_TOUCH_EVENTS) && USE(APPLE_INTERNAL_SDK)
#define ENABLE_TOUCH_EVENTS 1
#endif
#if !defined(ENABLE_WEB_ARCHIVE)
#define ENABLE_WEB_ARCHIVE 1
#endif
#if !defined(ENABLE_VIEW_MODE_CSS_MEDIA)
#define ENABLE_VIEW_MODE_CSS_MEDIA 0
#endif
#if !defined(ENABLE_WEBASSEMBLY)
#define ENABLE_WEBASSEMBLY (defined(ENABLE_B3_JIT) && ENABLE_B3_JIT)
#endif
#if !defined(ENABLE_WEBGL)
#define ENABLE_WEBGL 1
#endif
#if !defined(ENABLE_PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC)
#define ENABLE_PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC 1
#endif
#if !defined(ENABLE_DOWNLOAD_ATTRIBUTE)
#define ENABLE_DOWNLOAD_ATTRIBUTE 0
#endif
#endif /* PLATFORM(IOS) */
/* --------- Apple MAC port (not IOS) --------- */
#if PLATFORM(MAC)
#if !defined(ENABLE_CONTENT_EXTENSIONS)
#define ENABLE_CONTENT_EXTENSIONS 1
#endif
#if !defined(ENABLE_DASHBOARD_SUPPORT)
#define ENABLE_DASHBOARD_SUPPORT 1
#endif
#if !defined(ENABLE_FULLSCREEN_API)
#define ENABLE_FULLSCREEN_API 1
#endif
#if !defined(ENABLE_REMOTE_INSPECTOR)
#define ENABLE_REMOTE_INSPECTOR 1
#endif
#if !defined(ENABLE_INSPECTOR_ALTERNATE_DISPATCHERS)
#define ENABLE_INSPECTOR_ALTERNATE_DISPATCHERS 1
#endif
#if !defined(ENABLE_SMOOTH_SCROLLING)
#define ENABLE_SMOOTH_SCROLLING 1
#endif
#if !defined(ENABLE_ASYNC_SCROLLING)
#define ENABLE_ASYNC_SCROLLING 1
#endif
#if ENABLE(VIDEO)
#if !defined(ENABLE_VIDEO_TRACK)
#define ENABLE_VIDEO_TRACK 1
#endif
#endif
#if !defined(ENABLE_VIEW_MODE_CSS_MEDIA)
#define ENABLE_VIEW_MODE_CSS_MEDIA 0
#endif
#if !defined(ENABLE_WEBASSEMBLY)
#define ENABLE_WEBASSEMBLY (defined(ENABLE_B3_JIT) && ENABLE_B3_JIT)
#endif
#if !defined(ENABLE_WEB_ARCHIVE)
#define ENABLE_WEB_ARCHIVE 1
#endif
#if !defined(ENABLE_WEB_AUDIO)
#define ENABLE_WEB_AUDIO 1
#endif
#if !defined(ENABLE_CURSOR_VISIBILITY)
#define ENABLE_CURSOR_VISIBILITY 1
#endif
#if !defined(ENABLE_INPUT_TYPE_COLOR)
#define ENABLE_INPUT_TYPE_COLOR 1
#endif
#if !defined(ENABLE_INPUT_TYPE_COLOR_POPOVER)
#define ENABLE_INPUT_TYPE_COLOR_POPOVER 1
#endif
#if !defined(ENABLE_PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC)
#define ENABLE_PRIMARY_SNAPSHOTTED_PLUGIN_HEURISTIC 1
#endif
#if !defined(ENABLE_MAC_GESTURE_EVENTS) && USE(APPLE_INTERNAL_SDK)
#define ENABLE_MAC_GESTURE_EVENTS 1
#endif
#endif /* PLATFORM(MAC) */
#if PLATFORM(COCOA)
#if !defined(ENABLE_DATA_DETECTION)
#define ENABLE_DATA_DETECTION 0
#endif
#if !defined(ENABLE_LEGACY_ENCRYPTED_MEDIA)
#define ENABLE_LEGACY_ENCRYPTED_MEDIA 1
#endif
#if !defined(ENABLE_FILE_REPLACEMENT)
#define ENABLE_FILE_REPLACEMENT 1
#endif
#if !defined(ENABLE_KEYBOARD_KEY_ATTRIBUTE)
#define ENABLE_KEYBOARD_KEY_ATTRIBUTE 1
#endif
#if !defined(ENABLE_KEYBOARD_CODE_ATTRIBUTE)
#define ENABLE_KEYBOARD_CODE_ATTRIBUTE 1
#endif
#endif /* PLATFORM(COCOA) */
#if !PLATFORM(COCOA)
#if !defined(JSC_OBJC_API_ENABLED)
#define JSC_OBJC_API_ENABLED 0
#endif
#endif /* !PLATFORM(COCOA) */
/* --------- Apple Windows port --------- */
#if PLATFORM(WIN) && !PLATFORM(WIN_CAIRO)
#if !defined(ENABLE_FULLSCREEN_API)
#define ENABLE_FULLSCREEN_API 1
#endif
#if !defined(ENABLE_WEB_ARCHIVE)
#define ENABLE_WEB_ARCHIVE 1
#endif
#if !defined(ENABLE_WEBGL)
#define ENABLE_WEBGL 0
#endif
#if !defined(ENABLE_GEOLOCATION)
#define ENABLE_GEOLOCATION 1
#endif
#endif /* PLATFORM(WIN) && !PLATFORM(WIN_CAIRO) */
/* --------- Windows CAIRO port --------- */
/* PLATFORM(WIN_CAIRO) is a specialization of PLATFORM(WIN). */
/* PLATFORM(WIN) is always enabled when PLATFORM(WIN_CAIRO) is enabled. */
#if PLATFORM(WIN_CAIRO)
#if !defined(ENABLE_WEB_ARCHIVE)
#define ENABLE_WEB_ARCHIVE 1
#endif
#if !defined(ENABLE_VIEW_MODE_CSS_MEDIA)
#define ENABLE_VIEW_MODE_CSS_MEDIA 0
#endif
#if !defined(ENABLE_WEBGL)
#define ENABLE_WEBGL 1
#endif
#if !defined(ENABLE_GEOLOCATION)
#define ENABLE_GEOLOCATION 1
#endif
#endif /* PLATFORM(WIN_CAIRO) */
/* --------- Gtk port (Unix, Windows, Mac) --------- */
#if PLATFORM(GTK)
#if !defined(ENABLE_KEYBOARD_KEY_ATTRIBUTE)
#define ENABLE_KEYBOARD_KEY_ATTRIBUTE 1
#endif
#if !defined(ENABLE_KEYBOARD_CODE_ATTRIBUTE)
#define ENABLE_KEYBOARD_CODE_ATTRIBUTE 1
#endif
#endif /* PLATFORM(GTK) */
/* ENABLE macro defaults for WebCore */
/* Do not use PLATFORM() tests in this section ! */
#if !defined(ENABLE_3D_TRANSFORMS)
#define ENABLE_3D_TRANSFORMS 0
#endif
#if !defined(ENABLE_ACCELERATED_2D_CANVAS)
#define ENABLE_ACCELERATED_2D_CANVAS 0
#endif
#if !defined(ENABLE_ACCELERATED_OVERFLOW_SCROLLING)
#define ENABLE_ACCELERATED_OVERFLOW_SCROLLING 0
#endif
#if !defined(ENABLE_APNG)
#define ENABLE_APNG 1
#endif
#if !defined(ENABLE_CANVAS_PATH)
#define ENABLE_CANVAS_PATH 1
#endif
#if !defined(ENABLE_CANVAS_PROXY)
#define ENABLE_CANVAS_PROXY 0
#endif
#if !defined(ENABLE_CHANNEL_MESSAGING)
#define ENABLE_CHANNEL_MESSAGING 1
#endif
#if !defined(ENABLE_CONTENT_EXTENSIONS)
#define ENABLE_CONTENT_EXTENSIONS 0
#endif
#if !defined(ENABLE_CONTEXT_MENUS)
#define ENABLE_CONTEXT_MENUS 1
#endif
#if !defined(ENABLE_CSS3_TEXT)
#define ENABLE_CSS3_TEXT 0
#endif
#if !defined(ENABLE_CSS_BOX_DECORATION_BREAK)
#define ENABLE_CSS_BOX_DECORATION_BREAK 1
#endif
#if !defined(ENABLE_CSS_DEVICE_ADAPTATION)
#define ENABLE_CSS_DEVICE_ADAPTATION 0
#endif
#if !defined(ENABLE_CSS_COMPOSITING)
#define ENABLE_CSS_COMPOSITING 0
#endif
#if !defined(ENABLE_CSS_IMAGE_ORIENTATION)
#define ENABLE_CSS_IMAGE_ORIENTATION 0
#endif
#if !defined(ENABLE_CSS_IMAGE_RESOLUTION)
#define ENABLE_CSS_IMAGE_RESOLUTION 0
#endif
#if !defined(ENABLE_CURSOR_SUPPORT)
#define ENABLE_CURSOR_SUPPORT 1
#endif
#if !defined(ENABLE_CUSTOM_SCHEME_HANDLER)
#define ENABLE_CUSTOM_SCHEME_HANDLER 0
#endif
#if !defined(ENABLE_DASHBOARD_SUPPORT)
#define ENABLE_DASHBOARD_SUPPORT 0
#endif
#if !defined(ENABLE_DATALIST_ELEMENT)
#define ENABLE_DATALIST_ELEMENT 0
#endif
#if !defined(ENABLE_DATA_TRANSFER_ITEMS)
#define ENABLE_DATA_TRANSFER_ITEMS 0
#endif
#if !defined(ENABLE_DEVICE_ORIENTATION)
#define ENABLE_DEVICE_ORIENTATION 0
#endif
#if !defined(ENABLE_DOWNLOAD_ATTRIBUTE)
#define ENABLE_DOWNLOAD_ATTRIBUTE 1
#endif
#if !defined(ENABLE_DRAG_SUPPORT)
#define ENABLE_DRAG_SUPPORT 1
#endif
#if !defined(ENABLE_ENCRYPTED_MEDIA)
#define ENABLE_ENCRYPTED_MEDIA 0
#endif
#if !defined(ENABLE_FETCH_API)
#define ENABLE_FETCH_API 1
#endif
#if !defined(ENABLE_FILTERS_LEVEL_2)
#define ENABLE_FILTERS_LEVEL_2 0
#endif
#if !defined(ENABLE_FTPDIR)
#define ENABLE_FTPDIR 1
#endif
#if !defined(ENABLE_FULLSCREEN_API)
#define ENABLE_FULLSCREEN_API 0
#endif
#if !defined(ENABLE_GAMEPAD)
#define ENABLE_GAMEPAD 0
#endif
#if !defined(ENABLE_GAMEPAD_DEPRECATED)
#define ENABLE_GAMEPAD_DEPRECATED 0
#endif
#if !defined(ENABLE_GEOLOCATION)
#define ENABLE_GEOLOCATION 0
#endif
#if !defined(ENABLE_ICONDATABASE)
#define ENABLE_ICONDATABASE 1
#endif
#if !defined(ENABLE_IMAGE_DECODER_DOWN_SAMPLING)
#define ENABLE_IMAGE_DECODER_DOWN_SAMPLING 0
#endif
#if !defined(ENABLE_INDEXED_DATABASE)
#define ENABLE_INDEXED_DATABASE 0
#endif
#if !defined(ENABLE_INDEXED_DATABASE_IN_WORKERS)
#define ENABLE_INDEXED_DATABASE_IN_WORKERS 0
#endif
#if !defined(ENABLE_INPUT_TYPE_COLOR)
#define ENABLE_INPUT_TYPE_COLOR 0
#endif
#if !defined(ENABLE_INPUT_TYPE_COLOR_POPOVER)
#define ENABLE_INPUT_TYPE_COLOR_POPOVER 0
#endif
#if !defined(ENABLE_INPUT_TYPE_DATE)
#define ENABLE_INPUT_TYPE_DATE 0
#endif
#if !defined(ENABLE_INPUT_TYPE_DATETIME_INCOMPLETE)
#define ENABLE_INPUT_TYPE_DATETIME_INCOMPLETE 0
#endif
#if !defined(ENABLE_INPUT_TYPE_DATETIMELOCAL)
#define ENABLE_INPUT_TYPE_DATETIMELOCAL 0
#endif
#if !defined(ENABLE_INPUT_TYPE_MONTH)
#define ENABLE_INPUT_TYPE_MONTH 0
#endif
#if !defined(ENABLE_INPUT_TYPE_TIME)
#define ENABLE_INPUT_TYPE_TIME 0
#endif
#if !defined(ENABLE_INPUT_TYPE_WEEK)
#define ENABLE_INPUT_TYPE_WEEK 0
#endif
#if ENABLE(INPUT_TYPE_DATE) || ENABLE(INPUT_TYPE_DATETIME_INCOMPLETE) || ENABLE(INPUT_TYPE_DATETIMELOCAL) || ENABLE(INPUT_TYPE_MONTH) || ENABLE(INPUT_TYPE_TIME) || ENABLE(INPUT_TYPE_WEEK)
#if !defined(ENABLE_DATE_AND_TIME_INPUT_TYPES)
#define ENABLE_DATE_AND_TIME_INPUT_TYPES 1
#endif
#endif
#if !defined(ENABLE_INSPECTOR_ALTERNATE_DISPATCHERS)
#define ENABLE_INSPECTOR_ALTERNATE_DISPATCHERS 0
#endif
#if !defined(ENABLE_INTL)
#define ENABLE_INTL 0
#endif
#if !defined(ENABLE_JAVASCRIPT_I18N_API)
#define ENABLE_JAVASCRIPT_I18N_API 0
#endif
#if !defined(ENABLE_LEGACY_CSS_VENDOR_PREFIXES)
#define ENABLE_LEGACY_CSS_VENDOR_PREFIXES 0
#endif
#if !defined(ENABLE_LEGACY_VENDOR_PREFIXES)
#define ENABLE_LEGACY_VENDOR_PREFIXES 0
#endif
#if !defined(ENABLE_LETTERPRESS)
#define ENABLE_LETTERPRESS 0
#endif
#if !defined(ENABLE_LINK_PREFETCH)
#define ENABLE_LINK_PREFETCH 0
#endif
#if !defined(ENABLE_MATHML)
#define ENABLE_MATHML 1
#endif
#if !defined(ENABLE_MEDIA_CAPTURE)
#define ENABLE_MEDIA_CAPTURE 0
#endif
#if !defined(ENABLE_MEDIA_CONTROLS_SCRIPT)
#define ENABLE_MEDIA_CONTROLS_SCRIPT 0
#endif
#if !defined(ENABLE_MEDIA_SOURCE)
#define ENABLE_MEDIA_SOURCE 0
#endif
#if !defined(ENABLE_MEDIA_STATISTICS)
#define ENABLE_MEDIA_STATISTICS 0
#endif
#if !defined(ENABLE_MEDIA_STREAM)
#define ENABLE_MEDIA_STREAM 0
#endif
#if !defined(ENABLE_METER_ELEMENT)
#define ENABLE_METER_ELEMENT 1
#endif
#if !defined(ENABLE_MHTML)
#define ENABLE_MHTML 0
#endif
#if !defined(ENABLE_MOUSE_CURSOR_SCALE)
#define ENABLE_MOUSE_CURSOR_SCALE 0
#endif
#if !defined(ENABLE_MOUSE_FORCE_EVENTS)
#define ENABLE_MOUSE_FORCE_EVENTS 1
#endif
#if !defined(ENABLE_NAVIGATOR_CONTENT_UTILS)
#define ENABLE_NAVIGATOR_CONTENT_UTILS 0
#endif
#if !defined(ENABLE_NETSCAPE_PLUGIN_API)
#define ENABLE_NETSCAPE_PLUGIN_API 1
#endif
#if !defined(ENABLE_NETSCAPE_PLUGIN_METADATA_CACHE)
#define ENABLE_NETSCAPE_PLUGIN_METADATA_CACHE 0
#endif
#if !defined(ENABLE_NOTIFICATIONS)
#define ENABLE_NOTIFICATIONS 0
#endif
#if !defined(ENABLE_OPENTYPE_VERTICAL)
#define ENABLE_OPENTYPE_VERTICAL 0
#endif
#if !defined(ENABLE_ORIENTATION_EVENTS)
#define ENABLE_ORIENTATION_EVENTS 0
#endif
#if OS(WINDOWS)
#if !defined(ENABLE_PAN_SCROLLING)
#define ENABLE_PAN_SCROLLING 1
#endif
#endif
#if !defined(ENABLE_POINTER_LOCK)
#define ENABLE_POINTER_LOCK 1
#endif
#if !defined(ENABLE_PROXIMITY_EVENTS)
#define ENABLE_PROXIMITY_EVENTS 0
#endif
#if !defined(ENABLE_QUOTA)
#define ENABLE_QUOTA 0
#endif
#if !defined(ENABLE_REMOTE_INSPECTOR)
#define ENABLE_REMOTE_INSPECTOR 0
#endif
#if !defined(ENABLE_REQUEST_AUTOCOMPLETE)
#define ENABLE_REQUEST_AUTOCOMPLETE 0
#endif
#if !defined(ENABLE_RUBBER_BANDING)
#define ENABLE_RUBBER_BANDING 0
#endif
#if !defined(ENABLE_SMOOTH_SCROLLING)
#define ENABLE_SMOOTH_SCROLLING 0
#endif
#if !defined(ENABLE_SPEECH_SYNTHESIS)
#define ENABLE_SPEECH_SYNTHESIS 0
#endif
#if !defined(ENABLE_SPELLCHECK)
#define ENABLE_SPELLCHECK 0
#endif
#if !defined(ENABLE_STREAMS_API)
#define ENABLE_STREAMS_API 1
#endif
#if !defined(ENABLE_SVG_FONTS)
#define ENABLE_SVG_FONTS 1
#endif
#if !defined(ENABLE_TEXT_CARET)
#define ENABLE_TEXT_CARET 1
#endif
#if !defined(ENABLE_TEXT_SELECTION)
#define ENABLE_TEXT_SELECTION 1
#endif
#if !defined(ENABLE_ASYNC_SCROLLING)
#define ENABLE_ASYNC_SCROLLING 0
#endif
#if !defined(ENABLE_TOUCH_EVENTS)
#define ENABLE_TOUCH_EVENTS 0
#endif
#if !defined(ENABLE_TOUCH_ICON_LOADING)
#define ENABLE_TOUCH_ICON_LOADING 0
#endif
#if !defined(ENABLE_VIDEO)
#define ENABLE_VIDEO 0
#endif
#if !defined(ENABLE_VIDEO_TRACK)
#define ENABLE_VIDEO_TRACK 0
#endif
#if !defined(ENABLE_DATACUE_VALUE)
#define ENABLE_DATACUE_VALUE 0
#endif
#if !defined(ENABLE_VIEW_MODE_CSS_MEDIA)
#define ENABLE_VIEW_MODE_CSS_MEDIA 1
#endif
#if !defined(ENABLE_WEBGL)
#define ENABLE_WEBGL 0
#endif
#if !defined(ENABLE_GRAPHICS_CONTEXT_3D)
#define ENABLE_GRAPHICS_CONTEXT_3D ENABLE_WEBGL
#endif
#if !defined(ENABLE_WEB_ANIMATIONS)
#define ENABLE_WEB_ANIMATIONS 1
#endif
#if !defined(ENABLE_WEB_ARCHIVE)
#define ENABLE_WEB_ARCHIVE 0
#endif
#if !defined(ENABLE_WEB_AUDIO)
#define ENABLE_WEB_AUDIO 0
#endif
#if !defined(ENABLE_WEB_SOCKETS)
#define ENABLE_WEB_SOCKETS 1
#endif
#if !defined(ENABLE_WEB_TIMING)
#define ENABLE_WEB_TIMING 0
#endif
#if !defined(ENABLE_XSLT)
#define ENABLE_XSLT 1
#endif
#if !defined(ENABLE_KEYBOARD_KEY_ATTRIBUTE)
#define ENABLE_KEYBOARD_KEY_ATTRIBUTE 0
#endif
#if !defined(ENABLE_KEYBOARD_CODE_ATTRIBUTE)
#define ENABLE_KEYBOARD_CODE_ATTRIBUTE 0
#endif
#if !defined(ENABLE_DATA_INTERACTION)
#define ENABLE_DATA_INTERACTION 0
#endif
/* Asserts, invariants for macro definitions */
#if ENABLE(VIDEO_TRACK) && !ENABLE(VIDEO)
#error "ENABLE(VIDEO_TRACK) requires ENABLE(VIDEO)"
#endif
#if ENABLE(MEDIA_CONTROLS_SCRIPT) && !ENABLE(VIDEO)
#error "ENABLE(MEDIA_CONTROLS_SCRIPT) requires ENABLE(VIDEO)"
#endif
#if ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) && !ENABLE(REMOTE_INSPECTOR)
#error "ENABLE(INSPECTOR_ALTERNATE_DISPATCHERS) requires ENABLE(REMOTE_INSPECTOR)"
#endif
#if ENABLE(IOS_TOUCH_EVENTS) && !ENABLE(TOUCH_EVENTS)
#error "ENABLE(IOS_TOUCH_EVENTS) requires ENABLE(TOUCH_EVENTS)"
#endif
#if ENABLE(WEBGL) && !ENABLE(GRAPHICS_CONTEXT_3D)
#error "ENABLE(WEBGL) requires ENABLE(GRAPHICS_CONTEXT_3D)"
#endif
#if ENABLE(WEBGL2) && !ENABLE(WEBGL)
#error "ENABLE(WEBGL2) requires ENABLE(WEBGL)"
#endif
#endif /* WTF_FeatureDefines_h */

61
include/FilePrintStream.h Normal file
View File

@ -0,0 +1,61 @@
/*
* Copyright (C) 2012 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. ``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
* 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.
*/
#ifndef FilePrintStream_h
#define FilePrintStream_h
#include <stdio.h>
#include <wtf/PrintStream.h>
namespace WTF {
class FilePrintStream : public PrintStream {
public:
enum AdoptionMode {
Adopt,
Borrow
};
FilePrintStream(FILE*, AdoptionMode = Adopt);
virtual ~FilePrintStream();
WTF_EXPORT_PRIVATE static std::unique_ptr<FilePrintStream> open(const char* filename, const char* mode);
FILE* file() { return m_file; }
void vprintf(const char* format, va_list) override WTF_ATTRIBUTE_PRINTF(2, 0);
void flush() override;
private:
FILE* m_file;
AdoptionMode m_adoptionMode;
};
} // namespace WTF
using WTF::FilePrintStream;
#endif // FilePrintStream_h

117
include/FlipBytes.h Normal file
View File

@ -0,0 +1,117 @@
/*
* Copyright (C) 2013 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. ``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
* 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.
*/
#ifndef FlipBytes_h
#define FlipBytes_h
namespace WTF {
inline bool needToFlipBytesIfLittleEndian(bool littleEndian)
{
#if CPU(BIG_ENDIAN)
return littleEndian;
#else
return !littleEndian;
#endif
}
inline uint16_t flipBytes(uint16_t value)
{
return ((value & 0x00ff) << 8)
| ((value & 0xff00) >> 8);
}
inline uint32_t flipBytes(uint32_t value)
{
return ((value & 0x000000ff) << 24)
| ((value & 0x0000ff00) << 8)
| ((value & 0x00ff0000) >> 8)
| ((value & 0xff000000) >> 24);
}
inline uint64_t flipBytes(uint64_t value)
{
return ((value & 0x00000000000000ffull) << 56)
| ((value & 0x000000000000ff00ull) << 40)
| ((value & 0x0000000000ff0000ull) << 24)
| ((value & 0x00000000ff000000ull) << 8)
| ((value & 0x000000ff00000000ull) >> 8)
| ((value & 0x0000ff0000000000ull) >> 24)
| ((value & 0x00ff000000000000ull) >> 40)
| ((value & 0xff00000000000000ull) >> 56);
}
template<typename T>
inline T flipBytes(T value)
{
if (sizeof(value) == 1)
return value;
if (sizeof(value) == 2) {
union {
T original;
uint16_t word;
} u;
u.original = value;
u.word = flipBytes(u.word);
return u.original;
}
if (sizeof(value) == 4) {
union {
T original;
uint32_t word;
} u;
u.original = value;
u.word = flipBytes(u.word);
return u.original;
}
if (sizeof(value) == 8) {
union {
T original;
uint64_t word;
} u;
u.original = value;
u.word = flipBytes(u.word);
return u.original;
}
RELEASE_ASSERT_NOT_REACHED();
return T();
}
template<typename T>
inline T flipBytesIfLittleEndian(T value, bool littleEndian)
{
if (needToFlipBytesIfLittleEndian(littleEndian))
return flipBytes(value);
return value;
}
} // namespace WTF
using WTF::needToFlipBytesIfLittleEndian;
using WTF::flipBytes;
using WTF::flipBytesIfLittleEndian;
#endif // FlipBytes_h

View File

@ -0,0 +1,37 @@
/*
* Copyright (C) 2017 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. ``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
* 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
#define WTF_FORBID_HEAP_ALLOCATION \
private: \
void* operator new(size_t, void*) = delete; \
void* operator new[](size_t, void*) = delete; \
void* operator new(size_t) = delete; \
void operator delete(void*) = delete; \
void* operator new[](size_t size) = delete; \
void operator delete[](void*) = delete; \
void* operator new(size_t, NotNullTag, void* location) = delete; \
typedef int __thisIsHereToForceASemicolonAfterThisForbidHeapAllocationMacro

77
include/Forward.h Normal file
View File

@ -0,0 +1,77 @@
/*
* Copyright (C) 2006, 2009, 2011 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#pragma once
#include <stddef.h>
namespace std {
template<typename T> class optional;
}
namespace WTF {
template<typename T> class Function;
template<typename T> class LazyNeverDestroyed;
template<typename T> class NeverDestroyed;
template<typename T> class OptionSet;
template<typename T> class Ref;
template<typename T> class RefPtr;
template<typename T> class StringBuffer;
template<typename... T> class Variant;
template<typename T, size_t inlineCapacity, typename OverflowHandler, size_t minCapacity> class Vector;
class AtomicString;
class AtomicStringImpl;
class BinarySemaphore;
class CString;
class FunctionDispatcher;
class OrdinalNumber;
class PrintStream;
class String;
class StringBuilder;
class StringImpl;
class StringView;
class TextPosition;
}
using WTF::AtomicString;
using WTF::AtomicStringImpl;
using WTF::BinarySemaphore;
using WTF::CString;
using WTF::Function;
using WTF::FunctionDispatcher;
using WTF::LazyNeverDestroyed;
using WTF::NeverDestroyed;
using WTF::OptionSet;
using WTF::OrdinalNumber;
using WTF::PrintStream;
using WTF::Ref;
using WTF::RefPtr;
using WTF::String;
using WTF::StringBuffer;
using WTF::StringBuilder;
using WTF::StringImpl;
using WTF::StringView;
using WTF::TextPosition;
using WTF::Variant;
using WTF::Vector;

113
include/Function.h Normal file
View File

@ -0,0 +1,113 @@
/*
* 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 <memory>
#include <wtf/FastMalloc.h>
namespace WTF {
template<typename> class Function;
template <typename Out, typename... In>
class Function<Out(In...)> {
public:
Function() = default;
Function(std::nullptr_t) { }
template<typename CallableType, class = typename std::enable_if<!(std::is_pointer<CallableType>::value && std::is_function<typename std::remove_pointer<CallableType>::type>::value) && std::is_rvalue_reference<CallableType&&>::value>::type>
Function(CallableType&& callable)
: m_callableWrapper(std::make_unique<CallableWrapper<CallableType>>(WTFMove(callable)))
{
}
template<typename FunctionType, class = typename std::enable_if<std::is_pointer<FunctionType>::value && std::is_function<typename std::remove_pointer<FunctionType>::type>::value>::type>
Function(FunctionType f)
: m_callableWrapper(std::make_unique<CallableWrapper<FunctionType>>(WTFMove(f)))
{
}
Out operator()(In... in) const
{
if (m_callableWrapper)
return m_callableWrapper->call(std::forward<In>(in)...);
return Out();
}
explicit operator bool() const { return !!m_callableWrapper; }
template<typename CallableType, class = typename std::enable_if<!(std::is_pointer<CallableType>::value && std::is_function<typename std::remove_pointer<CallableType>::type>::value) && std::is_rvalue_reference<CallableType&&>::value>::type>
Function& operator=(CallableType&& callable)
{
m_callableWrapper = std::make_unique<CallableWrapper<CallableType>>(WTFMove(callable));
return *this;
}
template<typename FunctionType, class = typename std::enable_if<std::is_pointer<FunctionType>::value && std::is_function<typename std::remove_pointer<FunctionType>::type>::value>::type>
Function& operator=(FunctionType f)
{
m_callableWrapper = std::make_unique<CallableWrapper<FunctionType>>(WTFMove(f));
return *this;
}
Function& operator=(std::nullptr_t)
{
m_callableWrapper = nullptr;
return *this;
}
private:
class CallableWrapperBase {
WTF_MAKE_FAST_ALLOCATED;
public:
virtual ~CallableWrapperBase() { }
virtual Out call(In...) = 0;
};
template<typename CallableType>
class CallableWrapper : public CallableWrapperBase {
public:
explicit CallableWrapper(CallableType&& callable)
: m_callable(WTFMove(callable))
{
}
CallableWrapper(const CallableWrapper&) = delete;
CallableWrapper& operator=(const CallableWrapper&) = delete;
Out call(In... in) final { return m_callable(std::forward<In>(in)...); }
private:
CallableType m_callable;
};
std::unique_ptr<CallableWrapperBase> m_callableWrapper;
};
} // namespace WTF
using WTF::Function;

View File

@ -0,0 +1,51 @@
/*
* Copyright (C) 2013 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.
*/
#ifndef FunctionDispatcher_h
#define FunctionDispatcher_h
#include <wtf/Function.h>
#include <wtf/ThreadSafeRefCounted.h>
namespace WTF {
// FunctionDispatcher is an abstract representation of something that functions can be
// dispatched to. This can for example be a run loop or a work queue.
class FunctionDispatcher : public ThreadSafeRefCounted<FunctionDispatcher> {
public:
WTF_EXPORT_PRIVATE virtual ~FunctionDispatcher();
virtual void dispatch(Function<void ()>&&) = 0;
protected:
WTF_EXPORT_PRIVATE FunctionDispatcher();
};
} // namespace WTF
using WTF::FunctionDispatcher;
#endif // FunctionDispatcher_h

82
include/GetPtr.h Normal file
View File

@ -0,0 +1,82 @@
/*
* Copyright (C) 2006 Apple Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef WTF_GetPtr_h
#define WTF_GetPtr_h
#include <memory>
namespace WTF {
enum HashTableDeletedValueType { HashTableDeletedValue };
enum HashTableEmptyValueType { HashTableEmptyValue };
template <typename T> inline T* getPtr(T* p) { return p; }
template <typename T> struct IsSmartPtr {
static const bool value = false;
};
template <typename T, bool isSmartPtr>
struct GetPtrHelperBase;
template <typename T>
struct GetPtrHelperBase<T, false /* isSmartPtr */> {
typedef T* PtrType;
static T* getPtr(T& p) { return std::addressof(p); }
};
template <typename T>
struct GetPtrHelperBase<T, true /* isSmartPtr */> {
typedef typename T::PtrType PtrType;
static PtrType getPtr(const T& p) { return p.get(); }
};
template <typename T>
struct GetPtrHelper : GetPtrHelperBase<T, IsSmartPtr<T>::value> {
};
template <typename T>
inline typename GetPtrHelper<T>::PtrType getPtr(T& p)
{
return GetPtrHelper<T>::getPtr(p);
}
template <typename T>
inline typename GetPtrHelper<T>::PtrType getPtr(const T& p)
{
return GetPtrHelper<T>::getPtr(p);
}
// Explicit specialization for C++ standard library types.
template <typename T, typename Deleter> struct IsSmartPtr<std::unique_ptr<T, Deleter>> {
static const bool value = true;
};
template <typename T, typename Deleter>
struct GetPtrHelper<std::unique_ptr<T, Deleter>> {
typedef T* PtrType;
static T* getPtr(const std::unique_ptr<T, Deleter>& p) { return p.get(); }
};
} // namespace WTF
#endif // WTF_GetPtr_h

40
include/GlobalVersion.h Normal file
View File

@ -0,0 +1,40 @@
/*
* Copyright (C) 2017 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. ``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
* 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 <wtf/StdLibExtras.h>
namespace WTF {
typedef uint64_t GlobalVersion;
GlobalVersion newGlobalVersion();
} // namespace WTF
using WTF::GlobalVersion;
using WTF::newGlobalVersion;

223
include/GraphNodeWorklist.h Normal file
View File

@ -0,0 +1,223 @@
/*
* Copyright (C) 2015-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. ``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
* 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.
*/
#ifndef GraphNodeWorklist_h
#define GraphNodeWorklist_h
#include <wtf/HashSet.h>
namespace WTF {
template<typename Node, typename Set = HashSet<Node>>
class GraphNodeWorklist {
public:
GraphNodeWorklist() { }
~GraphNodeWorklist() { }
// Returns true if we didn't know about the node before.
bool push(Node node)
{
if (!m_seen.add(node))
return false;
m_stack.append(node);
return true;
}
template<typename Iterable>
void pushAll(const Iterable& iterable)
{
for (Node node : iterable)
push(node);
}
bool isEmpty() const { return m_stack.isEmpty(); }
bool notEmpty() const { return !m_stack.isEmpty(); }
Node pop()
{
if (m_stack.isEmpty())
return Node();
return m_stack.takeLast();
}
bool saw(Node node) { return m_seen.contains(node); }
const Set& seen() const { return m_seen; }
private:
Set m_seen;
Vector<Node, 16> m_stack;
};
template<typename Node, typename T>
struct GraphNodeWith {
GraphNodeWith()
: node()
, data()
{
}
GraphNodeWith(Node node, const T& data)
: node(node)
, data(data)
{
}
explicit operator bool() const { return !!node; }
Node node;
T data;
};
template<typename Node, typename T, typename Set = HashSet<Node>>
class ExtendedGraphNodeWorklist {
public:
ExtendedGraphNodeWorklist() { }
void forcePush(const GraphNodeWith<Node, T>& entry)
{
m_stack.append(entry);
}
void forcePush(Node node, const T& data)
{
forcePush(GraphNodeWith<Node, T>(node, data));
}
bool push(const GraphNodeWith<Node, T>& entry)
{
if (!m_seen.add(entry.node))
return false;
forcePush(entry);
return true;
}
bool push(Node node, const T& data)
{
return push(GraphNodeWith<Node, T>(node, data));
}
bool notEmpty() const { return !m_stack.isEmpty(); }
GraphNodeWith<Node, T> pop()
{
if (m_stack.isEmpty())
return GraphNodeWith<Node, T>();
return m_stack.takeLast();
}
private:
Set m_seen;
Vector<GraphNodeWith<Node, T>> m_stack;
};
enum class GraphVisitOrder : uint8_t {
Pre,
Post
};
template<typename Node>
struct GraphNodeWithOrder {
GraphNodeWithOrder()
: node()
, order(GraphVisitOrder::Pre)
{
}
GraphNodeWithOrder(Node node, GraphVisitOrder order)
: node(node)
, order(order)
{
}
explicit operator bool() const { return node; }
Node node;
GraphVisitOrder order;
};
template<typename Node, typename Set = HashSet<Node>>
class PostOrderGraphNodeWorklist {
public:
PostOrderGraphNodeWorklist()
{
}
~PostOrderGraphNodeWorklist()
{
}
bool pushPre(Node node)
{
return m_worklist.push(node, GraphVisitOrder::Pre);
}
void pushPost(Node node)
{
m_worklist.forcePush(node, GraphVisitOrder::Post);
}
bool push(Node node, GraphVisitOrder order = GraphVisitOrder::Pre)
{
switch (order) {
case GraphVisitOrder::Pre:
return pushPre(node);
case GraphVisitOrder::Post:
pushPost(node);
return true;
}
RELEASE_ASSERT_NOT_REACHED();
return false;
}
bool push(const GraphNodeWithOrder<Node>& data)
{
return push(data.node, data.order);
}
bool notEmpty() const { return m_worklist.notEmpty(); }
GraphNodeWithOrder<Node> pop()
{
GraphNodeWith<Node, GraphVisitOrder> result = m_worklist.pop();
return GraphNodeWithOrder<Node>(result.node, result.data);
}
private:
ExtendedGraphNodeWorklist<Node, GraphVisitOrder, Set> m_worklist;
};
} // namespace WTF
using WTF::GraphNodeWorklist;
using WTF::GraphNodeWith;
using WTF::ExtendedGraphNodeWorklist;
using WTF::GraphVisitOrder;
using WTF::GraphNodeWithOrder;
using WTF::PostOrderGraphNodeWorklist;
#endif // GraphNodeWorklist_h

128
include/GregorianDateTime.h Normal file
View File

@ -0,0 +1,128 @@
/*
* Copyright (C) 2012 Patrick Gansterer <paroga@paroga.com>
*
* 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 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 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.
*/
#ifndef WTF_GregorianDateTime_h
#define WTF_GregorianDateTime_h
#include <string.h>
#include <time.h>
#include <wtf/Noncopyable.h>
namespace WTF {
class GregorianDateTime {
WTF_MAKE_NONCOPYABLE(GregorianDateTime);
public:
GregorianDateTime()
: m_year(0)
, m_month(0)
, m_yearDay(0)
, m_monthDay(0)
, m_weekDay(0)
, m_hour(0)
, m_minute(0)
, m_second(0)
, m_utcOffset(0)
, m_isDST(0)
{
}
inline int year() const { return m_year; }
inline int month() const { return m_month; }
inline int yearDay() const { return m_yearDay; }
inline int monthDay() const { return m_monthDay; }
inline int weekDay() const { return m_weekDay; }
inline int hour() const { return m_hour; }
inline int minute() const { return m_minute; }
inline int second() const { return m_second; }
inline int utcOffset() const { return m_utcOffset; }
inline int isDST() const { return m_isDST; }
inline void setYear(int year) { m_year = year; }
inline void setMonth(int month) { m_month = month; }
inline void setYearDay(int yearDay) { m_yearDay = yearDay; }
inline void setMonthDay(int monthDay) { m_monthDay = monthDay; }
inline void setWeekDay(int weekDay) { m_weekDay = weekDay; }
inline void setHour(int hour) { m_hour = hour; }
inline void setMinute(int minute) { m_minute = minute; }
inline void setSecond(int second) { m_second = second; }
inline void setUtcOffset(int utcOffset) { m_utcOffset = utcOffset; }
inline void setIsDST(int isDST) { m_isDST = isDST; }
WTF_EXPORT_PRIVATE void setToCurrentLocalTime();
operator tm() const
{
tm ret;
memset(&ret, 0, sizeof(ret));
ret.tm_year = m_year - 1900;
ret.tm_mon = m_month;
ret.tm_yday = m_yearDay;
ret.tm_mday = m_monthDay;
ret.tm_wday = m_weekDay;
ret.tm_hour = m_hour;
ret.tm_min = m_minute;
ret.tm_sec = m_second;
ret.tm_isdst = m_isDST;
#if HAVE(TM_GMTOFF)
ret.tm_gmtoff = static_cast<long>(m_utcOffset);
#endif
return ret;
}
void copyFrom(const GregorianDateTime& other)
{
m_year = other.m_year;
m_month = other.m_month;
m_yearDay = other.m_yearDay;
m_monthDay = other.m_monthDay;
m_weekDay = other.m_weekDay;
m_hour = other.m_hour;
m_minute = other.m_minute;
m_second = other.m_second;
m_utcOffset = other.m_utcOffset;
m_isDST = other.m_isDST;
}
private:
int m_year;
int m_month;
int m_yearDay;
int m_monthDay;
int m_weekDay;
int m_hour;
int m_minute;
int m_second;
int m_utcOffset;
int m_isDST;
};
} // namespace WTF
using WTF::GregorianDateTime;
#endif // WTF_GregorianDateTime_h

325
include/HashCountedSet.h Normal file
View File

@ -0,0 +1,325 @@
/*
* Copyright (C) 2005, 2006, 2008, 2013, 2016 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef WTF_HashCountedSet_h
#define WTF_HashCountedSet_h
#include <initializer_list>
#include <wtf/Assertions.h>
#include <wtf/HashMap.h>
#include <wtf/Vector.h>
namespace WTF {
template<typename Value, typename HashFunctions = typename DefaultHash<Value>::Hash, typename Traits = HashTraits<Value>>
class HashCountedSet final {
WTF_MAKE_FAST_ALLOCATED;
private:
typedef HashMap<Value, unsigned, HashFunctions, Traits> ImplType;
public:
typedef Value ValueType;
typedef typename ImplType::iterator iterator;
typedef typename ImplType::const_iterator const_iterator;
typedef typename ImplType::AddResult AddResult;
HashCountedSet()
{
}
HashCountedSet(std::initializer_list<typename ImplType::KeyValuePairType> initializerList)
{
for (const auto& keyValuePair : initializerList)
add(keyValuePair.key, keyValuePair.value);
}
HashCountedSet(std::initializer_list<typename ImplType::KeyType> initializerList)
{
for (const auto& value : initializerList)
add(value);
}
void swap(HashCountedSet&);
unsigned size() const;
unsigned capacity() const;
bool isEmpty() const;
// Iterators iterate over pairs of values and counts.
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
iterator find(const ValueType&);
const_iterator find(const ValueType&) const;
bool contains(const ValueType&) const;
unsigned count(const ValueType&) const;
// Increments the count if an equal value is already present.
// The return value includes both an iterator to the value's location,
// and an isNewEntry bool that indicates whether it is a new or existing entry.
AddResult add(const ValueType&);
AddResult add(ValueType&&);
// Increments the count of a value by the passed amount.
AddResult add(const ValueType&, unsigned);
AddResult add(ValueType&&, unsigned);
// Decrements the count of the value, and removes it if count goes down to zero.
// Returns true if the value is removed.
bool remove(const ValueType&);
bool remove(iterator);
// Removes the value, regardless of its count.
// Returns true if a value was removed.
bool removeAll(iterator);
bool removeAll(const ValueType&);
// Clears the whole set.
void clear();
// Overloads for smart pointer keys that take the raw pointer type as the parameter.
template<typename V = ValueType> typename std::enable_if<IsSmartPtr<V>::value, iterator>::type find(typename GetPtrHelper<V>::PtrType);
template<typename V = ValueType> typename std::enable_if<IsSmartPtr<V>::value, const_iterator>::type find(typename GetPtrHelper<V>::PtrType) const;
template<typename V = ValueType> typename std::enable_if<IsSmartPtr<V>::value, bool>::type contains(typename GetPtrHelper<V>::PtrType) const;
template<typename V = ValueType> typename std::enable_if<IsSmartPtr<V>::value, unsigned>::type count(typename GetPtrHelper<V>::PtrType) const;
template<typename V = ValueType> typename std::enable_if<IsSmartPtr<V>::value, bool>::type remove(typename GetPtrHelper<V>::PtrType);
private:
ImplType m_impl;
};
template<typename Value, typename HashFunctions, typename Traits>
inline void HashCountedSet<Value, HashFunctions, Traits>::swap(HashCountedSet& other)
{
m_impl.swap(other.m_impl);
}
template<typename Value, typename HashFunctions, typename Traits>
inline unsigned HashCountedSet<Value, HashFunctions, Traits>::size() const
{
return m_impl.size();
}
template<typename Value, typename HashFunctions, typename Traits>
inline unsigned HashCountedSet<Value, HashFunctions, Traits>::capacity() const
{
return m_impl.capacity();
}
template<typename Value, typename HashFunctions, typename Traits>
inline bool HashCountedSet<Value, HashFunctions, Traits>::isEmpty() const
{
return size() == 0;
}
template<typename Value, typename HashFunctions, typename Traits>
inline typename HashCountedSet<Value, HashFunctions, Traits>::iterator HashCountedSet<Value, HashFunctions, Traits>::begin()
{
return m_impl.begin();
}
template<typename Value, typename HashFunctions, typename Traits>
inline typename HashCountedSet<Value, HashFunctions, Traits>::iterator HashCountedSet<Value, HashFunctions, Traits>::end()
{
return m_impl.end();
}
template<typename Value, typename HashFunctions, typename Traits>
inline typename HashCountedSet<Value, HashFunctions, Traits>::const_iterator HashCountedSet<Value, HashFunctions, Traits>::begin() const
{
return m_impl.begin();
}
template<typename Value, typename HashFunctions, typename Traits>
inline typename HashCountedSet<Value, HashFunctions, Traits>::const_iterator HashCountedSet<Value, HashFunctions, Traits>::end() const
{
return m_impl.end();
}
template<typename Value, typename HashFunctions, typename Traits>
inline typename HashCountedSet<Value, HashFunctions, Traits>::iterator HashCountedSet<Value, HashFunctions, Traits>::find(const ValueType& value)
{
return m_impl.find(value);
}
template<typename Value, typename HashFunctions, typename Traits>
inline typename HashCountedSet<Value, HashFunctions, Traits>::const_iterator HashCountedSet<Value, HashFunctions, Traits>::find(const ValueType& value) const
{
return m_impl.find(value);
}
template<typename Value, typename HashFunctions, typename Traits>
inline bool HashCountedSet<Value, HashFunctions, Traits>::contains(const ValueType& value) const
{
return m_impl.contains(value);
}
template<typename Value, typename HashFunctions, typename Traits>
inline unsigned HashCountedSet<Value, HashFunctions, Traits>::count(const ValueType& value) const
{
return m_impl.get(value);
}
template<typename Value, typename HashFunctions, typename Traits>
inline typename HashCountedSet<Value, HashFunctions, Traits>::AddResult HashCountedSet<Value, HashFunctions, Traits>::add(const ValueType &value)
{
AddResult result = m_impl.add(value, 0);
++result.iterator->value;
return result;
}
template<typename Value, typename HashFunctions, typename Traits>
inline typename HashCountedSet<Value, HashFunctions, Traits>::AddResult HashCountedSet<Value, HashFunctions, Traits>::add(ValueType&& value)
{
AddResult result = m_impl.add(std::forward<Value>(value), 0);
++result.iterator->value;
return result;
}
template<typename Value, typename HashFunctions, typename Traits>
inline typename HashCountedSet<Value, HashFunctions, Traits>::AddResult HashCountedSet<Value, HashFunctions, Traits>::add(const ValueType& value, unsigned count)
{
AddResult result = m_impl.add(value, 0);
result.iterator->value += count;
return result;
}
template<typename Value, typename HashFunctions, typename Traits>
inline typename HashCountedSet<Value, HashFunctions, Traits>::AddResult HashCountedSet<Value, HashFunctions, Traits>::add(ValueType&& value, unsigned count)
{
AddResult result = m_impl.add(std::forward<Value>(value), 0);
result.iterator->value += count;
return result;
}
template<typename Value, typename HashFunctions, typename Traits>
inline bool HashCountedSet<Value, HashFunctions, Traits>::remove(const ValueType& value)
{
return remove(find(value));
}
template<typename Value, typename HashFunctions, typename Traits>
inline bool HashCountedSet<Value, HashFunctions, Traits>::remove(iterator it)
{
if (it == end())
return false;
unsigned oldVal = it->value;
ASSERT(oldVal);
unsigned newVal = oldVal - 1;
if (newVal) {
it->value = newVal;
return false;
}
m_impl.remove(it);
return true;
}
template<typename Value, typename HashFunctions, typename Traits>
inline bool HashCountedSet<Value, HashFunctions, Traits>::removeAll(const ValueType& value)
{
return removeAll(find(value));
}
template<typename Value, typename HashFunctions, typename Traits>
inline bool HashCountedSet<Value, HashFunctions, Traits>::removeAll(iterator it)
{
if (it == end())
return false;
m_impl.remove(it);
return true;
}
template<typename Value, typename HashFunctions, typename Traits>
inline void HashCountedSet<Value, HashFunctions, Traits>::clear()
{
m_impl.clear();
}
template<typename Value, typename HashFunctions, typename Traits, typename VectorType>
inline void copyToVector(const HashCountedSet<Value, HashFunctions, Traits>& collection, VectorType& vector)
{
typedef typename HashCountedSet<Value, HashFunctions, Traits>::const_iterator iterator;
vector.resize(collection.size());
iterator it = collection.begin();
iterator end = collection.end();
for (unsigned i = 0; it != end; ++it, ++i)
vector[i] = *it;
}
template<typename Value, typename HashFunctions, typename Traits>
inline void copyToVector(const HashCountedSet<Value, HashFunctions, Traits>& collection, Vector<Value>& vector)
{
typedef typename HashCountedSet<Value, HashFunctions, Traits>::const_iterator iterator;
vector.resize(collection.size());
iterator it = collection.begin();
iterator end = collection.end();
for (unsigned i = 0; it != end; ++it, ++i)
vector[i] = (*it).key;
}
template<typename Value, typename HashFunctions, typename Traits>
template<typename V>
inline auto HashCountedSet<Value, HashFunctions, Traits>::find(typename GetPtrHelper<V>::PtrType value) -> typename std::enable_if<IsSmartPtr<V>::value, iterator>::type
{
return m_impl.find(value);
}
template<typename Value, typename HashFunctions, typename Traits>
template<typename V>
inline auto HashCountedSet<Value, HashFunctions, Traits>::find(typename GetPtrHelper<V>::PtrType value) const -> typename std::enable_if<IsSmartPtr<V>::value, const_iterator>::type
{
return m_impl.find(value);
}
template<typename Value, typename HashFunctions, typename Traits>
template<typename V>
inline auto HashCountedSet<Value, HashFunctions, Traits>::contains(typename GetPtrHelper<V>::PtrType value) const -> typename std::enable_if<IsSmartPtr<V>::value, bool>::type
{
return m_impl.contains(value);
}
template<typename Value, typename HashFunctions, typename Traits>
template<typename V>
inline auto HashCountedSet<Value, HashFunctions, Traits>::count(typename GetPtrHelper<V>::PtrType value) const -> typename std::enable_if<IsSmartPtr<V>::value, unsigned>::type
{
return m_impl.get(value);
}
template<typename Value, typename HashFunctions, typename Traits>
template<typename V>
inline auto HashCountedSet<Value, HashFunctions, Traits>::remove(typename GetPtrHelper<V>::PtrType value) -> typename std::enable_if<IsSmartPtr<V>::value, bool>::type
{
return remove(find(value));
}
} // namespace WTF
using WTF::HashCountedSet;
#endif /* WTF_HashCountedSet_h */

274
include/HashFunctions.h Normal file
View File

@ -0,0 +1,274 @@
/*
* Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef WTF_HashFunctions_h
#define WTF_HashFunctions_h
#include <stdint.h>
#include <wtf/GetPtr.h>
#include <wtf/RefPtr.h>
namespace WTF {
template<size_t size> struct IntTypes;
template<> struct IntTypes<1> { typedef int8_t SignedType; typedef uint8_t UnsignedType; };
template<> struct IntTypes<2> { typedef int16_t SignedType; typedef uint16_t UnsignedType; };
template<> struct IntTypes<4> { typedef int32_t SignedType; typedef uint32_t UnsignedType; };
template<> struct IntTypes<8> { typedef int64_t SignedType; typedef uint64_t UnsignedType; };
// integer hash function
// Thomas Wang's 32 Bit Mix Function: http://www.cris.com/~Ttwang/tech/inthash.htm
inline unsigned intHash(uint8_t key8)
{
unsigned key = key8;
key += ~(key << 15);
key ^= (key >> 10);
key += (key << 3);
key ^= (key >> 6);
key += ~(key << 11);
key ^= (key >> 16);
return key;
}
// Thomas Wang's 32 Bit Mix Function: http://www.cris.com/~Ttwang/tech/inthash.htm
inline unsigned intHash(uint16_t key16)
{
unsigned key = key16;
key += ~(key << 15);
key ^= (key >> 10);
key += (key << 3);
key ^= (key >> 6);
key += ~(key << 11);
key ^= (key >> 16);
return key;
}
// Thomas Wang's 32 Bit Mix Function: http://www.cris.com/~Ttwang/tech/inthash.htm
inline unsigned intHash(uint32_t key)
{
key += ~(key << 15);
key ^= (key >> 10);
key += (key << 3);
key ^= (key >> 6);
key += ~(key << 11);
key ^= (key >> 16);
return key;
}
// Thomas Wang's 64 bit Mix Function: http://www.cris.com/~Ttwang/tech/inthash.htm
inline unsigned intHash(uint64_t key)
{
key += ~(key << 32);
key ^= (key >> 22);
key += ~(key << 13);
key ^= (key >> 8);
key += (key << 3);
key ^= (key >> 15);
key += ~(key << 27);
key ^= (key >> 31);
return static_cast<unsigned>(key);
}
// Compound integer hash method: http://opendatastructures.org/versions/edition-0.1d/ods-java/node33.html#SECTION00832000000000000000
inline unsigned pairIntHash(unsigned key1, unsigned key2)
{
unsigned shortRandom1 = 277951225; // A random 32-bit value.
unsigned shortRandom2 = 95187966; // A random 32-bit value.
uint64_t longRandom = 19248658165952622LL; // A random 64-bit value.
uint64_t product = longRandom * (shortRandom1 * key1 + shortRandom2 * key2);
unsigned highBits = static_cast<unsigned>(product >> (sizeof(uint64_t) - sizeof(unsigned)));
return highBits;
}
template<typename T> struct IntHash {
static unsigned hash(T key) { return intHash(static_cast<typename IntTypes<sizeof(T)>::UnsignedType>(key)); }
static bool equal(T a, T b) { return a == b; }
static const bool safeToCompareToEmptyOrDeleted = true;
};
template<typename T> struct FloatHash {
typedef typename IntTypes<sizeof(T)>::UnsignedType Bits;
static unsigned hash(T key)
{
return intHash(bitwise_cast<Bits>(key));
}
static bool equal(T a, T b)
{
return bitwise_cast<Bits>(a) == bitwise_cast<Bits>(b);
}
static const bool safeToCompareToEmptyOrDeleted = true;
};
// pointer identity hash function
template<typename T, bool isSmartPointer>
struct PtrHashBase;
template <typename T>
struct PtrHashBase<T, false /* isSmartPtr */> {
typedef T PtrType;
static unsigned hash(PtrType key) { return IntHash<uintptr_t>::hash(reinterpret_cast<uintptr_t>(key)); }
static bool equal(PtrType a, PtrType b) { return a == b; }
static const bool safeToCompareToEmptyOrDeleted = true;
};
template <typename T>
struct PtrHashBase<T, true /* isSmartPtr */> {
typedef typename GetPtrHelper<T>::PtrType PtrType;
static unsigned hash(PtrType key) { return IntHash<uintptr_t>::hash(reinterpret_cast<uintptr_t>(key)); }
static bool equal(PtrType a, PtrType b) { return a == b; }
static const bool safeToCompareToEmptyOrDeleted = true;
static unsigned hash(const T& key) { return hash(getPtr(key)); }
static bool equal(const T& a, const T& b) { return getPtr(a) == getPtr(b); }
static bool equal(PtrType a, const T& b) { return a == getPtr(b); }
static bool equal(const T& a, PtrType b) { return getPtr(a) == b; }
};
template<typename T> struct PtrHash : PtrHashBase<T, IsSmartPtr<T>::value> {
};
template<typename P> struct PtrHash<Ref<P>> : PtrHashBase<Ref<P>, IsSmartPtr<Ref<P>>::value> {
static const bool safeToCompareToEmptyOrDeleted = false;
};
// default hash function for each type
template<typename T> struct DefaultHash;
template<typename T, typename U> struct PairHash {
static unsigned hash(const std::pair<T, U>& p)
{
return pairIntHash(DefaultHash<T>::Hash::hash(p.first), DefaultHash<U>::Hash::hash(p.second));
}
static bool equal(const std::pair<T, U>& a, const std::pair<T, U>& b)
{
return DefaultHash<T>::Hash::equal(a.first, b.first) && DefaultHash<U>::Hash::equal(a.second, b.second);
}
static const bool safeToCompareToEmptyOrDeleted = DefaultHash<T>::Hash::safeToCompareToEmptyOrDeleted && DefaultHash<U>::Hash::safeToCompareToEmptyOrDeleted;
};
template<typename T, typename U> struct IntPairHash {
static unsigned hash(const std::pair<T, U>& p) { return pairIntHash(p.first, p.second); }
static bool equal(const std::pair<T, U>& a, const std::pair<T, U>& b) { return PairHash<T, T>::equal(a, b); }
static const bool safeToCompareToEmptyOrDeleted = PairHash<T, U>::safeToCompareToEmptyOrDeleted;
};
template<typename... Types>
struct TupleHash {
template<size_t I = 0>
static typename std::enable_if<I < sizeof...(Types) - 1, unsigned>::type hash(const std::tuple<Types...>& t)
{
using IthTupleElementType = typename std::tuple_element<I, typename std::tuple<Types...>>::type;
return pairIntHash(DefaultHash<IthTupleElementType>::Hash::hash(std::get<I>(t)), hash<I + 1>(t));
}
template<size_t I = 0>
static typename std::enable_if<I == sizeof...(Types) - 1, unsigned>::type hash(const std::tuple<Types...>& t)
{
using IthTupleElementType = typename std::tuple_element<I, typename std::tuple<Types...>>::type;
return DefaultHash<IthTupleElementType>::Hash::hash(std::get<I>(t));
}
template<size_t I = 0>
static typename std::enable_if<I < sizeof...(Types) - 1, bool>::type equal(const std::tuple<Types...>& a, const std::tuple<Types...>& b)
{
using IthTupleElementType = typename std::tuple_element<I, typename std::tuple<Types...>>::type;
return DefaultHash<IthTupleElementType>::Hash::equal(std::get<I>(a), std::get<I>(b)) && equal<I + 1>(a, b);
}
template<size_t I = 0>
static typename std::enable_if<I == sizeof...(Types) - 1, bool>::type equal(const std::tuple<Types...>& a, const std::tuple<Types...>& b)
{
using IthTupleElementType = typename std::tuple_element<I, typename std::tuple<Types...>>::type;
return DefaultHash<IthTupleElementType>::Hash::equal(std::get<I>(a), std::get<I>(b));
}
// We should use safeToCompareToEmptyOrDeleted = DefaultHash<Types>::Hash::safeToCompareToEmptyOrDeleted &&... whenever
// we switch to C++17. We can't do anything better here right now because GCC can't do C++.
template<typename BoolType>
static constexpr bool allTrue(BoolType value) { return value; }
template<typename BoolType, typename... BoolTypes>
static constexpr bool allTrue(BoolType value, BoolTypes... values) { return value && allTrue(values...); }
static const bool safeToCompareToEmptyOrDeleted = allTrue(DefaultHash<Types>::Hash::safeToCompareToEmptyOrDeleted...);
};
// make IntHash the default hash function for many integer types
template<> struct DefaultHash<bool> { typedef IntHash<uint8_t> Hash; };
template<> struct DefaultHash<short> { typedef IntHash<unsigned> Hash; };
template<> struct DefaultHash<unsigned short> { typedef IntHash<unsigned> Hash; };
template<> struct DefaultHash<int> { typedef IntHash<unsigned> Hash; };
template<> struct DefaultHash<unsigned> { typedef IntHash<unsigned> Hash; };
template<> struct DefaultHash<long> { typedef IntHash<unsigned long> Hash; };
template<> struct DefaultHash<unsigned long> { typedef IntHash<unsigned long> Hash; };
template<> struct DefaultHash<long long> { typedef IntHash<unsigned long long> Hash; };
template<> struct DefaultHash<unsigned long long> { typedef IntHash<unsigned long long> Hash; };
#if defined(_NATIVE_WCHAR_T_DEFINED)
template<> struct DefaultHash<wchar_t> { typedef IntHash<wchar_t> Hash; };
#endif
template<> struct DefaultHash<float> { typedef FloatHash<float> Hash; };
template<> struct DefaultHash<double> { typedef FloatHash<double> Hash; };
// make PtrHash the default hash function for pointer types that don't specialize
template<typename P> struct DefaultHash<P*> { typedef PtrHash<P*> Hash; };
template<typename P> struct DefaultHash<RefPtr<P>> { typedef PtrHash<RefPtr<P>> Hash; };
template<typename P> struct DefaultHash<Ref<P>> { typedef PtrHash<Ref<P>> Hash; };
template<typename P, typename Deleter> struct DefaultHash<std::unique_ptr<P, Deleter>> { typedef PtrHash<std::unique_ptr<P, Deleter>> Hash; };
// make IntPairHash the default hash function for pairs of (at most) 32-bit integers.
template<> struct DefaultHash<std::pair<short, short>> { typedef IntPairHash<short, short> Hash; };
template<> struct DefaultHash<std::pair<short, unsigned short>> { typedef IntPairHash<short, unsigned short> Hash; };
template<> struct DefaultHash<std::pair<short, int>> { typedef IntPairHash<short, int> Hash; };
template<> struct DefaultHash<std::pair<short, unsigned>> { typedef IntPairHash<short, unsigned> Hash; };
template<> struct DefaultHash<std::pair<unsigned short, short>> { typedef IntPairHash<unsigned short, short> Hash; };
template<> struct DefaultHash<std::pair<unsigned short, unsigned short>> { typedef IntPairHash<unsigned short, unsigned short> Hash; };
template<> struct DefaultHash<std::pair<unsigned short, int>> { typedef IntPairHash<unsigned short, int> Hash; };
template<> struct DefaultHash<std::pair<unsigned short, unsigned>> { typedef IntPairHash<unsigned short, unsigned> Hash; };
template<> struct DefaultHash<std::pair<int, short>> { typedef IntPairHash<int, short> Hash; };
template<> struct DefaultHash<std::pair<int, unsigned short>> { typedef IntPairHash<int, unsigned short> Hash; };
template<> struct DefaultHash<std::pair<int, int>> { typedef IntPairHash<int, int> Hash; };
template<> struct DefaultHash<std::pair<int, unsigned>> { typedef IntPairHash<unsigned, unsigned> Hash; };
template<> struct DefaultHash<std::pair<unsigned, short>> { typedef IntPairHash<unsigned, short> Hash; };
template<> struct DefaultHash<std::pair<unsigned, unsigned short>> { typedef IntPairHash<unsigned, unsigned short> Hash; };
template<> struct DefaultHash<std::pair<unsigned, int>> { typedef IntPairHash<unsigned, int> Hash; };
template<> struct DefaultHash<std::pair<unsigned, unsigned>> { typedef IntPairHash<unsigned, unsigned> Hash; };
// make PairHash the default hash function for pairs of arbitrary values.
template<typename T, typename U> struct DefaultHash<std::pair<T, U>> { typedef PairHash<T, U> Hash; };
template<typename... Types> struct DefaultHash<std::tuple<Types...>> { typedef TupleHash<Types...> Hash; };
} // namespace WTF
using WTF::DefaultHash;
using WTF::IntHash;
using WTF::PtrHash;
#endif // WTF_HashFunctions_h

216
include/HashIterators.h Normal file
View File

@ -0,0 +1,216 @@
/*
* Copyright (C) 2007 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. ``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
* 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 <iterator>
namespace WTF {
template<typename HashTableType, typename KeyType, typename MappedType> struct HashTableConstKeysIterator;
template<typename HashTableType, typename KeyType, typename MappedType> struct HashTableConstValuesIterator;
template<typename HashTableType, typename KeyType, typename MappedType> struct HashTableKeysIterator;
template<typename HashTableType, typename KeyType, typename MappedType> struct HashTableValuesIterator;
template<typename HashTableType, typename KeyType, typename MappedType> struct HashTableConstIteratorAdapter<HashTableType, KeyValuePair<KeyType, MappedType>> : public std::iterator<std::forward_iterator_tag, KeyValuePair<KeyType, MappedType>, std::ptrdiff_t, const KeyValuePair<KeyType, MappedType>*, const KeyValuePair<KeyType, MappedType>&> {
private:
typedef KeyValuePair<KeyType, MappedType> ValueType;
public:
typedef HashTableConstKeysIterator<HashTableType, KeyType, MappedType> Keys;
typedef HashTableConstValuesIterator<HashTableType, KeyType, MappedType> Values;
HashTableConstIteratorAdapter() {}
HashTableConstIteratorAdapter(const typename HashTableType::const_iterator& impl) : m_impl(impl) {}
const ValueType* get() const { return (const ValueType*)m_impl.get(); }
const ValueType& operator*() const { return *get(); }
const ValueType* operator->() const { return get(); }
HashTableConstIteratorAdapter& operator++() { ++m_impl; return *this; }
// postfix ++ intentionally omitted
Keys keys() { return Keys(*this); }
Values values() { return Values(*this); }
typename HashTableType::const_iterator m_impl;
};
template<typename HashTableType, typename KeyType, typename MappedType> struct HashTableIteratorAdapter<HashTableType, KeyValuePair<KeyType, MappedType>> : public std::iterator<std::forward_iterator_tag, KeyValuePair<KeyType, MappedType>, std::ptrdiff_t, KeyValuePair<KeyType, MappedType>*, KeyValuePair<KeyType, MappedType>&> {
private:
typedef KeyValuePair<KeyType, MappedType> ValueType;
public:
typedef HashTableKeysIterator<HashTableType, KeyType, MappedType> Keys;
typedef HashTableValuesIterator<HashTableType, KeyType, MappedType> Values;
HashTableIteratorAdapter() {}
HashTableIteratorAdapter(const typename HashTableType::iterator& impl) : m_impl(impl) {}
ValueType* get() const { return (ValueType*)m_impl.get(); }
ValueType& operator*() const { return *get(); }
ValueType* operator->() const { return get(); }
HashTableIteratorAdapter& operator++() { ++m_impl; return *this; }
// postfix ++ intentionally omitted
operator HashTableConstIteratorAdapter<HashTableType, ValueType>() {
typename HashTableType::const_iterator i = m_impl;
return i;
}
Keys keys() { return Keys(*this); }
Values values() { return Values(*this); }
typename HashTableType::iterator m_impl;
};
template<typename HashTableType, typename KeyType, typename MappedType> struct HashTableConstKeysIterator : public std::iterator<std::forward_iterator_tag, KeyType, std::ptrdiff_t, const KeyType*, const KeyType&> {
private:
typedef HashTableConstIteratorAdapter<HashTableType, KeyValuePair<KeyType, MappedType>> ConstIterator;
public:
HashTableConstKeysIterator(const ConstIterator& impl) : m_impl(impl) {}
const KeyType* get() const { return &(m_impl.get()->key); }
const KeyType& operator*() const { return *get(); }
const KeyType* operator->() const { return get(); }
HashTableConstKeysIterator& operator++() { ++m_impl; return *this; }
// postfix ++ intentionally omitted
ConstIterator m_impl;
};
template<typename HashTableType, typename KeyType, typename MappedType> struct HashTableConstValuesIterator : public std::iterator<std::forward_iterator_tag, MappedType, std::ptrdiff_t, const MappedType*, const MappedType&> {
private:
typedef HashTableConstIteratorAdapter<HashTableType, KeyValuePair<KeyType, MappedType>> ConstIterator;
public:
HashTableConstValuesIterator(const ConstIterator& impl) : m_impl(impl) {}
const MappedType* get() const { return &(m_impl.get()->value); }
const MappedType& operator*() const { return *get(); }
const MappedType* operator->() const { return get(); }
HashTableConstValuesIterator& operator++() { ++m_impl; return *this; }
// postfix ++ intentionally omitted
ConstIterator m_impl;
};
template<typename HashTableType, typename KeyType, typename MappedType> struct HashTableKeysIterator : public std::iterator<std::forward_iterator_tag, KeyType, std::ptrdiff_t, KeyType*, KeyType&> {
private:
typedef HashTableIteratorAdapter<HashTableType, KeyValuePair<KeyType, MappedType>> Iterator;
typedef HashTableConstIteratorAdapter<HashTableType, KeyValuePair<KeyType, MappedType>> ConstIterator;
public:
HashTableKeysIterator(const Iterator& impl) : m_impl(impl) {}
KeyType* get() const { return &(m_impl.get()->key); }
KeyType& operator*() const { return *get(); }
KeyType* operator->() const { return get(); }
HashTableKeysIterator& operator++() { ++m_impl; return *this; }
// postfix ++ intentionally omitted
operator HashTableConstKeysIterator<HashTableType, KeyType, MappedType>() {
ConstIterator i = m_impl;
return i;
}
Iterator m_impl;
};
template<typename HashTableType, typename KeyType, typename MappedType> struct HashTableValuesIterator : public std::iterator<std::forward_iterator_tag, MappedType, std::ptrdiff_t, MappedType*, MappedType&> {
private:
typedef HashTableIteratorAdapter<HashTableType, KeyValuePair<KeyType, MappedType>> Iterator;
typedef HashTableConstIteratorAdapter<HashTableType, KeyValuePair<KeyType, MappedType>> ConstIterator;
public:
HashTableValuesIterator(const Iterator& impl) : m_impl(impl) {}
MappedType* get() const { return std::addressof(m_impl.get()->value); }
MappedType& operator*() const { return *get(); }
MappedType* operator->() const { return get(); }
HashTableValuesIterator& operator++() { ++m_impl; return *this; }
// postfix ++ intentionally omitted
operator HashTableConstValuesIterator<HashTableType, KeyType, MappedType>() {
ConstIterator i = m_impl;
return i;
}
Iterator m_impl;
};
template<typename T, typename U, typename V>
inline bool operator==(const HashTableConstKeysIterator<T, U, V>& a, const HashTableConstKeysIterator<T, U, V>& b)
{
return a.m_impl == b.m_impl;
}
template<typename T, typename U, typename V>
inline bool operator!=(const HashTableConstKeysIterator<T, U, V>& a, const HashTableConstKeysIterator<T, U, V>& b)
{
return a.m_impl != b.m_impl;
}
template<typename T, typename U, typename V>
inline bool operator==(const HashTableConstValuesIterator<T, U, V>& a, const HashTableConstValuesIterator<T, U, V>& b)
{
return a.m_impl == b.m_impl;
}
template<typename T, typename U, typename V>
inline bool operator!=(const HashTableConstValuesIterator<T, U, V>& a, const HashTableConstValuesIterator<T, U, V>& b)
{
return a.m_impl != b.m_impl;
}
template<typename T, typename U, typename V>
inline bool operator==(const HashTableKeysIterator<T, U, V>& a, const HashTableKeysIterator<T, U, V>& b)
{
return a.m_impl == b.m_impl;
}
template<typename T, typename U, typename V>
inline bool operator!=(const HashTableKeysIterator<T, U, V>& a, const HashTableKeysIterator<T, U, V>& b)
{
return a.m_impl != b.m_impl;
}
template<typename T, typename U, typename V>
inline bool operator==(const HashTableValuesIterator<T, U, V>& a, const HashTableValuesIterator<T, U, V>& b)
{
return a.m_impl == b.m_impl;
}
template<typename T, typename U, typename V>
inline bool operator!=(const HashTableValuesIterator<T, U, V>& a, const HashTableValuesIterator<T, U, V>& b)
{
return a.m_impl != b.m_impl;
}
} // namespace WTF

606
include/HashMap.h Normal file
View File

@ -0,0 +1,606 @@
/*
* Copyright (C) 2005-2008, 2011, 2013, 2017 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef WTF_HashMap_h
#define WTF_HashMap_h
#include <initializer_list>
#include <wtf/HashTable.h>
#include <wtf/IteratorRange.h>
namespace WTF {
template<typename T> struct KeyValuePairKeyExtractor {
static const typename T::KeyType& extract(const T& p) { return p.key; }
};
template<typename KeyArg, typename MappedArg, typename HashArg = typename DefaultHash<KeyArg>::Hash,
typename KeyTraitsArg = HashTraits<KeyArg>, typename MappedTraitsArg = HashTraits<MappedArg>>
class HashMap final {
WTF_MAKE_FAST_ALLOCATED;
private:
typedef KeyTraitsArg KeyTraits;
typedef MappedTraitsArg MappedTraits;
struct KeyValuePairTraits : KeyValuePairHashTraits<KeyTraits, MappedTraits> {
static const bool hasIsEmptyValueFunction = true;
static bool isEmptyValue(const typename KeyValuePairHashTraits<KeyTraits, MappedTraits>::TraitType& value)
{
return isHashTraitsEmptyValue<KeyTraits>(value.key);
}
};
public:
typedef typename KeyTraits::TraitType KeyType;
typedef typename MappedTraits::TraitType MappedType;
typedef typename KeyValuePairTraits::TraitType KeyValuePairType;
private:
typedef typename MappedTraits::PeekType MappedPeekType;
typedef typename MappedTraits::TakeType MappedTakeType;
typedef HashArg HashFunctions;
typedef HashTable<KeyType, KeyValuePairType, KeyValuePairKeyExtractor<KeyValuePairType>,
HashFunctions, KeyValuePairTraits, KeyTraits> HashTableType;
class HashMapKeysProxy;
class HashMapValuesProxy;
using IdentityTranslatorType = typename HashTableType::IdentityTranslatorType;
public:
typedef HashTableIteratorAdapter<HashTableType, KeyValuePairType> iterator;
typedef HashTableConstIteratorAdapter<HashTableType, KeyValuePairType> const_iterator;
typedef typename HashTableType::AddResult AddResult;
public:
HashMap()
{
}
HashMap(std::initializer_list<KeyValuePairType> initializerList)
{
for (const auto& keyValuePair : initializerList)
add(keyValuePair.key, keyValuePair.value);
}
void swap(HashMap&);
unsigned size() const;
unsigned capacity() const;
bool isEmpty() const;
// iterators iterate over pairs of keys and values
iterator begin();
iterator end();
const_iterator begin() const;
const_iterator end() const;
IteratorRange<typename iterator::Keys> keys() { return makeIteratorRange(begin().keys(), end().keys()); }
const IteratorRange<typename const_iterator::Keys> keys() const { return makeIteratorRange(begin().keys(), end().keys()); }
IteratorRange<typename iterator::Values> values() { return makeIteratorRange(begin().values(), end().values()); }
const IteratorRange<typename const_iterator::Values> values() const { return makeIteratorRange(begin().values(), end().values()); }
iterator find(const KeyType&);
const_iterator find(const KeyType&) const;
bool contains(const KeyType&) const;
MappedPeekType get(const KeyType&) const;
// Same as get(), but aggressively inlined.
MappedPeekType fastGet(const KeyType&) const;
// Replaces the value but not the key if the key is already present.
// Return value includes both an iterator to the key location,
// and an isNewEntry boolean that's true if a new entry was added.
template<typename V> AddResult set(const KeyType&, V&&);
template<typename V> AddResult set(KeyType&&, V&&);
// Does nothing if the key is already present.
// Return value includes both an iterator to the key location,
// and an isNewEntry boolean that's true if a new entry was added.
template<typename V> AddResult add(const KeyType&, V&&);
template<typename V> AddResult add(KeyType&&, V&&);
// Same as add(), but aggressively inlined.
template<typename V> AddResult fastAdd(const KeyType&, V&&);
template<typename V> AddResult fastAdd(KeyType&&, V&&);
template<typename Functor> AddResult ensure(const KeyType&, Functor&&);
template<typename Functor> AddResult ensure(KeyType&&, Functor&&);
bool remove(const KeyType&);
bool remove(iterator);
template<typename Functor>
void removeIf(Functor&&);
void clear();
MappedTakeType take(const KeyType&); // efficient combination of get with remove
// An alternate version of find() that finds the object by hashing and comparing
// with some other type, to avoid the cost of type conversion. HashTranslator
// must have the following function members:
// static unsigned hash(const T&);
// static bool equal(const ValueType&, const T&);
template<typename HashTranslator, typename T> iterator find(const T&);
template<typename HashTranslator, typename T> const_iterator find(const T&) const;
template<typename HashTranslator, typename T> bool contains(const T&) const;
template<typename HashTranslator, typename T> MappedPeekType get(const T&) const;
// An alternate version of add() that finds the object by hashing and comparing
// with some other type, to avoid the cost of type conversion if the object is already
// in the table. HashTranslator must have the following function members:
// static unsigned hash(const T&);
// static bool equal(const ValueType&, const T&);
// static translate(ValueType&, const T&, unsigned hashCode);
template<typename HashTranslator, typename K, typename V> AddResult add(K&&, V&&);
// Overloads for smart pointer keys that take the raw pointer type as the parameter.
template<typename K = KeyType> typename std::enable_if<IsSmartPtr<K>::value, iterator>::type find(typename GetPtrHelper<K>::PtrType);
template<typename K = KeyType> typename std::enable_if<IsSmartPtr<K>::value, const_iterator>::type find(typename GetPtrHelper<K>::PtrType) const;
template<typename K = KeyType> typename std::enable_if<IsSmartPtr<K>::value, bool>::type contains(typename GetPtrHelper<K>::PtrType) const;
template<typename K = KeyType> typename std::enable_if<IsSmartPtr<K>::value, MappedPeekType>::type inlineGet(typename GetPtrHelper<K>::PtrType) const;
template<typename K = KeyType> typename std::enable_if<IsSmartPtr<K>::value, MappedPeekType>::type get(typename GetPtrHelper<K>::PtrType) const;
template<typename K = KeyType> typename std::enable_if<IsSmartPtr<K>::value, bool>::type remove(typename GetPtrHelper<K>::PtrType);
template<typename K = KeyType> typename std::enable_if<IsSmartPtr<K>::value, MappedTakeType>::type take(typename GetPtrHelper<K>::PtrType);
void checkConsistency() const;
static bool isValidKey(const KeyType&);
private:
template<typename K, typename V>
AddResult inlineSet(K&&, V&&);
template<typename K, typename V>
AddResult inlineAdd(K&&, V&&);
template<typename K, typename F>
AddResult inlineEnsure(K&&, F&&);
HashTableType m_impl;
};
template<typename ValueTraits, typename HashFunctions>
struct HashMapTranslator {
template<typename T> static unsigned hash(const T& key) { return HashFunctions::hash(key); }
template<typename T, typename U> static bool equal(const T& a, const U& b) { return HashFunctions::equal(a, b); }
template<typename T, typename U, typename V> static void translate(T& location, U&& key, V&& mapped)
{
ValueTraits::KeyTraits::assignToEmpty(location.key, std::forward<U>(key));
ValueTraits::ValueTraits::assignToEmpty(location.value, std::forward<V>(mapped));
}
};
template<typename ValueTraits, typename HashFunctions>
struct HashMapEnsureTranslator {
template<typename T> static unsigned hash(const T& key) { return HashFunctions::hash(key); }
template<typename T, typename U> static bool equal(const T& a, const U& b) { return HashFunctions::equal(a, b); }
template<typename T, typename U, typename Functor> static void translate(T& location, U&& key, Functor&& functor)
{
ValueTraits::KeyTraits::assignToEmpty(location.key, std::forward<U>(key));
ValueTraits::ValueTraits::assignToEmpty(location.value, functor());
}
};
template<typename ValueTraits, typename Translator>
struct HashMapTranslatorAdapter {
template<typename T> static unsigned hash(const T& key) { return Translator::hash(key); }
template<typename T, typename U> static bool equal(const T& a, const U& b) { return Translator::equal(a, b); }
template<typename T, typename U, typename V> static void translate(T& location, U&& key, V&& mapped, unsigned hashCode)
{
Translator::translate(location.key, key, hashCode);
location.value = std::forward<V>(mapped);
}
};
template<typename T, typename U, typename V, typename W, typename X>
inline void HashMap<T, U, V, W, X>::swap(HashMap& other)
{
m_impl.swap(other.m_impl);
}
template<typename T, typename U, typename V, typename W, typename X>
inline unsigned HashMap<T, U, V, W, X>::size() const
{
return m_impl.size();
}
template<typename T, typename U, typename V, typename W, typename X>
inline unsigned HashMap<T, U, V, W, X>::capacity() const
{
return m_impl.capacity();
}
template<typename T, typename U, typename V, typename W, typename X>
inline bool HashMap<T, U, V, W, X>::isEmpty() const
{
return m_impl.isEmpty();
}
template<typename T, typename U, typename V, typename W, typename X>
inline auto HashMap<T, U, V, W, X>::begin() -> iterator
{
return m_impl.begin();
}
template<typename T, typename U, typename V, typename W, typename X>
inline auto HashMap<T, U, V, W, X>::end() -> iterator
{
return m_impl.end();
}
template<typename T, typename U, typename V, typename W, typename X>
inline auto HashMap<T, U, V, W, X>::begin() const -> const_iterator
{
return m_impl.begin();
}
template<typename T, typename U, typename V, typename W, typename X>
inline auto HashMap<T, U, V, W, X>::end() const -> const_iterator
{
return m_impl.end();
}
template<typename T, typename U, typename V, typename W, typename X>
inline auto HashMap<T, U, V, W, X>::find(const KeyType& key) -> iterator
{
return m_impl.find(key);
}
template<typename T, typename U, typename V, typename W, typename X>
inline auto HashMap<T, U, V, W, X>::find(const KeyType& key) const -> const_iterator
{
return m_impl.find(key);
}
template<typename T, typename U, typename V, typename W, typename X>
inline bool HashMap<T, U, V, W, X>::contains(const KeyType& key) const
{
return m_impl.contains(key);
}
template<typename T, typename U, typename V, typename W, typename X>
template<typename HashTranslator, typename TYPE>
inline typename HashMap<T, U, V, W, X>::iterator
HashMap<T, U, V, W, X>::find(const TYPE& value)
{
return m_impl.template find<HashMapTranslatorAdapter<KeyValuePairTraits, HashTranslator>>(value);
}
template<typename T, typename U, typename V, typename W, typename X>
template<typename HashTranslator, typename TYPE>
inline typename HashMap<T, U, V, W, X>::const_iterator
HashMap<T, U, V, W, X>::find(const TYPE& value) const
{
return m_impl.template find<HashMapTranslatorAdapter<KeyValuePairTraits, HashTranslator>>(value);
}
template<typename T, typename U, typename V, typename W, typename X>
template<typename HashTranslator, typename TYPE>
auto HashMap<T, U, V, W, X>::get(const TYPE& value) const -> MappedPeekType
{
auto* entry = const_cast<HashTableType&>(m_impl).template lookup<HashMapTranslatorAdapter<KeyValuePairTraits, HashTranslator>>(value);
if (!entry)
return MappedTraits::peek(MappedTraits::emptyValue());
return MappedTraits::peek(entry->value);
}
template<typename T, typename U, typename V, typename W, typename X>
template<typename HashTranslator, typename TYPE>
inline bool HashMap<T, U, V, W, X>::contains(const TYPE& value) const
{
return m_impl.template contains<HashMapTranslatorAdapter<KeyValuePairTraits, HashTranslator>>(value);
}
template<typename KeyArg, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg>
template<typename K, typename V>
auto HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>::inlineSet(K&& key, V&& value) -> AddResult
{
AddResult result = inlineAdd(std::forward<K>(key), std::forward<V>(value));
if (!result.isNewEntry) {
// The inlineAdd call above found an existing hash table entry; we need to set the mapped value.
result.iterator->value = std::forward<V>(value);
}
return result;
}
template<typename KeyArg, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg>
template<typename K, typename V>
ALWAYS_INLINE auto HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>::inlineAdd(K&& key, V&& value) -> AddResult
{
return m_impl.template add<HashMapTranslator<KeyValuePairTraits, HashFunctions>>(std::forward<K>(key), std::forward<V>(value));
}
template<typename KeyArg, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg>
template<typename K, typename F>
ALWAYS_INLINE auto HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>::inlineEnsure(K&& key, F&& functor) -> AddResult
{
return m_impl.template add<HashMapEnsureTranslator<KeyValuePairTraits, HashFunctions>>(std::forward<K>(key), std::forward<F>(functor));
}
template<typename KeyArg, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg>
template<typename T>
auto HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>::set(const KeyType& key, T&& mapped) -> AddResult
{
return inlineSet(key, std::forward<T>(mapped));
}
template<typename KeyArg, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg>
template<typename T>
auto HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>::set(KeyType&& key, T&& mapped) -> AddResult
{
return inlineSet(WTFMove(key), std::forward<T>(mapped));
}
template<typename KeyArg, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg>
template<typename HashTranslator, typename K, typename V>
auto HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>::add(K&& key, V&& value) -> AddResult
{
return m_impl.template addPassingHashCode<HashMapTranslatorAdapter<KeyValuePairTraits, HashTranslator>>(std::forward<K>(key), std::forward<V>(value));
}
template<typename KeyArg, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg>
template<typename T>
auto HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>::add(const KeyType& key, T&& mapped) -> AddResult
{
return inlineAdd(key, std::forward<T>(mapped));
}
template<typename KeyArg, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg>
template<typename T>
auto HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>::add(KeyType&& key, T&& mapped) -> AddResult
{
return inlineAdd(WTFMove(key), std::forward<T>(mapped));
}
template<typename KeyArg, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg>
template<typename T>
ALWAYS_INLINE auto HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>::fastAdd(const KeyType& key, T&& mapped) -> AddResult
{
return inlineAdd(key, std::forward<T>(mapped));
}
template<typename KeyArg, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg>
template<typename T>
ALWAYS_INLINE auto HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>::fastAdd(KeyType&& key, T&& mapped) -> AddResult
{
return inlineAdd(WTFMove(key), std::forward<T>(mapped));
}
template<typename KeyArg, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg>
template<typename Functor>
auto HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>::ensure(const KeyType& key, Functor&& functor) -> AddResult
{
return inlineEnsure(key, std::forward<Functor>(functor));
}
template<typename KeyArg, typename MappedArg, typename HashArg, typename KeyTraitsArg, typename MappedTraitsArg>
template<typename Functor>
auto HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg>::ensure(KeyType&& key, Functor&& functor) -> AddResult
{
return inlineEnsure(std::forward<KeyType>(key), std::forward<Functor>(functor));
}
template<typename T, typename U, typename V, typename W, typename MappedTraits>
inline auto HashMap<T, U, V, W, MappedTraits>::get(const KeyType& key) const -> MappedPeekType
{
return get<IdentityTranslatorType>(key);
}
template<typename T, typename U, typename V, typename W, typename MappedTraits>
ALWAYS_INLINE auto HashMap<T, U, V, W, MappedTraits>::fastGet(const KeyType& key) const -> MappedPeekType
{
KeyValuePairType* entry = const_cast<HashTableType&>(m_impl).template inlineLookup<IdentityTranslatorType>(key);
if (!entry)
return MappedTraits::peek(MappedTraits::emptyValue());
return MappedTraits::peek(entry->value);
}
template<typename T, typename U, typename V, typename W, typename X>
inline bool HashMap<T, U, V, W, X>::remove(iterator it)
{
if (it.m_impl == m_impl.end())
return false;
m_impl.internalCheckTableConsistency();
m_impl.removeWithoutEntryConsistencyCheck(it.m_impl);
return true;
}
template<typename T, typename U, typename V, typename W, typename X>
template<typename Functor>
inline void HashMap<T, U, V, W, X>::removeIf(Functor&& functor)
{
m_impl.removeIf(std::forward<Functor>(functor));
}
template<typename T, typename U, typename V, typename W, typename X>
inline bool HashMap<T, U, V, W, X>::remove(const KeyType& key)
{
return remove(find(key));
}
template<typename T, typename U, typename V, typename W, typename X>
inline void HashMap<T, U, V, W, X>::clear()
{
m_impl.clear();
}
template<typename T, typename U, typename V, typename W, typename MappedTraits>
auto HashMap<T, U, V, W, MappedTraits>::take(const KeyType& key) -> MappedTakeType
{
iterator it = find(key);
if (it == end())
return MappedTraits::take(MappedTraits::emptyValue());
auto value = MappedTraits::take(WTFMove(it->value));
remove(it);
return value;
}
template<typename T, typename U, typename V, typename W, typename X>
template<typename K>
inline auto HashMap<T, U, V, W, X>::find(typename GetPtrHelper<K>::PtrType key) -> typename std::enable_if<IsSmartPtr<K>::value, iterator>::type
{
return m_impl.template find<HashMapTranslator<KeyValuePairTraits, HashFunctions>>(key);
}
template<typename T, typename U, typename V, typename W, typename X>
template<typename K>
inline auto HashMap<T, U, V, W, X>::find(typename GetPtrHelper<K>::PtrType key) const -> typename std::enable_if<IsSmartPtr<K>::value, const_iterator>::type
{
return m_impl.template find<HashMapTranslator<KeyValuePairTraits, HashFunctions>>(key);
}
template<typename T, typename U, typename V, typename W, typename X>
template<typename K>
inline auto HashMap<T, U, V, W, X>::contains(typename GetPtrHelper<K>::PtrType key) const -> typename std::enable_if<IsSmartPtr<K>::value, bool>::type
{
return m_impl.template contains<HashMapTranslator<KeyValuePairTraits, HashFunctions>>(key);
}
template<typename T, typename U, typename V, typename W, typename X>
template<typename K>
inline auto HashMap<T, U, V, W, X>::inlineGet(typename GetPtrHelper<K>::PtrType key) const -> typename std::enable_if<IsSmartPtr<K>::value, MappedPeekType>::type
{
KeyValuePairType* entry = const_cast<HashTableType&>(m_impl).template inlineLookup<HashMapTranslator<KeyValuePairTraits, HashFunctions>>(key);
if (!entry)
return MappedTraits::peek(MappedTraits::emptyValue());
return MappedTraits::peek(entry->value);
}
template<typename T, typename U, typename V, typename W, typename X>
template<typename K>
auto HashMap<T, U, V, W, X>::get(typename GetPtrHelper<K>::PtrType key) const -> typename std::enable_if<IsSmartPtr<K>::value, MappedPeekType>::type
{
return inlineGet(key);
}
template<typename T, typename U, typename V, typename W, typename X>
template<typename K>
inline auto HashMap<T, U, V, W, X>::remove(typename GetPtrHelper<K>::PtrType key) -> typename std::enable_if<IsSmartPtr<K>::value, bool>::type
{
return remove(find(key));
}
template<typename T, typename U, typename V, typename W, typename X>
template<typename K>
inline auto HashMap<T, U, V, W, X>::take(typename GetPtrHelper<K>::PtrType key) -> typename std::enable_if<IsSmartPtr<K>::value, MappedTakeType>::type
{
iterator it = find(key);
if (it == end())
return MappedTraits::take(MappedTraits::emptyValue());
auto value = MappedTraits::take(WTFMove(it->value));
remove(it);
return value;
}
template<typename T, typename U, typename V, typename W, typename X>
inline void HashMap<T, U, V, W, X>::checkConsistency() const
{
m_impl.checkTableConsistency();
}
template<typename T, typename U, typename V, typename W, typename X>
inline bool HashMap<T, U, V, W, X>::isValidKey(const KeyType& key)
{
if (KeyTraits::isDeletedValue(key))
return false;
if (HashFunctions::safeToCompareToEmptyOrDeleted) {
if (key == KeyTraits::emptyValue())
return false;
} else {
if (isHashTraitsEmptyValue<KeyTraits>(key))
return false;
}
return true;
}
template<typename T, typename U, typename V, typename W, typename X>
bool operator==(const HashMap<T, U, V, W, X>& a, const HashMap<T, U, V, W, X>& b)
{
if (a.size() != b.size())
return false;
typedef typename HashMap<T, U, V, W, X>::const_iterator const_iterator;
const_iterator end = a.end();
const_iterator notFound = b.end();
for (const_iterator it = a.begin(); it != end; ++it) {
const_iterator bPos = b.find(it->key);
if (bPos == notFound || it->value != bPos->value)
return false;
}
return true;
}
template<typename T, typename U, typename V, typename W, typename X>
inline bool operator!=(const HashMap<T, U, V, W, X>& a, const HashMap<T, U, V, W, X>& b)
{
return !(a == b);
}
template<typename T, typename U, typename V, typename W, typename X, typename Y>
inline void copyToVector(const HashMap<T, U, V, W, X>& collection, Y& vector)
{
typedef typename HashMap<T, U, V, W, X>::const_iterator iterator;
vector.resize(collection.size());
iterator it = collection.begin();
iterator end = collection.end();
for (unsigned i = 0; it != end; ++it, ++i)
vector[i] = { (*it).key, (*it).value };
}
template<typename T, typename U, typename V, typename W, typename X, typename Y>
inline void copyKeysToVector(const HashMap<T, U, V, W, X>& collection, Y& vector)
{
typedef typename HashMap<T, U, V, W, X>::const_iterator::Keys iterator;
vector.resize(collection.size());
iterator it = collection.begin().keys();
iterator end = collection.end().keys();
for (unsigned i = 0; it != end; ++it, ++i)
vector[i] = *it;
}
template<typename T, typename U, typename V, typename W, typename X, typename Y>
inline void copyValuesToVector(const HashMap<T, U, V, W, X>& collection, Y& vector)
{
typedef typename HashMap<T, U, V, W, X>::const_iterator::Values iterator;
vector.resize(collection.size());
iterator it = collection.begin().values();
iterator end = collection.end().values();
for (unsigned i = 0; it != end; ++it, ++i)
vector[i] = *it;
}
} // namespace WTF
using WTF::HashMap;
#endif /* WTF_HashMap_h */

45
include/HashMethod.h Normal file
View File

@ -0,0 +1,45 @@
/*
* Copyright (C) 2014 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. ``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
* 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.
*/
#ifndef HashMethod_h
#define HashMethod_h
#include <wtf/StdLibExtras.h>
namespace WTF {
template<typename T>
struct HashMethod {
size_t operator()(const T& value) const
{
return value.hash();
}
};
} // namespace WTF
using WTF::HashMethod;
#endif // HashMethod_h

395
include/HashSet.h Normal file
View File

@ -0,0 +1,395 @@
/*
* Copyright (C) 2005, 2006, 2007, 2008, 2011, 2013, 2017 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef WTF_HashSet_h
#define WTF_HashSet_h
#include <initializer_list>
#include <wtf/FastMalloc.h>
#include <wtf/GetPtr.h>
#include <wtf/HashTable.h>
namespace WTF {
struct IdentityExtractor;
template<typename Value, typename HashFunctions, typename Traits> class HashSet;
template<typename ValueArg, typename HashArg = typename DefaultHash<ValueArg>::Hash,
typename TraitsArg = HashTraits<ValueArg>> class HashSet final {
WTF_MAKE_FAST_ALLOCATED;
private:
typedef HashArg HashFunctions;
typedef TraitsArg ValueTraits;
typedef typename ValueTraits::TakeType TakeType;
public:
typedef typename ValueTraits::TraitType ValueType;
private:
typedef HashTable<ValueType, ValueType, IdentityExtractor,
HashFunctions, ValueTraits, ValueTraits> HashTableType;
public:
typedef HashTableConstIteratorAdapter<HashTableType, ValueType> iterator;
typedef HashTableConstIteratorAdapter<HashTableType, ValueType> const_iterator;
typedef typename HashTableType::AddResult AddResult;
HashSet()
{
}
HashSet(std::initializer_list<ValueArg> initializerList)
{
for (const auto& value : initializerList)
add(value);
}
void swap(HashSet&);
unsigned size() const;
unsigned capacity() const;
bool isEmpty() const;
iterator begin() const;
iterator end() const;
iterator find(const ValueType&) const;
bool contains(const ValueType&) const;
// An alternate version of find() that finds the object by hashing and comparing
// with some other type, to avoid the cost of type conversion. HashTranslator
// must have the following function members:
// static unsigned hash(const T&);
// static bool equal(const ValueType&, const T&);
template<typename HashTranslator, typename T> iterator find(const T&) const;
template<typename HashTranslator, typename T> bool contains(const T&) const;
// The return value includes both an iterator to the added value's location,
// and an isNewEntry bool that indicates if it is a new or existing entry in the set.
AddResult add(const ValueType&);
AddResult add(ValueType&&);
void addVoid(const ValueType&);
void addVoid(ValueType&&);
// An alternate version of add() that finds the object by hashing and comparing
// with some other type, to avoid the cost of type conversion if the object is already
// in the table. HashTranslator must have the following function members:
// static unsigned hash(const T&);
// static bool equal(const ValueType&, const T&);
// static translate(ValueType&, const T&, unsigned hashCode);
template<typename HashTranslator, typename T> AddResult add(const T&);
// Attempts to add a list of things to the set. Returns true if any of
// them are new to the set. Returns false if the set is unchanged.
template<typename IteratorType>
bool add(IteratorType begin, IteratorType end);
bool remove(const ValueType&);
bool remove(iterator);
template<typename Functor>
void removeIf(const Functor&);
void clear();
TakeType take(const ValueType&);
TakeType take(iterator);
TakeType takeAny();
// Overloads for smart pointer values that take the raw pointer type as the parameter.
template<typename V = ValueType> typename std::enable_if<IsSmartPtr<V>::value, iterator>::type find(typename GetPtrHelper<V>::PtrType) const;
template<typename V = ValueType> typename std::enable_if<IsSmartPtr<V>::value, bool>::type contains(typename GetPtrHelper<V>::PtrType) const;
template<typename V = ValueType> typename std::enable_if<IsSmartPtr<V>::value, bool>::type remove(typename GetPtrHelper<V>::PtrType);
template<typename V = ValueType> typename std::enable_if<IsSmartPtr<V>::value, TakeType>::type take(typename GetPtrHelper<V>::PtrType);
static bool isValidValue(const ValueType&);
template<typename OtherCollection>
bool operator==(const OtherCollection&) const;
template<typename OtherCollection>
bool operator!=(const OtherCollection&) const;
private:
HashTableType m_impl;
};
struct IdentityExtractor {
template<typename T> static const T& extract(const T& t) { return t; }
};
template<typename ValueTraits, typename HashFunctions>
struct HashSetTranslator {
template<typename T> static unsigned hash(const T& key) { return HashFunctions::hash(key); }
template<typename T, typename U> static bool equal(const T& a, const U& b) { return HashFunctions::equal(a, b); }
template<typename T, typename U, typename V> static void translate(T& location, U&&, V&& value)
{
ValueTraits::assignToEmpty(location, std::forward<V>(value));
}
};
template<typename Translator>
struct HashSetTranslatorAdapter {
template<typename T> static unsigned hash(const T& key) { return Translator::hash(key); }
template<typename T, typename U> static bool equal(const T& a, const U& b) { return Translator::equal(a, b); }
template<typename T, typename U> static void translate(T& location, const U& key, const U&, unsigned hashCode)
{
Translator::translate(location, key, hashCode);
}
};
template<typename T, typename U, typename V>
inline void HashSet<T, U, V>::swap(HashSet& other)
{
m_impl.swap(other.m_impl);
}
template<typename T, typename U, typename V>
inline unsigned HashSet<T, U, V>::size() const
{
return m_impl.size();
}
template<typename T, typename U, typename V>
inline unsigned HashSet<T, U, V>::capacity() const
{
return m_impl.capacity();
}
template<typename T, typename U, typename V>
inline bool HashSet<T, U, V>::isEmpty() const
{
return m_impl.isEmpty();
}
template<typename T, typename U, typename V>
inline auto HashSet<T, U, V>::begin() const -> iterator
{
return m_impl.begin();
}
template<typename T, typename U, typename V>
inline auto HashSet<T, U, V>::end() const -> iterator
{
return m_impl.end();
}
template<typename T, typename U, typename V>
inline auto HashSet<T, U, V>::find(const ValueType& value) const -> iterator
{
return m_impl.find(value);
}
template<typename T, typename U, typename V>
inline bool HashSet<T, U, V>::contains(const ValueType& value) const
{
return m_impl.contains(value);
}
template<typename Value, typename HashFunctions, typename Traits>
template<typename HashTranslator, typename T>
inline auto HashSet<Value, HashFunctions, Traits>::find(const T& value) const -> iterator
{
return m_impl.template find<HashSetTranslatorAdapter<HashTranslator>>(value);
}
template<typename Value, typename HashFunctions, typename Traits>
template<typename HashTranslator, typename T>
inline bool HashSet<Value, HashFunctions, Traits>::contains(const T& value) const
{
return m_impl.template contains<HashSetTranslatorAdapter<HashTranslator>>(value);
}
template<typename T, typename U, typename V>
inline auto HashSet<T, U, V>::add(const ValueType& value) -> AddResult
{
return m_impl.add(value);
}
template<typename T, typename U, typename V>
inline auto HashSet<T, U, V>::add(ValueType&& value) -> AddResult
{
return m_impl.add(WTFMove(value));
}
template<typename T, typename U, typename V>
inline void HashSet<T, U, V>::addVoid(const ValueType& value)
{
m_impl.add(value);
}
template<typename T, typename U, typename V>
inline void HashSet<T, U, V>::addVoid(ValueType&& value)
{
m_impl.add(WTFMove(value));
}
template<typename Value, typename HashFunctions, typename Traits>
template<typename HashTranslator, typename T>
inline auto HashSet<Value, HashFunctions, Traits>::add(const T& value) -> AddResult
{
return m_impl.template addPassingHashCode<HashSetTranslatorAdapter<HashTranslator>>(value, value);
}
template<typename T, typename U, typename V>
template<typename IteratorType>
inline bool HashSet<T, U, V>::add(IteratorType begin, IteratorType end)
{
bool changed = false;
for (IteratorType iter = begin; iter != end; ++iter)
changed |= add(*iter).isNewEntry;
return changed;
}
template<typename T, typename U, typename V>
inline bool HashSet<T, U, V>::remove(iterator it)
{
if (it.m_impl == m_impl.end())
return false;
m_impl.internalCheckTableConsistency();
m_impl.removeWithoutEntryConsistencyCheck(it.m_impl);
return true;
}
template<typename T, typename U, typename V>
inline bool HashSet<T, U, V>::remove(const ValueType& value)
{
return remove(find(value));
}
template<typename T, typename U, typename V>
template<typename Functor>
inline void HashSet<T, U, V>::removeIf(const Functor& functor)
{
m_impl.removeIf(functor);
}
template<typename T, typename U, typename V>
inline void HashSet<T, U, V>::clear()
{
m_impl.clear();
}
template<typename T, typename U, typename V>
inline auto HashSet<T, U, V>::take(iterator it) -> TakeType
{
if (it == end())
return ValueTraits::take(ValueTraits::emptyValue());
auto result = ValueTraits::take(WTFMove(const_cast<ValueType&>(*it)));
remove(it);
return result;
}
template<typename T, typename U, typename V>
inline auto HashSet<T, U, V>::take(const ValueType& value) -> TakeType
{
return take(find(value));
}
template<typename T, typename U, typename V>
inline auto HashSet<T, U, V>::takeAny() -> TakeType
{
return take(begin());
}
template<typename Value, typename HashFunctions, typename Traits>
template<typename V>
inline auto HashSet<Value, HashFunctions, Traits>::find(typename GetPtrHelper<V>::PtrType value) const -> typename std::enable_if<IsSmartPtr<V>::value, iterator>::type
{
return m_impl.template find<HashSetTranslator<Traits, HashFunctions>>(value);
}
template<typename Value, typename HashFunctions, typename Traits>
template<typename V>
inline auto HashSet<Value, HashFunctions, Traits>::contains(typename GetPtrHelper<V>::PtrType value) const -> typename std::enable_if<IsSmartPtr<V>::value, bool>::type
{
return m_impl.template contains<HashSetTranslator<Traits, HashFunctions>>(value);
}
template<typename Value, typename HashFunctions, typename Traits>
template<typename V>
inline auto HashSet<Value, HashFunctions, Traits>::remove(typename GetPtrHelper<V>::PtrType value) -> typename std::enable_if<IsSmartPtr<V>::value, bool>::type
{
return remove(find(value));
}
template<typename Value, typename HashFunctions, typename Traits>
template<typename V>
inline auto HashSet<Value, HashFunctions, Traits>::take(typename GetPtrHelper<V>::PtrType value) -> typename std::enable_if<IsSmartPtr<V>::value, TakeType>::type
{
return take(find(value));
}
template<typename T, typename U, typename V>
inline bool HashSet<T, U, V>::isValidValue(const ValueType& value)
{
if (ValueTraits::isDeletedValue(value))
return false;
if (HashFunctions::safeToCompareToEmptyOrDeleted) {
if (value == ValueTraits::emptyValue())
return false;
} else {
if (isHashTraitsEmptyValue<ValueTraits>(value))
return false;
}
return true;
}
template<typename C, typename W>
inline void copyToVector(const C& collection, W& vector)
{
typedef typename C::const_iterator iterator;
vector.resize(collection.size());
iterator it = collection.begin();
iterator end = collection.end();
for (unsigned i = 0; it != end; ++it, ++i)
vector[i] = *it;
}
template<typename T, typename U, typename V>
template<typename OtherCollection>
inline bool HashSet<T, U, V>::operator==(const OtherCollection& otherCollection) const
{
if (size() != otherCollection.size())
return false;
for (const auto& other : otherCollection) {
if (!contains(other))
return false;
}
return true;
}
template<typename T, typename U, typename V>
template<typename OtherCollection>
inline bool HashSet<T, U, V>::operator!=(const OtherCollection& otherCollection) const
{
return !(*this == otherCollection);
}
} // namespace WTF
using WTF::HashSet;
#endif /* WTF_HashSet_h */

1538
include/HashTable.h Normal file

File diff suppressed because it is too large Load Diff

379
include/HashTraits.h Normal file
View File

@ -0,0 +1,379 @@
/*
* Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef WTF_HashTraits_h
#define WTF_HashTraits_h
#include <limits>
#include <utility>
#include <wtf/HashFunctions.h>
#include <wtf/Optional.h>
#include <wtf/StdLibExtras.h>
namespace WTF {
class String;
template<typename T> struct HashTraits;
template<bool isInteger, typename T> struct GenericHashTraitsBase;
template<typename T> struct GenericHashTraitsBase<false, T> {
// The emptyValueIsZero flag is used to optimize allocation of empty hash tables with zeroed memory.
static const bool emptyValueIsZero = false;
// The hasIsEmptyValueFunction flag allows the hash table to automatically generate code to check
// for the empty value when it can be done with the equality operator, but allows custom functions
// for cases like String that need them.
static const bool hasIsEmptyValueFunction = false;
// The starting table size. Can be overridden when we know beforehand that
// a hash table will have at least N entries.
static const unsigned minimumTableSize = 8;
};
// Default integer traits disallow both 0 and -1 as keys (max value instead of -1 for unsigned).
template<typename T> struct GenericHashTraitsBase<true, T> : GenericHashTraitsBase<false, T> {
static const bool emptyValueIsZero = true;
static void constructDeletedValue(T& slot) { slot = static_cast<T>(-1); }
static bool isDeletedValue(T value) { return value == static_cast<T>(-1); }
};
template<typename T> struct GenericHashTraits : GenericHashTraitsBase<std::is_integral<T>::value, T> {
typedef T TraitType;
typedef T EmptyValueType;
static T emptyValue() { return T(); }
template<typename U, typename V>
static void assignToEmpty(U& emptyValue, V&& value)
{
emptyValue = std::forward<V>(value);
}
// Type for return value of functions that do not transfer ownership, such as get.
typedef T PeekType;
template<typename U> static U&& peek(U&& value) { return std::forward<U>(value); }
typedef T TakeType;
template<typename U> static TakeType take(U&& value) { return std::forward<U>(value); }
};
template<typename T> struct HashTraits : GenericHashTraits<T> { };
template<typename T> struct FloatHashTraits : GenericHashTraits<T> {
static T emptyValue() { return std::numeric_limits<T>::infinity(); }
static void constructDeletedValue(T& slot) { slot = -std::numeric_limits<T>::infinity(); }
static bool isDeletedValue(T value) { return value == -std::numeric_limits<T>::infinity(); }
};
template<> struct HashTraits<float> : FloatHashTraits<float> { };
template<> struct HashTraits<double> : FloatHashTraits<double> { };
// Default unsigned traits disallow both 0 and max as keys -- use these traits to allow zero and disallow max - 1.
template<typename T> struct UnsignedWithZeroKeyHashTraits : GenericHashTraits<T> {
static const bool emptyValueIsZero = false;
static T emptyValue() { return std::numeric_limits<T>::max(); }
static void constructDeletedValue(T& slot) { slot = std::numeric_limits<T>::max() - 1; }
static bool isDeletedValue(T value) { return value == std::numeric_limits<T>::max() - 1; }
};
template<typename T> struct SignedWithZeroKeyHashTraits : GenericHashTraits<T> {
static const bool emptyValueIsZero = false;
static T emptyValue() { return std::numeric_limits<T>::min(); }
static void constructDeletedValue(T& slot) { slot = std::numeric_limits<T>::max(); }
static bool isDeletedValue(T value) { return value == std::numeric_limits<T>::max(); }
};
// Can be used with strong enums, allows zero as key.
template<typename T> struct StrongEnumHashTraits : GenericHashTraits<T> {
using UnderlyingType = typename std::underlying_type<T>::type;
static const bool emptyValueIsZero = false;
static T emptyValue() { return static_cast<T>(std::numeric_limits<UnderlyingType>::max()); }
static void constructDeletedValue(T& slot) { slot = static_cast<T>(std::numeric_limits<UnderlyingType>::max() - 1); }
static bool isDeletedValue(T value) { return value == static_cast<T>(std::numeric_limits<UnderlyingType>::max() - 1); }
};
template<typename P> struct HashTraits<P*> : GenericHashTraits<P*> {
static const bool emptyValueIsZero = true;
static void constructDeletedValue(P*& slot) { slot = reinterpret_cast<P*>(-1); }
static bool isDeletedValue(P* value) { return value == reinterpret_cast<P*>(-1); }
};
template<typename T> struct SimpleClassHashTraits : GenericHashTraits<T> {
static const bool emptyValueIsZero = true;
static void constructDeletedValue(T& slot) { new (NotNull, std::addressof(slot)) T(HashTableDeletedValue); }
static bool isDeletedValue(const T& value) { return value.isHashTableDeletedValue(); }
};
template<typename T, typename Deleter> struct HashTraits<std::unique_ptr<T, Deleter>> : SimpleClassHashTraits<std::unique_ptr<T, Deleter>> {
typedef std::nullptr_t EmptyValueType;
static EmptyValueType emptyValue() { return nullptr; }
static void constructDeletedValue(std::unique_ptr<T, Deleter>& slot) { new (NotNull, std::addressof(slot)) std::unique_ptr<T, Deleter> { reinterpret_cast<T*>(-1) }; }
static bool isDeletedValue(const std::unique_ptr<T, Deleter>& value) { return value.get() == reinterpret_cast<T*>(-1); }
typedef T* PeekType;
static T* peek(const std::unique_ptr<T, Deleter>& value) { return value.get(); }
static T* peek(std::nullptr_t) { return nullptr; }
static void customDeleteBucket(std::unique_ptr<T, Deleter>& value)
{
// The custom delete function exists to avoid a dead store before the value is destructed.
// The normal destruction sequence of a bucket would be:
// 1) Call the destructor of unique_ptr.
// 2) unique_ptr store a zero for its internal pointer.
// 3) unique_ptr destroys its value.
// 4) Call constructDeletedValue() to set the bucket as destructed.
//
// The problem is the call in (3) prevents the compile from eliminating the dead store in (2)
// becase a side effect of free() could be observing the value.
//
// This version of deleteBucket() ensures the dead 2 stores changing "value"
// are on the same side of the function call.
ASSERT(!isDeletedValue(value));
T* pointer = value.release();
constructDeletedValue(value);
// The null case happens if a caller uses std::move() to remove the pointer before calling remove()
// with an iterator. This is very uncommon.
if (LIKELY(pointer))
Deleter()(pointer);
}
};
template<typename P> struct HashTraits<RefPtr<P>> : SimpleClassHashTraits<RefPtr<P>> {
static P* emptyValue() { return nullptr; }
typedef P* PeekType;
static PeekType peek(const RefPtr<P>& value) { return value.get(); }
static PeekType peek(P* value) { return value; }
static void customDeleteBucket(RefPtr<P>& value)
{
// See unique_ptr's customDeleteBucket() for an explanation.
ASSERT(!SimpleClassHashTraits<RefPtr<P>>::isDeletedValue(value));
auto valueToBeDestroyed = WTFMove(value);
SimpleClassHashTraits<RefPtr<P>>::constructDeletedValue(value);
}
};
template<typename P> struct HashTraits<Ref<P>> : SimpleClassHashTraits<Ref<P>> {
static const bool emptyValueIsZero = true;
static Ref<P> emptyValue() { return HashTableEmptyValue; }
static const bool hasIsEmptyValueFunction = true;
static bool isEmptyValue(const Ref<P>& value) { return value.isHashTableEmptyValue(); }
static void assignToEmpty(Ref<P>& emptyValue, Ref<P>&& newValue) { ASSERT(isEmptyValue(emptyValue)); emptyValue.assignToHashTableEmptyValue(WTFMove(newValue)); }
typedef P* PeekType;
static PeekType peek(const Ref<P>& value) { return const_cast<PeekType>(value.ptrAllowingHashTableEmptyValue()); }
static PeekType peek(P* value) { return value; }
typedef std::optional<Ref<P>> TakeType;
static TakeType take(Ref<P>&& value) { return isEmptyValue(value) ? std::nullopt : std::optional<Ref<P>>(WTFMove(value)); }
};
template<> struct HashTraits<String> : SimpleClassHashTraits<String> {
static const bool hasIsEmptyValueFunction = true;
static bool isEmptyValue(const String&);
static void customDeleteBucket(String&);
};
// This struct template is an implementation detail of the isHashTraitsEmptyValue function,
// which selects either the emptyValue function or the isEmptyValue function to check for empty values.
template<typename Traits, bool hasEmptyValueFunction> struct HashTraitsEmptyValueChecker;
template<typename Traits> struct HashTraitsEmptyValueChecker<Traits, true> {
template<typename T> static bool isEmptyValue(const T& value) { return Traits::isEmptyValue(value); }
};
template<typename Traits> struct HashTraitsEmptyValueChecker<Traits, false> {
template<typename T> static bool isEmptyValue(const T& value) { return value == Traits::emptyValue(); }
};
template<typename Traits, typename T> inline bool isHashTraitsEmptyValue(const T& value)
{
return HashTraitsEmptyValueChecker<Traits, Traits::hasIsEmptyValueFunction>::isEmptyValue(value);
}
template<typename Traits, typename T>
struct HashTraitHasCustomDelete {
static T& bucketArg;
template<typename X> static std::true_type TestHasCustomDelete(X*, decltype(X::customDeleteBucket(bucketArg))* = nullptr);
static std::false_type TestHasCustomDelete(...);
typedef decltype(TestHasCustomDelete(static_cast<Traits*>(nullptr))) ResultType;
static const bool value = ResultType::value;
};
template<typename Traits, typename T>
typename std::enable_if<HashTraitHasCustomDelete<Traits, T>::value>::type
hashTraitsDeleteBucket(T& value)
{
Traits::customDeleteBucket(value);
}
template<typename Traits, typename T>
typename std::enable_if<!HashTraitHasCustomDelete<Traits, T>::value>::type
hashTraitsDeleteBucket(T& value)
{
value.~T();
Traits::constructDeletedValue(value);
}
template<typename FirstTraitsArg, typename SecondTraitsArg>
struct PairHashTraits : GenericHashTraits<std::pair<typename FirstTraitsArg::TraitType, typename SecondTraitsArg::TraitType>> {
typedef FirstTraitsArg FirstTraits;
typedef SecondTraitsArg SecondTraits;
typedef std::pair<typename FirstTraits::TraitType, typename SecondTraits::TraitType> TraitType;
typedef std::pair<typename FirstTraits::EmptyValueType, typename SecondTraits::EmptyValueType> EmptyValueType;
static const bool emptyValueIsZero = FirstTraits::emptyValueIsZero && SecondTraits::emptyValueIsZero;
static EmptyValueType emptyValue() { return std::make_pair(FirstTraits::emptyValue(), SecondTraits::emptyValue()); }
static const unsigned minimumTableSize = FirstTraits::minimumTableSize;
static void constructDeletedValue(TraitType& slot) { FirstTraits::constructDeletedValue(slot.first); }
static bool isDeletedValue(const TraitType& value) { return FirstTraits::isDeletedValue(value.first); }
};
template<typename First, typename Second>
struct HashTraits<std::pair<First, Second>> : public PairHashTraits<HashTraits<First>, HashTraits<Second>> { };
template<typename FirstTrait, typename... Traits>
struct TupleHashTraits : GenericHashTraits<std::tuple<typename FirstTrait::TraitType, typename Traits::TraitType...>> {
typedef std::tuple<typename FirstTrait::TraitType, typename Traits::TraitType...> TraitType;
typedef std::tuple<typename FirstTrait::EmptyValueType, typename Traits::EmptyValueType...> EmptyValueType;
// We should use emptyValueIsZero = Traits::emptyValueIsZero &&... whenever we switch to C++17. We can't do anything
// better here right now because GCC can't do C++.
template<typename BoolType>
static constexpr bool allTrue(BoolType value) { return value; }
template<typename BoolType, typename... BoolTypes>
static constexpr bool allTrue(BoolType value, BoolTypes... values) { return value && allTrue(values...); }
static const bool emptyValueIsZero = allTrue(FirstTrait::emptyValueIsZero, Traits::emptyValueIsZero...);
static EmptyValueType emptyValue() { return std::make_tuple(FirstTrait::emptyValue(), Traits::emptyValue()...); }
static const unsigned minimumTableSize = FirstTrait::minimumTableSize;
static void constructDeletedValue(TraitType& slot) { FirstTrait::constructDeletedValue(std::get<0>(slot)); }
static bool isDeletedValue(const TraitType& value) { return FirstTrait::isDeletedValue(std::get<0>(value)); }
};
template<typename... Traits>
struct HashTraits<std::tuple<Traits...>> : public TupleHashTraits<HashTraits<Traits>...> { };
template<typename KeyTypeArg, typename ValueTypeArg>
struct KeyValuePair {
typedef KeyTypeArg KeyType;
KeyValuePair()
{
}
template<typename K, typename V>
KeyValuePair(K&& key, V&& value)
: key(std::forward<K>(key))
, value(std::forward<V>(value))
{
}
template <typename OtherKeyType, typename OtherValueType>
KeyValuePair(KeyValuePair<OtherKeyType, OtherValueType>&& other)
: key(std::forward<OtherKeyType>(other.key))
, value(std::forward<OtherValueType>(other.value))
{
}
KeyTypeArg key;
ValueTypeArg value { };
};
template<typename KeyTraitsArg, typename ValueTraitsArg>
struct KeyValuePairHashTraits : GenericHashTraits<KeyValuePair<typename KeyTraitsArg::TraitType, typename ValueTraitsArg::TraitType>> {
typedef KeyTraitsArg KeyTraits;
typedef ValueTraitsArg ValueTraits;
typedef KeyValuePair<typename KeyTraits::TraitType, typename ValueTraits::TraitType> TraitType;
typedef KeyValuePair<typename KeyTraits::EmptyValueType, typename ValueTraits::EmptyValueType> EmptyValueType;
typedef typename ValueTraitsArg::TraitType ValueType;
static const bool emptyValueIsZero = KeyTraits::emptyValueIsZero && ValueTraits::emptyValueIsZero;
static EmptyValueType emptyValue() { return KeyValuePair<typename KeyTraits::EmptyValueType, typename ValueTraits::EmptyValueType>(KeyTraits::emptyValue(), ValueTraits::emptyValue()); }
static const unsigned minimumTableSize = KeyTraits::minimumTableSize;
static void constructDeletedValue(TraitType& slot) { KeyTraits::constructDeletedValue(slot.key); }
static bool isDeletedValue(const TraitType& value) { return KeyTraits::isDeletedValue(value.key); }
static void customDeleteBucket(TraitType& value)
{
static_assert(std::is_trivially_destructible<KeyValuePair<int, int>>::value,
"The wrapper itself has to be trivially destructible for customDeleteBucket() to make sense, since we do not destruct the wrapper itself.");
hashTraitsDeleteBucket<KeyTraits>(value.key);
value.value.~ValueType();
}
};
template<typename Key, typename Value>
struct HashTraits<KeyValuePair<Key, Value>> : public KeyValuePairHashTraits<HashTraits<Key>, HashTraits<Value>> { };
template<typename T>
struct NullableHashTraits : public HashTraits<T> {
static const bool emptyValueIsZero = false;
static T emptyValue() { return reinterpret_cast<T>(1); }
};
// Useful for classes that want complete control over what is empty and what is deleted,
// and how to construct both.
template<typename T>
struct CustomHashTraits : public GenericHashTraits<T> {
static const bool emptyValueIsZero = false;
static const bool hasIsEmptyValueFunction = true;
static void constructDeletedValue(T& slot)
{
new (NotNull, std::addressof(slot)) T(T::DeletedValue);
}
static bool isDeletedValue(const T& value)
{
return value.isDeletedValue();
}
static T emptyValue()
{
return T(T::EmptyValue);
}
static bool isEmptyValue(const T& value)
{
return value.isEmptyValue();
}
};
} // namespace WTF
using WTF::HashTraits;
using WTF::KeyValuePair;
using WTF::PairHashTraits;
using WTF::NullableHashTraits;
using WTF::SimpleClassHashTraits;
#endif // WTF_HashTraits_h

389
include/Hasher.h Normal file
View File

@ -0,0 +1,389 @@
/*
* Copyright (C) 2005-2006, 2008, 2010, 2013, 2016 Apple Inc. All rights reserved.
* Copyright (C) 2010 Patrick Gansterer <paroga@paroga.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef WTF_Hasher_h
#define WTF_Hasher_h
#include <unicode/utypes.h>
#include <wtf/text/LChar.h>
namespace WTF {
// Paul Hsieh's SuperFastHash
// http://www.azillionmonkeys.com/qed/hash.html
// LChar data is interpreted as Latin-1-encoded (zero extended to 16 bits).
// NOTE: The hash computation here must stay in sync with the create_hash_table script in
// JavaScriptCore and the CodeGeneratorJS.pm script in WebCore.
// Golden ratio. Arbitrary start value to avoid mapping all zeros to a hash value of zero.
static constexpr const unsigned stringHashingStartValue = 0x9E3779B9U;
class StringHasher {
public:
static constexpr const unsigned flagCount = 8; // Save 8 bits for StringImpl to use as flags.
static constexpr const unsigned maskHash = (1U << (sizeof(unsigned) * 8 - flagCount)) - 1;
StringHasher()
: m_hash(stringHashingStartValue)
, m_hasPendingCharacter(false)
, m_pendingCharacter(0)
{
}
// The hasher hashes two characters at a time, and thus an "aligned" hasher is one
// where an even number of characters have been added. Callers that always add
// characters two at a time can use the "assuming aligned" functions.
void addCharactersAssumingAligned(UChar a, UChar b)
{
ASSERT(!m_hasPendingCharacter);
m_hash += a;
m_hash = (m_hash << 16) ^ ((b << 11) ^ m_hash);
m_hash += m_hash >> 11;
}
void addCharacter(UChar character)
{
if (m_hasPendingCharacter) {
m_hasPendingCharacter = false;
addCharactersAssumingAligned(m_pendingCharacter, character);
return;
}
m_pendingCharacter = character;
m_hasPendingCharacter = true;
}
void addCharacters(UChar a, UChar b)
{
if (m_hasPendingCharacter) {
#if !ASSERT_DISABLED
m_hasPendingCharacter = false;
#endif
addCharactersAssumingAligned(m_pendingCharacter, a);
m_pendingCharacter = b;
#if !ASSERT_DISABLED
m_hasPendingCharacter = true;
#endif
return;
}
addCharactersAssumingAligned(a, b);
}
template<typename T, UChar Converter(T)> void addCharactersAssumingAligned(const T* data, unsigned length)
{
ASSERT(!m_hasPendingCharacter);
bool remainder = length & 1;
length >>= 1;
while (length--) {
addCharactersAssumingAligned(Converter(data[0]), Converter(data[1]));
data += 2;
}
if (remainder)
addCharacter(Converter(*data));
}
template<typename T> void addCharactersAssumingAligned(const T* data, unsigned length)
{
addCharactersAssumingAligned<T, defaultConverter>(data, length);
}
template<typename T, UChar Converter(T)> void addCharactersAssumingAligned(const T* data)
{
ASSERT(!m_hasPendingCharacter);
while (T a = *data++) {
T b = *data++;
if (!b) {
addCharacter(Converter(a));
break;
}
addCharactersAssumingAligned(Converter(a), Converter(b));
}
}
template<typename T> void addCharactersAssumingAligned(const T* data)
{
addCharactersAssumingAligned<T, defaultConverter>(data);
}
template<typename T, UChar Converter(T)> void addCharacters(const T* data, unsigned length)
{
if (!length)
return;
if (m_hasPendingCharacter) {
m_hasPendingCharacter = false;
addCharactersAssumingAligned(m_pendingCharacter, Converter(*data++));
--length;
}
addCharactersAssumingAligned<T, Converter>(data, length);
}
template<typename T> void addCharacters(const T* data, unsigned length)
{
addCharacters<T, defaultConverter>(data, length);
}
template<typename T, UChar Converter(T)> void addCharacters(const T* data)
{
if (m_hasPendingCharacter && *data) {
m_hasPendingCharacter = false;
addCharactersAssumingAligned(m_pendingCharacter, Converter(*data++));
}
addCharactersAssumingAligned<T, Converter>(data);
}
template<typename T> void addCharacters(const T* data)
{
addCharacters<T, defaultConverter>(data);
}
unsigned hashWithTop8BitsMasked() const
{
return finalizeAndMaskTop8Bits(processPendingCharacter());
}
unsigned hash() const
{
return finalize(processPendingCharacter());
}
template<typename T, UChar Converter(T)> static unsigned computeHashAndMaskTop8Bits(const T* data, unsigned length)
{
StringHasher hasher;
hasher.addCharactersAssumingAligned<T, Converter>(data, length);
return hasher.hashWithTop8BitsMasked();
}
template<typename T, UChar Converter(T)> static unsigned computeHashAndMaskTop8Bits(const T* data)
{
StringHasher hasher;
hasher.addCharactersAssumingAligned<T, Converter>(data);
return hasher.hashWithTop8BitsMasked();
}
template<typename T> static unsigned computeHashAndMaskTop8Bits(const T* data, unsigned length)
{
return computeHashAndMaskTop8Bits<T, defaultConverter>(data, length);
}
template<typename T> static unsigned computeHashAndMaskTop8Bits(const T* data)
{
return computeHashAndMaskTop8Bits<T, defaultConverter>(data);
}
template<typename T, UChar Converter(T)> static unsigned computeHash(const T* data, unsigned length)
{
StringHasher hasher;
hasher.addCharactersAssumingAligned<T, Converter>(data, length);
return hasher.hash();
}
template<typename T, UChar Converter(T)> static unsigned computeHash(const T* data)
{
StringHasher hasher;
hasher.addCharactersAssumingAligned<T, Converter>(data);
return hasher.hash();
}
template<typename T> static unsigned computeHash(const T* data, unsigned length)
{
return computeHash<T, defaultConverter>(data, length);
}
template<typename T> static unsigned computeHash(const T* data)
{
return computeHash<T, defaultConverter>(data);
}
static unsigned hashMemory(const void* data, unsigned length)
{
size_t lengthInUChar = length / sizeof(UChar);
StringHasher hasher;
hasher.addCharactersAssumingAligned(static_cast<const UChar*>(data), lengthInUChar);
for (size_t i = 0; i < length % sizeof(UChar); ++i)
hasher.addCharacter(static_cast<const char*>(data)[lengthInUChar * sizeof(UChar) + i]);
return hasher.hash();
}
template<size_t length> static unsigned hashMemory(const void* data)
{
return hashMemory(data, length);
}
static constexpr unsigned finalize(unsigned hash)
{
return avoidZero(avalancheBits(hash));
}
static constexpr unsigned finalizeAndMaskTop8Bits(unsigned hash)
{
// Reserving space from the high bits for flags preserves most of the hash's
// value, since hash lookup typically masks out the high bits anyway.
return avoidZero(avalancheBits(hash) & StringHasher::maskHash);
}
template<typename T, unsigned charactersCount>
static constexpr unsigned computeLiteralHash(const T (&characters)[charactersCount])
{
return StringHasher::finalize(computeLiteralHashImpl(stringHashingStartValue, 0, characters, charactersCount - 1));
}
template<typename T, unsigned charactersCount>
static constexpr unsigned computeLiteralHashAndMaskTop8Bits(const T (&characters)[charactersCount])
{
return StringHasher::finalizeAndMaskTop8Bits(computeLiteralHashImpl(stringHashingStartValue, 0, characters, charactersCount - 1));
}
private:
static UChar defaultConverter(UChar character)
{
return character;
}
static UChar defaultConverter(LChar character)
{
return character;
}
ALWAYS_INLINE static constexpr unsigned avalancheBits3(unsigned hash)
{
return hash ^ (hash << 10);
}
ALWAYS_INLINE static constexpr unsigned avalancheBits2(unsigned hash)
{
return avalancheBits3(hash + (hash >> 15));
}
ALWAYS_INLINE static constexpr unsigned avalancheBits1(unsigned hash)
{
return avalancheBits2(hash ^ (hash << 2));
}
ALWAYS_INLINE static constexpr unsigned avalancheBits0(unsigned hash)
{
return avalancheBits1(hash + (hash >> 5));
}
ALWAYS_INLINE static constexpr unsigned avalancheBits(unsigned hash)
{
return avalancheBits0(hash ^ (hash << 3));
}
// This avoids ever returning a hash code of 0, since that is used to
// signal "hash not computed yet". Setting the high bit maintains
// reasonable fidelity to a hash code of 0 because it is likely to yield
// exactly 0 when hash lookup masks out the high bits.
ALWAYS_INLINE static constexpr unsigned avoidZero(unsigned hash)
{
return hash ? hash : (0x80000000 >> StringHasher::flagCount);
}
unsigned processPendingCharacter() const
{
unsigned result = m_hash;
// Handle end case.
if (m_hasPendingCharacter) {
result += m_pendingCharacter;
result ^= result << 11;
result += result >> 17;
}
return result;
}
// FIXME: This code limits itself to the older, more limited C++11 constexpr capabilities, using
// recursion instead of looping, for example. Would be nice to rewrite this in a simpler way
// once we no longer need to support compilers like GCC 4.9 that do not yet support it.
static constexpr unsigned calculateWithRemainingLastCharacter1(unsigned hash)
{
return hash + (hash >> 17);
}
static constexpr unsigned calculateWithRemainingLastCharacter0(unsigned hash)
{
return calculateWithRemainingLastCharacter1((hash << 11) ^ hash);
}
static constexpr unsigned calculateWithRemainingLastCharacter(unsigned hash, unsigned character)
{
return calculateWithRemainingLastCharacter0(hash + character);
}
static constexpr unsigned calculate1(unsigned hash)
{
return hash + (hash >> 11);
}
static constexpr unsigned calculate0(unsigned hash, unsigned secondCharacter)
{
return calculate1((hash << 16) ^ ((secondCharacter << 11) ^ hash));
}
static constexpr unsigned calculate(unsigned hash, unsigned firstCharacter, unsigned secondCharacter)
{
return calculate0(hash + firstCharacter, secondCharacter);
}
static constexpr unsigned computeLiteralHashImpl(unsigned hash, unsigned index, const char* characters, unsigned length)
{
return (index == length)
? hash : ((index + 1) == length)
? calculateWithRemainingLastCharacter(hash, characters[index])
: computeLiteralHashImpl(calculate(hash, characters[index], characters[index + 1]), index + 2, characters, length);
}
unsigned m_hash;
bool m_hasPendingCharacter;
UChar m_pendingCharacter;
};
class IntegerHasher {
public:
void add(unsigned integer)
{
m_underlyingHasher.addCharactersAssumingAligned(integer, integer >> 16);
}
unsigned hash() const
{
return m_underlyingHasher.hash();
}
private:
StringHasher m_underlyingHasher;
};
} // namespace WTF
using WTF::IntegerHasher;
using WTF::StringHasher;
#endif // WTF_Hasher_h

118
include/HexNumber.h Normal file
View File

@ -0,0 +1,118 @@
/*
* Copyright (C) 2011 Research In Motion Limited. All rights reserved.
* Copyright (C) 2016 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#pragma once
#include <wtf/text/StringConcatenate.h>
namespace WTF {
enum HexConversionMode { Lowercase, Uppercase };
namespace Internal {
inline const LChar* hexDigitsForMode(HexConversionMode mode)
{
static const LChar lowercaseHexDigits[17] = "0123456789abcdef";
static const LChar uppercaseHexDigits[17] = "0123456789ABCDEF";
return mode == Lowercase ? lowercaseHexDigits : uppercaseHexDigits;
}
} // namespace Internal
template<typename T>
inline void appendByteAsHex(unsigned char byte, T& destination, HexConversionMode mode = Uppercase)
{
auto* hexDigits = Internal::hexDigitsForMode(mode);
destination.append(hexDigits[byte >> 4]);
destination.append(hexDigits[byte & 0xF]);
}
template<typename T>
inline void placeByteAsHexCompressIfPossible(unsigned char byte, T& destination, unsigned& index, HexConversionMode mode = Uppercase)
{
auto* hexDigits = Internal::hexDigitsForMode(mode);
if (byte >= 0x10)
destination[index++] = hexDigits[byte >> 4];
destination[index++] = hexDigits[byte & 0xF];
}
template<typename T>
inline void placeByteAsHex(unsigned char byte, T& destination, HexConversionMode mode = Uppercase)
{
auto* hexDigits = Internal::hexDigitsForMode(mode);
*destination++ = hexDigits[byte >> 4];
*destination++ = hexDigits[byte & 0xF];
}
template<typename T>
inline void appendUnsignedAsHex(unsigned number, T& destination, HexConversionMode mode = Uppercase)
{
auto* hexDigits = Internal::hexDigitsForMode(mode);
Vector<LChar, 8> result;
do {
result.append(hexDigits[number % 16]);
number >>= 4;
} while (number > 0);
result.reverse();
destination.append(result.data(), result.size());
}
template<typename T>
inline void appendUnsigned64AsHex(uint64_t number, T& destination, HexConversionMode mode = Uppercase)
{
auto* hexDigits = Internal::hexDigitsForMode(mode);
Vector<LChar, 8> result;
do {
result.append(hexDigits[number % 16]);
number >>= 4;
} while (number > 0);
result.reverse();
destination.append(result.data(), result.size());
}
// Same as appendUnsignedAsHex, but using exactly 'desiredDigits' for the conversion.
template<typename T>
inline void appendUnsignedAsHexFixedSize(unsigned number, T& destination, unsigned desiredDigits, HexConversionMode mode = Uppercase)
{
ASSERT(desiredDigits);
auto* hexDigits = Internal::hexDigitsForMode(mode);
Vector<LChar, 8> result;
do {
result.append(hexDigits[number % 16]);
number >>= 4;
} while (result.size() < desiredDigits);
ASSERT(result.size() == desiredDigits);
result.reverse();
destination.append(result.data(), result.size());
}
} // namespace WTF
using WTF::appendByteAsHex;
using WTF::appendUnsignedAsHex;
using WTF::appendUnsignedAsHexFixedSize;
using WTF::placeByteAsHex;
using WTF::placeByteAsHexCompressIfPossible;
using WTF::Lowercase;

67
include/Indenter.h Normal file
View File

@ -0,0 +1,67 @@
/*
* 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. ``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
* 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.
*/
#ifndef Indenter_h
#define Indenter_h
#include <wtf/PrintStream.h>
#include <wtf/text/WTFString.h>
namespace WTF {
class Indenter {
public:
Indenter(unsigned count = 0, String string = ASCIILiteral(" "))
: m_count(count)
, m_string(string)
{ }
Indenter(const Indenter& other)
: m_count(other.m_count)
, m_string(other.m_string)
{ }
void dump(PrintStream& out) const
{
unsigned levels = m_count;
while (levels--)
out.print(m_string);
}
unsigned operator++() { return ++m_count; }
unsigned operator++(int) { return m_count++; }
unsigned operator--() { return --m_count; }
unsigned operator--(int) { return m_count--; }
private:
unsigned m_count;
String m_string;
};
} // namespace WTF
using WTF::Indenter;
#endif // Indenter_h

41
include/IndexKeyType.h Normal file
View File

@ -0,0 +1,41 @@
/*
* Copyright (C) 2017 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. ``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
* 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
namespace WTF {
template<typename T>
struct IndexKeyType {
static size_t index(const T& key) { return key.index(); }
};
template<typename T>
struct IndexKeyType<T*> {
static size_t index(T* key) { return key->index(); }
};
} // namespace WTF

97
include/IndexMap.h Normal file
View File

@ -0,0 +1,97 @@
/*
* Copyright (C) 2015-2017 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. ``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
* 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 <wtf/IndexKeyType.h>
#include <wtf/Vector.h>
namespace WTF {
// This is a map for keys that have an index(). It's super efficient for BasicBlocks. It's only
// efficient for Values if you don't create too many of these maps, since Values can have very
// sparse indices and there are a lot of Values.
template<typename Key, typename Value>
class IndexMap {
public:
IndexMap()
{
}
template<typename... Args>
explicit IndexMap(size_t size, Args&&... args)
{
m_vector.fill(Value(std::forward<Args>(args)...), size);
}
template<typename... Args>
void resize(size_t size, Args&&... args)
{
m_vector.fill(Value(std::forward<Args>(args)...), size);
}
template<typename... Args>
void clear(Args&&... args)
{
m_vector.fill(Value(std::forward<Args>(args)...), m_vector.size());
}
size_t size() const { return m_vector.size(); }
Value& operator[](size_t index)
{
return m_vector[index];
}
const Value& operator[](size_t index) const
{
return m_vector[index];
}
Value& operator[](const Key& key)
{
return m_vector[IndexKeyType<Key>::index(key)];
}
const Value& operator[](const Key& key) const
{
return m_vector[IndexKeyType<Key>::index(key)];
}
template<typename PassedValue>
void append(const Key& key, PassedValue&& value)
{
RELEASE_ASSERT(IndexKeyType<Key>::index(key) == m_vector.size());
m_vector.append(std::forward<PassedValue>(value));
}
private:
Vector<Value, 0, UnsafeVectorOverflow> m_vector;
};
} // namespace WTF
using WTF::IndexMap;

164
include/IndexSet.h Normal file
View File

@ -0,0 +1,164 @@
/*
* Copyright (C) 2015-2017 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. ``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
* 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 <wtf/BitVector.h>
#include <wtf/CommaPrinter.h>
#include <wtf/IndexKeyType.h>
namespace WTF {
// This is a set for things that have an index(). It's super efficient for BasicBlocks. It's only
// efficient for Values if you don't create too many of these sets, since Values can have very sparse
// indices and there are a lot of Values.
// If you want a set of BasicBlocks, you do IndexSet<BasicBlock>. So, T = BasicBlock.
template<typename T>
class IndexSet {
public:
IndexSet()
{
}
bool add(const T& value)
{
return !m_set.set(IndexKeyType<T>::index(value));
}
template<typename Iterable>
bool addAll(const Iterable& iterable)
{
bool result = false;
for (const T& value : iterable)
result |= add(value);
return result;
}
bool remove(const T& value)
{
return m_set.clear(IndexKeyType<T>::index(value));
}
bool contains(const T& value) const
{
if (!value)
return false;
return m_set.get(IndexKeyType<T>::index(value));
}
size_t size() const
{
return m_set.bitCount();
}
bool isEmpty() const
{
return !size();
}
template<typename CollectionType>
class Iterable {
public:
Iterable(const CollectionType& collection, const BitVector& set)
: m_collection(collection)
, m_set(set)
{
}
class iterator {
public:
iterator()
: m_collection(nullptr)
{
}
iterator(const CollectionType& collection, BitVector::iterator iter)
: m_collection(&collection)
, m_iter(iter)
{
}
T operator*()
{
return m_collection->at(*m_iter);
}
iterator& operator++()
{
++m_iter;
return *this;
}
bool operator==(const iterator& other) const
{
return m_iter == other.m_iter;
}
bool operator!=(const iterator& other) const
{
return !(*this == other);
}
private:
const CollectionType* m_collection;
BitVector::iterator m_iter;
};
iterator begin() const { return iterator(m_collection, m_set.begin()); }
iterator end() const { return iterator(m_collection, m_set.end()); }
private:
const CollectionType& m_collection;
const BitVector& m_set;
};
// For basic blocks, you do:
// indexSet.values(procedure);
//
// For values, you do:
// indexSet.values(procedure.values());
template<typename CollectionType>
Iterable<CollectionType> values(const CollectionType& collection) const
{
return Iterable<CollectionType>(collection, indices());
}
const BitVector& indices() const { return m_set; }
void dump(PrintStream& out) const
{
CommaPrinter comma;
for (size_t index : indices())
out.print(comma, T::dumpPrefix, index);
}
private:
BitVector m_set;
};
} // namespace WTF
using WTF::IndexSet;

235
include/IndexSparseSet.h Normal file
View File

@ -0,0 +1,235 @@
/*
* Copyright (C) 2015-2017 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. ``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
* 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.
*/
#ifndef IndexSparseSet_h
#define IndexSparseSet_h
#include <wtf/HashTraits.h>
#include <wtf/Vector.h>
namespace WTF {
// IndexSparseSet is an efficient set of integers that can only be valued
// between zero and size() - 1.
//
// The implementation is using Briggs Sparse Set representation. We allocate
// memory from 0 to size() - 1 to do mapping in O(1), but we never initialize
// that memory. When adding/removing values to the set, they are added in a list
// and the corresponding bucket is initialized to the position in the list.
//
// The assumption here is that we only need a sparse subset of number live at any
// time.
template<typename T>
struct DefaultIndexSparseSetTraits {
typedef T EntryType;
static T create(unsigned entry)
{
return entry;
}
static unsigned key(const T& entry)
{
return entry;
}
};
template<typename KeyType, typename ValueType>
struct DefaultIndexSparseSetTraits<KeyValuePair<KeyType, ValueType>> {
typedef KeyValuePair<KeyType, ValueType> EntryType;
template<typename PassedValueType>
static EntryType create(unsigned key, PassedValueType&& value)
{
return EntryType(key, std::forward<PassedValueType>(value));
}
static unsigned key(const EntryType& entry)
{
return entry.key;
}
};
template<typename EntryType = unsigned, typename EntryTypeTraits = DefaultIndexSparseSetTraits<EntryType>, typename OverflowHandler = CrashOnOverflow>
class IndexSparseSet {
typedef Vector<EntryType, 0, OverflowHandler> ValueList;
public:
explicit IndexSparseSet(unsigned size);
template<typename... Arguments>
bool add(unsigned, Arguments&&...);
template<typename... Arguments>
bool set(unsigned, Arguments&&...);
bool remove(unsigned);
void clear();
unsigned size() const;
bool isEmpty() const;
bool contains(unsigned) const;
const EntryType* get(unsigned) const;
EntryType* get(unsigned);
typedef typename ValueList::const_iterator const_iterator;
const_iterator begin() const;
const_iterator end() const;
void sort();
const ValueList& values() const { return m_values; }
private:
Vector<unsigned, 0, OverflowHandler, 1> m_map;
ValueList m_values;
};
template<typename EntryType, typename EntryTypeTraits, typename OverflowHandler>
inline IndexSparseSet<EntryType, EntryTypeTraits, OverflowHandler>::IndexSparseSet(unsigned size)
{
m_map.resize(size);
}
template<typename EntryType, typename EntryTypeTraits, typename OverflowHandler>
template<typename... Arguments>
inline bool IndexSparseSet<EntryType, EntryTypeTraits, OverflowHandler>::add(unsigned value, Arguments&&... arguments)
{
if (contains(value))
return false;
unsigned newPosition = m_values.size();
m_values.append(EntryTypeTraits::create(value, std::forward<Arguments>(arguments)...));
m_map[value] = newPosition;
return true;
}
template<typename EntryType, typename EntryTypeTraits, typename OverflowHandler>
template<typename... Arguments>
inline bool IndexSparseSet<EntryType, EntryTypeTraits, OverflowHandler>::set(unsigned value, Arguments&&... arguments)
{
if (EntryType* entry = get(value)) {
*entry = EntryTypeTraits::create(value, std::forward<Arguments>(arguments)...);
return false;
}
unsigned newPosition = m_values.size();
m_values.append(EntryTypeTraits::create(value, std::forward<Arguments>(arguments)...));
m_map[value] = newPosition;
return true;
}
template<typename EntryType, typename EntryTypeTraits, typename OverflowHandler>
inline bool IndexSparseSet<EntryType, EntryTypeTraits, OverflowHandler>::remove(unsigned value)
{
unsigned position = m_map[value];
if (position >= m_values.size())
return false;
if (m_values[position] == value) {
EntryType lastValue = m_values.last();
m_values[position] = WTFMove(lastValue);
m_map[EntryTypeTraits::key(lastValue)] = position;
m_values.removeLast();
return true;
}
return false;
}
template<typename EntryType, typename EntryTypeTraits, typename OverflowHandler>
void IndexSparseSet<EntryType, EntryTypeTraits, OverflowHandler>::clear()
{
m_values.resize(0);
}
template<typename EntryType, typename EntryTypeTraits, typename OverflowHandler>
unsigned IndexSparseSet<EntryType, EntryTypeTraits, OverflowHandler>::size() const
{
return m_values.size();
}
template<typename EntryType, typename EntryTypeTraits, typename OverflowHandler>
bool IndexSparseSet<EntryType, EntryTypeTraits, OverflowHandler>::isEmpty() const
{
return !size();
}
template<typename EntryType, typename EntryTypeTraits, typename OverflowHandler>
bool IndexSparseSet<EntryType, EntryTypeTraits, OverflowHandler>::contains(unsigned value) const
{
unsigned position = m_map[value];
if (position >= m_values.size())
return false;
return EntryTypeTraits::key(m_values[position]) == value;
}
template<typename EntryType, typename EntryTypeTraits, typename OverflowHandler>
auto IndexSparseSet<EntryType, EntryTypeTraits, OverflowHandler>::get(unsigned value) -> EntryType*
{
unsigned position = m_map[value];
if (position >= m_values.size())
return nullptr;
EntryType& entry = m_values[position];
if (EntryTypeTraits::key(entry) != value)
return nullptr;
return &entry;
}
template<typename EntryType, typename EntryTypeTraits, typename OverflowHandler>
auto IndexSparseSet<EntryType, EntryTypeTraits, OverflowHandler>::get(unsigned value) const -> const EntryType*
{
return const_cast<IndexSparseSet*>(this)->get(value);
}
template<typename EntryType, typename EntryTypeTraits, typename OverflowHandler>
void IndexSparseSet<EntryType, EntryTypeTraits, OverflowHandler>::sort()
{
std::sort(
m_values.begin(), m_values.end(),
[&] (const EntryType& a, const EntryType& b) {
return EntryTypeTraits::key(a) < EntryTypeTraits::key(b);
});
}
template<typename EntryType, typename EntryTypeTraits, typename OverflowHandler>
auto IndexSparseSet<EntryType, EntryTypeTraits, OverflowHandler>::begin() const -> const_iterator
{
return m_values.begin();
}
template<typename EntryType, typename EntryTypeTraits, typename OverflowHandler>
auto IndexSparseSet<EntryType, EntryTypeTraits, OverflowHandler>::end() const -> const_iterator
{
return m_values.end();
}
} // namespace WTF
using WTF::DefaultIndexSparseSetTraits;
using WTF::IndexSparseSet;
#endif // IndexSparseSet_h

View File

@ -0,0 +1,81 @@
/*
* Copyright (C) 2015-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. ``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
* 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 <type_traits>
namespace WTF {
template<class Container>
class IndexedContainerIterator {
public:
IndexedContainerIterator()
: m_container(nullptr)
, m_index(0)
{
}
IndexedContainerIterator(const Container& container, unsigned index)
: m_container(&container)
, m_index(findNext(index))
{
}
auto operator*() -> typename std::result_of<decltype(&Container::at)(const Container, unsigned)>::type
{
return m_container->at(m_index);
}
IndexedContainerIterator& operator++()
{
m_index = findNext(m_index + 1);
return *this;
}
bool operator==(const IndexedContainerIterator& other) const
{
ASSERT(m_container == other.m_container);
return m_index == other.m_index;
}
bool operator!=(const IndexedContainerIterator& other) const
{
return !(*this == other);
}
private:
unsigned findNext(unsigned index)
{
while (index < m_container->size() && !m_container->at(index))
index++;
return index;
}
const Container* m_container;
unsigned m_index;
};
} // namespace WTF

98
include/InlineASM.h Normal file
View File

@ -0,0 +1,98 @@
/*
* Copyright (C) 2011 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. ``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
* 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.
*/
#ifndef InlineASM_h
#define InlineASM_h
/* asm directive helpers */
#if OS(DARWIN) || (OS(WINDOWS) && CPU(X86))
#define SYMBOL_STRING(name) "_" #name
#else
#define SYMBOL_STRING(name) #name
#endif
#if OS(IOS)
#define THUMB_FUNC_PARAM(name) SYMBOL_STRING(name)
#else
#define THUMB_FUNC_PARAM(name)
#endif
#if (OS(LINUX) || OS(FREEBSD)) && CPU(X86_64)
#define GLOBAL_REFERENCE(name) #name "@plt"
#elif CPU(X86) && COMPILER(MINGW)
#define GLOBAL_REFERENCE(name) "@" #name "@4"
#elif OS(LINUX) && CPU(X86) && defined(__PIC__)
#define GLOBAL_REFERENCE(name) SYMBOL_STRING(name) "@plt"
#else
#define GLOBAL_REFERENCE(name) SYMBOL_STRING(name)
#endif
#if HAVE(INTERNAL_VISIBILITY)
#define LOCAL_REFERENCE(name) SYMBOL_STRING(name)
#else
#define LOCAL_REFERENCE(name) GLOBAL_REFERENCE(name)
#endif
#if OS(DARWIN)
// Mach-O platform
#define HIDE_SYMBOL(name) ".private_extern _" #name
#elif OS(AIX)
// IBM's own file format
#define HIDE_SYMBOL(name) ".lglobl " #name
#elif OS(LINUX) \
|| OS(FREEBSD) \
|| OS(OPENBSD) \
|| OS(SOLARIS) \
|| (OS(HPUX) && CPU(IA64)) \
|| OS(NETBSD)
// ELF platform
#define HIDE_SYMBOL(name) ".hidden " #name
#else
#define HIDE_SYMBOL(name)
#endif
// FIXME: figure out how this works on all the platforms. I know that
// on ELF, the preferred form is ".Lstuff" as opposed to "Lstuff".
// Don't know about any of the others.
#if OS(DARWIN)
#define LOCAL_LABEL_STRING(name) "L" #name
#elif OS(LINUX) \
|| OS(FREEBSD) \
|| OS(OPENBSD) \
|| OS(HURD) \
|| OS(NETBSD) \
|| COMPILER(MINGW)
// GNU as-compatible syntax.
#define LOCAL_LABEL_STRING(name) ".L" #name
#endif
#if (CPU(ARM_TRADITIONAL) && (defined(thumb2) || defined(__thumb2__) || defined(__thumb) || defined(__thumb__))) || CPU(ARM_THUMB2)
#define INLINE_ARM_FUNCTION(name) ".thumb" "\n" ".thumb_func " THUMB_FUNC_PARAM(name) "\n"
#else
#define INLINE_ARM_FUNCTION(name)
#endif
#endif // InlineASM_h

85
include/Insertion.h Normal file
View File

@ -0,0 +1,85 @@
/*
* Copyright (C) 2013, 2015-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. ``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
* 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.
*/
#ifndef Insertion_h
#define Insertion_h
namespace WTF {
template<typename T>
class Insertion {
public:
Insertion() { }
template<typename U>
Insertion(size_t index, U&& element)
: m_index(index)
, m_element(std::forward<U>(element))
{
}
size_t index() const { return m_index; }
const T& element() const { return m_element; }
T& element() { return m_element; }
bool operator<(const Insertion& other) const
{
return m_index < other.m_index;
}
private:
size_t m_index { 0 };
T m_element { };
};
template<typename TargetVectorType, typename InsertionVectorType>
size_t executeInsertions(TargetVectorType& target, InsertionVectorType& insertions)
{
size_t numInsertions = insertions.size();
if (!numInsertions)
return 0;
size_t originalTargetSize = target.size();
target.grow(target.size() + numInsertions);
size_t lastIndex = target.size();
for (size_t indexInInsertions = numInsertions; indexInInsertions--;) {
ASSERT(!indexInInsertions || insertions[indexInInsertions].index() >= insertions[indexInInsertions - 1].index());
ASSERT_UNUSED(originalTargetSize, insertions[indexInInsertions].index() <= originalTargetSize);
size_t firstIndex = insertions[indexInInsertions].index() + indexInInsertions;
size_t indexOffset = indexInInsertions + 1;
for (size_t i = lastIndex; --i > firstIndex;)
target[i] = WTFMove(target[i - indexOffset]);
target[firstIndex] = WTFMove(insertions[indexInInsertions].element());
lastIndex = firstIndex;
}
insertions.resize(0);
return numInsertions;
}
} // namespace WTF
using WTF::Insertion;
using WTF::executeInsertions;
#endif // Insertion_h

113
include/IteratorAdaptors.h Normal file
View File

@ -0,0 +1,113 @@
/*
* Copyright (C) 2013 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.
*/
#ifndef WTF_IteratorAdaptors_h
#define WTF_IteratorAdaptors_h
#include <type_traits>
namespace WTF {
template<typename Predicate, typename Iterator>
class FilterIterator {
public:
FilterIterator(Predicate pred, Iterator begin, Iterator end)
: m_pred(WTFMove(pred))
, m_iter(WTFMove(begin))
, m_end(WTFMove(end))
{
while (m_iter != m_end && !m_pred(*m_iter))
++m_iter;
}
FilterIterator& operator++()
{
while (m_iter != m_end) {
++m_iter;
if (m_iter == m_end || m_pred(*m_iter))
break;
}
return *this;
}
const typename std::remove_const<decltype(*std::declval<Iterator>())>::type operator*() const
{
ASSERT(m_iter != m_end);
ASSERT(m_pred(*m_iter));
return *m_iter;
}
inline bool operator==(FilterIterator& other) const { return m_iter == other.m_iter; }
inline bool operator!=(FilterIterator& other) const { return m_iter != other.m_iter; }
private:
const Predicate m_pred;
Iterator m_iter;
Iterator m_end;
};
template<typename Predicate, typename Iterator>
inline FilterIterator<Predicate, Iterator> makeFilterIterator(Predicate&& pred, Iterator&& begin, Iterator&& end)
{
return FilterIterator<Predicate, Iterator>(std::forward<Predicate>(pred), std::forward<Iterator>(begin), std::forward<Iterator>(end));
}
template<typename Transform, typename Iterator>
class TransformIterator {
public:
TransformIterator(Transform&& transform, Iterator&& iter)
: m_transform(WTFMove(transform))
, m_iter(WTFMove(iter))
{
}
TransformIterator& operator++()
{
++m_iter;
return *this;
}
const typename std::remove_const<decltype(std::declval<Transform>()(*std::declval<Iterator>()))>::type operator*() const
{
return m_transform(*m_iter);
}
inline bool operator==(TransformIterator& other) const { return m_iter == other.m_iter; }
inline bool operator!=(TransformIterator& other) const { return m_iter != other.m_iter; }
private:
const Transform m_transform;
Iterator m_iter;
};
template<typename Transform, typename Iterator>
inline TransformIterator<Transform, Iterator> makeTransformIterator(Transform&& transform, Iterator&& iter)
{
return TransformIterator<Transform, Iterator>(WTFMove(transform), WTFMove(iter));
}
} // namespace WTF
#endif // WTF_IteratorAdaptors_h

56
include/IteratorRange.h Normal file
View File

@ -0,0 +1,56 @@
/*
* Copyright (C) 2013 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.
*/
#ifndef WTF_IteratorRange_h
#define WTF_IteratorRange_h
namespace WTF {
template<typename Iterator>
class IteratorRange {
public:
IteratorRange(Iterator begin, Iterator end)
: m_begin(WTFMove(begin))
, m_end(WTFMove(end))
{
}
Iterator begin() const { return m_begin; }
Iterator end() const { return m_end; }
private:
Iterator m_begin;
Iterator m_end;
};
template<typename Iterator>
IteratorRange<Iterator> makeIteratorRange(Iterator&& begin, Iterator&& end)
{
return IteratorRange<Iterator>(std::forward<Iterator>(begin), std::forward<Iterator>(end));
}
} // namespace WTF
#endif // WTF_IteratorRange_h

107
include/LEBDecoder.h Normal file
View File

@ -0,0 +1,107 @@
/*
* 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. ``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
* 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 "Compiler.h"
#include <algorithm>
// This file contains a bunch of helper functions for decoding LEB numbers.
// See https://en.wikipedia.org/wiki/LEB128 for more information about the
// LEB format.
namespace WTF { namespace LEBDecoder {
template<typename T>
inline bool WARN_UNUSED_RETURN decodeUInt(const uint8_t* bytes, size_t length, size_t& offset, T& result)
{
const size_t numBits = sizeof(T) * CHAR_BIT;
const size_t maxByteLength = (numBits - 1) / 7 + 1; // numBits / 7 rounding up.
if (length <= offset)
return false;
result = 0;
unsigned shift = 0;
size_t last = std::min(maxByteLength, length - offset) - 1;
for (unsigned i = 0; true; ++i) {
uint8_t byte = bytes[offset++];
result |= static_cast<T>(byte & 0x7f) << shift;
shift += 7;
if (!(byte & 0x80))
return true;
if (i == last)
return false;
}
RELEASE_ASSERT_NOT_REACHED();
return true;
}
template<typename T>
inline bool WARN_UNUSED_RETURN decodeInt(const uint8_t* bytes, size_t length, size_t& offset, T& result)
{
const size_t numBits = sizeof(T) * CHAR_BIT;
const size_t maxByteLength = (numBits - 1) / 7 + 1; // numBits / 7 rounding up.
if (length <= offset)
return false;
result = 0;
unsigned shift = 0;
size_t last = std::min(maxByteLength, length - offset) - 1;
uint8_t byte;
for (unsigned i = 0; true; ++i) {
byte = bytes[offset++];
result |= static_cast<T>(byte & 0x7f) << shift;
shift += 7;
if (!(byte & 0x80))
break;
if (i == last)
return false;
}
using UnsignedT = typename std::make_unsigned<T>::type;
if (shift < numBits && (byte & 0x40))
result = static_cast<T>(static_cast<UnsignedT>(result) | (static_cast<UnsignedT>(-1) << shift));
return true;
}
inline bool WARN_UNUSED_RETURN decodeUInt32(const uint8_t* bytes, size_t length, size_t& offset, uint32_t& result)
{
return decodeUInt<uint32_t>(bytes, length, offset, result);
}
inline bool WARN_UNUSED_RETURN decodeUInt64(const uint8_t* bytes, size_t length, size_t& offset, uint64_t& result)
{
return decodeUInt<uint64_t>(bytes, length, offset, result);
}
inline bool WARN_UNUSED_RETURN decodeInt32(const uint8_t* bytes, size_t length, size_t& offset, int32_t& result)
{
return decodeInt<int32_t>(bytes, length, offset, result);
}
inline bool WARN_UNUSED_RETURN decodeInt64(const uint8_t* bytes, size_t length, size_t& offset, int64_t& result)
{
return decodeInt<int64_t>(bytes, length, offset, result);
}
} } // WTF::LEBDecoder

187
include/ListDump.h Normal file
View File

@ -0,0 +1,187 @@
/*
* Copyright (C) 2013, 2015 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. ``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
* 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.
*/
#ifndef ListDump_h
#define ListDump_h
#include "CommaPrinter.h"
#include "PrintStream.h"
#include "StringPrintStream.h"
namespace WTF {
template<typename T>
class ListDump {
public:
ListDump(const T& list, const char* comma)
: m_list(list)
, m_comma(comma)
{
}
void dump(PrintStream& out) const
{
for (auto iter = m_list.begin(); iter != m_list.end(); ++iter)
out.print(m_comma, *iter);
}
private:
const T& m_list;
CommaPrinter m_comma;
};
template<typename T>
class PointerListDump {
public:
PointerListDump(const T& list, const char* comma)
: m_list(list)
, m_comma(comma)
{
}
void dump(PrintStream& out) const
{
for (auto iter = m_list.begin(); iter != m_list.end(); ++iter)
out.print(m_comma, pointerDump(*iter));
}
private:
const T& m_list;
CommaPrinter m_comma;
};
template<typename T>
class MapDump {
public:
MapDump(const T& map, const char* arrow, const char* comma)
: m_map(map)
, m_arrow(arrow)
, m_comma(comma)
{
}
void dump(PrintStream& out) const
{
for (auto iter = m_map.begin(); iter != m_map.end(); ++iter)
out.print(m_comma, iter->key, m_arrow, iter->value);
}
private:
const T& m_map;
const char* m_arrow;
CommaPrinter m_comma;
};
template<typename T>
ListDump<T> listDump(const T& list, const char* comma = ", ")
{
return ListDump<T>(list, comma);
}
template<typename T>
PointerListDump<T> pointerListDump(const T& list, const char* comma = ", ")
{
return PointerListDump<T>(list, comma);
}
template<typename T, typename Comparator>
CString sortedListDump(const T& list, const Comparator& comparator, const char* comma = ", ")
{
Vector<typename T::ValueType> myList;
myList.appendRange(list.begin(), list.end());
std::sort(myList.begin(), myList.end(), comparator);
StringPrintStream out;
CommaPrinter commaPrinter(comma);
for (unsigned i = 0; i < myList.size(); ++i)
out.print(commaPrinter, myList[i]);
return out.toCString();
}
template<typename T>
CString sortedListDump(const T& list, const char* comma = ", ")
{
return sortedListDump(list, std::less<typename T::ValueType>(), comma);
}
template<typename T>
MapDump<T> mapDump(const T& map, const char* arrow = "=>", const char* comma = ", ")
{
return MapDump<T>(map, arrow, comma);
}
template<typename T, typename Comparator>
CString sortedMapDump(const T& map, const Comparator& comparator, const char* arrow = "=>", const char* comma = ", ")
{
Vector<typename T::KeyType> keys;
for (auto iter = map.begin(); iter != map.end(); ++iter)
keys.append(iter->key);
std::sort(keys.begin(), keys.end(), comparator);
StringPrintStream out;
CommaPrinter commaPrinter(comma);
for (unsigned i = 0; i < keys.size(); ++i)
out.print(commaPrinter, keys[i], arrow, map.get(keys[i]));
return out.toCString();
}
template<typename T, typename U>
class ListDumpInContext {
public:
ListDumpInContext(const T& list, U* context, const char* comma)
: m_list(list)
, m_context(context)
, m_comma(comma)
{
}
void dump(PrintStream& out) const
{
for (auto iter = m_list.begin(); iter != m_list.end(); ++iter)
out.print(m_comma, inContext(*iter, m_context));
}
private:
const T& m_list;
U* m_context;
CommaPrinter m_comma;
};
template<typename T, typename U>
ListDumpInContext<T, U> listDumpInContext(
const T& list, U* context, const char* comma = ", ")
{
return ListDumpInContext<T, U>(list, context, comma);
}
} // namespace WTF
using WTF::listDump;
using WTF::listDumpInContext;
using WTF::mapDump;
using WTF::pointerListDump;
using WTF::sortedListDump;
using WTF::sortedMapDump;
#endif // ListDump_h

714
include/ListHashSet.h Normal file
View File

@ -0,0 +1,714 @@
/*
* Copyright (C) 2005, 2006, 2007, 2008, 2011, 2012, 2013 Apple Inc. All rights reserved.
* Copyright (C) 2011, Benjamin Poulain <ikipou@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#pragma once
#include <wtf/HashSet.h>
namespace WTF {
// ListHashSet: Just like HashSet, this class provides a Set
// interface - a collection of unique objects with O(1) insertion,
// removal and test for containership. However, it also has an
// order - iterating it will always give back values in the order
// in which they are added.
// Unlike iteration of most WTF Hash data structures, iteration is
// guaranteed safe against mutation of the ListHashSet, except for
// removal of the item currently pointed to by a given iterator.
template<typename Value, typename HashFunctions> class ListHashSet;
template<typename ValueArg, typename HashArg> class ListHashSetIterator;
template<typename ValueArg, typename HashArg> class ListHashSetConstIterator;
template<typename ValueArg> struct ListHashSetNode;
template<typename HashArg> struct ListHashSetNodeHashFunctions;
template<typename HashArg> struct ListHashSetTranslator;
template<typename ValueArg, typename HashArg = typename DefaultHash<ValueArg>::Hash> class ListHashSet {
WTF_MAKE_FAST_ALLOCATED;
private:
typedef ListHashSetNode<ValueArg> Node;
typedef HashTraits<Node*> NodeTraits;
typedef ListHashSetNodeHashFunctions<HashArg> NodeHash;
typedef ListHashSetTranslator<HashArg> BaseTranslator;
typedef HashArg HashFunctions;
public:
typedef ValueArg ValueType;
typedef ListHashSetIterator<ValueType, HashArg> iterator;
typedef ListHashSetConstIterator<ValueType, HashArg> const_iterator;
friend class ListHashSetConstIterator<ValueType, HashArg>;
typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
typedef HashTableAddResult<iterator> AddResult;
ListHashSet() = default;
ListHashSet(const ListHashSet&);
ListHashSet(ListHashSet&&);
ListHashSet& operator=(const ListHashSet&);
ListHashSet& operator=(ListHashSet&&);
~ListHashSet();
void swap(ListHashSet&);
unsigned size() const;
unsigned capacity() const;
bool isEmpty() const;
iterator begin() { return makeIterator(m_head); }
iterator end() { return makeIterator(nullptr); }
const_iterator begin() const { return makeConstIterator(m_head); }
const_iterator end() const { return makeConstIterator(nullptr); }
reverse_iterator rbegin() { return reverse_iterator(end()); }
reverse_iterator rend() { return reverse_iterator(begin()); }
const_reverse_iterator rbegin() const { return const_reverse_iterator(end()); }
const_reverse_iterator rend() const { return const_reverse_iterator(begin()); }
ValueType& first();
const ValueType& first() const;
void removeFirst();
ValueType takeFirst();
ValueType& last();
const ValueType& last() const;
void removeLast();
ValueType takeLast();
iterator find(const ValueType&);
const_iterator find(const ValueType&) const;
bool contains(const ValueType&) const;
// An alternate version of find() that finds the object by hashing and comparing
// with some other type, to avoid the cost of type conversion.
// The HashTranslator interface is defined in HashSet.
// FIXME: We should reverse the order of the template arguments so that callers
// can just pass the translator let the compiler deduce T.
template<typename T, typename HashTranslator> iterator find(const T&);
template<typename T, typename HashTranslator> const_iterator find(const T&) const;
template<typename T, typename HashTranslator> bool contains(const T&) const;
// The return value of add is a pair of an iterator to the new value's location,
// and a bool that is true if an new entry was added.
AddResult add(const ValueType&);
AddResult add(ValueType&&);
// Add the value to the end of the collection. If the value was already in
// the list, it is moved to the end.
AddResult appendOrMoveToLast(const ValueType&);
AddResult appendOrMoveToLast(ValueType&&);
// Add the value to the beginning of the collection. If the value was already in
// the list, it is moved to the beginning.
AddResult prependOrMoveToFirst(const ValueType&);
AddResult prependOrMoveToFirst(ValueType&&);
AddResult insertBefore(const ValueType& beforeValue, const ValueType& newValue);
AddResult insertBefore(const ValueType& beforeValue, ValueType&& newValue);
AddResult insertBefore(iterator, const ValueType&);
AddResult insertBefore(iterator, ValueType&&);
bool remove(const ValueType&);
bool remove(iterator);
void clear();
private:
void unlink(Node*);
void unlinkAndDelete(Node*);
void appendNode(Node*);
void prependNode(Node*);
void insertNodeBefore(Node* beforeNode, Node* newNode);
void deleteAllNodes();
iterator makeIterator(Node*);
const_iterator makeConstIterator(Node*) const;
HashTable<Node*, Node*, IdentityExtractor, NodeHash, NodeTraits, NodeTraits> m_impl;
Node* m_head { nullptr };
Node* m_tail { nullptr };
};
template<typename ValueArg> struct ListHashSetNode {
WTF_MAKE_FAST_ALLOCATED;
public:
template<typename T>
ListHashSetNode(T&& value)
: m_value(std::forward<T>(value))
{
}
ValueArg m_value;
ListHashSetNode* m_prev { nullptr };
ListHashSetNode* m_next { nullptr };
};
template<typename HashArg> struct ListHashSetNodeHashFunctions {
template<typename T> static unsigned hash(const T& key) { return HashArg::hash(key->m_value); }
template<typename T> static bool equal(const T& a, const T& b) { return HashArg::equal(a->m_value, b->m_value); }
static const bool safeToCompareToEmptyOrDeleted = false;
};
template<typename ValueArg, typename HashArg> class ListHashSetIterator {
private:
typedef ListHashSet<ValueArg, HashArg> ListHashSetType;
typedef ListHashSetIterator<ValueArg, HashArg> iterator;
typedef ListHashSetConstIterator<ValueArg, HashArg> const_iterator;
typedef ListHashSetNode<ValueArg> Node;
typedef ValueArg ValueType;
friend class ListHashSet<ValueArg, HashArg>;
ListHashSetIterator(const ListHashSetType* set, Node* position) : m_iterator(set, position) { }
public:
typedef ptrdiff_t difference_type;
typedef ValueType value_type;
typedef ValueType* pointer;
typedef ValueType& reference;
typedef std::bidirectional_iterator_tag iterator_category;
ListHashSetIterator() { }
// default copy, assignment and destructor are OK
ValueType* get() const { return const_cast<ValueType*>(m_iterator.get()); }
ValueType& operator*() const { return *get(); }
ValueType* operator->() const { return get(); }
iterator& operator++() { ++m_iterator; return *this; }
// postfix ++ intentionally omitted
iterator& operator--() { --m_iterator; return *this; }
// postfix -- intentionally omitted
// Comparison.
bool operator==(const iterator& other) const { return m_iterator == other.m_iterator; }
bool operator!=(const iterator& other) const { return m_iterator != other.m_iterator; }
operator const_iterator() const { return m_iterator; }
private:
Node* node() { return m_iterator.node(); }
const_iterator m_iterator;
};
template<typename ValueArg, typename HashArg> class ListHashSetConstIterator {
private:
typedef ListHashSet<ValueArg, HashArg> ListHashSetType;
typedef ListHashSetIterator<ValueArg, HashArg> iterator;
typedef ListHashSetConstIterator<ValueArg, HashArg> const_iterator;
typedef ListHashSetNode<ValueArg> Node;
typedef ValueArg ValueType;
friend class ListHashSet<ValueArg, HashArg>;
friend class ListHashSetIterator<ValueArg, HashArg>;
ListHashSetConstIterator(const ListHashSetType* set, Node* position)
: m_set(set)
, m_position(position)
{
}
public:
typedef ptrdiff_t difference_type;
typedef const ValueType value_type;
typedef const ValueType* pointer;
typedef const ValueType& reference;
typedef std::bidirectional_iterator_tag iterator_category;
ListHashSetConstIterator()
{
}
const ValueType* get() const
{
return std::addressof(m_position->m_value);
}
const ValueType& operator*() const { return *get(); }
const ValueType* operator->() const { return get(); }
const_iterator& operator++()
{
ASSERT(m_position);
m_position = m_position->m_next;
return *this;
}
// postfix ++ intentionally omitted
const_iterator& operator--()
{
ASSERT(m_position != m_set->m_head);
if (!m_position)
m_position = m_set->m_tail;
else
m_position = m_position->m_prev;
return *this;
}
// postfix -- intentionally omitted
// Comparison.
bool operator==(const const_iterator& other) const
{
return m_position == other.m_position;
}
bool operator!=(const const_iterator& other) const
{
return m_position != other.m_position;
}
private:
Node* node() { return m_position; }
const ListHashSetType* m_set;
Node* m_position;
};
template<typename HashFunctions>
struct ListHashSetTranslator {
template<typename T> static unsigned hash(const T& key) { return HashFunctions::hash(key); }
template<typename T, typename U> static bool equal(const T& a, const U& b) { return HashFunctions::equal(a->m_value, b); }
template<typename T, typename U, typename V> static void translate(T*& location, U&& key, V&&)
{
location = new T(std::forward<U>(key));
}
};
template<typename T, typename U>
inline ListHashSet<T, U>::ListHashSet(const ListHashSet& other)
{
for (auto it = other.begin(), end = other.end(); it != end; ++it)
add(*it);
}
template<typename T, typename U>
inline ListHashSet<T, U>& ListHashSet<T, U>::operator=(const ListHashSet& other)
{
ListHashSet tmp(other);
swap(tmp);
return *this;
}
template<typename T, typename U>
inline ListHashSet<T, U>::ListHashSet(ListHashSet&& other)
: m_impl(WTFMove(other.m_impl))
, m_head(std::exchange(other.m_head, nullptr))
, m_tail(std::exchange(other.m_tail, nullptr))
{
}
template<typename T, typename U>
inline ListHashSet<T, U>& ListHashSet<T, U>::operator=(ListHashSet&& other)
{
m_impl = WTFMove(other.m_impl);
m_head = std::exchange(other.m_head, nullptr);
m_tail = std::exchange(other.m_tail, nullptr);
return *this;
}
template<typename T, typename U>
inline void ListHashSet<T, U>::swap(ListHashSet& other)
{
m_impl.swap(other.m_impl);
std::swap(m_head, other.m_head);
std::swap(m_tail, other.m_tail);
}
template<typename T, typename U>
inline ListHashSet<T, U>::~ListHashSet()
{
deleteAllNodes();
}
template<typename T, typename U>
inline unsigned ListHashSet<T, U>::size() const
{
return m_impl.size();
}
template<typename T, typename U>
inline unsigned ListHashSet<T, U>::capacity() const
{
return m_impl.capacity();
}
template<typename T, typename U>
inline bool ListHashSet<T, U>::isEmpty() const
{
return m_impl.isEmpty();
}
template<typename T, typename U>
inline T& ListHashSet<T, U>::first()
{
ASSERT(!isEmpty());
return m_head->m_value;
}
template<typename T, typename U>
inline void ListHashSet<T, U>::removeFirst()
{
takeFirst();
}
template<typename T, typename U>
inline T ListHashSet<T, U>::takeFirst()
{
ASSERT(!isEmpty());
auto it = m_impl.find(m_head);
T result = WTFMove((*it)->m_value);
m_impl.remove(it);
unlinkAndDelete(m_head);
return result;
}
template<typename T, typename U>
inline const T& ListHashSet<T, U>::first() const
{
ASSERT(!isEmpty());
return m_head->m_value;
}
template<typename T, typename U>
inline T& ListHashSet<T, U>::last()
{
ASSERT(!isEmpty());
return m_tail->m_value;
}
template<typename T, typename U>
inline const T& ListHashSet<T, U>::last() const
{
ASSERT(!isEmpty());
return m_tail->m_value;
}
template<typename T, typename U>
inline void ListHashSet<T, U>::removeLast()
{
takeLast();
}
template<typename T, typename U>
inline T ListHashSet<T, U>::takeLast()
{
ASSERT(!isEmpty());
auto it = m_impl.find(m_tail);
T result = WTFMove((*it)->m_value);
m_impl.remove(it);
unlinkAndDelete(m_tail);
return result;
}
template<typename T, typename U>
inline auto ListHashSet<T, U>::find(const ValueType& value) -> iterator
{
auto it = m_impl.template find<BaseTranslator>(value);
if (it == m_impl.end())
return end();
return makeIterator(*it);
}
template<typename T, typename U>
inline auto ListHashSet<T, U>::find(const ValueType& value) const -> const_iterator
{
auto it = m_impl.template find<BaseTranslator>(value);
if (it == m_impl.end())
return end();
return makeConstIterator(*it);
}
template<typename Translator>
struct ListHashSetTranslatorAdapter {
template<typename T> static unsigned hash(const T& key) { return Translator::hash(key); }
template<typename T, typename U> static bool equal(const T& a, const U& b) { return Translator::equal(a->m_value, b); }
};
template<typename ValueType, typename U>
template<typename T, typename HashTranslator>
inline auto ListHashSet<ValueType, U>::find(const T& value) -> iterator
{
auto it = m_impl.template find<ListHashSetTranslatorAdapter<HashTranslator>>(value);
if (it == m_impl.end())
return end();
return makeIterator(*it);
}
template<typename ValueType, typename U>
template<typename T, typename HashTranslator>
inline auto ListHashSet<ValueType, U>::find(const T& value) const -> const_iterator
{
auto it = m_impl.template find<ListHashSetTranslatorAdapter<HashTranslator>>(value);
if (it == m_impl.end())
return end();
return makeConstIterator(*it);
}
template<typename ValueType, typename U>
template<typename T, typename HashTranslator>
inline bool ListHashSet<ValueType, U>::contains(const T& value) const
{
return m_impl.template contains<ListHashSetTranslatorAdapter<HashTranslator>>(value);
}
template<typename T, typename U>
inline bool ListHashSet<T, U>::contains(const ValueType& value) const
{
return m_impl.template contains<BaseTranslator>(value);
}
template<typename T, typename U>
auto ListHashSet<T, U>::add(const ValueType& value) -> AddResult
{
auto result = m_impl.template add<BaseTranslator>(value, nullptr);
if (result.isNewEntry)
appendNode(*result.iterator);
return AddResult(makeIterator(*result.iterator), result.isNewEntry);
}
template<typename T, typename U>
auto ListHashSet<T, U>::add(ValueType&& value) -> AddResult
{
auto result = m_impl.template add<BaseTranslator>(WTFMove(value), nullptr);
if (result.isNewEntry)
appendNode(*result.iterator);
return AddResult(makeIterator(*result.iterator), result.isNewEntry);
}
template<typename T, typename U>
auto ListHashSet<T, U>::appendOrMoveToLast(const ValueType& value) -> AddResult
{
auto result = m_impl.template add<BaseTranslator>(value, nullptr);
Node* node = *result.iterator;
if (!result.isNewEntry)
unlink(node);
appendNode(node);
return AddResult(makeIterator(*result.iterator), result.isNewEntry);
}
template<typename T, typename U>
auto ListHashSet<T, U>::appendOrMoveToLast(ValueType&& value) -> AddResult
{
auto result = m_impl.template add<BaseTranslator>(WTFMove(value), nullptr);
Node* node = *result.iterator;
if (!result.isNewEntry)
unlink(node);
appendNode(node);
return AddResult(makeIterator(*result.iterator), result.isNewEntry);
}
template<typename T, typename U>
auto ListHashSet<T, U>::prependOrMoveToFirst(const ValueType& value) -> AddResult
{
auto result = m_impl.template add<BaseTranslator>(value, nullptr);
Node* node = *result.iterator;
if (!result.isNewEntry)
unlink(node);
prependNode(node);
return AddResult(makeIterator(*result.iterator), result.isNewEntry);
}
template<typename T, typename U>
auto ListHashSet<T, U>::prependOrMoveToFirst(ValueType&& value) -> AddResult
{
auto result = m_impl.template add<BaseTranslator>(WTFMove(value), nullptr);
Node* node = *result.iterator;
if (!result.isNewEntry)
unlink(node);
prependNode(node);
return AddResult(makeIterator(*result.iterator), result.isNewEntry);
}
template<typename T, typename U>
auto ListHashSet<T, U>::insertBefore(const ValueType& beforeValue, const ValueType& newValue) -> AddResult
{
return insertBefore(find(beforeValue), newValue);
}
template<typename T, typename U>
auto ListHashSet<T, U>::insertBefore(const ValueType& beforeValue, ValueType&& newValue) -> AddResult
{
return insertBefore(find(beforeValue), WTFMove(newValue));
}
template<typename T, typename U>
auto ListHashSet<T, U>::insertBefore(iterator it, const ValueType& newValue) -> AddResult
{
auto result = m_impl.template add<BaseTranslator>(newValue, nullptr);
if (result.isNewEntry)
insertNodeBefore(it.node(), *result.iterator);
return AddResult(makeIterator(*result.iterator), result.isNewEntry);
}
template<typename T, typename U>
auto ListHashSet<T, U>::insertBefore(iterator it, ValueType&& newValue) -> AddResult
{
auto result = m_impl.template add<BaseTranslator>(WTFMove(newValue), nullptr);
if (result.isNewEntry)
insertNodeBefore(it.node(), *result.iterator);
return AddResult(makeIterator(*result.iterator), result.isNewEntry);
}
template<typename T, typename U>
inline bool ListHashSet<T, U>::remove(iterator it)
{
if (it == end())
return false;
m_impl.remove(it.node());
unlinkAndDelete(it.node());
return true;
}
template<typename T, typename U>
inline bool ListHashSet<T, U>::remove(const ValueType& value)
{
return remove(find(value));
}
template<typename T, typename U>
inline void ListHashSet<T, U>::clear()
{
deleteAllNodes();
m_impl.clear();
m_head = nullptr;
m_tail = nullptr;
}
template<typename T, typename U>
void ListHashSet<T, U>::unlink(Node* node)
{
if (!node->m_prev) {
ASSERT(node == m_head);
m_head = node->m_next;
} else {
ASSERT(node != m_head);
node->m_prev->m_next = node->m_next;
}
if (!node->m_next) {
ASSERT(node == m_tail);
m_tail = node->m_prev;
} else {
ASSERT(node != m_tail);
node->m_next->m_prev = node->m_prev;
}
}
template<typename T, typename U>
void ListHashSet<T, U>::unlinkAndDelete(Node* node)
{
unlink(node);
delete node;
}
template<typename T, typename U>
void ListHashSet<T, U>::appendNode(Node* node)
{
node->m_prev = m_tail;
node->m_next = nullptr;
if (m_tail) {
ASSERT(m_head);
m_tail->m_next = node;
} else {
ASSERT(!m_head);
m_head = node;
}
m_tail = node;
}
template<typename T, typename U>
void ListHashSet<T, U>::prependNode(Node* node)
{
node->m_prev = nullptr;
node->m_next = m_head;
if (m_head)
m_head->m_prev = node;
else
m_tail = node;
m_head = node;
}
template<typename T, typename U>
void ListHashSet<T, U>::insertNodeBefore(Node* beforeNode, Node* newNode)
{
if (!beforeNode)
return appendNode(newNode);
newNode->m_next = beforeNode;
newNode->m_prev = beforeNode->m_prev;
if (beforeNode->m_prev)
beforeNode->m_prev->m_next = newNode;
beforeNode->m_prev = newNode;
if (!newNode->m_prev)
m_head = newNode;
}
template<typename T, typename U>
void ListHashSet<T, U>::deleteAllNodes()
{
if (!m_head)
return;
for (Node* node = m_head, *next = m_head->m_next; node; node = next, next = node ? node->m_next : nullptr)
delete node;
}
template<typename T, typename U>
inline auto ListHashSet<T, U>::makeIterator(Node* position) -> iterator
{
return iterator(this, position);
}
template<typename T, typename U>
inline auto ListHashSet<T, U>::makeConstIterator(Node* position) const -> const_iterator
{
return const_iterator(this, position);
}
} // namespace WTF
using WTF::ListHashSet;

370
include/Liveness.h Normal file
View File

@ -0,0 +1,370 @@
/*
* Copyright (C) 2015-2017 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. ``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
* 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 <wtf/BitVector.h>
#include <wtf/IndexSparseSet.h>
#include <wtf/StdLibExtras.h>
namespace WTF {
// HEADS UP: The algorithm here is duplicated in AirRegLiveness.h. That one uses sets rather
// than fancy vectors, because that's better for register liveness analysis.
template<typename Adapter>
class Liveness : public Adapter {
public:
typedef typename Adapter::CFG CFG;
typedef typename Adapter::Thing Thing;
typedef Vector<unsigned, 4, UnsafeVectorOverflow> IndexVector;
typedef IndexSparseSet<unsigned, DefaultIndexSparseSetTraits<unsigned>, UnsafeVectorOverflow> Workset;
template<typename... Arguments>
Liveness(CFG& cfg, Arguments&&... arguments)
: Adapter(std::forward<Arguments>(arguments)...)
, m_cfg(cfg)
, m_workset(Adapter::numIndices())
, m_liveAtHead(cfg.template newMap<IndexVector>())
, m_liveAtTail(cfg.template newMap<IndexVector>())
{
}
// This calculator has to be run in reverse.
class LocalCalc {
public:
LocalCalc(Liveness& liveness, typename CFG::Node block)
: m_liveness(liveness)
, m_block(block)
{
auto& workset = liveness.m_workset;
workset.clear();
IndexVector& liveAtTail = liveness.m_liveAtTail[block];
for (unsigned index : liveAtTail)
workset.add(index);
}
class Iterable {
public:
Iterable(Liveness& liveness)
: m_liveness(liveness)
{
}
class iterator {
public:
iterator(Adapter& adapter, Workset::const_iterator sparceSetIterator)
: m_adapter(adapter)
, m_sparceSetIterator(sparceSetIterator)
{
}
iterator& operator++()
{
++m_sparceSetIterator;
return *this;
}
typename Adapter::Thing operator*() const
{
return m_adapter.indexToValue(*m_sparceSetIterator);
}
bool operator==(const iterator& other) { return m_sparceSetIterator == other.m_sparceSetIterator; }
bool operator!=(const iterator& other) { return m_sparceSetIterator != other.m_sparceSetIterator; }
private:
Adapter& m_adapter;
Workset::const_iterator m_sparceSetIterator;
};
iterator begin() const { return iterator(m_liveness, m_liveness.m_workset.begin()); }
iterator end() const { return iterator(m_liveness, m_liveness.m_workset.end()); }
bool contains(const typename Adapter::Thing& thing) const
{
return m_liveness.m_workset.contains(m_liveness.valueToIndex(thing));
}
private:
Liveness& m_liveness;
};
Iterable live() const
{
return Iterable(m_liveness);
}
bool isLive(const typename Adapter::Thing& thing) const
{
return live().contains(thing);
}
void execute(unsigned instIndex)
{
auto& workset = m_liveness.m_workset;
// Want an easy example to help you visualize how this works?
// Check out B3VariableLiveness.h.
//
// Want a hard example to help you understand the hard cases?
// Check out AirLiveness.h.
m_liveness.forEachDef(
m_block, instIndex + 1,
[&] (unsigned index) {
workset.remove(index);
});
m_liveness.forEachUse(
m_block, instIndex,
[&] (unsigned index) {
workset.add(index);
});
}
private:
Liveness& m_liveness;
typename CFG::Node m_block;
};
const IndexVector& rawLiveAtHead(typename CFG::Node block)
{
return m_liveAtHead[block];
}
template<typename UnderlyingIterable>
class Iterable {
public:
Iterable(Liveness& liveness, const UnderlyingIterable& iterable)
: m_liveness(liveness)
, m_iterable(iterable)
{
}
class iterator {
public:
iterator()
: m_liveness(nullptr)
, m_iter()
{
}
iterator(Liveness& liveness, typename UnderlyingIterable::const_iterator iter)
: m_liveness(&liveness)
, m_iter(iter)
{
}
typename Adapter::Thing operator*()
{
return m_liveness->indexToValue(*m_iter);
}
iterator& operator++()
{
++m_iter;
return *this;
}
bool operator==(const iterator& other) const
{
ASSERT(m_liveness == other.m_liveness);
return m_iter == other.m_iter;
}
bool operator!=(const iterator& other) const
{
return !(*this == other);
}
private:
Liveness* m_liveness;
typename UnderlyingIterable::const_iterator m_iter;
};
iterator begin() const { return iterator(m_liveness, m_iterable.begin()); }
iterator end() const { return iterator(m_liveness, m_iterable.end()); }
bool contains(const typename Adapter::Thing& thing) const
{
return m_liveness.m_workset.contains(m_liveness.valueToIndex(thing));
}
private:
Liveness& m_liveness;
const UnderlyingIterable& m_iterable;
};
Iterable<IndexVector> liveAtHead(typename CFG::Node block)
{
return Iterable<IndexVector>(*this, m_liveAtHead[block]);
}
Iterable<IndexVector> liveAtTail(typename CFG::Node block)
{
return Iterable<IndexVector>(*this, m_liveAtTail[block]);
}
Workset& workset() { return m_workset; }
class LiveAtHead {
public:
LiveAtHead(Liveness& liveness)
: m_liveness(liveness)
{
for (unsigned blockIndex = m_liveness.m_cfg.numNodes(); blockIndex--;) {
typename CFG::Node block = m_liveness.m_cfg.node(blockIndex);
if (!block)
continue;
std::sort(m_liveness.m_liveAtHead[block].begin(), m_liveness.m_liveAtHead[block].end());
}
}
bool isLiveAtHead(typename CFG::Node block, const typename Adapter::Thing& thing)
{
return !!tryBinarySearch<unsigned>(m_liveness.m_liveAtHead[block], m_liveness.m_liveAtHead[block].size(), m_liveness.valueToIndex(thing), [] (unsigned* value) { return *value; });
}
private:
Liveness& m_liveness;
};
LiveAtHead liveAtHead() { return LiveAtHead(*this); }
protected:
void compute()
{
Adapter::prepareToCompute();
// The liveAtTail of each block automatically contains the LateUse's of the terminal.
for (unsigned blockIndex = m_cfg.numNodes(); blockIndex--;) {
typename CFG::Node block = m_cfg.node(blockIndex);
if (!block)
continue;
IndexVector& liveAtTail = m_liveAtTail[block];
Adapter::forEachUse(
block, Adapter::blockSize(block),
[&] (unsigned index) {
liveAtTail.append(index);
});
std::sort(liveAtTail.begin(), liveAtTail.end());
removeRepeatedElements(liveAtTail);
}
// Blocks with new live values at tail.
BitVector dirtyBlocks;
for (size_t blockIndex = m_cfg.numNodes(); blockIndex--;)
dirtyBlocks.set(blockIndex);
IndexVector mergeBuffer;
bool changed;
do {
changed = false;
for (size_t blockIndex = m_cfg.numNodes(); blockIndex--;) {
typename CFG::Node block = m_cfg.node(blockIndex);
if (!block)
continue;
if (!dirtyBlocks.quickClear(blockIndex))
continue;
LocalCalc localCalc(*this, block);
for (size_t instIndex = Adapter::blockSize(block); instIndex--;)
localCalc.execute(instIndex);
// Handle the early def's of the first instruction.
Adapter::forEachDef(
block, 0,
[&] (unsigned index) {
m_workset.remove(index);
});
IndexVector& liveAtHead = m_liveAtHead[block];
// We only care about Tmps that were discovered in this iteration. It is impossible
// to remove a live value from the head.
// We remove all the values we already knew about so that we only have to deal with
// what is new in LiveAtHead.
if (m_workset.size() == liveAtHead.size())
m_workset.clear();
else {
for (unsigned liveIndexAtHead : liveAtHead)
m_workset.remove(liveIndexAtHead);
}
if (m_workset.isEmpty())
continue;
liveAtHead.reserveCapacity(liveAtHead.size() + m_workset.size());
for (unsigned newValue : m_workset)
liveAtHead.uncheckedAppend(newValue);
m_workset.sort();
for (typename CFG::Node predecessor : m_cfg.predecessors(block)) {
IndexVector& liveAtTail = m_liveAtTail[predecessor];
if (liveAtTail.isEmpty())
liveAtTail = m_workset.values();
else {
mergeBuffer.resize(liveAtTail.size() + m_workset.size());
auto iter = mergeDeduplicatedSorted(
liveAtTail.begin(), liveAtTail.end(),
m_workset.begin(), m_workset.end(),
mergeBuffer.begin());
mergeBuffer.resize(iter - mergeBuffer.begin());
if (mergeBuffer.size() == liveAtTail.size())
continue;
RELEASE_ASSERT(mergeBuffer.size() > liveAtTail.size());
liveAtTail = mergeBuffer;
}
dirtyBlocks.quickSet(predecessor->index());
changed = true;
}
}
} while (changed);
}
private:
friend class LocalCalc;
friend class LocalCalc::Iterable;
CFG& m_cfg;
Workset m_workset;
typename CFG::template Map<IndexVector> m_liveAtHead;
typename CFG::template Map<IndexVector> m_liveAtTail;
};
} // namespace WTF

153
include/Lock.h Normal file
View File

@ -0,0 +1,153 @@
/*
* Copyright (C) 2015-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. ``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
* 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.
*/
#ifndef WTF_Lock_h
#define WTF_Lock_h
#include <wtf/LockAlgorithm.h>
#include <wtf/Locker.h>
#include <wtf/Noncopyable.h>
namespace TestWebKitAPI {
struct LockInspector;
};
namespace WTF {
typedef LockAlgorithm<uint8_t, 1, 2> DefaultLockAlgorithm;
// This is a fully adaptive mutex that only requires 1 byte of storage. It has fast paths that are
// competetive to a spinlock (uncontended locking is inlined and is just a CAS, microcontention is
// handled by spinning and yielding), and a slow path that is competetive to std::mutex (if a lock
// cannot be acquired in a short period of time, the thread is put to sleep until the lock is
// available again). It uses less memory than a std::mutex. This lock guarantees eventual stochastic
// fairness, even in programs that relock the lock immediately after unlocking it. Except when there
// are collisions between this lock and other locks in the ParkingLot, this lock will guarantee that
// at worst one call to unlock() per millisecond will do a direct hand-off to the thread that is at
// the head of the queue. When there are collisions, each collision increases the fair unlock delay
// by one millisecond in the worst case.
// This is a struct without a constructor or destructor so that it can be statically initialized.
// Use Lock in instance variables.
struct LockBase {
void lock()
{
if (UNLIKELY(!DefaultLockAlgorithm::lockFastAssumingZero(m_byte)))
lockSlow();
}
bool tryLock()
{
return DefaultLockAlgorithm::tryLock(m_byte);
}
// Need this version for std::unique_lock.
bool try_lock()
{
return tryLock();
}
// Relinquish the lock. Either one of the threads that were waiting for the lock, or some other
// thread that happens to be running, will be able to grab the lock. This bit of unfairness is
// called barging, and we allow it because it maximizes throughput. However, we bound how unfair
// barging can get by ensuring that every once in a while, when there is a thread waiting on the
// lock, we hand the lock to that thread directly. Every time unlock() finds a thread waiting,
// we check if the last time that we did a fair unlock was more than roughly 1ms ago; if so, we
// unlock fairly. Fairness matters most for long critical sections, and this virtually
// guarantees that long critical sections always get a fair lock.
void unlock()
{
if (UNLIKELY(!DefaultLockAlgorithm::unlockFastAssumingZero(m_byte)))
unlockSlow();
}
// This is like unlock() but it guarantees that we unlock the lock fairly. For short critical
// sections, this is much slower than unlock(). For long critical sections, unlock() will learn
// to be fair anyway. However, if you plan to relock the lock right after unlocking and you want
// to ensure that some other thread runs in the meantime, this is probably the function you
// want.
void unlockFairly()
{
if (UNLIKELY(!DefaultLockAlgorithm::unlockFastAssumingZero(m_byte)))
unlockFairlySlow();
}
void safepoint()
{
if (UNLIKELY(!DefaultLockAlgorithm::safepointFast(m_byte)))
safepointSlow();
}
bool isHeld() const
{
return DefaultLockAlgorithm::isLocked(m_byte);
}
bool isLocked() const
{
return isHeld();
}
protected:
friend struct TestWebKitAPI::LockInspector;
static const uint8_t isHeldBit = 1;
static const uint8_t hasParkedBit = 2;
WTF_EXPORT_PRIVATE void lockSlow();
WTF_EXPORT_PRIVATE void unlockSlow();
WTF_EXPORT_PRIVATE void unlockFairlySlow();
WTF_EXPORT_PRIVATE void safepointSlow();
// Method used for testing only.
bool isFullyReset() const
{
return !m_byte.load();
}
Atomic<uint8_t> m_byte;
};
class Lock : public LockBase {
WTF_MAKE_NONCOPYABLE(Lock);
WTF_MAKE_FAST_ALLOCATED;
public:
Lock()
{
m_byte.store(0, std::memory_order_relaxed);
}
};
typedef LockBase StaticLock;
typedef Locker<LockBase> LockHolder;
} // namespace WTF
using WTF::Lock;
using WTF::LockHolder;
using WTF::StaticLock;
#endif // WTF_Lock_h

247
include/LockAlgorithm.h Normal file
View File

@ -0,0 +1,247 @@
/*
* Copyright (C) 2015-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. ``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
* 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.
*/
#ifndef WTF_LockAlgorithm_h
#define WTF_LockAlgorithm_h
#include <thread>
#include <wtf/Atomics.h>
#include <wtf/Compiler.h>
#include <wtf/ParkingLot.h>
namespace WTF {
// This is the algorithm used by WTF::Lock. You can use it to project one lock onto any atomic
// field. The limit of one lock is due to the use of the field's address as a key to find the lock's
// queue.
template<typename LockType, LockType isHeldBit, LockType hasParkedBit>
class LockAlgorithm {
static const bool verbose = false;
static const LockType mask = isHeldBit | hasParkedBit;
public:
static bool lockFastAssumingZero(Atomic<LockType>& lock)
{
return lock.compareExchangeWeak(0, isHeldBit, std::memory_order_acquire);
}
static bool lockFast(Atomic<LockType>& lock)
{
return lock.transaction(
[&] (LockType& value) -> bool {
if (value & isHeldBit)
return false;
value |= isHeldBit;
return true;
},
std::memory_order_acquire);
}
static void lock(Atomic<LockType>& lock)
{
if (UNLIKELY(!lockFast(lock)))
lockSlow(lock);
}
static bool tryLock(Atomic<LockType>& lock)
{
for (;;) {
uint8_t currentByteValue = lock.load(std::memory_order_relaxed);
if (currentByteValue & isHeldBit)
return false;
if (lock.compareExchangeWeak(currentByteValue, currentByteValue | isHeldBit, std::memory_order_acquire))
return true;
}
}
static bool unlockFastAssumingZero(Atomic<LockType>& lock)
{
return lock.compareExchangeWeak(isHeldBit, 0, std::memory_order_release);
}
static bool unlockFast(Atomic<LockType>& lock)
{
return lock.transaction(
[&] (LockType& value) -> bool {
if ((value & mask) != isHeldBit)
return false;
value &= ~isHeldBit;
return true;
},
std::memory_order_relaxed);
}
static void unlock(Atomic<LockType>& lock)
{
if (UNLIKELY(!unlockFast(lock)))
unlockSlow(lock, Unfair);
}
static void unlockFairly(Atomic<LockType>& lock)
{
if (UNLIKELY(!unlockFast(lock)))
unlockSlow(lock, Fair);
}
static bool safepointFast(const Atomic<LockType>& lock)
{
WTF::compilerFence();
return !(lock.load(std::memory_order_relaxed) & hasParkedBit);
}
static void safepoint(Atomic<LockType>& lock)
{
if (UNLIKELY(!safepointFast(lock)))
safepointSlow(lock);
}
static bool isLocked(const Atomic<LockType>& lock)
{
return lock.load(std::memory_order_acquire) & isHeldBit;
}
NEVER_INLINE static void lockSlow(Atomic<LockType>& lock)
{
unsigned spinCount = 0;
// This magic number turns out to be optimal based on past JikesRVM experiments.
const unsigned spinLimit = 40;
for (;;) {
uint8_t currentByteValue = lock.load();
// We allow ourselves to barge in.
if (!(currentByteValue & isHeldBit)
&& lock.compareExchangeWeak(currentByteValue, currentByteValue | isHeldBit))
return;
// If there is nobody parked and we haven't spun too much, we can just try to spin around.
if (!(currentByteValue & hasParkedBit) && spinCount < spinLimit) {
spinCount++;
std::this_thread::yield();
continue;
}
// Need to park. We do this by setting the parked bit first, and then parking. We spin around
// if the parked bit wasn't set and we failed at setting it.
if (!(currentByteValue & hasParkedBit)
&& !lock.compareExchangeWeak(currentByteValue, currentByteValue | hasParkedBit))
continue;
// We now expect the value to be isHeld|hasParked. So long as that's the case, we can park.
ParkingLot::ParkResult parkResult =
ParkingLot::compareAndPark(&lock, currentByteValue | isHeldBit | hasParkedBit);
if (parkResult.wasUnparked) {
switch (static_cast<Token>(parkResult.token)) {
case DirectHandoff:
// The lock was never released. It was handed to us directly by the thread that did
// unlock(). This means we're done!
RELEASE_ASSERT(isLocked(lock));
return;
case BargingOpportunity:
// This is the common case. The thread that called unlock() has released the lock,
// and we have been woken up so that we may get an opportunity to grab the lock. But
// other threads may barge, so the best that we can do is loop around and try again.
break;
}
}
// We have awoken, or we never parked because the byte value changed. Either way, we loop
// around and try again.
}
}
enum Fairness {
Fair,
Unfair
};
NEVER_INLINE static void unlockSlow(Atomic<LockType>& lock, Fairness fairness)
{
// We could get here because the weak CAS in unlock() failed spuriously, or because there is
// someone parked. So, we need a CAS loop: even if right now the lock is just held, it could
// be held and parked if someone attempts to lock just as we are unlocking.
for (;;) {
uint8_t oldByteValue = lock.load();
RELEASE_ASSERT(
(oldByteValue & mask) == isHeldBit
|| (oldByteValue & mask) == (isHeldBit | hasParkedBit));
if ((oldByteValue & mask) == isHeldBit) {
if (lock.compareExchangeWeak(oldByteValue, oldByteValue & ~isHeldBit))
return;
continue;
}
// Someone is parked. Unpark exactly one thread. We may hand the lock to that thread
// directly, or we will unlock the lock at the same time as we unpark to allow for barging.
// When we unlock, we may leave the parked bit set if there is a chance that there are still
// other threads parked.
ASSERT((oldByteValue & mask) == (isHeldBit | hasParkedBit));
ParkingLot::unparkOne(
&lock,
[&] (ParkingLot::UnparkResult result) -> intptr_t {
// We are the only ones that can clear either the isHeldBit or the hasParkedBit,
// so we should still see both bits set right now.
ASSERT((lock.load() & mask) == (isHeldBit | hasParkedBit));
if (result.didUnparkThread && (fairness == Fair || result.timeToBeFair)) {
// We don't unlock anything. Instead, we hand the lock to the thread that was
// waiting.
return DirectHandoff;
}
lock.transaction(
[&] (LockType& value) -> bool {
value &= ~mask;
if (result.mayHaveMoreThreads)
value |= hasParkedBit;
return true;
});
return BargingOpportunity;
});
return;
}
}
NEVER_INLINE static void safepointSlow(Atomic<LockType>& lockWord)
{
unlockFairly(lockWord);
lock(lockWord);
}
private:
enum Token {
BargingOpportunity,
DirectHandoff
};
};
} // namespace WTF
using WTF::LockAlgorithm;
#endif // WTF_LockAlgorithm_h

View File

@ -0,0 +1,58 @@
/*
* 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. ``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
* 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 <wtf/PrintStream.h>
#include <wtf/RecursiveLockAdapter.h>
#include <wtf/WordLock.h>
namespace WTF {
// Makes every call to print() atomic.
class LockedPrintStream : public PrintStream {
public:
LockedPrintStream(std::unique_ptr<PrintStream> target);
virtual ~LockedPrintStream();
void vprintf(const char* format, va_list) override WTF_ATTRIBUTE_PRINTF(2, 0);
void flush() override;
protected:
PrintStream& begin() override;
void end() override;
private:
// This needs to be a recursive lock because a printInternal or dump method could assert,
// and that assert might want to log. Better to let it. This needs to be a WordLock so that
// LockedPrintStream (i.e. cataLog) can be used to debug ParkingLot and Lock.
RecursiveLockAdapter<WordLock> m_lock;
std::unique_ptr<PrintStream> m_target;
};
} // namespace WTF
using WTF::LockedPrintStream;

138
include/Locker.h Normal file
View File

@ -0,0 +1,138 @@
/*
* Copyright (C) 2008, 2013, 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.
* 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE 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 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.
*/
#ifndef Locker_h
#define Locker_h
#include <wtf/Assertions.h>
#include <wtf/Noncopyable.h>
namespace WTF {
enum NoLockingNecessaryTag { NoLockingNecessary };
class AbstractLocker {
WTF_MAKE_NONCOPYABLE(AbstractLocker);
public:
AbstractLocker(NoLockingNecessaryTag)
{
}
protected:
AbstractLocker()
{
}
};
template <typename T> class Locker : public AbstractLocker {
public:
explicit Locker(T& lockable) : m_lockable(&lockable) { lock(); }
explicit Locker(T* lockable) : m_lockable(lockable) { lock(); }
// You should be wary of using this constructor. It's only applicable
// in places where there is a locking protocol for a particular object
// but it's not necessary to engage in that protocol yet. For example,
// this often happens when an object is newly allocated and it can not
// be accessed concurrently.
Locker(NoLockingNecessaryTag) : m_lockable(nullptr) { }
Locker(int) = delete;
~Locker()
{
if (m_lockable)
m_lockable->unlock();
}
static Locker tryLock(T& lockable)
{
Locker result(NoLockingNecessary);
if (lockable.tryLock()) {
result.m_lockable = &lockable;
return result;
}
return result;
}
explicit operator bool() const { return !!m_lockable; }
void unlockEarly()
{
m_lockable->unlock();
m_lockable = 0;
}
// It's great to be able to pass lockers around. It enables custom locking adaptors like
// JSC::LockDuringMarking.
Locker(Locker&& other)
: m_lockable(other.m_lockable)
{
other.m_lockable = nullptr;
}
Locker& operator=(Locker&& other)
{
if (m_lockable)
m_lockable->unlock();
m_lockable = other.m_lockable;
other.m_lockable = nullptr;
return *this;
}
private:
void lock()
{
if (m_lockable)
m_lockable->lock();
}
T* m_lockable;
};
// Use this lock scope like so:
// auto locker = holdLock(lock);
template<typename LockType>
Locker<LockType> holdLock(LockType& lock)
{
return Locker<LockType>(lock);
}
template<typename LockType>
Locker<LockType> tryHoldLock(LockType& lock)
{
return Locker<LockType>::tryLock(lock);
}
}
using WTF::AbstractLocker;
using WTF::Locker;
using WTF::NoLockingNecessaryTag;
using WTF::NoLockingNecessary;
using WTF::holdLock;
#endif

111
include/LocklessBag.h Normal file
View File

@ -0,0 +1,111 @@
/*
* Copyright (C) 2017 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. ``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
* 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 <wtf/Atomics.h>
#include <wtf/Noncopyable.h>
namespace WTF {
// This a simple single consumer, multiple producer Bag data structure.
template<typename T>
class LocklessBag {
WTF_MAKE_NONCOPYABLE(LocklessBag);
public:
struct Node {
WTF_MAKE_FAST_ALLOCATED;
public:
T data;
Node* next;
};
LocklessBag()
: m_head(nullptr)
{
}
enum PushResult { Empty, NonEmpty };
PushResult add(T&& element)
{
Node* newNode = new Node();
newNode->data = std::forward<T>(element);
Node* oldHead;
m_head.transaction([&] (Node*& head) {
oldHead = head;
newNode->next = head;
head = newNode;
return true;
});
return oldHead == nullptr ? Empty : NonEmpty;
}
// CONSUMER FUNCTIONS: Everything below here is only safe to call from the consumer thread.
// This function is actually safe to call from more than one thread, but ONLY if no thread can call consumeAll.
template<typename Functor>
void iterate(const Functor& func)
{
Node* node = m_head.load();
while (node) {
const T& data = node->data;
func(data);
node = node->next;
}
}
template<typename Functor>
void consumeAll(const Functor& func)
{
consumeAllWithNode([&] (T&& data, Node* node) {
func(WTFMove(data));
delete node;
});
}
template<typename Functor>
void consumeAllWithNode(const Functor& func)
{
Node* node = m_head.exchange(nullptr);
while (node) {
Node* oldNode = node;
node = node->next;
func(WTFMove(oldNode->data), oldNode);
}
}
~LocklessBag()
{
consumeAll([] (T&&) { });
}
private:
Atomic<Node*> m_head;
};
} // namespace WTF

View File

@ -0,0 +1,38 @@
/*
* 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. ``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
* 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 <wtf/text/WTFString.h>
namespace WTF {
WTF_EXPORT_PRIVATE void resetAccumulatedLogs();
WTF_EXPORT_PRIVATE String getAndResetAccumulatedLogs();
} // namespace WTF
using WTF::resetAccumulatedLogs;
using WTF::getAndResetAccumulatedLogs;

52
include/LoggingHashID.h Normal file
View File

@ -0,0 +1,52 @@
/*
* Copyright (C) 2017 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. ``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
* 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 <wtf/GlobalVersion.h>
#include <wtf/Noncopyable.h>
#include <wtf/PrintStream.h>
namespace WTF {
class LoggingHashID {
WTF_MAKE_NONCOPYABLE(LoggingHashID);
public:
LoggingHashID()
: m_version(newGlobalVersion())
{
}
void dump(PrintStream& out) const
{
out.print("_", m_version);
}
private:
GlobalVersion m_version;
};
} // namespace WTF

308
include/LoggingHashMap.h Normal file
View File

@ -0,0 +1,308 @@
/*
* Copyright (C) 2017 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. ``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
* 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 <wtf/DataLog.h>
#include <wtf/HashMap.h>
#include <wtf/LoggingHashID.h>
#include <wtf/LoggingHashTraits.h>
namespace WTF {
template<
const char* typeArguments,
typename KeyArg, typename MappedArg, typename HashArg = typename DefaultHash<KeyArg>::Hash,
typename KeyTraitsArg = HashTraits<KeyArg>, typename MappedTraitsArg = HashTraits<MappedArg>,
typename LoggingKeyTraits = LoggingHashKeyTraits<KeyArg>,
typename LoggingValueTraits = LoggingHashValueTraits<MappedArg>>
class LoggingHashMap final {
WTF_MAKE_FAST_ALLOCATED;
public:
typedef WTF::HashMap<KeyArg, MappedArg, HashArg, KeyTraitsArg, MappedTraitsArg> HashMap;
typedef typename HashMap::KeyType KeyType;
typedef typename HashMap::MappedType MappedType;
typedef typename HashMap::KeyValuePairType KeyValuePairType;
typedef typename HashMap::iterator iterator;
typedef typename HashMap::const_iterator const_iterator;
typedef typename HashMap::AddResult AddResult;
LoggingHashMap()
{
dataLog("auto* ", m_id, " = new HashMap<", typeArguments, ">();\n");
}
~LoggingHashMap()
{
dataLog("delete ", m_id, ";\n");
}
LoggingHashMap(const LoggingHashMap& other)
: m_map(other.m_map)
{
dataLog("auto* ", m_id, " = new HashMap(*", other.m_id, ");");
}
LoggingHashMap(LoggingHashMap&& other)
: m_map(other.m_map)
{
dataLog("auto* ", m_id, " = new HashMap(WTFMove(*", other.m_id, "));");
}
LoggingHashMap& operator=(const LoggingHashMap& other)
{
dataLog("*", m_id, " = *", other.m_id, ";\n");
m_map = other.m_map;
}
LoggingHashMap& operator=(LoggingHashMap&& other)
{
dataLog("*", m_id, " = WTFMove(*", other.m_id, ");\n");
m_map = WTFMove(other.m_map);
}
void swap(LoggingHashMap& other)
{
dataLog(m_id, "->swap(*", RawPointer(&other), ");\n");
m_map.swap(other.m_map);
}
// A bunch of stuff does not get logged.
unsigned size() const { return m_map.size(); }
unsigned capacity() const { return m_map.capacity(); }
bool isEmpty() const { return m_map.isEmpty(); }
iterator begin() { return m_map.begin(); }
iterator end() { return m_map.end(); }
const_iterator begin() const { return m_map.begin(); }
const_iterator end() const { return m_map.end(); }
auto keys() { return m_map.keys(); }
const auto keys() const { return m_map.keys(); }
auto values() { return m_map.values(); }
const auto values() const { return m_map.values(); }
iterator find(const KeyType& key)
{
StringPrintStream string;
string.print("{\n");
string.print(" auto iter = ", m_id, "->find(");
LoggingKeyTraits::print(string, key);
string.print(");\n");
iterator result = m_map.find(key);
if (result == m_map.end())
string.print(" RELEASE_ASSERT(iter == ", m_id, "->end());\n");
else
string.print(" RELEASE_ASSERT(iter != ", m_id, "->end());\n");
string.print("}\n");
dataLog(string.toCString());
return result;
}
const_iterator find(const KeyType& key) const
{
StringPrintStream string;
string.print("{\n");
string.print(" auto iter = ", m_id, "->find(");
LoggingKeyTraits::print(string, key);
string.print(");\n");
const_iterator result = m_map.find(key);
if (result == m_map.end())
string.print(" RELEASE_ASSERT(iter == ", m_id, "->end());\n");
else
string.print(" RELEASE_ASSERT(iter != ", m_id, "->end());\n");
string.print("}\n");
dataLog(string.toCString());
return result;
}
bool contains(const KeyType& key) const
{
return find(key) != end();
}
MappedPeekType get(const KeyType& key) const
{
find(key);
return m_map.get(key);
}
MappedPeekType fastGet(const KeyType& key) const
{
find(key);
return m_map.fastGet(key);
}
template<typename PassedType>
AddResult set(const KeyType& key, PassedType&& passedValue)
{
StringPrintStream string;
string.print(m_id, "->set(");
LoggingKeyTraits::print(string, key);
string.print(", ");
LoggingValueTraits::print(string, passedValue);
string.print(");\n");
dataLog(string.toCString());
return set(key, std::forward<PassedType>(passedValue));
}
template<typename PassedType>
AddResult set(KeyType&& key, PassedType&& passedValue)
{
StringPrintStream string;
string.print(m_id, "->set(");
LoggingKeyTraits::print(string, key);
string.print(", ");
LoggingValueTraits::print(string, passedValue);
string.print(");\n");
dataLog(string.toCString());
return set(WTFMove(key), std::forward<PassedType>(passedValue));
}
template<typename PassedType>
AddResult add(const KeyType& key, PassedType&& passedValue)
{
StringPrintStream string;
string.print(m_id, "->add(");
LoggingKeyTraits::print(string, key);
string.print(", ");
LoggingValueTraits::print(string, passedValue);
string.print(");\n");
dataLog(string.toCString());
return add(key, std::forward<PassedType>(passedValue));
}
template<typename PassedType>
AddResult add(KeyType&& key, PassedType&& passedValue)
{
StringPrintStream string;
string.print(m_id, "->add(");
LoggingKeyTraits::print(string, key);
string.print(", ");
LoggingValueTraits::print(string, passedValue);
string.print(");\n");
dataLog(string.toCString());
return add(WTFMove(key), std::forward<PassedType>(passedValue));
}
template<typename PassedType>
AddResult fastAdd(const KeyType& key, PassedType&& passedValue)
{
return add(key, std::forward<PassedType>(passedValue));
}
template<typename PassedType>
AddResult fastAdd(KeyType&& key, PassedType&& passedValue)
{
return add(WTFMove(key), std::forward<PassedType>(passedValue));
}
template<typename Func>
AddResult ensure(const KeyType& key, Func&& func)
{
StringPrintStream string;
string.print(m_id, "->ensure(");
LoggingKeyTraits::print(string, key);
string.print(", ");
string.print("[] () { return ");
bool didCallFunctor = false;
auto result = m_map.ensure(
key,
[&] () {
didCallFunctor = true;
auto result = func();
LoggingValueTraits::print(string, result);
return result;
});
if (!didCallFunctor)
LoggingValueTraits::print(string, MappedTraitsArg::emptyValue());
string.print("; });\n");
dataLog(string.toCString());
return result;
}
template<typename Func>
AddResult ensure(KeyType&& key, Func&& func)
{
StringPrintStream string;
string.print(m_id, "->ensure(");
LoggingKeyTraits::print(string, key);
string.print(", ");
string.print("[] () { return ");
bool didCallFunctor = false;
auto result = m_map.ensure(
WTFMove(key),
[&] () {
didCallFunctor = true;
auto result = func();
LoggingValueTraits::print(string, result);
return result;
});
if (!didCallFunctor)
LoggingValueTraits::print(string, MappedTraitsArg::emptyValue());
string.print("; });\n");
dataLog(string.toCString());
return result;
}
bool remove(const KeyType& key)
{
StringPrintStream string;
string.print(m_id, "->remove(");
LoggingKeyTraits::print(string, key);
string.print(");\n");
dataLog(string.toCString());
return m_map.remove(key);
}
bool remove(iterator iter)
{
// FIXME: It would be nice if we could do better than this.
if (iter == end())
return false;
return remove(iter->key);
}
// FIXME: Implement removeIf().
void clear()
{
dataLog(m_id, "->clear();\n");
m_map.clear();
}
// FIXME: Implement the no-convert overloads.
private:
HashMap m_map;
LoggingHashID m_id;
};
} // namespace WTF
using WTF::LoggingHashMap;

248
include/LoggingHashSet.h Normal file
View File

@ -0,0 +1,248 @@
/*
* Copyright (C) 2017 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. ``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
* 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 <wtf/DataLog.h>
#include <wtf/HashSet.h>
#include <wtf/LoggingHashID.h>
#include <wtf/LoggingHashTraits.h>
namespace WTF {
template<
const char* typeArguments,
typename ValueArg, typename HashArg = typename DefaultHash<ValueArg>::Hash,
typename TraitsArg = HashTraits<ValueArg>,
typename LoggingTraits = LoggingHashKeyTraits<ValueArg>>
class LoggingHashSet final {
WTF_MAKE_FAST_ALLOCATED;
typedef TraitsArg ValueTraits;
typedef typename ValueTraits::TakeType TakeType;
public:
typedef WTF::HashSet<ValueArg, HashArg, TraitsArg> HashSet;
typedef typename HashSet::ValueType ValueType;
typedef typename HashSet::iterator iterator;
typedef typename HashSet::const_iterator const_iterator;
typedef typename HashSet::AddResult AddResult;
LoggingHashSet()
{
dataLog("auto* ", m_id, " = new HashSet<", typeArguments, ">();\n");
}
~LoggingHashSet()
{
dataLog("delete ", m_id, ";\n");
}
LoggingHashSet(const LoggingHashSet& other)
: m_set(other.m_set)
{
dataLog("auto* ", m_id, " = new HashSet<", typeArguments, ">(*", other.m_id, ");\n");
}
LoggingHashSet(LoggingHashSet&& other)
: m_set(other.m_set)
{
dataLog("auto* ", m_id, " = new HashSet<", typeArguments, ">(WTFMove(*", other.m_id, "));\n");
}
LoggingHashSet& operator=(const LoggingHashSet& other)
{
dataLog("*", m_id, " = *", other.m_id, ";\n");
m_set = other.m_set;
return *this;
}
LoggingHashSet& operator=(LoggingHashSet&& other)
{
dataLog("*", m_id, " = WTFMove(*", other.m_id, ");\n");
m_set = WTFMove(other.m_set);
return *this;
}
void swap(LoggingHashSet& other)
{
dataLog(m_id, "->swap(*", other.m_id, ");\n");
m_set.swap(other.m_set);
}
unsigned size() const { return m_set.size(); }
unsigned capacity() const { return m_set.capacity(); }
bool isEmpty() const { return m_set.isEmpty(); }
iterator begin() const { return m_set.begin(); }
iterator end() const { return m_set.end(); }
iterator find(const ValueType& value) const
{
StringPrintStream string;
string.print("{\n");
string.print(" auto iter = ", m_id, "->find(");
LoggingTraits::print(string, value);
string.print(");\n");
iterator result = m_set.find(value);
if (result == m_set.end())
string.print(" RELEASE_ASSERT(iter == ", m_id, "->end());\n");
else
string.print(" RELEASE_ASSERT(iter != ", m_id, "->end());\n");
string.print("}\n");
dataLog(string.toCString());
return result;
}
bool contains(const ValueType& value) const
{
return find(value) != end();
}
// FIXME: Implement the translator versions of find() and friends.
AddResult add(const ValueType& value)
{
StringPrintStream string;
string.print(m_id, "->add(");
LoggingTraits::print(string, value);
string.print(");\n");
dataLog(string.toCString());
return m_set.add(value);
}
AddResult add(ValueType&& value)
{
StringPrintStream string;
string.print(m_id, "->add(");
LoggingTraits::print(string, value);
string.print(");\n");
dataLog(string.toCString());
return m_set.add(WTFMove(value));
}
void addVoid(const ValueType& value)
{
StringPrintStream string;
string.print(m_id, "->addVoid(");
LoggingTraits::print(string, value);
string.print(");\n");
dataLog(string.toCString());
m_set.addVoid(value);
}
void addVoid(ValueType&& value)
{
StringPrintStream string;
string.print(m_id, "->addVoid(");
LoggingTraits::print(string, value);
string.print(");\n");
dataLog(string.toCString());
m_set.addVoid(WTFMove(value));
}
template<typename IteratorType>
bool add(IteratorType begin, IteratorType end)
{
bool changed = false;
for (IteratorType iter = begin; iter != end; ++iter)
changed |= add(*iter).isNewEntry;
return changed;
}
bool remove(iterator iter)
{
// FIXME: We should do much better than this!
if (iter == end())
return false;
return remove(*iter);
}
bool remove(const ValueType& value)
{
StringPrintStream string;
string.print(m_id, "->remove(");
LoggingTraits::print(string, value);
string.print(");\n");
dataLog(string.toCString());
return m_set.remove(value);
}
// FIXME: Implement removeIf
void clear()
{
dataLog(m_id, "->clear();\n");
m_set.clear();
}
TakeType take(const ValueType& value)
{
StringPrintStream string;
string.print(m_id, "->remove(");
LoggingTraits::print(string, value);
string.print(");\n");
dataLog(string.toCString());
return m_set.take(value);
}
TakeType take(iterator iter)
{
return take(*iter);
}
TakeType takeAny()
{
dataLog(m_id, "->takeAny();\n");
return m_set.takeAny();
}
template<typename OtherCollection>
bool operator==(const OtherCollection& otherCollection) const
{
if (size() != otherCollection.size())
return false;
for (const auto& other : otherCollection) {
if (!contains(other))
return false;
}
return true;
}
template<typename OtherCollection>
bool operator!=(const OtherCollection& other) const
{
return !(*this == other);
}
private:
HashSet m_set;
LoggingHashID m_id;
};
} // namespace WTF
using WTF::LoggingHashSet;

View File

@ -0,0 +1,51 @@
/*
* Copyright (C) 2017 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. ``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
* 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
namespace WTF {
template<typename T>
struct LoggingHashKeyTraits {
// When overriding this, you can play a trick: if you dataLog() directly, then this will print as
// a separate line before the one being printed now.
static void print(PrintStream& out, const T& key)
{
out.print(key);
}
};
template<typename T>
struct LoggingHashValueTraits {
// When overriding this, you can play a trick: if you dataLog() directly, then this will print as
// a separate line before the one being printed now.
static void print(PrintStream& out, const T&)
{
out.print("Data<", sizeof(T), ">()");
}
};
} // namespace WTF

76
include/MD5.h Normal file
View File

@ -0,0 +1,76 @@
/*
* Copyright (C) 2010 Google 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:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * 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.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
* OWNER OR 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.
*/
#ifndef WTF_MD5_h
#define WTF_MD5_h
#include <array>
#include <wtf/Vector.h>
#if PLATFORM(COCOA)
#include <CommonCrypto/CommonDigest.h>
#endif
namespace WTF {
class MD5 {
public:
WTF_EXPORT_PRIVATE MD5();
void addBytes(const Vector<uint8_t>& input)
{
addBytes(input.data(), input.size());
}
WTF_EXPORT_PRIVATE void addBytes(const uint8_t* input, size_t length);
// Size of the SHA1 hash
WTF_EXPORT_PRIVATE static const size_t hashSize = 16;
// type for computing MD5 hash
typedef std::array<uint8_t, hashSize> Digest;
// checksum has a side effect of resetting the state of the object.
WTF_EXPORT_PRIVATE void checksum(Digest&);
private:
#if PLATFORM(COCOA)
CC_MD5_CTX m_context;
#else
uint32_t m_buf[4];
uint32_t m_bits[2];
uint8_t m_in[64];
#endif
};
} // namespace WTF
using WTF::MD5;
#endif // WTF_MD5_h

117
include/MainThread.h Normal file
View File

@ -0,0 +1,117 @@
/*
* Copyright (C) 2007, 2008, 2010, 2016 Apple Inc. All rights reserved.
* Copyright (C) 2007 Justin Haygood (jhaygood@reaktix.com)
*
* 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.
* 3. Neither the name of Apple Inc. ("Apple") nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY APPLE 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 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.
*/
#ifndef MainThread_h
#define MainThread_h
#include <stdint.h>
#include <wtf/Function.h>
#include <wtf/Optional.h>
#include <wtf/Threading.h>
namespace WTF {
class PrintStream;
// Must be called from the main thread.
WTF_EXPORT_PRIVATE void initializeMainThread();
WTF_EXPORT_PRIVATE void callOnMainThread(Function<void ()>&&);
#if PLATFORM(COCOA)
WTF_EXPORT_PRIVATE void callOnWebThreadOrDispatchAsyncOnMainThread(void (^block)());
#endif
WTF_EXPORT_PRIVATE void setMainThreadCallbacksPaused(bool paused);
WTF_EXPORT_PRIVATE bool isMainThread();
WTF_EXPORT_PRIVATE bool canAccessThreadLocalDataForThread(ThreadIdentifier);
#if USE(WEB_THREAD)
WTF_EXPORT_PRIVATE bool isWebThread();
WTF_EXPORT_PRIVATE bool isUIThread();
WTF_EXPORT_PRIVATE void initializeWebThread();
WTF_EXPORT_PRIVATE void initializeApplicationUIThreadIdentifier();
WTF_EXPORT_PRIVATE void initializeWebThreadIdentifier();
void initializeWebThreadPlatform();
#else
inline bool isWebThread() { return isMainThread(); }
inline bool isUIThread() { return isMainThread(); }
#endif // USE(WEB_THREAD)
WTF_EXPORT_PRIVATE void initializeGCThreads();
enum class GCThreadType {
Main,
Helper
};
void printInternal(PrintStream&, GCThreadType);
WTF_EXPORT_PRIVATE void registerGCThread(GCThreadType);
WTF_EXPORT_PRIVATE std::optional<GCThreadType> mayBeGCThread();
WTF_EXPORT_PRIVATE bool isMainThreadOrGCThread();
// NOTE: these functions are internal to the callOnMainThread implementation.
void initializeMainThreadPlatform();
void scheduleDispatchFunctionsOnMainThread();
void dispatchFunctionsFromMainThread();
#if OS(DARWIN) && !USE(GLIB)
#if !USE(WEB_THREAD)
// This version of initializeMainThread sets up the main thread as corresponding
// to the process's main thread, and not necessarily the thread that calls this
// function. It should only be used as a legacy aid for Mac WebKit.
WTF_EXPORT_PRIVATE void initializeMainThreadToProcessMainThread();
#endif // !USE(WEB_THREAD)
void initializeMainThreadToProcessMainThreadPlatform();
#endif
} // namespace WTF
using WTF::GCThreadType;
using WTF::callOnMainThread;
using WTF::canAccessThreadLocalDataForThread;
using WTF::isMainThread;
using WTF::isMainThreadOrGCThread;
using WTF::isUIThread;
using WTF::isWebThread;
using WTF::mayBeGCThread;
using WTF::setMainThreadCallbacksPaused;
#if PLATFORM(COCOA)
using WTF::callOnWebThreadOrDispatchAsyncOnMainThread;
#endif
#if USE(WEB_THREAD)
using WTF::initializeWebThread;
using WTF::initializeApplicationUIThreadIdentifier;
using WTF::initializeWebThreadIdentifier;
#endif
#endif // MainThread_h

130
include/MallocPtr.h Normal file
View File

@ -0,0 +1,130 @@
/*
* Copyright (C) 2013 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.
*/
#ifndef MallocPtr_h
#define MallocPtr_h
// MallocPtr is a smart pointer class that calls fastFree in its destructor.
// It is intended to be used for pointers where the C++ lifetime semantics
// (calling constructors and destructors) is not desired.
namespace WTF {
template<typename T> class MallocPtr {
public:
MallocPtr()
: m_ptr(nullptr)
{
}
MallocPtr(std::nullptr_t)
: m_ptr(nullptr)
{
}
MallocPtr(MallocPtr&& other)
: m_ptr(other.leakPtr())
{
}
~MallocPtr()
{
fastFree(m_ptr);
}
T* get() const
{
return m_ptr;
}
T *leakPtr() WARN_UNUSED_RETURN
{
return std::exchange(m_ptr, nullptr);
}
bool operator!() const
{
return !m_ptr;
}
T& operator*() const
{
ASSERT(m_ptr);
return *m_ptr;
}
T* operator->() const
{
return m_ptr;
}
MallocPtr& operator=(MallocPtr&& other)
{
MallocPtr ptr = WTFMove(other);
swap(ptr);
return *this;
}
void swap(MallocPtr& other)
{
std::swap(m_ptr, other.m_ptr);
}
template<typename U> friend MallocPtr<U> adoptMallocPtr(U*);
static MallocPtr malloc(size_t size)
{
MallocPtr mallocPtr;
mallocPtr.m_ptr = static_cast<T*>(fastMalloc(size));
return mallocPtr;
}
void realloc(size_t newSize)
{
m_ptr = static_cast<T*>(fastRealloc(m_ptr, newSize));
}
private:
explicit MallocPtr(T* ptr)
: m_ptr(ptr)
{
}
T* m_ptr;
};
template<typename U> MallocPtr<U> adoptMallocPtr(U* ptr)
{
return MallocPtr<U>(ptr);
}
} // namespace WTF
using WTF::MallocPtr;
using WTF::adoptMallocPtr;
#endif // MallocPtr_h

Some files were not shown because too many files have changed in this diff Show More