mirror of
https://github.com/darlinghq/darling-WTF.git
synced 2024-11-23 11:59:47 +00:00
Create header folder again
This commit is contained in:
parent
48466209ad
commit
fc0f8616ea
@ -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
273
include/ASCIICType.h
Normal 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
58
include/Algorithms.h
Normal 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
528
include/Assertions.h
Normal 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
479
include/Atomics.h
Normal 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
61
include/AutodrainedPool.h
Normal 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
192
include/AutomaticThread.h
Normal 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
295
include/BackwardsGraph.h
Normal 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
148
include/Bag.h
Normal 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
49
include/BagToHashMap.h
Normal 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
485
include/BitVector.h
Normal 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
401
include/Bitmap.h
Normal 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
|
32
include/BlockObjCExceptions.h
Normal file
32
include/BlockObjCExceptions.h
Normal 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
170
include/BlockPtr.h
Normal 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
96
include/BlockStack.h
Normal 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
267
include/BloomFilter.h
Normal 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
81
include/Box.h
Normal 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
2488
include/Brigand.h
Normal file
File diff suppressed because it is too large
Load Diff
102
include/BubbleSort.h
Normal file
102
include/BubbleSort.h
Normal 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
|
||||
|
252
include/BumpPointerAllocator.h
Normal file
252
include/BumpPointerAllocator.h
Normal 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
65
include/ByteOrder.h
Normal 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
46
include/CPUTime.h
Normal 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
852
include/CheckedArithmetic.h
Normal 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
70
include/CheckedBoolean.h
Normal 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
44
include/ClockType.h
Normal 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
66
include/CommaPrinter.h
Normal 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
|
||||
|
59
include/CompilationThread.h
Normal file
59
include/CompilationThread.h
Normal 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
377
include/Compiler.h
Normal 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
192
include/Condition.h
Normal 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
146
include/CrossThreadCopier.h
Normal 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
121
include/CrossThreadQueue.h
Normal 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
102
include/CrossThreadTask.h
Normal 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;
|
38
include/CryptographicUtilities.h
Normal file
38
include/CryptographicUtilities.h
Normal 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
|
41
include/CryptographicallyRandomNumber.h
Normal file
41
include/CryptographicallyRandomNumber.h
Normal 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
86
include/CurrentTime.h
Normal 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
79
include/DataLog.h
Normal 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
158
include/DateMath.h
Normal 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
41
include/DebugUtilities.h
Normal 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
108
include/DecimalNumber.h
Normal 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
|
120
include/DeferrableRefCounted.h
Normal file
120
include/DeferrableRefCounted.h
Normal 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;
|
51
include/DeprecatedOptional.h
Normal file
51
include/DeprecatedOptional.h
Normal 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
752
include/Deque.h
Normal 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
83
include/DisallowCType.h
Normal 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
103
include/DispatchPtr.h
Normal 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
752
include/Dominators.h
Normal 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
220
include/DoublyLinkedList.h
Normal 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
64
include/EnumTraits.h
Normal 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
454
include/Expected.h
Normal 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
119
include/ExportMacros.h
Normal 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
580
include/FastBitVector.h
Normal 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
198
include/FastMalloc.h
Normal 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
65
include/FastTLS.h
Normal 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
765
include/FeatureDefines.h
Normal 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
61
include/FilePrintStream.h
Normal 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
117
include/FlipBytes.h
Normal 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
|
||||
|
37
include/ForbidHeapAllocation.h
Normal file
37
include/ForbidHeapAllocation.h
Normal 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
77
include/Forward.h
Normal 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
113
include/Function.h
Normal 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;
|
51
include/FunctionDispatcher.h
Normal file
51
include/FunctionDispatcher.h
Normal 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
82
include/GetPtr.h
Normal 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
40
include/GlobalVersion.h
Normal 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
223
include/GraphNodeWorklist.h
Normal 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
128
include/GregorianDateTime.h
Normal 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
325
include/HashCountedSet.h
Normal 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
274
include/HashFunctions.h
Normal 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
216
include/HashIterators.h
Normal 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
606
include/HashMap.h
Normal 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
45
include/HashMethod.h
Normal 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
395
include/HashSet.h
Normal 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
1538
include/HashTable.h
Normal file
File diff suppressed because it is too large
Load Diff
379
include/HashTraits.h
Normal file
379
include/HashTraits.h
Normal 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
389
include/Hasher.h
Normal 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
118
include/HexNumber.h
Normal 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
67
include/Indenter.h
Normal 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
41
include/IndexKeyType.h
Normal 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
97
include/IndexMap.h
Normal 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
164
include/IndexSet.h
Normal 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
235
include/IndexSparseSet.h
Normal 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
|
81
include/IndexedContainerIterator.h
Normal file
81
include/IndexedContainerIterator.h
Normal 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
98
include/InlineASM.h
Normal 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
85
include/Insertion.h
Normal 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
113
include/IteratorAdaptors.h
Normal 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
56
include/IteratorRange.h
Normal 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
107
include/LEBDecoder.h
Normal 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
187
include/ListDump.h
Normal 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
714
include/ListHashSet.h
Normal 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
370
include/Liveness.h
Normal 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
153
include/Lock.h
Normal 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
247
include/LockAlgorithm.h
Normal 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
|
||||
|
58
include/LockedPrintStream.h
Normal file
58
include/LockedPrintStream.h
Normal 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
138
include/Locker.h
Normal 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
111
include/LocklessBag.h
Normal 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
|
38
include/LoggingAccumulator.h
Normal file
38
include/LoggingAccumulator.h
Normal 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
52
include/LoggingHashID.h
Normal 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
308
include/LoggingHashMap.h
Normal 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
248
include/LoggingHashSet.h
Normal 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;
|
51
include/LoggingHashTraits.h
Normal file
51
include/LoggingHashTraits.h
Normal 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
76
include/MD5.h
Normal 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
117
include/MainThread.h
Normal 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
130
include/MallocPtr.h
Normal 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
Loading…
Reference in New Issue
Block a user