├── tests ├── bad_lex.jakt ├── hello.jakt └── fat_arrow.jakt ├── README.md ├── runtime ├── AK │ ├── Noncopyable.h │ ├── BitCast.h │ ├── Assertions.h │ ├── kstdio.h │ ├── AllOf.h │ ├── Try.h │ ├── ScopeGuard.h │ ├── Find.h │ ├── UnicodeUtils.h │ ├── kmalloc.h │ ├── StringHash.h │ ├── HashFunctions.h │ ├── kmalloc.cpp │ ├── TypeCasts.h │ ├── RefCounted.h │ ├── TypedTransfer.h │ ├── TypeList.h │ ├── Memory.h │ ├── Forward.h │ ├── Traits.h │ ├── StringUtils.h │ ├── Types.h │ ├── StringView.cpp │ ├── Concepts.h │ ├── Error.h │ ├── Iterator.h │ ├── StringBuilder.cpp │ ├── Platform.h │ ├── Weakable.h │ ├── GenericLexer.cpp │ ├── LinearArray.h │ ├── MemMem.h │ ├── NumericLimits.h │ ├── StdLibExtras.h │ ├── WeakPtr.h │ ├── Tuple.h │ ├── StringBuilder.h │ ├── CharacterTypes.h │ ├── GenericLexer.h │ ├── NonnullRefPtr.h │ ├── String.cpp │ ├── HashMap.h │ ├── String.h │ ├── Span.h │ ├── Function.h │ ├── Debug.h │ ├── RefPtr.h │ └── StringView.h ├── IO │ ├── File.h │ └── File.cpp ├── Builtins │ ├── Set.h │ ├── Dictionary.h │ └── Array.h ├── prelude.jakt └── lib.h └── LICENSE /tests/bad_lex.jakt: -------------------------------------------------------------------------------- 1 | function main() { 2 | %*^&%$^\ 3 | } 4 | 5 | -------------------------------------------------------------------------------- /tests/hello.jakt: -------------------------------------------------------------------------------- 1 | function main() { 2 | println("well, hello friends") 3 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Jakt self-host compiler 2 | (requires latest Jakt main to build) 3 | 4 | -------------------------------------------------------------------------------- /tests/fat_arrow.jakt: -------------------------------------------------------------------------------- 1 | function foo() => 3 2 | 3 | function main() { 4 | println("{}", foo()) 5 | } -------------------------------------------------------------------------------- /runtime/AK/Noncopyable.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2020, Andreas Kling 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #define AK_MAKE_NONCOPYABLE(c) \ 10 | private: \ 11 | c(c const&) = delete; \ 12 | c& operator=(c const&) = delete 13 | 14 | #define AK_MAKE_NONMOVABLE(c) \ 15 | private: \ 16 | c(c&&) = delete; \ 17 | c& operator=(c&&) = delete 18 | -------------------------------------------------------------------------------- /runtime/AK/BitCast.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, the SerenityOS developers. 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | namespace AK { 10 | 11 | template 12 | inline T bit_cast(const U& a) 13 | { 14 | #if (__has_builtin(__builtin_bit_cast)) 15 | return __builtin_bit_cast(T, a); 16 | #else 17 | static_assert(sizeof(T) == sizeof(U)); 18 | 19 | T result; 20 | __builtin_memcpy(&result, &a, sizeof(T)); 21 | return result; 22 | #endif 23 | } 24 | 25 | } 26 | 27 | using AK::bit_cast; 28 | -------------------------------------------------------------------------------- /runtime/AK/Assertions.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2020, Andreas Kling 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #if defined(KERNEL) 10 | # include 11 | #else 12 | # include 13 | # define VERIFY assert 14 | # define VERIFY_NOT_REACHED() assert(false) /* NOLINT(cert-dcl03-c,misc-static-assert) No, this can't be static_assert, it's a runtime check */ 15 | static constexpr bool TODO = false; 16 | # define TODO() VERIFY(TODO) /* NOLINT(cert-dcl03-c,misc-static-assert) No, this can't be static_assert, it's a runtime check */ 17 | #endif 18 | -------------------------------------------------------------------------------- /runtime/IO/File.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Andreas Kling 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | class File final : public RefCounted { 16 | public: 17 | static ErrorOr> open_for_reading(String path); 18 | static ErrorOr> open_for_writing(String path); 19 | 20 | ErrorOr read(Array); 21 | ErrorOr write(Array); 22 | 23 | ErrorOr> read_all(); 24 | 25 | ~File(); 26 | 27 | private: 28 | File(); 29 | 30 | FILE* m_stdio_file { nullptr }; 31 | }; 32 | -------------------------------------------------------------------------------- /runtime/AK/kstdio.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2020, Andreas Kling 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #ifdef __serenity__ 10 | # ifdef KERNEL 11 | # include 12 | # else 13 | # include 14 | # include 15 | extern "C" { 16 | void dbgputstr(char const*, size_t); 17 | int sprintf(char* buf, char const* fmt, ...) __attribute__((format(printf, 2, 3))); 18 | int snprintf(char* buffer, size_t, char const* fmt, ...) __attribute__((format(printf, 3, 4))); 19 | } 20 | # endif 21 | #else 22 | # include 23 | inline void dbgputstr(char const* characters, size_t length) 24 | { 25 | fwrite(characters, 1, length, stderr); 26 | } 27 | #endif 28 | template 29 | inline void dbgputstr(char const (&array)[N]) 30 | { 31 | return ::dbgputstr(array, N); 32 | } 33 | -------------------------------------------------------------------------------- /runtime/AK/AllOf.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, the SerenityOS developers. 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace AK { 14 | 15 | template TIterator> 16 | constexpr bool all_of( 17 | TIterator const& begin, 18 | TEndIterator const& end, 19 | auto const& predicate) 20 | { 21 | constexpr auto negated_predicate = [](auto const& pred) { 22 | return [&](auto const& elem) { return !pred(elem); }; 23 | }; 24 | return !(find_if(begin, end, negated_predicate(predicate)) != end); 25 | } 26 | 27 | template 28 | constexpr bool all_of(Container&& container, auto const& predicate) 29 | { 30 | return all_of(container.begin(), container.end(), predicate); 31 | } 32 | 33 | } 34 | 35 | using AK::all_of; 36 | -------------------------------------------------------------------------------- /runtime/AK/Try.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, Andreas Kling 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | // NOTE: These macros work with any result type that has the expected APIs. 10 | // It's designed with AK::ErrorOr in mind. 11 | 12 | #define TRY(...) \ 13 | ({ \ 14 | auto _temporary_result = (__VA_ARGS__); \ 15 | if (_temporary_result.is_error()) \ 16 | return _temporary_result.release_error(); \ 17 | _temporary_result.release_value(); \ 18 | }) 19 | 20 | #define MUST(...) \ 21 | ({ \ 22 | auto _temporary_result = (__VA_ARGS__); \ 23 | VERIFY(!_temporary_result.is_error()); \ 24 | _temporary_result.release_value(); \ 25 | }) 26 | -------------------------------------------------------------------------------- /runtime/AK/ScopeGuard.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2020, Andreas Kling 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | namespace AK { 12 | 13 | template 14 | class ScopeGuard { 15 | public: 16 | ScopeGuard(Callback callback) 17 | : m_callback(move(callback)) 18 | { 19 | } 20 | 21 | ~ScopeGuard() 22 | { 23 | m_callback(); 24 | } 25 | 26 | private: 27 | Callback m_callback; 28 | }; 29 | 30 | template 31 | class ArmedScopeGuard { 32 | public: 33 | ArmedScopeGuard(Callback callback) 34 | : m_callback(move(callback)) 35 | { 36 | } 37 | 38 | ~ArmedScopeGuard() 39 | { 40 | if (m_armed) 41 | m_callback(); 42 | } 43 | 44 | void disarm() { m_armed = false; } 45 | 46 | private: 47 | Callback m_callback; 48 | bool m_armed { true }; 49 | }; 50 | 51 | } 52 | 53 | using AK::ArmedScopeGuard; 54 | using AK::ScopeGuard; 55 | -------------------------------------------------------------------------------- /runtime/AK/Find.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, the SerenityOS developers. 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace AK { 14 | 15 | template TIterator, typename TUnaryPredicate> 16 | constexpr TIterator find_if(TIterator first, TEndIterator last, TUnaryPredicate&& pred) 17 | { 18 | for (; first != last; ++first) { 19 | if (pred(*first)) { 20 | return first; 21 | } 22 | } 23 | return last; 24 | } 25 | 26 | template TIterator, typename T> 27 | constexpr TIterator find(TIterator first, TEndIterator last, T const& value) 28 | { 29 | return find_if(first, last, [&](auto const& v) { return Traits::equals(value, v); }); 30 | } 31 | 32 | template TIterator, typename T> 33 | constexpr size_t find_index(TIterator first, TEndIterator last, T const& value) requires(requires(TIterator it) { it.index(); }) 34 | { 35 | return find_if(first, last, [&](auto const& v) { return Traits::equals(value, v); }).index(); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /runtime/AK/UnicodeUtils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, Max Wipfli 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | namespace AK::UnicodeUtils { 12 | 13 | template 14 | [[nodiscard]] constexpr int code_point_to_utf8(u32 code_point, Callback callback) 15 | { 16 | if (code_point <= 0x7f) { 17 | callback((char)code_point); 18 | return 1; 19 | } else if (code_point <= 0x07ff) { 20 | callback((char)(((code_point >> 6) & 0x1f) | 0xc0)); 21 | callback((char)(((code_point >> 0) & 0x3f) | 0x80)); 22 | return 2; 23 | } else if (code_point <= 0xffff) { 24 | callback((char)(((code_point >> 12) & 0x0f) | 0xe0)); 25 | callback((char)(((code_point >> 6) & 0x3f) | 0x80)); 26 | callback((char)(((code_point >> 0) & 0x3f) | 0x80)); 27 | return 3; 28 | } else if (code_point <= 0x10ffff) { 29 | callback((char)(((code_point >> 18) & 0x07) | 0xf0)); 30 | callback((char)(((code_point >> 12) & 0x3f) | 0x80)); 31 | callback((char)(((code_point >> 6) & 0x3f) | 0x80)); 32 | callback((char)(((code_point >> 0) & 0x3f) | 0x80)); 33 | return 4; 34 | } 35 | return -1; 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /runtime/AK/kmalloc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2021, Andreas Kling 3 | * Copyright (c) 2021, Daniel Bertalan 4 | * 5 | * SPDX-License-Identifier: BSD-2-Clause 6 | */ 7 | 8 | #pragma once 9 | 10 | #include 11 | 12 | #if defined(KERNEL) 13 | # include 14 | #else 15 | # include 16 | # include 17 | 18 | # define kcalloc calloc 19 | # define kmalloc malloc 20 | # define kmalloc_good_size malloc_good_size 21 | 22 | inline void kfree_sized(void* ptr, size_t) 23 | { 24 | free(ptr); 25 | } 26 | #endif 27 | 28 | #ifndef __serenity__ 29 | # include 30 | 31 | # ifndef AK_OS_MACOS 32 | extern "C" { 33 | inline size_t malloc_good_size(size_t size) { return size; } 34 | } 35 | # else 36 | # include 37 | # endif 38 | #endif 39 | 40 | using std::nothrow; 41 | 42 | inline void* kmalloc_array(Checked a, Checked b) 43 | { 44 | auto size = a * b; 45 | VERIFY(!size.has_overflow()); 46 | return kmalloc(size.value()); 47 | } 48 | 49 | inline void* kmalloc_array(Checked a, Checked b, Checked c) 50 | { 51 | auto size = a * b * c; 52 | VERIFY(!size.has_overflow()); 53 | return kmalloc(size.value()); 54 | } 55 | -------------------------------------------------------------------------------- /runtime/AK/StringHash.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2021, the SerenityOS developers. 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | namespace AK { 12 | 13 | constexpr u32 string_hash(char const* characters, size_t length, u32 seed = 0) 14 | { 15 | u32 hash = seed; 16 | for (size_t i = 0; i < length; ++i) { 17 | hash += (u32)characters[i]; 18 | hash += (hash << 10); 19 | hash ^= (hash >> 6); 20 | } 21 | hash += hash << 3; 22 | hash ^= hash >> 11; 23 | hash += hash << 15; 24 | return hash; 25 | } 26 | 27 | constexpr u32 case_insensitive_string_hash(char const* characters, size_t length, u32 seed = 0) 28 | { 29 | // AK/CharacterTypes.h cannot be included from here. 30 | auto to_lowercase = [](char ch) -> u32 { 31 | if (ch >= 'A' && ch <= 'Z') 32 | return static_cast(ch) + 0x20; 33 | return static_cast(ch); 34 | }; 35 | 36 | u32 hash = seed; 37 | for (size_t i = 0; i < length; ++i) { 38 | hash += to_lowercase(characters[i]); 39 | hash += (hash << 10); 40 | hash ^= (hash >> 6); 41 | } 42 | hash += hash << 3; 43 | hash ^= hash >> 11; 44 | hash += hash << 15; 45 | return hash; 46 | } 47 | 48 | } 49 | 50 | using AK::string_hash; 51 | -------------------------------------------------------------------------------- /runtime/AK/HashFunctions.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2020, Andreas Kling 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | constexpr unsigned int_hash(u32 key) 12 | { 13 | key += ~(key << 15); 14 | key ^= (key >> 10); 15 | key += (key << 3); 16 | key ^= (key >> 6); 17 | key += ~(key << 11); 18 | key ^= (key >> 16); 19 | return key; 20 | } 21 | 22 | constexpr unsigned double_hash(u32 key) 23 | { 24 | unsigned const magic = 0xBA5EDB01; 25 | if (key == magic) 26 | return 0u; 27 | if (key == 0u) 28 | key = magic; 29 | 30 | key ^= key << 13; 31 | key ^= key >> 17; 32 | key ^= key << 5; 33 | return key; 34 | } 35 | 36 | constexpr unsigned pair_int_hash(u32 key1, u32 key2) 37 | { 38 | return int_hash((int_hash(key1) * 209) ^ (int_hash(key2 * 413))); 39 | } 40 | 41 | constexpr unsigned u64_hash(u64 key) 42 | { 43 | u32 first = key & 0xFFFFFFFF; 44 | u32 last = key >> 32; 45 | return pair_int_hash(first, last); 46 | } 47 | 48 | constexpr unsigned ptr_hash(FlatPtr ptr) 49 | { 50 | if constexpr (sizeof(ptr) == 8) 51 | return u64_hash(ptr); 52 | else 53 | return int_hash(ptr); 54 | } 55 | 56 | inline unsigned ptr_hash(void const* ptr) 57 | { 58 | return ptr_hash(FlatPtr(ptr)); 59 | } 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2022, JT, Andreas Kling 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /runtime/AK/kmalloc.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2020, Andreas Kling 3 | * Copyright (c) 2021, Daniel Bertalan 4 | * 5 | * SPDX-License-Identifier: BSD-2-Clause 6 | */ 7 | 8 | #if defined(__serenity__) && !defined(KERNEL) 9 | 10 | # include 11 | # include 12 | 13 | // However deceptively simple these functions look, they must not be inlined. 14 | // Memory allocated in one translation unit has to be deallocatable in another 15 | // translation unit, so these functions must be the same everywhere. 16 | // By making these functions global, this invariant is enforced. 17 | 18 | void* operator new(size_t size) 19 | { 20 | void* ptr = malloc(size); 21 | VERIFY(ptr); 22 | return ptr; 23 | } 24 | 25 | void* operator new(size_t size, std::nothrow_t const&) noexcept 26 | { 27 | return malloc(size); 28 | } 29 | 30 | void operator delete(void* ptr) noexcept 31 | { 32 | return free(ptr); 33 | } 34 | 35 | void operator delete(void* ptr, size_t) noexcept 36 | { 37 | return free(ptr); 38 | } 39 | 40 | void* operator new[](size_t size) 41 | { 42 | void* ptr = malloc(size); 43 | VERIFY(ptr); 44 | return ptr; 45 | } 46 | 47 | void* operator new[](size_t size, std::nothrow_t const&) noexcept 48 | { 49 | return malloc(size); 50 | } 51 | 52 | void operator delete[](void* ptr) noexcept 53 | { 54 | return free(ptr); 55 | } 56 | 57 | void operator delete[](void* ptr, size_t) noexcept 58 | { 59 | return free(ptr); 60 | } 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /runtime/AK/TypeCasts.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, Andreas Kling 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace AK { 16 | 17 | template 18 | ALWAYS_INLINE bool is(InputType& input) 19 | { 20 | if constexpr (requires { input.template fast_is(); }) { 21 | return input.template fast_is(); 22 | } 23 | return dynamic_cast*>(&input); 24 | } 25 | 26 | template 27 | ALWAYS_INLINE bool is(InputType* input) 28 | { 29 | return input && is(*input); 30 | } 31 | 32 | template 33 | ALWAYS_INLINE bool is(NonnullRefPtr const& input) 34 | { 35 | return is(*input); 36 | } 37 | 38 | template 39 | ALWAYS_INLINE CopyConst* verify_cast(InputType* input) 40 | { 41 | static_assert(IsBaseOf); 42 | VERIFY(!input || is(*input)); 43 | return static_cast*>(input); 44 | } 45 | 46 | template 47 | ALWAYS_INLINE CopyConst& verify_cast(InputType& input) 48 | { 49 | static_assert(IsBaseOf); 50 | VERIFY(is(input)); 51 | return static_cast&>(input); 52 | } 53 | 54 | } 55 | 56 | using AK::is; 57 | using AK::verify_cast; 58 | -------------------------------------------------------------------------------- /runtime/AK/RefCounted.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2020, Andreas Kling 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #ifdef KERNEL 10 | # include 11 | #else 12 | 13 | # include 14 | # include 15 | # include 16 | # include 17 | # include 18 | 19 | namespace AK { 20 | 21 | class RefCountedBase { 22 | AK_MAKE_NONCOPYABLE(RefCountedBase); 23 | AK_MAKE_NONMOVABLE(RefCountedBase); 24 | 25 | public: 26 | using RefCountType = unsigned int; 27 | 28 | ALWAYS_INLINE void ref() const 29 | { 30 | VERIFY(m_ref_count > 0); 31 | VERIFY(!Checked::addition_would_overflow(m_ref_count, 1)); 32 | ++m_ref_count; 33 | } 34 | 35 | [[nodiscard]] bool try_ref() const 36 | { 37 | if (m_ref_count == 0) 38 | return false; 39 | ref(); 40 | return true; 41 | } 42 | 43 | [[nodiscard]] RefCountType ref_count() const { return m_ref_count; } 44 | 45 | protected: 46 | RefCountedBase() = default; 47 | ~RefCountedBase() { VERIFY(!m_ref_count); } 48 | 49 | ALWAYS_INLINE RefCountType deref_base() const 50 | { 51 | VERIFY(m_ref_count); 52 | return --m_ref_count; 53 | } 54 | 55 | RefCountType mutable m_ref_count { 1 }; 56 | }; 57 | 58 | template 59 | class RefCounted : public RefCountedBase { 60 | public: 61 | bool unref() const 62 | { 63 | auto* that = const_cast(static_cast(this)); 64 | 65 | auto new_ref_count = deref_base(); 66 | if (new_ref_count == 0) { 67 | if constexpr (requires { that->will_be_destroyed(); }) 68 | that->will_be_destroyed(); 69 | delete static_cast(this); 70 | return true; 71 | } 72 | return false; 73 | } 74 | }; 75 | 76 | } 77 | 78 | using AK::RefCounted; 79 | using AK::RefCountedBase; 80 | 81 | #endif 82 | -------------------------------------------------------------------------------- /runtime/AK/TypedTransfer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, the SerenityOS developers. 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | namespace AK { 12 | 13 | template 14 | class TypedTransfer { 15 | public: 16 | static void move(T* destination, T* source, size_t count) 17 | { 18 | if (count == 0) 19 | return; 20 | 21 | if constexpr (Traits::is_trivial()) { 22 | __builtin_memmove(destination, source, count * sizeof(T)); 23 | return; 24 | } 25 | 26 | for (size_t i = 0; i < count; ++i) { 27 | if (destination <= source) 28 | new (&destination[i]) T(std::move(source[i])); 29 | else 30 | new (&destination[count - i - 1]) T(std::move(source[count - i - 1])); 31 | } 32 | } 33 | 34 | static size_t copy(T* destination, const T* source, size_t count) 35 | { 36 | if (count == 0) 37 | return 0; 38 | 39 | if constexpr (Traits::is_trivial()) { 40 | if (count == 1) 41 | *destination = *source; 42 | else 43 | __builtin_memmove(destination, source, count * sizeof(T)); 44 | return count; 45 | } 46 | 47 | for (size_t i = 0; i < count; ++i) { 48 | if (destination <= source) 49 | new (&destination[i]) T(source[i]); 50 | else 51 | new (&destination[count - i - 1]) T(source[count - i - 1]); 52 | } 53 | 54 | return count; 55 | } 56 | 57 | static bool compare(const T* a, const T* b, size_t count) 58 | { 59 | if (count == 0) 60 | return true; 61 | 62 | if constexpr (Traits::is_trivial()) 63 | return !__builtin_memcmp(a, b, count * sizeof(T)); 64 | 65 | for (size_t i = 0; i < count; ++i) { 66 | if (a[i] != b[i]) 67 | return false; 68 | } 69 | 70 | return true; 71 | } 72 | }; 73 | 74 | } 75 | -------------------------------------------------------------------------------- /runtime/AK/TypeList.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, the SerenityOS developers. 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | namespace AK { 12 | 13 | template 14 | struct TypeList; 15 | 16 | template 17 | struct TypeListElement; 18 | 19 | template 20 | struct TypeListElement> 21 | : TypeListElement> { 22 | }; 23 | 24 | template 25 | struct TypeListElement<0, TypeList> { 26 | using Type = Head; 27 | }; 28 | 29 | template 30 | struct TypeList { 31 | static constexpr unsigned size = sizeof...(Types); 32 | 33 | template 34 | using Type = typename TypeListElement>::Type; 35 | }; 36 | 37 | template 38 | struct TypeWrapper { 39 | using Type = T; 40 | }; 41 | 42 | template 43 | constexpr void for_each_type_impl(F&& f, IndexSequence) 44 | { 45 | (forward(f)(TypeWrapper> {}), ...); 46 | } 47 | 48 | template 49 | constexpr void for_each_type(F&& f) 50 | { 51 | for_each_type_impl(forward(f), MakeIndexSequence {}); 52 | } 53 | 54 | template 55 | constexpr void for_each_type_zipped_impl(F&& f, IndexSequence) 56 | { 57 | (forward(f)(TypeWrapper> {}, TypeWrapper> {}), ...); 58 | } 59 | 60 | template 61 | constexpr void for_each_type_zipped(F&& f) 62 | { 63 | static_assert(ListA::size == ListB::size, "Can't zip TypeLists that aren't the same size!"); 64 | for_each_type_zipped_impl(forward(f), MakeIndexSequence {}); 65 | } 66 | 67 | } 68 | 69 | using AK::for_each_type; 70 | using AK::for_each_type_zipped; 71 | using AK::TypeList; 72 | using AK::TypeListElement; 73 | using AK::TypeWrapper; 74 | -------------------------------------------------------------------------------- /runtime/AK/Memory.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, Andreas Kling 3 | * Copyright (c) 2021-2022, Brian Gianforcaro 4 | * 5 | * SPDX-License-Identifier: BSD-2-Clause 6 | */ 7 | 8 | #pragma once 9 | 10 | #include 11 | 12 | #if defined(KERNEL) 13 | # include 14 | #else 15 | # include 16 | # include 17 | #endif 18 | 19 | ALWAYS_INLINE void fast_u32_copy(u32* dest, u32 const* src, size_t count) 20 | { 21 | #if ARCH(I386) || ARCH(X86_64) 22 | asm volatile( 23 | "rep movsl\n" 24 | : "+S"(src), "+D"(dest), "+c"(count)::"memory"); 25 | #else 26 | __builtin_memcpy(dest, src, count * 4); 27 | #endif 28 | } 29 | 30 | ALWAYS_INLINE void fast_u32_fill(u32* dest, u32 value, size_t count) 31 | { 32 | #if ARCH(I386) || ARCH(X86_64) 33 | asm volatile( 34 | "rep stosl\n" 35 | : "=D"(dest), "=c"(count) 36 | : "D"(dest), "c"(count), "a"(value) 37 | : "memory"); 38 | #else 39 | for (auto* p = dest; p < (dest + count); ++p) { 40 | *p = value; 41 | } 42 | #endif 43 | } 44 | 45 | namespace AK { 46 | 47 | inline void secure_zero(void* ptr, size_t size) 48 | { 49 | __builtin_memset(ptr, 0, size); 50 | // The memory barrier is here to avoid the compiler optimizing 51 | // away the memset when we rely on it for wiping secrets. 52 | asm volatile("" :: 53 | : "memory"); 54 | } 55 | 56 | // Naive implementation of a constant time buffer comparison function. 57 | // The goal being to not use any conditional branching so calls are 58 | // guarded against potential timing attacks. 59 | // 60 | // See OpenBSD's timingsafe_memcmp for more advanced implementations. 61 | inline bool timing_safe_compare(void const* b1, void const* b2, size_t len) 62 | { 63 | auto* c1 = static_cast(b1); 64 | auto* c2 = static_cast(b2); 65 | 66 | u8 res = 0; 67 | for (size_t i = 0; i < len; i++) { 68 | res |= c1[i] ^ c2[i]; 69 | } 70 | 71 | // FIXME: !res can potentially inject branches depending 72 | // on which toolchain is being used for compilation. Ideally 73 | // we would use a more advanced algorithm. 74 | return !res; 75 | } 76 | 77 | } 78 | 79 | using AK::secure_zero; 80 | using AK::timing_safe_compare; 81 | -------------------------------------------------------------------------------- /runtime/IO/File.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Andreas Kling 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | File::File() 11 | { 12 | } 13 | 14 | File::~File() 15 | { 16 | fclose(m_stdio_file); 17 | } 18 | 19 | ErrorOr> File::open_for_reading(String path) 20 | { 21 | auto* stdio_file = fopen(path.c_string(), "rb"); 22 | if (!stdio_file) { 23 | return Error::from_errno(errno); 24 | } 25 | auto file = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) File)); 26 | file->m_stdio_file = stdio_file; 27 | return file; 28 | } 29 | 30 | ErrorOr> File::open_for_writing(String path) 31 | { 32 | auto* stdio_file = fopen(path.c_string(), "wb"); 33 | if (!stdio_file) { 34 | return Error::from_errno(errno); 35 | } 36 | auto file = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) File)); 37 | file->m_stdio_file = stdio_file; 38 | return file; 39 | } 40 | 41 | ErrorOr> File::read_all() 42 | { 43 | Array entire_file; 44 | 45 | while (true) { 46 | u8 buffer[4096]; 47 | auto nread = fread(buffer, 1, sizeof(buffer), m_stdio_file); 48 | if (nread == 0) { 49 | if (feof(m_stdio_file)) { 50 | return entire_file; 51 | } 52 | auto error = ferror(m_stdio_file); 53 | return Error::from_errno(error); 54 | } 55 | size_t old_size = entire_file.size(); 56 | TRY(entire_file.add_size(nread)); 57 | memcpy(entire_file.unsafe_data() + old_size, buffer, nread); 58 | } 59 | } 60 | 61 | ErrorOr File::read(Array buffer) 62 | { 63 | auto nread = fread(buffer.unsafe_data(), 1, buffer.size(), m_stdio_file); 64 | if (nread == 0) { 65 | if (feof(m_stdio_file)) 66 | return 0; 67 | auto error = ferror(m_stdio_file); 68 | return Error::from_errno(error); 69 | } 70 | return nread; 71 | } 72 | 73 | ErrorOr File::write(Array data) 74 | { 75 | auto nwritten = fwrite(data.unsafe_data(), 1, data.size(), m_stdio_file); 76 | if (nwritten == 0) { 77 | auto error = ferror(m_stdio_file); 78 | return Error::from_errno(error); 79 | } 80 | return nwritten; 81 | } 82 | -------------------------------------------------------------------------------- /runtime/AK/Forward.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, Andreas Kling 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | namespace AK { 12 | 13 | class Bitmap; 14 | class Error; 15 | class GenericLexer; 16 | class String; 17 | class StringBuilder; 18 | class StringImpl; 19 | class StringView; 20 | class Time; 21 | class Utf8CodePointIterator; 22 | class Utf8View; 23 | 24 | template 25 | class Span; 26 | 27 | template 28 | struct LinearArray; 29 | 30 | template 31 | class SimpleIterator; 32 | 33 | using ReadonlyBytes = Span; 34 | using Bytes = Span; 35 | 36 | template 37 | class Atomic; 38 | 39 | template 40 | struct Traits; 41 | 42 | template, bool IsOrdered = false> 43 | class HashTable; 44 | 45 | template> 46 | using OrderedHashTable = HashTable; 47 | 48 | template, bool IsOrdered = false> 49 | class HashMap; 50 | 51 | template> 52 | using OrderedHashMap = HashMap; 53 | 54 | template 55 | class Function; 56 | 57 | template 58 | class Function; 59 | 60 | template 61 | class NonnullRefPtr; 62 | 63 | template 64 | class Optional; 65 | 66 | #ifdef KERNEL 67 | template 68 | struct RefPtrTraits; 69 | 70 | template> 71 | class RefPtr; 72 | #else 73 | template 74 | class RefPtr; 75 | #endif 76 | 77 | template 78 | class WeakPtr; 79 | 80 | template 81 | class [[nodiscard]] ErrorOr; 82 | 83 | } 84 | 85 | using AK::Atomic; 86 | using AK::Bitmap; 87 | using AK::Bytes; 88 | using AK::Error; 89 | using AK::ErrorOr; 90 | using AK::Function; 91 | using AK::GenericLexer; 92 | using AK::HashMap; 93 | using AK::HashTable; 94 | using AK::LinearArray; 95 | using AK::NonnullRefPtr; 96 | using AK::Optional; 97 | using AK::ReadonlyBytes; 98 | using AK::RefPtr; 99 | using AK::Span; 100 | using AK::String; 101 | using AK::StringBuilder; 102 | using AK::StringImpl; 103 | using AK::StringView; 104 | using AK::Time; 105 | using AK::Traits; 106 | -------------------------------------------------------------------------------- /runtime/AK/Traits.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2022, Andreas Kling 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | namespace AK { 17 | 18 | template 19 | struct GenericTraits { 20 | using PeekType = T&; 21 | using ConstPeekType = T const&; 22 | static constexpr bool is_trivial() { return false; } 23 | static constexpr bool equals(const T& a, const T& b) { return a == b; } 24 | template U> 25 | static bool equals(U const& a, T const& b) { return a == b; } 26 | }; 27 | 28 | template 29 | struct Traits : public GenericTraits { 30 | }; 31 | 32 | template 33 | requires(IsIntegral) struct Traits : public GenericTraits { 34 | static constexpr bool is_trivial() { return true; } 35 | static constexpr unsigned hash(T value) 36 | { 37 | if constexpr (sizeof(T) < 8) 38 | return int_hash(value); 39 | else 40 | return u64_hash(value); 41 | } 42 | }; 43 | 44 | #ifndef KERNEL 45 | template 46 | requires(IsFloatingPoint) struct Traits : public GenericTraits { 47 | static constexpr bool is_trivial() { return true; } 48 | static constexpr unsigned hash(T value) 49 | { 50 | if constexpr (sizeof(T) < 8) 51 | return int_hash(bit_cast(value)); 52 | else 53 | return u64_hash(bit_cast(value)); 54 | } 55 | }; 56 | #endif 57 | 58 | template 59 | requires(IsPointer && !Detail::IsPointerOfType) struct Traits : public GenericTraits { 60 | static unsigned hash(T p) { return ptr_hash((FlatPtr)p); } 61 | static constexpr bool is_trivial() { return true; } 62 | }; 63 | 64 | template 65 | struct Traits : public GenericTraits { 66 | static unsigned hash(T value) { return Traits>::hash(to_underlying(value)); } 67 | static constexpr bool is_trivial() { return Traits>::is_trivial(); } 68 | }; 69 | 70 | template 71 | requires(Detail::IsPointerOfType) struct Traits : public GenericTraits { 72 | static unsigned hash(T const value) { return string_hash(value, strlen(value)); } 73 | static constexpr bool equals(T const a, T const b) { return strcmp(a, b); } 74 | static constexpr bool is_trivial() { return true; } 75 | }; 76 | 77 | } 78 | 79 | using AK::GenericTraits; 80 | using AK::Traits; 81 | -------------------------------------------------------------------------------- /runtime/AK/StringUtils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2020, Andreas Kling 3 | * Copyright (c) 2020, Fei Wu 4 | * 5 | * SPDX-License-Identifier: BSD-2-Clause 6 | */ 7 | 8 | #pragma once 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | namespace AK { 15 | 16 | namespace Detail { 17 | template 18 | inline constexpr bool IsHashCompatible = true; 19 | } 20 | 21 | enum class CaseSensitivity { 22 | CaseInsensitive, 23 | CaseSensitive, 24 | }; 25 | 26 | enum class TrimMode { 27 | Left, 28 | Right, 29 | Both 30 | }; 31 | 32 | enum class TrimWhitespace { 33 | Yes, 34 | No, 35 | }; 36 | 37 | struct MaskSpan { 38 | size_t start; 39 | size_t length; 40 | 41 | bool operator==(MaskSpan const& other) const 42 | { 43 | return start == other.start && length == other.length; 44 | } 45 | bool operator!=(MaskSpan const& other) const 46 | { 47 | return !(*this == other); 48 | } 49 | }; 50 | 51 | namespace StringUtils { 52 | 53 | template 54 | Optional convert_to_int(StringView, TrimWhitespace = TrimWhitespace::Yes); 55 | template 56 | Optional convert_to_uint(StringView, TrimWhitespace = TrimWhitespace::Yes); 57 | template 58 | Optional convert_to_uint_from_hex(StringView, TrimWhitespace = TrimWhitespace::Yes); 59 | template 60 | Optional convert_to_uint_from_octal(StringView, TrimWhitespace = TrimWhitespace::Yes); 61 | bool equals_ignoring_case(StringView, StringView); 62 | bool ends_with(StringView a, StringView b, CaseSensitivity); 63 | bool starts_with(StringView, StringView, CaseSensitivity); 64 | bool contains(StringView, StringView, CaseSensitivity); 65 | bool is_whitespace(StringView); 66 | StringView trim(StringView string, StringView characters, TrimMode mode); 67 | StringView trim_whitespace(StringView string, TrimMode mode); 68 | 69 | Optional find(StringView haystack, char needle, size_t start = 0); 70 | Optional find(StringView haystack, StringView needle, size_t start = 0); 71 | Optional find_last(StringView haystack, char needle); 72 | ErrorOr> find_all(StringView haystack, StringView needle); 73 | enum class SearchDirection { 74 | Forward, 75 | Backward 76 | }; 77 | Optional find_any_of(StringView haystack, StringView needles, SearchDirection); 78 | 79 | ErrorOr replace(StringView, StringView needle, StringView replacement, bool all_occurrences = false); 80 | size_t count(StringView, StringView needle); 81 | 82 | } 83 | 84 | } 85 | 86 | using AK::CaseSensitivity; 87 | using AK::TrimMode; 88 | using AK::TrimWhitespace; 89 | -------------------------------------------------------------------------------- /runtime/Builtins/Set.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Mustafa Quraish 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | namespace JaktInternal { 13 | 14 | template 15 | struct SetStorage : public RefCounted> { 16 | HashTable table; 17 | }; 18 | 19 | template 20 | class SetIterator { 21 | using Storage = SetStorage; 22 | using Iterator = typename HashTable::Iterator; 23 | 24 | public: 25 | SetIterator(NonnullRefPtr storage) 26 | : m_storage(move(storage)) 27 | , m_iterator(m_storage->table.begin()) 28 | { 29 | } 30 | 31 | Optional next() 32 | { 33 | if (m_iterator == m_storage->table.end()) 34 | return {}; 35 | auto res = *m_iterator; 36 | ++m_iterator; 37 | return res; 38 | } 39 | 40 | private: 41 | NonnullRefPtr m_storage; 42 | Iterator m_iterator; 43 | }; 44 | 45 | template 46 | class Set : public HashTable { 47 | private: 48 | using Storage = SetStorage; 49 | 50 | public: 51 | bool remove(T const& value) { return m_storage->table.remove(value); } 52 | bool contains(T const& value) const { return m_storage->table.contains(value); } 53 | 54 | ErrorOr add(T const& value) { return m_storage->table.set(value); } 55 | ErrorOr add(T&& value) { return m_storage->table.set(move(value)); } 56 | ErrorOr ensure_capacity(size_t capacity) { return m_storage->table.try_ensure_capacity(capacity); } 57 | 58 | bool is_empty() const { return m_storage->table.is_empty(); } 59 | size_t capacity() const { return m_storage->table.capacity(); } 60 | size_t size() const { return m_storage->table.size(); } 61 | void clear() { m_storage->table.clear(); } 62 | 63 | [[nodiscard]] u32 hash() const 64 | { 65 | u32 hash = 0; 66 | for (auto& value : *this) { 67 | hash = pair_int_hash(hash, value.hash()); 68 | } 69 | return hash; 70 | } 71 | 72 | static ErrorOr create_empty() 73 | { 74 | auto storage = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) Storage)); 75 | return Set { move(storage) }; 76 | } 77 | 78 | static ErrorOr create_with_values(std::initializer_list list) 79 | { 80 | auto set = TRY(create_empty()); 81 | TRY(set.ensure_capacity(list.size())); 82 | for (auto& value : list) 83 | TRY(set.add(value)); 84 | return set; 85 | } 86 | 87 | SetIterator iterator() const { return SetIterator { m_storage }; } 88 | 89 | private: 90 | explicit Set(NonnullRefPtr storage) 91 | : m_storage(move(storage)) 92 | { 93 | } 94 | 95 | NonnullRefPtr m_storage; 96 | }; 97 | 98 | } 99 | 100 | using JaktInternal::Set; 101 | -------------------------------------------------------------------------------- /runtime/AK/Types.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2020, Andreas Kling 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | using u64 = __UINT64_TYPE__; 13 | using u32 = __UINT32_TYPE__; 14 | using u16 = __UINT16_TYPE__; 15 | using u8 = __UINT8_TYPE__; 16 | using i64 = __INT64_TYPE__; 17 | using i32 = __INT32_TYPE__; 18 | using i16 = __INT16_TYPE__; 19 | using i8 = __INT8_TYPE__; 20 | 21 | #ifdef _WIN32 22 | using ssize_t = MakeSigned; 23 | #endif 24 | 25 | #ifdef __serenity__ 26 | 27 | using size_t = __SIZE_TYPE__; 28 | using ssize_t = MakeSigned; 29 | 30 | using ptrdiff_t = __PTRDIFF_TYPE__; 31 | 32 | using intptr_t = __INTPTR_TYPE__; 33 | using uintptr_t = __UINTPTR_TYPE__; 34 | 35 | using uint8_t = u8; 36 | using uint16_t = u16; 37 | using uint32_t = u32; 38 | using uint64_t = u64; 39 | 40 | using int8_t = i8; 41 | using int16_t = i16; 42 | using int32_t = i32; 43 | using int64_t = i64; 44 | 45 | using pid_t = int; 46 | 47 | #else 48 | # include 49 | # include 50 | # include 51 | 52 | # ifdef __ptrdiff_t 53 | using __ptrdiff_t = __PTRDIFF_TYPE__; 54 | # endif 55 | 56 | #endif 57 | 58 | using FlatPtr = Conditional; 59 | 60 | constexpr u64 KiB = 1024; 61 | constexpr u64 MiB = KiB * KiB; 62 | constexpr u64 GiB = KiB * KiB * KiB; 63 | constexpr u64 TiB = KiB * KiB * KiB * KiB; 64 | constexpr u64 PiB = KiB * KiB * KiB * KiB * KiB; 65 | constexpr u64 EiB = KiB * KiB * KiB * KiB * KiB * KiB; 66 | 67 | namespace std { // NOLINT(cert-dcl58-cpp) nullptr_t must be in ::std:: for some analysis tools 68 | using nullptr_t = decltype(nullptr); 69 | } 70 | 71 | static constexpr FlatPtr explode_byte(u8 b) 72 | { 73 | FlatPtr value = b; 74 | if constexpr (sizeof(FlatPtr) == 4) 75 | return value << 24 | value << 16 | value << 8 | value; 76 | else if (sizeof(FlatPtr) == 8) 77 | return value << 56 | value << 48 | value << 40 | value << 32 | value << 24 | value << 16 | value << 8 | value; 78 | } 79 | 80 | static_assert(explode_byte(0xff) == (FlatPtr)0xffffffffffffffffull); 81 | static_assert(explode_byte(0x80) == (FlatPtr)0x8080808080808080ull); 82 | static_assert(explode_byte(0x7f) == (FlatPtr)0x7f7f7f7f7f7f7f7full); 83 | static_assert(explode_byte(0) == 0); 84 | 85 | constexpr size_t align_up_to(const size_t value, const size_t alignment) 86 | { 87 | return (value + (alignment - 1)) & ~(alignment - 1); 88 | } 89 | 90 | enum class [[nodiscard]] TriState : u8 { 91 | False, 92 | True, 93 | Unknown 94 | }; 95 | 96 | namespace AK { 97 | 98 | enum MemoryOrder { 99 | memory_order_relaxed = __ATOMIC_RELAXED, 100 | memory_order_consume = __ATOMIC_CONSUME, 101 | memory_order_acquire = __ATOMIC_ACQUIRE, 102 | memory_order_release = __ATOMIC_RELEASE, 103 | memory_order_acq_rel = __ATOMIC_ACQ_REL, 104 | memory_order_seq_cst = __ATOMIC_SEQ_CST 105 | }; 106 | 107 | } 108 | -------------------------------------------------------------------------------- /runtime/AK/StringView.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2021, Andreas Kling 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #ifndef KERNEL 13 | # include 14 | #endif 15 | 16 | namespace AK { 17 | 18 | StringView::StringView(String const& string) 19 | : m_characters(string.c_string()) 20 | , m_length(string.length()) 21 | { 22 | } 23 | 24 | bool StringView::starts_with(char ch) const 25 | { 26 | if (is_empty()) 27 | return false; 28 | return ch == characters_without_null_termination()[0]; 29 | } 30 | 31 | bool StringView::starts_with(StringView str, CaseSensitivity case_sensitivity) const 32 | { 33 | return StringUtils::starts_with(*this, str, case_sensitivity); 34 | } 35 | 36 | bool StringView::ends_with(char ch) const 37 | { 38 | if (is_empty()) 39 | return false; 40 | return ch == characters_without_null_termination()[length() - 1]; 41 | } 42 | 43 | bool StringView::ends_with(StringView str, CaseSensitivity case_sensitivity) const 44 | { 45 | return StringUtils::ends_with(*this, str, case_sensitivity); 46 | } 47 | 48 | bool StringView::contains(char needle) const 49 | { 50 | for (char current : *this) { 51 | if (current == needle) 52 | return true; 53 | } 54 | return false; 55 | } 56 | 57 | bool StringView::contains(StringView needle, CaseSensitivity case_sensitivity) const 58 | { 59 | return StringUtils::contains(*this, needle, case_sensitivity); 60 | } 61 | 62 | bool StringView::equals_ignoring_case(StringView other) const 63 | { 64 | return StringUtils::equals_ignoring_case(*this, other); 65 | } 66 | 67 | template 68 | Optional StringView::to_int() const 69 | { 70 | return StringUtils::convert_to_int(*this); 71 | } 72 | 73 | template Optional StringView::to_int() const; 74 | template Optional StringView::to_int() const; 75 | template Optional StringView::to_int() const; 76 | template Optional StringView::to_int() const; 77 | template Optional StringView::to_int() const; 78 | 79 | template 80 | Optional StringView::to_uint() const 81 | { 82 | return StringUtils::convert_to_uint(*this); 83 | } 84 | 85 | template Optional StringView::to_uint() const; 86 | template Optional StringView::to_uint() const; 87 | template Optional StringView::to_uint() const; 88 | template Optional StringView::to_uint() const; 89 | template Optional StringView::to_uint() const; 90 | template Optional StringView::to_uint() const; 91 | template Optional StringView::to_uint() const; 92 | 93 | bool StringView::operator==(String const& string) const 94 | { 95 | return *this == string.view(); 96 | } 97 | 98 | ErrorOr StringView::to_string() const { return String::copy(*this); } 99 | 100 | ErrorOr> StringView::find_all(StringView needle) const 101 | { 102 | return StringUtils::find_all(*this, needle); 103 | } 104 | 105 | } 106 | -------------------------------------------------------------------------------- /runtime/AK/Concepts.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, the SerenityOS developers. 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | namespace AK::Concepts { 13 | 14 | template 15 | concept Integral = IsIntegral; 16 | 17 | template 18 | concept FloatingPoint = IsFloatingPoint; 19 | 20 | template 21 | concept Fundamental = IsFundamental; 22 | 23 | template 24 | concept Arithmetic = IsArithmetic; 25 | 26 | template 27 | concept Signed = IsSigned; 28 | 29 | template 30 | concept Unsigned = IsUnsigned; 31 | 32 | template 33 | concept Enum = IsEnum; 34 | 35 | template 36 | concept SameAs = IsSame; 37 | 38 | template 39 | concept OneOf = IsOneOf; 40 | 41 | template 42 | concept OneOfIgnoringCV = IsOneOfIgnoringCV; 43 | 44 | template typename S> 45 | concept SpecializationOf = IsSpecializationOf; 46 | 47 | template 48 | concept AnyString = Detail::IsConstructible; 49 | 50 | template 51 | concept HashCompatible = IsHashCompatible, Detail::Decay>; 52 | 53 | // FIXME: remove once Clang formats these properly. 54 | // clang-format off 55 | 56 | // Any indexable, sized, contiguous data structure. 57 | template 58 | concept ArrayLike = requires(ArrayT array, SizeT index) 59 | { 60 | { 61 | array[index] 62 | } 63 | -> SameAs&>; 64 | 65 | { 66 | array.size() 67 | } 68 | -> SameAs; 69 | 70 | { 71 | array.span() 72 | } 73 | -> SameAs>>; 74 | 75 | { 76 | array.data() 77 | } 78 | -> SameAs*>; 79 | }; 80 | 81 | template 82 | concept VoidFunction = requires(Func func, Args... args) 83 | { 84 | { 85 | func(args...) 86 | } 87 | -> SameAs; 88 | }; 89 | 90 | template 91 | concept IteratorPairWith = requires(T it, EndT end) 92 | { 93 | *it; 94 | { it != end } -> SameAs; 95 | ++it; 96 | }; 97 | 98 | template 99 | concept IterableContainer = requires 100 | { 101 | { declval().begin() } -> IteratorPairWith().end())>; 102 | }; 103 | 104 | // clang-format on 105 | } 106 | 107 | using AK::Concepts::Arithmetic; 108 | using AK::Concepts::ArrayLike; 109 | using AK::Concepts::Enum; 110 | using AK::Concepts::FloatingPoint; 111 | using AK::Concepts::Fundamental; 112 | using AK::Concepts::Integral; 113 | using AK::Concepts::IterableContainer; 114 | using AK::Concepts::IteratorPairWith; 115 | using AK::Concepts::OneOf; 116 | using AK::Concepts::OneOfIgnoringCV; 117 | using AK::Concepts::SameAs; 118 | using AK::Concepts::Signed; 119 | using AK::Concepts::SpecializationOf; 120 | using AK::Concepts::Unsigned; 121 | using AK::Concepts::VoidFunction; 122 | -------------------------------------------------------------------------------- /runtime/AK/Error.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, Andreas Kling 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | #if defined(__serenity__) && defined(KERNEL) 14 | # include 15 | #else 16 | # include 17 | # include 18 | #endif 19 | 20 | namespace AK { 21 | 22 | class Error { 23 | public: 24 | static Error from_errno(int code) { return Error(code); } 25 | 26 | bool is_errno() const { return m_code != 0; } 27 | 28 | int code() const { return m_code; } 29 | 30 | protected: 31 | Error(int code) 32 | : m_code(code) 33 | { 34 | } 35 | 36 | private: 37 | int m_code { 0 }; 38 | bool m_syscall { false }; 39 | }; 40 | 41 | template 42 | class [[nodiscard]] ErrorOr final : public Variant { 43 | public: 44 | using Variant::Variant; 45 | 46 | template 47 | ALWAYS_INLINE ErrorOr(U&& value) requires(!IsSame, ErrorOr>) 48 | : Variant(forward(value)) 49 | { 50 | } 51 | 52 | #ifdef __serenity__ 53 | ErrorOr(ErrnoCode code) 54 | : Variant(Error::from_errno(code)) 55 | { 56 | } 57 | #endif 58 | 59 | T& value() 60 | { 61 | return this->template get(); 62 | } 63 | T const& value() const { return this->template get(); } 64 | ErrorType& error() { return this->template get(); } 65 | ErrorType const& error() const { return this->template get(); } 66 | 67 | bool is_error() const { return this->template has(); } 68 | 69 | T release_value() { return move(value()); } 70 | ErrorType release_error() { return move(error()); } 71 | 72 | T release_value_but_fixme_should_propagate_errors() 73 | { 74 | VERIFY(!is_error()); 75 | return release_value(); 76 | } 77 | 78 | private: 79 | // 'downcast' is fishy in this context. Let's hide it by making it private. 80 | using Variant::downcast; 81 | }; 82 | 83 | // Partial specialization for void value type 84 | template 85 | class [[nodiscard]] ErrorOr { 86 | public: 87 | ErrorOr(ErrorType error) 88 | : m_error(move(error)) 89 | { 90 | } 91 | 92 | #ifdef __serenity__ 93 | ErrorOr(ErrnoCode code) 94 | : m_error(Error::from_errno(code)) 95 | { 96 | } 97 | #endif 98 | 99 | ErrorOr() = default; 100 | ErrorOr(ErrorOr&& other) = default; 101 | ErrorOr(ErrorOr const& other) = default; 102 | ~ErrorOr() = default; 103 | 104 | ErrorOr& operator=(ErrorOr&& other) = default; 105 | ErrorOr& operator=(ErrorOr const& other) = default; 106 | 107 | ErrorType& error() { return m_error.value(); } 108 | bool is_error() const { return m_error.has_value(); } 109 | ErrorType release_error() { return m_error.release_value(); } 110 | void release_value() { } 111 | 112 | private: 113 | Optional m_error; 114 | }; 115 | 116 | } 117 | 118 | using AK::Error; 119 | using AK::ErrorOr; 120 | -------------------------------------------------------------------------------- /runtime/AK/Iterator.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, the SerenityOS developers. 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | namespace AK { 12 | 13 | template 14 | class SimpleIterator { 15 | public: 16 | friend Container; 17 | 18 | constexpr bool is_end() const { return m_index == SimpleIterator::end(m_container).m_index; } 19 | constexpr size_t index() const { return m_index; } 20 | 21 | constexpr bool operator==(SimpleIterator other) const { return m_index == other.m_index; } 22 | constexpr bool operator!=(SimpleIterator other) const { return m_index != other.m_index; } 23 | constexpr bool operator<(SimpleIterator other) const { return m_index < other.m_index; } 24 | constexpr bool operator>(SimpleIterator other) const { return m_index > other.m_index; } 25 | constexpr bool operator<=(SimpleIterator other) const { return m_index <= other.m_index; } 26 | constexpr bool operator>=(SimpleIterator other) const { return m_index >= other.m_index; } 27 | 28 | constexpr SimpleIterator operator+(ptrdiff_t delta) const { return SimpleIterator { m_container, m_index + delta }; } 29 | constexpr SimpleIterator operator-(ptrdiff_t delta) const { return SimpleIterator { m_container, m_index - delta }; } 30 | 31 | constexpr ptrdiff_t operator-(SimpleIterator other) const { return static_cast(m_index) - other.m_index; } 32 | 33 | constexpr SimpleIterator operator++() 34 | { 35 | ++m_index; 36 | return *this; 37 | } 38 | constexpr SimpleIterator operator++(int) 39 | { 40 | ++m_index; 41 | return SimpleIterator { m_container, m_index - 1 }; 42 | } 43 | 44 | constexpr SimpleIterator operator--() 45 | { 46 | --m_index; 47 | return *this; 48 | } 49 | constexpr SimpleIterator operator--(int) 50 | { 51 | --m_index; 52 | return SimpleIterator { m_container, m_index + 1 }; 53 | } 54 | 55 | ALWAYS_INLINE constexpr ValueType const& operator*() const { return m_container[m_index]; } 56 | ALWAYS_INLINE constexpr ValueType& operator*() { return m_container[m_index]; } 57 | 58 | ALWAYS_INLINE constexpr ValueType const* operator->() const { return &m_container[m_index]; } 59 | ALWAYS_INLINE constexpr ValueType* operator->() { return &m_container[m_index]; } 60 | 61 | SimpleIterator& operator=(SimpleIterator const& other) 62 | { 63 | m_index = other.m_index; 64 | return *this; 65 | } 66 | SimpleIterator(SimpleIterator const& obj) = default; 67 | 68 | private: 69 | static constexpr SimpleIterator begin(Container& container) { return { container, 0 }; } 70 | static constexpr SimpleIterator end(Container& container) 71 | { 72 | using RawContainerType = RemoveCV; 73 | 74 | if constexpr (IsSame || IsSame) 75 | return { container, container.length() }; 76 | else 77 | return { container, container.size() }; 78 | } 79 | 80 | constexpr SimpleIterator(Container& container, size_t index) 81 | : m_container(container) 82 | , m_index(index) 83 | { 84 | } 85 | 86 | Container& m_container; 87 | size_t m_index; 88 | }; 89 | 90 | } 91 | -------------------------------------------------------------------------------- /runtime/AK/StringBuilder.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2021, Andreas Kling 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | namespace AK { 14 | 15 | inline ErrorOr StringBuilder::will_append(size_t size) 16 | { 17 | TRY(m_buffer.add_capacity(size)); 18 | return {}; 19 | } 20 | 21 | StringBuilder::StringBuilder() 22 | { 23 | } 24 | 25 | ErrorOr StringBuilder::try_append(StringView string) 26 | { 27 | if (string.is_empty()) 28 | return {}; 29 | TRY(will_append(string.length())); 30 | TRY(m_buffer.push_values((u8 const*)string.characters_without_null_termination(), string.length())); 31 | return {}; 32 | } 33 | 34 | ErrorOr StringBuilder::try_append(char ch) 35 | { 36 | TRY(will_append(1)); 37 | TRY(m_buffer.push(ch)); 38 | return {}; 39 | } 40 | 41 | void StringBuilder::append(StringView string) 42 | { 43 | MUST(try_append(string)); 44 | } 45 | 46 | ErrorOr StringBuilder::try_append(char const* characters, size_t length) 47 | { 48 | return try_append(StringView { characters, length }); 49 | } 50 | 51 | void StringBuilder::append(char const* characters, size_t length) 52 | { 53 | MUST(try_append(characters, length)); 54 | } 55 | 56 | void StringBuilder::append(char ch) 57 | { 58 | MUST(try_append(ch)); 59 | } 60 | 61 | ErrorOr StringBuilder::to_string() const 62 | { 63 | if (is_empty()) 64 | return String::empty(); 65 | return String::copy(string_view()); 66 | } 67 | 68 | StringView StringBuilder::string_view() const 69 | { 70 | return StringView { data(), m_buffer.size() }; 71 | } 72 | 73 | void StringBuilder::clear() 74 | { 75 | static_cast(m_buffer.resize(0)); 76 | } 77 | 78 | ErrorOr StringBuilder::try_append_code_point(u32 code_point) 79 | { 80 | auto nwritten = AK::UnicodeUtils::code_point_to_utf8(code_point, [this](char c) { append(c); }); 81 | if (nwritten < 0) { 82 | TRY(try_append(0xef)); 83 | TRY(try_append(0xbf)); 84 | TRY(try_append(0xbd)); 85 | } 86 | return {}; 87 | } 88 | 89 | void StringBuilder::append_code_point(u32 code_point) 90 | { 91 | MUST(try_append_code_point(code_point)); 92 | } 93 | 94 | void StringBuilder::append_as_lowercase(char ch) 95 | { 96 | if (ch >= 'A' && ch <= 'Z') 97 | append(ch + 0x20); 98 | else 99 | append(ch); 100 | } 101 | 102 | void StringBuilder::append_escaped_for_json(StringView string) 103 | { 104 | MUST(try_append_escaped_for_json(string)); 105 | } 106 | 107 | ErrorOr StringBuilder::try_append_escaped_for_json(StringView string) 108 | { 109 | for (auto ch : string) { 110 | switch (ch) { 111 | case '\b': 112 | TRY(try_append("\\b")); 113 | break; 114 | case '\n': 115 | TRY(try_append("\\n")); 116 | break; 117 | case '\t': 118 | TRY(try_append("\\t")); 119 | break; 120 | case '\"': 121 | TRY(try_append("\\\"")); 122 | break; 123 | case '\\': 124 | TRY(try_append("\\\\")); 125 | break; 126 | default: 127 | if (ch >= 0 && ch <= 0x1f) 128 | TRY(try_appendff("\\u{:04x}", ch)); 129 | else 130 | TRY(try_append(ch)); 131 | } 132 | } 133 | return {}; 134 | } 135 | 136 | } 137 | -------------------------------------------------------------------------------- /runtime/AK/Platform.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2020, Andreas Kling 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #ifdef __i386__ 10 | # define AK_ARCH_I386 1 11 | #endif 12 | 13 | #ifdef __x86_64__ 14 | # define AK_ARCH_X86_64 1 15 | #endif 16 | 17 | #ifdef __aarch64__ 18 | # define AK_ARCH_AARCH64 1 19 | #endif 20 | 21 | #if defined(__APPLE__) && defined(__MACH__) 22 | # define AK_OS_MACOS 23 | # define AK_OS_BSD_GENERIC 24 | #endif 25 | 26 | #if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__DragonFly__) 27 | # define AK_OS_BSD_GENERIC 28 | #endif 29 | 30 | #define ARCH(arch) (defined(AK_ARCH_##arch) && AK_ARCH_##arch) 31 | 32 | #if ARCH(I386) || ARCH(X86_64) 33 | # define VALIDATE_IS_X86() 34 | #else 35 | # define VALIDATE_IS_X86() static_assert(false, "Trying to include x86 only header on non x86 platform"); 36 | #endif 37 | 38 | #if !defined(__clang__) && !defined(__CLION_IDE_) 39 | # define AK_HAS_CONDITIONALLY_TRIVIAL 40 | #endif 41 | 42 | #ifdef ALWAYS_INLINE 43 | # undef ALWAYS_INLINE 44 | #endif 45 | #define ALWAYS_INLINE __attribute__((always_inline)) inline 46 | 47 | #ifdef NEVER_INLINE 48 | # undef NEVER_INLINE 49 | #endif 50 | #define NEVER_INLINE __attribute__((noinline)) 51 | 52 | #ifdef FLATTEN 53 | # undef FLATTEN 54 | #endif 55 | #define FLATTEN __attribute__((flatten)) 56 | 57 | #ifdef RETURNS_NONNULL 58 | # undef RETURNS_NONNULL 59 | #endif 60 | #define RETURNS_NONNULL __attribute__((returns_nonnull)) 61 | 62 | #ifdef NO_SANITIZE_ADDRESS 63 | # undef NO_SANITIZE_ADDRESS 64 | #endif 65 | #define NO_SANITIZE_ADDRESS __attribute__((no_sanitize_address)) 66 | 67 | #ifdef NAKED 68 | # undef NAKED 69 | #endif 70 | #define NAKED __attribute__((naked)) 71 | 72 | #ifdef DISALLOW 73 | # undef DISALLOW 74 | #endif 75 | #ifdef __clang__ 76 | # define DISALLOW(message) __attribute__((diagnose_if(1, message, "error"))) 77 | #else 78 | # define DISALLOW(message) __attribute__((error(message))) 79 | #endif 80 | 81 | // GCC doesn't have __has_feature but clang does 82 | #ifndef __has_feature 83 | # define __has_feature(...) 0 84 | #endif 85 | 86 | #if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) 87 | # define HAS_ADDRESS_SANITIZER 88 | # define ASAN_POISON_MEMORY_REGION(addr, size) __asan_poison_memory_region(addr, size) 89 | # define ASAN_UNPOISON_MEMORY_REGION(addr, size) __asan_unpoison_memory_region(addr, size) 90 | #else 91 | # define ASAN_POISON_MEMORY_REGION(addr, size) 92 | # define ASAN_UNPOISON_MEMORY_REGION(addr, size) 93 | #endif 94 | 95 | #if !defined(__serenity__) && !defined(_WIN32) 96 | // On macOS (at least Mojave), Apple's version of this header is not wrapped 97 | // in extern "C". 98 | # ifdef AK_OS_MACOS 99 | extern "C" { 100 | # endif 101 | # include 102 | # undef PAGE_SIZE 103 | # define PAGE_SIZE sysconf(_SC_PAGESIZE) 104 | # ifdef AK_OS_MACOS 105 | }; 106 | # endif 107 | #endif 108 | 109 | #ifdef AK_OS_BSD_GENERIC 110 | # define CLOCK_MONOTONIC_COARSE CLOCK_MONOTONIC 111 | # define CLOCK_REALTIME_COARSE CLOCK_REALTIME 112 | #endif 113 | 114 | #ifndef SYSTEM_CACHE_ALIGNMENT_SIZE 115 | # if ARCH(AARCH64) || ARCH(x86_64) 116 | # define SYSTEM_CACHE_ALIGNMENT_SIZE 64 117 | # else 118 | # define SYSTEM_CACHE_ALIGNMENT_SIZE 128 119 | # endif 120 | #endif /* SYSTEM_CACHE_ALIGNMENT_SIZE */ 121 | 122 | #ifdef CACHE_ALIGNED 123 | # undef CACHE_ALIGNED 124 | #endif 125 | #define CACHE_ALIGNED alignas(SYSTEM_CACHE_ALIGNMENT_SIZE) 126 | -------------------------------------------------------------------------------- /runtime/AK/Weakable.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2022, Andreas Kling 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #ifdef KERNEL 10 | # include 11 | #else 12 | # include 13 | # include 14 | # include 15 | # include 16 | # include 17 | 18 | namespace AK { 19 | 20 | template 21 | class Weakable; 22 | template 23 | class WeakPtr; 24 | 25 | class WeakLink : public RefCounted { 26 | template 27 | friend class Weakable; 28 | template 29 | friend class WeakPtr; 30 | 31 | public: 32 | template 33 | RefPtr strong_ref() const 34 | requires(IsBaseOf) 35 | { 36 | RefPtr ref; 37 | 38 | { 39 | if (!(m_consumers.fetch_add(1u << 1, AK::MemoryOrder::memory_order_acquire) & 1u)) { 40 | T* ptr = (T*)m_ptr.load(AK::MemoryOrder::memory_order_acquire); 41 | if (ptr && ptr->try_ref()) 42 | ref = adopt_ref(*ptr); 43 | } 44 | m_consumers.fetch_sub(1u << 1, AK::MemoryOrder::memory_order_release); 45 | } 46 | 47 | return ref; 48 | } 49 | 50 | template 51 | T* unsafe_ptr() const 52 | { 53 | if (m_consumers.load(AK::MemoryOrder::memory_order_relaxed) & 1u) 54 | return nullptr; 55 | // NOTE: This may return a non-null pointer even if revocation 56 | // has been triggered as there is a possible race! But it's "unsafe" 57 | // anyway because we return a raw pointer without ensuring a 58 | // reference... 59 | return (T*)m_ptr.load(AK::MemoryOrder::memory_order_acquire); 60 | } 61 | 62 | bool is_null() const 63 | { 64 | return unsafe_ptr() == nullptr; 65 | } 66 | 67 | void revoke() 68 | { 69 | auto current_consumers = m_consumers.fetch_or(1u, AK::MemoryOrder::memory_order_relaxed); 70 | VERIFY(!(current_consumers & 1u)); 71 | // We flagged revocation, now wait until everyone trying to obtain 72 | // a strong reference is done 73 | while (current_consumers > 0) { 74 | current_consumers = m_consumers.load(AK::MemoryOrder::memory_order_acquire) & ~1u; 75 | } 76 | // No one is trying to use it (anymore) 77 | m_ptr.store(nullptr, AK::MemoryOrder::memory_order_release); 78 | } 79 | 80 | private: 81 | template 82 | explicit WeakLink(T& weakable) 83 | : m_ptr(&weakable) 84 | { 85 | } 86 | mutable Atomic m_ptr; 87 | mutable Atomic m_consumers; // LSB indicates revocation in progress 88 | }; 89 | 90 | template 91 | class Weakable { 92 | private: 93 | class Link; 94 | 95 | public: 96 | template 97 | WeakPtr make_weak_ptr() const 98 | { 99 | return MUST(try_make_weak_ptr()); 100 | } 101 | 102 | template 103 | ErrorOr> try_make_weak_ptr() const; 104 | 105 | protected: 106 | Weakable() = default; 107 | 108 | ~Weakable() 109 | { 110 | revoke_weak_ptrs(); 111 | } 112 | 113 | void revoke_weak_ptrs() 114 | { 115 | if (auto link = move(m_link)) 116 | link->revoke(); 117 | } 118 | 119 | private: 120 | mutable RefPtr m_link; 121 | }; 122 | 123 | } 124 | 125 | using AK::Weakable; 126 | 127 | #endif 128 | -------------------------------------------------------------------------------- /runtime/AK/GenericLexer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, Benoit Lormeau 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #ifndef KERNEL 13 | # include 14 | #endif 15 | 16 | namespace AK { 17 | // Consume a number of characters 18 | StringView GenericLexer::consume(size_t count) 19 | { 20 | if (count == 0) 21 | return {}; 22 | 23 | size_t start = m_index; 24 | size_t length = min(count, m_input.length() - m_index); 25 | m_index += length; 26 | 27 | return m_input.substring_view(start, length); 28 | } 29 | 30 | // Consume the rest of the input 31 | StringView GenericLexer::consume_all() 32 | { 33 | if (is_eof()) 34 | return {}; 35 | 36 | auto rest = m_input.substring_view(m_index, m_input.length() - m_index); 37 | m_index = m_input.length(); 38 | return rest; 39 | } 40 | 41 | // Consume until a new line is found 42 | StringView GenericLexer::consume_line() 43 | { 44 | size_t start = m_index; 45 | while (!is_eof() && peek() != '\r' && peek() != '\n') 46 | m_index++; 47 | size_t length = m_index - start; 48 | 49 | consume_specific('\r'); 50 | consume_specific('\n'); 51 | 52 | if (length == 0) 53 | return {}; 54 | return m_input.substring_view(start, length); 55 | } 56 | 57 | // Consume and return characters until `stop` is peek'd 58 | StringView GenericLexer::consume_until(char stop) 59 | { 60 | size_t start = m_index; 61 | while (!is_eof() && peek() != stop) 62 | m_index++; 63 | size_t length = m_index - start; 64 | 65 | if (length == 0) 66 | return {}; 67 | return m_input.substring_view(start, length); 68 | } 69 | 70 | // Consume and return characters until the string `stop` is found 71 | StringView GenericLexer::consume_until(char const* stop) 72 | { 73 | size_t start = m_index; 74 | while (!is_eof() && !next_is(stop)) 75 | m_index++; 76 | size_t length = m_index - start; 77 | 78 | if (length == 0) 79 | return {}; 80 | return m_input.substring_view(start, length); 81 | } 82 | 83 | // Consume and return characters until the string `stop` is found 84 | StringView GenericLexer::consume_until(StringView stop) 85 | { 86 | size_t start = m_index; 87 | while (!is_eof() && !next_is(stop)) 88 | m_index++; 89 | size_t length = m_index - start; 90 | 91 | if (length == 0) 92 | return {}; 93 | return m_input.substring_view(start, length); 94 | } 95 | 96 | /* 97 | * Consume a string surrounded by single or double quotes. The returned 98 | * StringView does not include the quotes. An escape character can be provided 99 | * to capture the enclosing quotes. Please note that the escape character will 100 | * still be in the resulting StringView 101 | */ 102 | StringView GenericLexer::consume_quoted_string(char escape_char) 103 | { 104 | if (!next_is(is_quote)) 105 | return {}; 106 | 107 | char quote_char = consume(); 108 | size_t start = m_index; 109 | while (!is_eof()) { 110 | if (next_is(escape_char)) 111 | m_index++; 112 | else if (next_is(quote_char)) 113 | break; 114 | m_index++; 115 | } 116 | size_t length = m_index - start; 117 | 118 | if (peek() != quote_char) { 119 | // Restore the index in case the string is unterminated 120 | m_index = start - 1; 121 | return {}; 122 | } 123 | 124 | // Ignore closing quote 125 | ignore(); 126 | 127 | return m_input.substring_view(start, length); 128 | } 129 | 130 | } 131 | -------------------------------------------------------------------------------- /runtime/Builtins/Dictionary.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2022, Andreas Kling 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace JaktInternal { 15 | 16 | template 17 | struct DictionaryStorage : public RefCounted> { 18 | HashMap map; 19 | }; 20 | 21 | template 22 | class DictionaryIterator { 23 | using Storage = DictionaryStorage; 24 | using Iterator = typename HashMap::IteratorType; 25 | 26 | public: 27 | DictionaryIterator(NonnullRefPtr storage) 28 | : m_storage(move(storage)) 29 | , m_iterator(m_storage->map.begin()) 30 | { 31 | } 32 | 33 | Optional> next() 34 | { 35 | if (m_iterator == m_storage->map.end()) 36 | return {}; 37 | auto res = *m_iterator; 38 | ++m_iterator; 39 | return Tuple(res.key, res.value); 40 | } 41 | 42 | private: 43 | NonnullRefPtr m_storage; 44 | Iterator m_iterator; 45 | }; 46 | 47 | template 48 | class Dictionary { 49 | using Storage = DictionaryStorage; 50 | 51 | public: 52 | bool is_empty() const { return m_storage->map.is_empty(); } 53 | size_t size() const { return m_storage->map.size(); } 54 | void clear() { m_storage->map.clear(); } 55 | 56 | ErrorOr set(K const& key, V value) 57 | { 58 | TRY(m_storage->map.set(key, move(value))); 59 | return {}; 60 | } 61 | 62 | bool remove(K const& key) { return m_storage->map.remove(key); } 63 | bool contains(K const& key) const { return m_storage->map.contains(key); } 64 | 65 | Optional get(K const& key) const { return m_storage->map.get(key); } 66 | V& operator[](K const& key) { return m_storage->map.get(key).value(); } 67 | V const& operator[](K const& key) const { return m_storage->map.get(key).value(); } 68 | 69 | ErrorOr> keys() const 70 | { 71 | Array keys; 72 | TRY(keys.ensure_capacity(m_storage->map.size())); 73 | for (auto& it : m_storage->map) { 74 | MUST(keys.push(it.key)); 75 | } 76 | return keys; 77 | } 78 | 79 | ErrorOr ensure_capacity(size_t capacity) 80 | { 81 | TRY(m_storage->map.ensure_capacity(capacity)); 82 | return {}; 83 | } 84 | 85 | // FIXME: Remove this constructor once Jakt knows how to call Dictionary::create_empty() 86 | Dictionary() 87 | : m_storage(MUST(adopt_nonnull_ref_or_enomem(new (nothrow) Storage))) 88 | { 89 | } 90 | 91 | static ErrorOr create_empty() 92 | { 93 | auto storage = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) Storage)); 94 | return Dictionary { move(storage) }; 95 | } 96 | 97 | struct Entry { 98 | K key; 99 | V value; 100 | }; 101 | static ErrorOr create_with_entries(std::initializer_list list) 102 | { 103 | auto dictionary = TRY(create_empty()); 104 | TRY(dictionary.ensure_capacity(list.size())); 105 | for (auto& item : list) 106 | TRY(dictionary.set(item.key, item.value)); 107 | return dictionary; 108 | } 109 | 110 | DictionaryIterator iterator() const { return DictionaryIterator { m_storage }; } 111 | 112 | private: 113 | explicit Dictionary(NonnullRefPtr storage) 114 | : m_storage(move(storage)) 115 | { 116 | } 117 | 118 | NonnullRefPtr m_storage; 119 | }; 120 | 121 | } 122 | 123 | using JaktInternal::Dictionary; 124 | -------------------------------------------------------------------------------- /runtime/prelude.jakt: -------------------------------------------------------------------------------- 1 | extern struct String { 2 | function number(anonymous number: i64) throws -> String 3 | function split(this, anonymous c: c_char) throws -> [String] 4 | function c_string(this) -> raw c_char 5 | function to_int(this) -> i32? 6 | function to_uint(this) -> u32? 7 | function is_whitespace(this) -> bool 8 | function hash(this) -> u32 9 | function substring(this, start: usize, length: usize) throws -> String 10 | function repeated(character: c_char, count: usize) throws -> String 11 | function is_empty(this) -> bool 12 | function length(this) -> usize 13 | } 14 | 15 | extern struct ArrayIterator { 16 | function next(mutable this) -> T? 17 | } 18 | 19 | extern struct Array { 20 | function is_empty(this) -> bool 21 | function contains(this, anonymous value: T) -> bool 22 | function size(this) -> usize 23 | function capacity(this) -> usize 24 | function ensure_capacity(this, anonymous capacity: usize) throws 25 | function add_capacity(this, anonymous capacity: usize) throws 26 | function resize(mutable this, anonymous size: usize) throws 27 | function push(mutable this, anonymous value: T) throws 28 | function pop(mutable this) -> T? 29 | function iterator(this) -> ArrayIterator 30 | } 31 | 32 | extern struct Optional { 33 | function has_value(this) -> bool 34 | function value(this) -> T 35 | function value_or(this, anonymous x: T) -> T 36 | function Optional(anonymous x: S) -> Optional 37 | } 38 | 39 | extern struct WeakPtr { 40 | function has_value(this) -> bool 41 | function clear(mutable this) 42 | } 43 | 44 | extern struct DictionaryIterator { 45 | function next(mutable this) -> (K, V)? 46 | } 47 | 48 | extern struct Dictionary { 49 | function is_empty(this) -> bool 50 | function get(this, anonymous key: K) -> V? 51 | function contains(this, anonymous key: K) -> bool 52 | function set(mutable this, key: K, value: V) throws 53 | function remove(mutable this, anonymous key: K) -> bool 54 | function ensure_capacity(mutable this, anonymous capacity: usize) throws 55 | function clear(mutable this) 56 | function size(this) -> usize 57 | function capacity(this) -> usize 58 | function keys(this) -> [K] 59 | function hash(this) -> u32 60 | function Dictionary() -> [A:B] 61 | function iterator(this) -> DictionaryIterator 62 | } 63 | 64 | extern struct SetIterator { 65 | function next(mutable this) -> T? 66 | } 67 | 68 | extern struct Set { 69 | function is_empty(this) -> bool 70 | function contains(this, anonymous value: V) -> bool 71 | function add(mutable this, anonymous value: V) throws 72 | function remove(mutable this, anonymous value: V) -> bool 73 | function ensure_capacity(mutable this, anonymous capacity: usize) throws 74 | function clear(mutable this) 75 | function size(this) -> usize 76 | function capacity(this) -> usize 77 | function hash(this) -> u32 78 | function Set() -> Set 79 | function iterator(this) -> SetIterator 80 | } 81 | 82 | extern struct Tuple {} 83 | 84 | extern struct Range { 85 | function next(mutable this) -> T? 86 | } 87 | 88 | extern struct Error { 89 | function code(this) -> i32 90 | function from_errno(anonymous errno: i32) -> Error 91 | } 92 | 93 | extern class File { 94 | public function open_for_reading(anonymous path: String) throws -> File 95 | public function open_for_writing(anonymous path: String) throws -> File 96 | 97 | public function read(mutable this, anonymous buffer: [u8]) throws -> usize 98 | public function write(mutable this, anonymous data: [u8]) throws -> usize 99 | 100 | public function read_all(mutable this) throws -> [u8] 101 | } 102 | 103 | extern function as_saturated(anonymous input: T) -> U 104 | extern function as_truncated(anonymous input: T) -> U 105 | -------------------------------------------------------------------------------- /runtime/AK/LinearArray.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, the SerenityOS developers. 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | namespace AK { 13 | 14 | template 15 | struct LinearArray { 16 | using ValueType = T; 17 | 18 | [[nodiscard]] constexpr T const* data() const { return __data; } 19 | [[nodiscard]] constexpr T* data() { return __data; } 20 | 21 | [[nodiscard]] constexpr size_t size() const { return Size; } 22 | 23 | [[nodiscard]] constexpr Span span() const { return { __data, Size }; } 24 | [[nodiscard]] constexpr Span span() { return { __data, Size }; } 25 | 26 | [[nodiscard]] constexpr T const& at(size_t index) const 27 | { 28 | VERIFY(index < size()); 29 | return __data[index]; 30 | } 31 | [[nodiscard]] constexpr T& at(size_t index) 32 | { 33 | VERIFY(index < size()); 34 | return __data[index]; 35 | } 36 | 37 | [[nodiscard]] constexpr T const& first() const { return at(0); } 38 | [[nodiscard]] constexpr T& first() { return at(0); } 39 | 40 | [[nodiscard]] constexpr T const& last() const requires(Size > 0) { return at(Size - 1); } 41 | [[nodiscard]] constexpr T& last() requires(Size > 0) { return at(Size - 1); } 42 | 43 | [[nodiscard]] constexpr bool is_empty() const { return size() == 0; } 44 | 45 | [[nodiscard]] constexpr T const& operator[](size_t index) const { return at(index); } 46 | [[nodiscard]] constexpr T& operator[](size_t index) { return at(index); } 47 | 48 | template 49 | [[nodiscard]] constexpr bool operator==(LinearArray const& other) const { return span() == other.span(); } 50 | 51 | using ConstIterator = SimpleIterator; 52 | using Iterator = SimpleIterator; 53 | 54 | [[nodiscard]] constexpr ConstIterator begin() const { return ConstIterator::begin(*this); } 55 | [[nodiscard]] constexpr Iterator begin() { return Iterator::begin(*this); } 56 | 57 | [[nodiscard]] constexpr ConstIterator end() const { return ConstIterator::end(*this); } 58 | [[nodiscard]] constexpr Iterator end() { return Iterator::end(*this); } 59 | 60 | [[nodiscard]] constexpr operator Span() const { return span(); } 61 | [[nodiscard]] constexpr operator Span() { return span(); } 62 | 63 | constexpr size_t fill(T const& value) 64 | { 65 | for (size_t idx = 0; idx < Size; ++idx) 66 | __data[idx] = value; 67 | 68 | return Size; 69 | } 70 | 71 | [[nodiscard]] constexpr T max() const requires(requires(T x, T y) { x < y; }) 72 | { 73 | static_assert(Size > 0, "No values to max() over"); 74 | 75 | T value = __data[0]; 76 | for (size_t i = 1; i < Size; ++i) 77 | value = AK::max(__data[i], value); 78 | return value; 79 | } 80 | 81 | [[nodiscard]] constexpr T min() const requires(requires(T x, T y) { x > y; }) 82 | { 83 | static_assert(Size > 0, "No values to min() over"); 84 | 85 | T value = __data[0]; 86 | for (size_t i = 1; i < Size; ++i) 87 | value = AK::min(__data[i], value); 88 | return value; 89 | } 90 | 91 | T __data[Size]; 92 | }; 93 | 94 | template 95 | LinearArray(T, Types...) -> LinearArray; 96 | 97 | namespace Detail { 98 | template 99 | constexpr auto integer_sequence_generate_LinearArray([[maybe_unused]] T const offset, IntegerSequence) -> LinearArray 100 | { 101 | return { { (offset + Is)... } }; 102 | } 103 | } 104 | 105 | template 106 | constexpr static auto iota_LinearArray(T const offset = {}) 107 | { 108 | static_assert(N >= T {}, "Negative sizes not allowed in iota_LinearArray()"); 109 | return Detail::integer_sequence_generate_LinearArray(offset, MakeIntegerSequence()); 110 | } 111 | 112 | } 113 | 114 | using AK::LinearArray; 115 | using AK::iota_LinearArray; 116 | -------------------------------------------------------------------------------- /runtime/AK/MemMem.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, the SerenityOS developers. 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace AK { 15 | 16 | namespace Detail { 17 | constexpr void const* bitap_bitwise(void const* haystack, size_t haystack_length, void const* needle, size_t needle_length) 18 | { 19 | VERIFY(needle_length < 32); 20 | 21 | u64 lookup = 0xfffffffe; 22 | 23 | constexpr size_t mask_length = (size_t)((u8)-1) + 1; 24 | u64 needle_mask[mask_length]; 25 | 26 | for (size_t i = 0; i < mask_length; ++i) 27 | needle_mask[i] = 0xffffffff; 28 | 29 | for (size_t i = 0; i < needle_length; ++i) 30 | needle_mask[((u8 const*)needle)[i]] &= ~(0x00000001 << i); 31 | 32 | for (size_t i = 0; i < haystack_length; ++i) { 33 | lookup |= needle_mask[((u8 const*)haystack)[i]]; 34 | lookup <<= 1; 35 | 36 | if (0 == (lookup & (0x00000001 << needle_length))) 37 | return ((u8 const*)haystack) + i - needle_length + 1; 38 | } 39 | 40 | return nullptr; 41 | } 42 | } 43 | 44 | template 45 | inline Optional memmem(HaystackIterT const& haystack_begin, HaystackIterT const& haystack_end, Span needle) requires(requires { (*haystack_begin).data(); (*haystack_begin).size(); }) 46 | { 47 | int table[needle.size()]; 48 | auto prepare_kmp_partial_table = [&] { 49 | size_t position = 1; 50 | int candidate = 0; 51 | 52 | table[0] = -1; 53 | while (position < needle.size()) { 54 | if (needle[position] == needle[candidate]) { 55 | table[position] = table[candidate]; 56 | } else { 57 | table[position] = candidate; 58 | do { 59 | candidate = table[candidate]; 60 | } while (candidate >= 0 && needle[candidate] != needle[position]); 61 | } 62 | ++position; 63 | ++candidate; 64 | } 65 | return table; 66 | }; 67 | 68 | prepare_kmp_partial_table(); 69 | size_t total_haystack_index = 0; 70 | size_t current_haystack_index = 0; 71 | int needle_index = 0; 72 | auto haystack_it = haystack_begin; 73 | 74 | while (haystack_it != haystack_end) { 75 | auto&& chunk = *haystack_it; 76 | if (current_haystack_index >= chunk.size()) { 77 | current_haystack_index = 0; 78 | ++haystack_it; 79 | continue; 80 | } 81 | if (needle[needle_index] == chunk[current_haystack_index]) { 82 | ++needle_index; 83 | ++current_haystack_index; 84 | ++total_haystack_index; 85 | if ((size_t)needle_index == needle.size()) 86 | return total_haystack_index - needle_index; 87 | continue; 88 | } 89 | needle_index = table[needle_index]; 90 | if (needle_index < 0) { 91 | ++needle_index; 92 | ++current_haystack_index; 93 | ++total_haystack_index; 94 | } 95 | } 96 | 97 | return {}; 98 | } 99 | 100 | inline Optional memmem_optional(void const* haystack, size_t haystack_length, void const* needle, size_t needle_length) 101 | { 102 | if (needle_length == 0) 103 | return 0; 104 | 105 | if (haystack_length < needle_length) 106 | return {}; 107 | 108 | if (haystack_length == needle_length) { 109 | if (__builtin_memcmp(haystack, needle, haystack_length) == 0) 110 | return 0; 111 | return {}; 112 | } 113 | 114 | if (needle_length < 32) { 115 | auto const* ptr = Detail::bitap_bitwise(haystack, haystack_length, needle, needle_length); 116 | if (ptr) 117 | return static_cast((FlatPtr)ptr - (FlatPtr)haystack); 118 | return {}; 119 | } 120 | 121 | // Fallback to KMP. 122 | LinearArray, 1> spans { Span { (u8 const*)haystack, haystack_length } }; 123 | return memmem(spans.begin(), spans.end(), { (u8 const*)needle, needle_length }); 124 | } 125 | 126 | inline void const* memmem(void const* haystack, size_t haystack_length, void const* needle, size_t needle_length) 127 | { 128 | auto offset = memmem_optional(haystack, haystack_length, needle, needle_length); 129 | if (offset.has_value()) 130 | return ((u8 const*)haystack) + offset.value(); 131 | 132 | return nullptr; 133 | } 134 | 135 | } 136 | -------------------------------------------------------------------------------- /runtime/AK/NumericLimits.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, Andreas Kling 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | namespace AK { 12 | 13 | template 14 | struct NumericLimits { 15 | }; 16 | 17 | template<> 18 | struct NumericLimits { 19 | static constexpr bool min() { return false; } 20 | static constexpr bool max() { return true; } 21 | static constexpr bool is_signed() { return false; } 22 | }; 23 | 24 | template<> 25 | struct NumericLimits { 26 | static constexpr signed char min() { return -__SCHAR_MAX__ - 1; } 27 | static constexpr signed char max() { return __SCHAR_MAX__; } 28 | static constexpr bool is_signed() { return true; } 29 | }; 30 | 31 | template<> 32 | struct NumericLimits { 33 | static constexpr char min() { return -__SCHAR_MAX__ - 1; } 34 | static constexpr char max() { return __SCHAR_MAX__; } 35 | static constexpr bool is_signed() { return true; } 36 | }; 37 | 38 | template<> 39 | struct NumericLimits { 40 | static constexpr short min() { return -__SHRT_MAX__ - 1; } 41 | static constexpr short max() { return __SHRT_MAX__; } 42 | static constexpr bool is_signed() { return true; } 43 | }; 44 | 45 | template<> 46 | struct NumericLimits { 47 | static constexpr int min() { return -__INT_MAX__ - 1; } 48 | static constexpr int max() { return __INT_MAX__; } 49 | static constexpr bool is_signed() { return true; } 50 | }; 51 | 52 | template<> 53 | struct NumericLimits { 54 | static constexpr long min() { return -__LONG_MAX__ - 1; } 55 | static constexpr long max() { return __LONG_MAX__; } 56 | static constexpr bool is_signed() { return true; } 57 | }; 58 | 59 | template<> 60 | struct NumericLimits { 61 | static constexpr long long min() { return -__LONG_LONG_MAX__ - 1; } 62 | static constexpr long long max() { return __LONG_LONG_MAX__; } 63 | static constexpr bool is_signed() { return true; } 64 | }; 65 | 66 | template<> 67 | struct NumericLimits { 68 | static constexpr unsigned char min() { return 0; } 69 | static constexpr unsigned char max() { return __SCHAR_MAX__ * 2u + 1; } 70 | static constexpr bool is_signed() { return false; } 71 | }; 72 | 73 | template<> 74 | struct NumericLimits { 75 | static constexpr unsigned short min() { return 0; } 76 | static constexpr unsigned short max() { return __SHRT_MAX__ * 2u + 1; } 77 | static constexpr bool is_signed() { return false; } 78 | }; 79 | 80 | template<> 81 | struct NumericLimits { 82 | static constexpr unsigned min() { return 0; } 83 | static constexpr unsigned max() { return __INT_MAX__ * 2u + 1; } 84 | static constexpr bool is_signed() { return false; } 85 | }; 86 | 87 | template<> 88 | struct NumericLimits { 89 | static constexpr unsigned long min() { return 0; } 90 | static constexpr unsigned long max() { return __LONG_MAX__ * 2ul + 1; } 91 | static constexpr bool is_signed() { return false; } 92 | }; 93 | 94 | template<> 95 | struct NumericLimits { 96 | static constexpr unsigned long long min() { return 0; } 97 | static constexpr unsigned long long max() { return __LONG_LONG_MAX__ * 2ull + 1; } 98 | static constexpr bool is_signed() { return false; } 99 | }; 100 | 101 | #ifndef KERNEL 102 | template<> 103 | struct NumericLimits { 104 | static constexpr float lowest() { return -__FLT_MAX__; } 105 | static constexpr float min() { return __FLT_MIN__; } 106 | static constexpr float max() { return __FLT_MAX__; } 107 | static constexpr float epsilon() { return __FLT_EPSILON__; } 108 | static constexpr bool is_signed() { return true; } 109 | }; 110 | 111 | template<> 112 | struct NumericLimits { 113 | static constexpr double lowest() { return -__DBL_MAX__; } 114 | static constexpr double min() { return __DBL_MIN__; } 115 | static constexpr double max() { return __DBL_MAX__; } 116 | static constexpr double epsilon() { return __DBL_EPSILON__; } 117 | static constexpr bool is_signed() { return true; } 118 | }; 119 | 120 | template<> 121 | struct NumericLimits { 122 | static constexpr long double lowest() { return -__LDBL_MAX__; } 123 | static constexpr long double min() { return __LDBL_MIN__; } 124 | static constexpr long double max() { return __LDBL_MAX__; } 125 | static constexpr long double epsilon() { return __LDBL_EPSILON__; } 126 | static constexpr bool is_signed() { return true; } 127 | }; 128 | #endif 129 | 130 | } 131 | 132 | using AK::NumericLimits; 133 | -------------------------------------------------------------------------------- /runtime/AK/StdLibExtras.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2021, Andreas Kling 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | #include 12 | 13 | template 14 | constexpr auto round_up_to_power_of_two(T value, U power_of_two) requires(IsIntegral&& IsIntegral) 15 | { 16 | return ((value - 1) & ~(power_of_two - 1)) + power_of_two; 17 | } 18 | 19 | template 20 | constexpr bool is_power_of_two(T value) requires(IsIntegral) 21 | { 22 | return value && !((value) & (value - 1)); 23 | } 24 | 25 | // HACK: clang-format does not format this correctly because of the requires clause above. 26 | // Disabling formatting for that doesn't help either. 27 | // 28 | // clang-format off 29 | #ifndef AK_DONT_REPLACE_STD 30 | namespace std { // NOLINT(cert-dcl58-cpp) Names in std to aid tools 31 | 32 | // NOTE: These are in the "std" namespace since some compilers and static analyzers rely on it. 33 | 34 | template 35 | constexpr T&& forward(AK::Detail::RemoveReference& param) 36 | { 37 | return static_cast(param); 38 | } 39 | 40 | template 41 | constexpr T&& forward(AK::Detail::RemoveReference&& param) noexcept 42 | { 43 | static_assert(!IsLvalueReference, "Can't forward an rvalue as an lvalue."); 44 | return static_cast(param); 45 | } 46 | 47 | template 48 | constexpr T&& move(T& arg) 49 | { 50 | return static_cast(arg); 51 | } 52 | 53 | } 54 | #else 55 | #include 56 | #endif 57 | // clang-format on 58 | 59 | using std::forward; 60 | using std::move; 61 | 62 | namespace AK::Detail { 63 | template 64 | struct _RawPtr { 65 | using Type = T*; 66 | }; 67 | } 68 | 69 | namespace AK { 70 | 71 | template 72 | constexpr SizeType array_size(T (&)[N]) 73 | { 74 | return N; 75 | } 76 | 77 | template 78 | constexpr T min(const T& a, IdentityType const& b) 79 | { 80 | return b < a ? b : a; 81 | } 82 | 83 | template 84 | constexpr T max(const T& a, IdentityType const& b) 85 | { 86 | return a < b ? b : a; 87 | } 88 | 89 | template 90 | constexpr T clamp(const T& value, IdentityType const& min, IdentityType const& max) 91 | { 92 | VERIFY(max >= min); 93 | if (value > max) 94 | return max; 95 | if (value < min) 96 | return min; 97 | return value; 98 | } 99 | 100 | template 101 | constexpr T mix(T const& v1, T const& v2, U const& interpolation) 102 | { 103 | return v1 + (v2 - v1) * interpolation; 104 | } 105 | 106 | template 107 | constexpr T ceil_div(T a, U b) 108 | { 109 | static_assert(sizeof(T) == sizeof(U)); 110 | T result = a / b; 111 | if ((a % b) != 0) 112 | ++result; 113 | return result; 114 | } 115 | 116 | template 117 | inline void swap(T& a, U& b) 118 | { 119 | if (&a == &b) 120 | return; 121 | U tmp = move((U&)a); 122 | a = (T &&) move(b); 123 | b = move(tmp); 124 | } 125 | 126 | template 127 | constexpr T exchange(T& slot, U&& value) 128 | { 129 | T old_value = move(slot); 130 | slot = forward(value); 131 | return old_value; 132 | } 133 | 134 | template 135 | using RawPtr = typename Detail::_RawPtr::Type; 136 | 137 | template 138 | constexpr decltype(auto) to_underlying(V value) requires(IsEnum) 139 | { 140 | return static_cast>(value); 141 | } 142 | 143 | constexpr bool is_constant_evaluated() 144 | { 145 | #if __has_builtin(__builtin_is_constant_evaluated) 146 | return __builtin_is_constant_evaluated(); 147 | #else 148 | return false; 149 | #endif 150 | } 151 | 152 | // These can't be exported into the global namespace as they would clash with the C standard library. 153 | 154 | #define __DEFINE_GENERIC_ABS(type, zero, intrinsic) \ 155 | constexpr type abs(type num) \ 156 | { \ 157 | if (is_constant_evaluated()) \ 158 | return num < (zero) ? -num : num; \ 159 | return __builtin_##intrinsic(num); \ 160 | } 161 | 162 | __DEFINE_GENERIC_ABS(int, 0, abs); 163 | __DEFINE_GENERIC_ABS(long, 0L, labs); 164 | __DEFINE_GENERIC_ABS(long long, 0LL, llabs); 165 | #ifndef KERNEL 166 | __DEFINE_GENERIC_ABS(float, 0.0F, fabsf); 167 | __DEFINE_GENERIC_ABS(double, 0.0, fabs); 168 | __DEFINE_GENERIC_ABS(long double, 0.0L, fabsl); 169 | #endif 170 | 171 | #undef __DEFINE_GENERIC_ABS 172 | 173 | } 174 | 175 | using AK::array_size; 176 | using AK::ceil_div; 177 | using AK::clamp; 178 | using AK::exchange; 179 | using AK::is_constant_evaluated; 180 | using AK::max; 181 | using AK::min; 182 | using AK::mix; 183 | using AK::RawPtr; 184 | using AK::swap; 185 | using AK::to_underlying; 186 | -------------------------------------------------------------------------------- /runtime/AK/WeakPtr.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2020, Andreas Kling 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #ifdef KERNEL 10 | # include 11 | #else 12 | 13 | # include 14 | 15 | namespace AK { 16 | 17 | template 18 | class [[nodiscard]] WeakPtr { 19 | template 20 | friend class Weakable; 21 | 22 | public: 23 | WeakPtr() = default; 24 | 25 | // Someone decided that `WeakPtr` should be constructible from `None` in Jakt. 26 | WeakPtr(NullOptional) {} 27 | 28 | template 29 | WeakPtr(WeakPtr const& other) requires(IsBaseOf) 30 | : m_link(other.m_link) 31 | { 32 | } 33 | 34 | template 35 | WeakPtr(WeakPtr&& other) requires(IsBaseOf) 36 | : m_link(other.take_link()) 37 | { 38 | } 39 | 40 | template 41 | WeakPtr& operator=(WeakPtr&& other) requires(IsBaseOf) 42 | { 43 | m_link = other.take_link(); 44 | return *this; 45 | } 46 | 47 | template 48 | WeakPtr& operator=(WeakPtr const& other) requires(IsBaseOf) 49 | { 50 | if ((void const*)this != (void const*)&other) 51 | m_link = other.m_link; 52 | return *this; 53 | } 54 | 55 | WeakPtr& operator=(std::nullptr_t) 56 | { 57 | clear(); 58 | return *this; 59 | } 60 | 61 | template 62 | WeakPtr(const U& object) requires(IsBaseOf) 63 | : m_link(object.template make_weak_ptr().take_link()) 64 | { 65 | } 66 | 67 | template 68 | WeakPtr(const U* object) requires(IsBaseOf) 69 | { 70 | if (object) 71 | m_link = object->template make_weak_ptr().take_link(); 72 | } 73 | 74 | template 75 | WeakPtr(RefPtr const& object) requires(IsBaseOf) 76 | { 77 | if (object) 78 | m_link = object->template make_weak_ptr().take_link(); 79 | } 80 | 81 | template 82 | WeakPtr(NonnullRefPtr const& object) requires(IsBaseOf) 83 | { 84 | m_link = object->template make_weak_ptr().take_link(); 85 | } 86 | 87 | template 88 | WeakPtr& operator=(const U& object) requires(IsBaseOf) 89 | { 90 | m_link = object.template make_weak_ptr().take_link(); 91 | return *this; 92 | } 93 | 94 | template 95 | WeakPtr& operator=(const U* object) requires(IsBaseOf) 96 | { 97 | if (object) 98 | m_link = object->template make_weak_ptr().take_link(); 99 | else 100 | m_link = nullptr; 101 | return *this; 102 | } 103 | 104 | template 105 | WeakPtr& operator=(RefPtr const& object) requires(IsBaseOf) 106 | { 107 | if (object) 108 | m_link = object->template make_weak_ptr().take_link(); 109 | else 110 | m_link = nullptr; 111 | return *this; 112 | } 113 | 114 | template 115 | WeakPtr& operator=(NonnullRefPtr const& object) requires(IsBaseOf) 116 | { 117 | m_link = object->template make_weak_ptr().take_link(); 118 | return *this; 119 | } 120 | 121 | [[nodiscard]] RefPtr strong_ref() const 122 | { 123 | return RefPtr { ptr() }; 124 | } 125 | 126 | T* ptr() const { return unsafe_ptr(); } 127 | T* operator->() { return unsafe_ptr(); } 128 | const T* operator->() const { return unsafe_ptr(); } 129 | operator const T*() const { return unsafe_ptr(); } 130 | operator T*() { return unsafe_ptr(); } 131 | 132 | [[nodiscard]] T* unsafe_ptr() const 133 | { 134 | if (m_link) 135 | return m_link->template unsafe_ptr(); 136 | return nullptr; 137 | } 138 | 139 | operator bool() const { return m_link ? !m_link->is_null() : false; } 140 | 141 | [[nodiscard]] bool is_null() const { return !m_link || m_link->is_null(); } 142 | 143 | [[nodiscard]] bool has_value() const { return !is_null(); } 144 | T* value() { return ptr(); } 145 | T const* value() const { return ptr(); } 146 | 147 | void clear() { m_link = nullptr; } 148 | 149 | [[nodiscard]] RefPtr take_link() { return move(m_link); } 150 | 151 | private: 152 | WeakPtr(RefPtr const& link) 153 | : m_link(link) 154 | { 155 | } 156 | 157 | RefPtr m_link; 158 | }; 159 | 160 | template 161 | template 162 | inline ErrorOr> Weakable::try_make_weak_ptr() const 163 | { 164 | if (!m_link) 165 | m_link = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) WeakLink(const_cast(static_cast(*this))))); 166 | 167 | return WeakPtr(m_link); 168 | } 169 | 170 | template 171 | struct Formatter> : Formatter { 172 | ErrorOr format(FormatBuilder& builder, WeakPtr const& value) 173 | { 174 | return Formatter::format(builder, value.ptr()); 175 | } 176 | }; 177 | 178 | template 179 | ErrorOr> try_make_weak_ptr_if_nonnull(T const* ptr) 180 | { 181 | if (ptr) { 182 | return ptr->template try_make_weak_ptr(); 183 | } 184 | return WeakPtr {}; 185 | } 186 | 187 | template 188 | WeakPtr make_weak_ptr_if_nonnull(T const* ptr) 189 | { 190 | return MUST(try_make_weak_ptr_if_nonnull(ptr)); 191 | } 192 | 193 | } 194 | 195 | using AK::WeakPtr; 196 | #endif 197 | -------------------------------------------------------------------------------- /runtime/AK/Tuple.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, Ali Mohammad Pur 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | 12 | namespace AK::Detail { 13 | 14 | template 15 | struct Tuple { 16 | }; 17 | 18 | template 19 | struct Tuple { 20 | Tuple(T&& value) requires(!IsSame) 21 | : value(forward(value)) 22 | { 23 | } 24 | 25 | Tuple(const T& value) 26 | : value(value) 27 | { 28 | } 29 | 30 | template 31 | U& get() 32 | { 33 | static_assert(IsSame, "Invalid tuple access"); 34 | return value; 35 | } 36 | 37 | template 38 | const U& get() const 39 | { 40 | return const_cast&>(*this).get(); 41 | } 42 | 43 | template 44 | U& get_with_index() 45 | { 46 | static_assert(IsSame && index == 0, "Invalid tuple access"); 47 | return value; 48 | } 49 | 50 | template 51 | const U& get_with_index() const 52 | { 53 | return const_cast&>(*this).get_with_index(); 54 | } 55 | 56 | private: 57 | T value; 58 | }; 59 | 60 | template 61 | struct Tuple : Tuple { 62 | 63 | template 64 | Tuple(FirstT&& first, RestT&&... rest) 65 | : Tuple(forward(rest)...) 66 | , value(forward(first)) 67 | { 68 | } 69 | 70 | Tuple(T&& first, TRest&&... rest) 71 | : Tuple(move(rest)...) 72 | , value(move(first)) 73 | { 74 | } 75 | 76 | template 77 | U& get() 78 | { 79 | if constexpr (IsSame) 80 | return value; 81 | else 82 | return Tuple::template get(); 83 | } 84 | 85 | template 86 | const U& get() const 87 | { 88 | return const_cast&>(*this).get(); 89 | } 90 | 91 | template 92 | U& get_with_index() 93 | { 94 | if constexpr (IsSame && index == 0) 95 | return value; 96 | else 97 | return Tuple::template get_with_index(); 98 | } 99 | 100 | template 101 | const U& get_with_index() const 102 | { 103 | return const_cast&>(*this).get_with_index(); 104 | } 105 | 106 | private: 107 | T value; 108 | }; 109 | 110 | } 111 | 112 | namespace AK { 113 | 114 | template 115 | struct Tuple : Detail::Tuple { 116 | using Types = TypeList; 117 | using Detail::Tuple::Tuple; 118 | using Indices = MakeIndexSequence; 119 | 120 | Tuple(Tuple&& other) 121 | : Tuple(move(other), Indices()) 122 | { 123 | } 124 | 125 | Tuple(Tuple const& other) 126 | : Tuple(other, Indices()) 127 | { 128 | } 129 | 130 | Tuple& operator=(Tuple&& other) 131 | { 132 | set(move(other), Indices()); 133 | return *this; 134 | } 135 | 136 | Tuple& operator=(Tuple const& other) 137 | { 138 | set(other, Indices()); 139 | return *this; 140 | } 141 | 142 | template 143 | auto& get() 144 | { 145 | return Detail::Tuple::template get(); 146 | } 147 | 148 | template 149 | auto& get() 150 | { 151 | return Detail::Tuple::template get_with_index, index>(); 152 | } 153 | 154 | template 155 | auto& get() const 156 | { 157 | return Detail::Tuple::template get(); 158 | } 159 | 160 | template 161 | auto& get() const 162 | { 163 | return Detail::Tuple::template get_with_index, index>(); 164 | } 165 | 166 | template 167 | auto apply_as_args(F&& f) 168 | { 169 | return apply_as_args(forward(f), Indices()); 170 | } 171 | 172 | template 173 | auto apply_as_args(F&& f) const 174 | { 175 | return apply_as_args(forward(f), Indices()); 176 | } 177 | 178 | static constexpr auto size() { return sizeof...(Ts); } 179 | 180 | private: 181 | template 182 | Tuple(Tuple&& other, IndexSequence) 183 | : Detail::Tuple(move(other.get())...) 184 | { 185 | } 186 | 187 | template 188 | Tuple(Tuple const& other, IndexSequence) 189 | : Detail::Tuple(other.get()...) 190 | { 191 | } 192 | 193 | template 194 | void set(Tuple&& other, IndexSequence) 195 | { 196 | ((get() = move(other.get())), ...); 197 | } 198 | 199 | template 200 | void set(Tuple const& other, IndexSequence) 201 | { 202 | ((get() = other.get()), ...); 203 | } 204 | 205 | template 206 | auto apply_as_args(F&& f, IndexSequence) 207 | { 208 | return forward(f)(get()...); 209 | } 210 | 211 | template 212 | auto apply_as_args(F&& f, IndexSequence) const 213 | { 214 | return forward(f)(get()...); 215 | } 216 | }; 217 | 218 | template 219 | Tuple(Args... args) -> Tuple; 220 | 221 | } 222 | 223 | using AK::Tuple; 224 | -------------------------------------------------------------------------------- /runtime/AK/StringBuilder.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2021, Andreas Kling 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | namespace AK { 20 | 21 | class StringBuilder { 22 | public: 23 | explicit StringBuilder(); 24 | ~StringBuilder() = default; 25 | 26 | ErrorOr try_append(StringView); 27 | ErrorOr try_append_code_point(u32); 28 | ErrorOr try_append(char); 29 | template 30 | ErrorOr try_appendff(StringView&& fmtstr, Parameters const&... parameters) 31 | { 32 | VariadicFormatParams variadic_format_params { parameters... }; 33 | return vformat(*this, fmtstr, variadic_format_params); 34 | } 35 | ErrorOr try_append(char const*, size_t); 36 | ErrorOr try_append_escaped_for_json(StringView); 37 | 38 | void append(StringView); 39 | void append(char); 40 | void append_code_point(u32); 41 | void append(char const*, size_t); 42 | 43 | void append_as_lowercase(char); 44 | void append_escaped_for_json(StringView); 45 | 46 | template 47 | void appendff(StringView&& fmtstr, Parameters const&... parameters) 48 | { 49 | VariadicFormatParams variadic_format_params { parameters... }; 50 | MUST(vformat(*this, fmtstr, variadic_format_params)); 51 | } 52 | 53 | [[nodiscard]] ErrorOr to_string() const; 54 | 55 | [[nodiscard]] StringView string_view() const; 56 | void clear(); 57 | 58 | [[nodiscard]] size_t length() const { return m_buffer.size(); } 59 | [[nodiscard]] bool is_empty() const { return m_buffer.is_empty(); } 60 | 61 | template 62 | void join(SeparatorType const& separator, CollectionType const& collection, StringView fmtstr = "{}"sv) 63 | { 64 | bool first = true; 65 | for (auto& item : collection) { 66 | if (first) 67 | first = false; 68 | else 69 | append(separator); 70 | appendff(fmtstr, item); 71 | } 72 | } 73 | 74 | private: 75 | ErrorOr will_append(size_t); 76 | u8* data() { return m_buffer.unsafe_data(); } 77 | u8 const* data() const { return const_cast(this)->m_buffer.unsafe_data(); } 78 | 79 | Array m_buffer; 80 | }; 81 | 82 | } 83 | 84 | using AK::StringBuilder; 85 | 86 | namespace AK { 87 | 88 | template 89 | void append_value(StringBuilder& string_builder, T const& value) 90 | { 91 | if constexpr (IsSame) 92 | string_builder.append("\""); 93 | string_builder.appendff("{}", value); 94 | if constexpr (IsSame) 95 | string_builder.append("\""); 96 | } 97 | 98 | template 99 | struct Formatter> : Formatter { 100 | ErrorOr format(FormatBuilder& builder, JaktInternal::Array const& value) 101 | { 102 | StringBuilder string_builder; 103 | string_builder.append("["); 104 | for (size_t i = 0; i < value.size(); ++i) { 105 | append_value(string_builder, value[i]); 106 | if (i != value.size() - 1) 107 | string_builder.append(", "); 108 | } 109 | string_builder.append("]"); 110 | return Formatter::format(builder, TRY(string_builder.to_string())); 111 | } 112 | }; 113 | 114 | template 115 | struct Formatter> : Formatter { 116 | ErrorOr format(FormatBuilder& builder, JaktInternal::Set const& set) 117 | { 118 | StringBuilder string_builder; 119 | string_builder.append("{"); 120 | auto iter = set.iterator(); 121 | 122 | for (size_t i = 0; i < set.size(); ++i) { 123 | append_value(string_builder, iter.next().value()); 124 | if (i != set.size() - 1) 125 | string_builder.append(", "); 126 | } 127 | string_builder.append("}"); 128 | return Formatter::format(builder, TRY(string_builder.to_string())); 129 | } 130 | }; 131 | 132 | template 133 | struct Formatter> : Formatter { 134 | ErrorOr format(FormatBuilder& builder, JaktInternal::Dictionary const& dict) 135 | { 136 | StringBuilder string_builder; 137 | string_builder.append("["); 138 | auto iter = dict.iterator(); 139 | 140 | for (size_t i = 0; i < dict.size(); ++i) { 141 | auto item = iter.next().value(); 142 | append_value(string_builder, item.template get<0>()); 143 | string_builder.append(": "); 144 | append_value(string_builder, item.template get<1>()); 145 | if (i != dict.size() - 1) 146 | string_builder.append(", "); 147 | } 148 | string_builder.append("]"); 149 | return Formatter::format(builder, TRY(string_builder.to_string())); 150 | } 151 | }; 152 | 153 | template 154 | struct Formatter> : Formatter { 155 | ErrorOr format(FormatBuilder& builder, AK::Tuple const& tuple) 156 | { 157 | StringBuilder string_builder; 158 | string_builder.append("("); 159 | if constexpr (sizeof...(Ts) > 0) { 160 | tuple.apply_as_args([&](auto first, auto... args) { 161 | append_value(string_builder, first); 162 | ((string_builder.append(", "), append_value(string_builder, args)), ...); 163 | }); 164 | } 165 | 166 | string_builder.append(")"); 167 | return Formatter::format(builder, TRY(string_builder.to_string())); 168 | } 169 | }; 170 | 171 | } 172 | -------------------------------------------------------------------------------- /runtime/AK/CharacterTypes.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2021, Max Wipfli 3 | * Copyright (c) 2022, the SerenityOS developers. 4 | * 5 | * SPDX-License-Identifier: BSD-2-Clause 6 | */ 7 | 8 | #pragma once 9 | 10 | #include 11 | #include 12 | 13 | // NOTE: For a quick reference for most of this, see https://www.cplusplus.com/reference/cctype/ and https://infra.spec.whatwg.org/#code-points. 14 | // NOTE: To avoid ambiguity when including this header, all methods contains names should contain "ascii" or "unicode". 15 | 16 | namespace AK { 17 | 18 | constexpr bool is_ascii(u32 code_point) 19 | { 20 | return code_point < 0x80; 21 | } 22 | 23 | constexpr bool is_ascii_digit(u32 code_point) 24 | { 25 | return code_point >= '0' && code_point <= '9'; 26 | } 27 | 28 | constexpr bool is_ascii_upper_alpha(u32 code_point) 29 | { 30 | return (code_point >= 'A' && code_point <= 'Z'); 31 | } 32 | 33 | constexpr bool is_ascii_lower_alpha(u32 code_point) 34 | { 35 | return (code_point >= 'a' && code_point <= 'z'); 36 | } 37 | 38 | constexpr bool is_ascii_alpha(u32 code_point) 39 | { 40 | return is_ascii_lower_alpha(code_point) || is_ascii_upper_alpha(code_point); 41 | } 42 | 43 | constexpr bool is_ascii_alphanumeric(u32 code_point) 44 | { 45 | return is_ascii_alpha(code_point) || is_ascii_digit(code_point); 46 | } 47 | 48 | constexpr bool is_ascii_binary_digit(u32 code_point) 49 | { 50 | return code_point == '0' || code_point == '1'; 51 | } 52 | 53 | constexpr bool is_ascii_octal_digit(u32 code_point) 54 | { 55 | return code_point >= '0' && code_point <= '7'; 56 | } 57 | 58 | constexpr bool is_ascii_hex_digit(u32 code_point) 59 | { 60 | return is_ascii_digit(code_point) || (code_point >= 'A' && code_point <= 'F') || (code_point >= 'a' && code_point <= 'f'); 61 | } 62 | 63 | constexpr bool is_ascii_blank(u32 code_point) 64 | { 65 | return code_point == '\t' || code_point == ' '; 66 | } 67 | 68 | constexpr bool is_ascii_space(u32 code_point) 69 | { 70 | return code_point == ' ' || code_point == '\t' || code_point == '\n' || code_point == '\v' || code_point == '\f' || code_point == '\r'; 71 | } 72 | 73 | constexpr bool is_ascii_punctuation(u32 code_point) 74 | { 75 | return (code_point >= 0x21 && code_point <= 0x2F) || (code_point >= 0x3A && code_point <= 0x40) || (code_point >= 0x5B && code_point <= 0x60) || (code_point >= 0x7B && code_point <= 0x7E); 76 | } 77 | 78 | constexpr bool is_ascii_graphical(u32 code_point) 79 | { 80 | return code_point >= 0x21 && code_point <= 0x7E; 81 | } 82 | 83 | constexpr bool is_ascii_printable(u32 code_point) 84 | { 85 | return code_point >= 0x20 && code_point <= 0x7E; 86 | } 87 | 88 | constexpr bool is_ascii_c0_control(u32 code_point) 89 | { 90 | return code_point < 0x20; 91 | } 92 | 93 | constexpr bool is_ascii_control(u32 code_point) 94 | { 95 | return is_ascii_c0_control(code_point) || code_point == 0x7F; 96 | } 97 | 98 | constexpr bool is_unicode(u32 code_point) 99 | { 100 | return code_point <= 0x10FFFF; 101 | } 102 | 103 | constexpr bool is_unicode_control(u32 code_point) 104 | { 105 | return is_ascii_c0_control(code_point) || (code_point >= 0x7E && code_point <= 0x9F); 106 | } 107 | 108 | constexpr bool is_unicode_surrogate(u32 code_point) 109 | { 110 | return code_point >= 0xD800 && code_point <= 0xDFFF; 111 | } 112 | 113 | constexpr bool is_unicode_scalar_value(u32 code_point) 114 | { 115 | return is_unicode(code_point) && !is_unicode_surrogate(code_point); 116 | } 117 | 118 | constexpr bool is_unicode_noncharacter(u32 code_point) 119 | { 120 | return is_unicode(code_point) && ((code_point >= 0xFDD0 && code_point <= 0xFDEF) || ((code_point & 0xFFFE) == 0xFFFE) || ((code_point & 0xFFFF) == 0xFFFF)); 121 | } 122 | 123 | constexpr u32 to_ascii_lowercase(u32 code_point) 124 | { 125 | if (is_ascii_upper_alpha(code_point)) 126 | return code_point + 0x20; 127 | return code_point; 128 | } 129 | 130 | constexpr u32 to_ascii_uppercase(u32 code_point) 131 | { 132 | if (is_ascii_lower_alpha(code_point)) 133 | return code_point - 0x20; 134 | return code_point; 135 | } 136 | 137 | constexpr u32 parse_ascii_digit(u32 code_point) 138 | { 139 | if (is_ascii_digit(code_point)) 140 | return code_point - '0'; 141 | VERIFY_NOT_REACHED(); 142 | } 143 | 144 | constexpr u32 parse_ascii_hex_digit(u32 code_point) 145 | { 146 | if (is_ascii_digit(code_point)) 147 | return parse_ascii_digit(code_point); 148 | if (code_point >= 'A' && code_point <= 'F') 149 | return code_point - 'A' + 10; 150 | if (code_point >= 'a' && code_point <= 'f') 151 | return code_point - 'a' + 10; 152 | VERIFY_NOT_REACHED(); 153 | } 154 | 155 | constexpr u32 parse_ascii_base36_digit(u32 code_point) 156 | { 157 | if (is_ascii_digit(code_point)) 158 | return parse_ascii_digit(code_point); 159 | if (code_point >= 'A' && code_point <= 'Z') 160 | return code_point - 'A' + 10; 161 | if (code_point >= 'a' && code_point <= 'z') 162 | return code_point - 'a' + 10; 163 | VERIFY_NOT_REACHED(); 164 | } 165 | 166 | constexpr u32 to_ascii_base36_digit(u32 digit) 167 | { 168 | constexpr LinearArray base36_map = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z' }; 169 | VERIFY(digit < base36_map.size()); 170 | return base36_map[digit]; 171 | } 172 | 173 | } 174 | 175 | using AK::is_ascii; 176 | using AK::is_ascii_alpha; 177 | using AK::is_ascii_alphanumeric; 178 | using AK::is_ascii_binary_digit; 179 | using AK::is_ascii_blank; 180 | using AK::is_ascii_c0_control; 181 | using AK::is_ascii_control; 182 | using AK::is_ascii_digit; 183 | using AK::is_ascii_graphical; 184 | using AK::is_ascii_hex_digit; 185 | using AK::is_ascii_lower_alpha; 186 | using AK::is_ascii_octal_digit; 187 | using AK::is_ascii_printable; 188 | using AK::is_ascii_punctuation; 189 | using AK::is_ascii_space; 190 | using AK::is_ascii_upper_alpha; 191 | using AK::is_unicode; 192 | using AK::is_unicode_control; 193 | using AK::is_unicode_noncharacter; 194 | using AK::is_unicode_scalar_value; 195 | using AK::is_unicode_surrogate; 196 | using AK::parse_ascii_base36_digit; 197 | using AK::parse_ascii_digit; 198 | using AK::parse_ascii_hex_digit; 199 | using AK::to_ascii_base36_digit; 200 | using AK::to_ascii_lowercase; 201 | using AK::to_ascii_uppercase; 202 | -------------------------------------------------------------------------------- /runtime/AK/GenericLexer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020, Benoit Lormeau 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | 11 | namespace AK { 12 | 13 | class GenericLexer { 14 | public: 15 | constexpr explicit GenericLexer(StringView input) 16 | : m_input(input) 17 | { 18 | } 19 | 20 | constexpr size_t tell() const { return m_index; } 21 | constexpr size_t tell_remaining() const { return m_input.length() - m_index; } 22 | 23 | StringView remaining() const { return m_input.substring_view(m_index); } 24 | 25 | constexpr bool is_eof() const { return m_index >= m_input.length(); } 26 | 27 | constexpr char peek(size_t offset = 0) const 28 | { 29 | return (m_index + offset < m_input.length()) ? m_input[m_index + offset] : '\0'; 30 | } 31 | 32 | constexpr bool next_is(char expected) const 33 | { 34 | return peek() == expected; 35 | } 36 | 37 | constexpr bool next_is(StringView expected) const 38 | { 39 | for (size_t i = 0; i < expected.length(); ++i) 40 | if (peek(i) != expected[i]) 41 | return false; 42 | return true; 43 | } 44 | 45 | constexpr bool next_is(char const* expected) const 46 | { 47 | for (size_t i = 0; expected[i] != '\0'; ++i) 48 | if (peek(i) != expected[i]) 49 | return false; 50 | return true; 51 | } 52 | 53 | constexpr void retreat() 54 | { 55 | VERIFY(m_index > 0); 56 | --m_index; 57 | } 58 | 59 | constexpr void retreat(size_t count) 60 | { 61 | VERIFY(m_index >= count); 62 | m_index -= count; 63 | } 64 | 65 | constexpr char consume() 66 | { 67 | VERIFY(!is_eof()); 68 | return m_input[m_index++]; 69 | } 70 | 71 | template 72 | constexpr bool consume_specific(const T& next) 73 | { 74 | if (!next_is(next)) 75 | return false; 76 | 77 | if constexpr (requires { next.length(); }) { 78 | ignore(next.length()); 79 | } else { 80 | ignore(sizeof(next)); 81 | } 82 | return true; 83 | } 84 | 85 | #ifndef KERNEL 86 | bool consume_specific(String const& next) 87 | { 88 | return consume_specific(StringView { next }); 89 | } 90 | #endif 91 | 92 | constexpr bool consume_specific(char const* next) 93 | { 94 | return consume_specific(StringView { next }); 95 | } 96 | 97 | constexpr char consume_escaped_character(char escape_char = '\\', StringView escape_map = "n\nr\rt\tb\bf\f") 98 | { 99 | if (!consume_specific(escape_char)) 100 | return consume(); 101 | 102 | auto c = consume(); 103 | 104 | for (size_t i = 0; i < escape_map.length(); i += 2) { 105 | if (c == escape_map[i]) 106 | return escape_map[i + 1]; 107 | } 108 | 109 | return c; 110 | } 111 | 112 | StringView consume(size_t count); 113 | StringView consume_all(); 114 | StringView consume_line(); 115 | StringView consume_until(char); 116 | StringView consume_until(char const*); 117 | StringView consume_until(StringView); 118 | StringView consume_quoted_string(char escape_char = 0); 119 | 120 | constexpr void ignore(size_t count = 1) 121 | { 122 | count = min(count, m_input.length() - m_index); 123 | m_index += count; 124 | } 125 | 126 | constexpr void ignore_until(char stop) 127 | { 128 | while (!is_eof() && peek() != stop) { 129 | ++m_index; 130 | } 131 | ignore(); 132 | } 133 | 134 | constexpr void ignore_until(char const* stop) 135 | { 136 | while (!is_eof() && !next_is(stop)) { 137 | ++m_index; 138 | } 139 | ignore(__builtin_strlen(stop)); 140 | } 141 | 142 | /* 143 | * Conditions are used to match arbitrary characters. You can use lambdas, 144 | * ctype functions, or is_any_of() and its derivatives (see below). 145 | * A few examples: 146 | * - `if (lexer.next_is(isdigit))` 147 | * - `auto name = lexer.consume_while([](char c) { return isalnum(c) || c == '_'; });` 148 | * - `lexer.ignore_until(is_any_of("<^>"));` 149 | */ 150 | 151 | // Test the next character against a Condition 152 | template 153 | constexpr bool next_is(TPredicate pred) const 154 | { 155 | return pred(peek()); 156 | } 157 | 158 | // Consume and return characters while `pred` returns true 159 | template 160 | StringView consume_while(TPredicate pred) 161 | { 162 | size_t start = m_index; 163 | while (!is_eof() && pred(peek())) 164 | ++m_index; 165 | size_t length = m_index - start; 166 | 167 | if (length == 0) 168 | return {}; 169 | return m_input.substring_view(start, length); 170 | } 171 | 172 | // Consume and return characters until `pred` return true 173 | template 174 | StringView consume_until(TPredicate pred) 175 | { 176 | size_t start = m_index; 177 | while (!is_eof() && !pred(peek())) 178 | ++m_index; 179 | size_t length = m_index - start; 180 | 181 | if (length == 0) 182 | return {}; 183 | return m_input.substring_view(start, length); 184 | } 185 | 186 | // Ignore characters while `pred` returns true 187 | template 188 | constexpr void ignore_while(TPredicate pred) 189 | { 190 | while (!is_eof() && pred(peek())) 191 | ++m_index; 192 | } 193 | 194 | // Ignore characters until `pred` return true 195 | // We don't skip the stop character as it may not be a unique value 196 | template 197 | constexpr void ignore_until(TPredicate pred) 198 | { 199 | while (!is_eof() && !pred(peek())) 200 | ++m_index; 201 | } 202 | 203 | protected: 204 | StringView m_input; 205 | size_t m_index { 0 }; 206 | }; 207 | 208 | constexpr auto is_any_of(StringView values) 209 | { 210 | return [values](auto c) { return values.contains(c); }; 211 | } 212 | 213 | constexpr auto is_not_any_of(StringView values) 214 | { 215 | return [values](auto c) { return !values.contains(c); }; 216 | } 217 | 218 | constexpr auto is_path_separator = is_any_of("/\\"); 219 | constexpr auto is_quote = is_any_of("'\""); 220 | 221 | } 222 | 223 | using AK::GenericLexer; 224 | using AK::is_any_of; 225 | using AK::is_path_separator; 226 | using AK::is_quote; 227 | -------------------------------------------------------------------------------- /runtime/AK/NonnullRefPtr.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2020, Andreas Kling 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #define NONNULLREFPTR_SCRUB_BYTE 0xe1 10 | 11 | #ifdef KERNEL 12 | # include 13 | #else 14 | # include 15 | # include 16 | # include 17 | # include 18 | # include 19 | 20 | namespace AK { 21 | 22 | template 23 | class RefPtr; 24 | 25 | template 26 | ALWAYS_INLINE void ref_if_not_null(T* ptr) 27 | { 28 | if (ptr) 29 | ptr->ref(); 30 | } 31 | 32 | template 33 | ALWAYS_INLINE void unref_if_not_null(T* ptr) 34 | { 35 | if (ptr) 36 | ptr->unref(); 37 | } 38 | 39 | template 40 | class [[nodiscard]] NonnullRefPtr { 41 | template 42 | friend class RefPtr; 43 | template 44 | friend class NonnullRefPtr; 45 | template 46 | friend class WeakPtr; 47 | 48 | public: 49 | using ElementType = T; 50 | 51 | enum AdoptTag { Adopt }; 52 | 53 | ALWAYS_INLINE NonnullRefPtr(T const& object) 54 | : m_ptr(const_cast(&object)) 55 | { 56 | m_ptr->ref(); 57 | } 58 | 59 | template 60 | ALWAYS_INLINE NonnullRefPtr(U const& object) requires(IsConvertible) 61 | : m_ptr(const_cast(static_cast(&object))) 62 | { 63 | m_ptr->ref(); 64 | } 65 | 66 | ALWAYS_INLINE NonnullRefPtr(AdoptTag, T& object) 67 | : m_ptr(&object) 68 | { 69 | } 70 | 71 | ALWAYS_INLINE NonnullRefPtr(NonnullRefPtr&& other) 72 | : m_ptr(&other.leak_ref()) 73 | { 74 | } 75 | 76 | template 77 | ALWAYS_INLINE NonnullRefPtr(NonnullRefPtr&& other) requires(IsConvertible) 78 | : m_ptr(static_cast(&other.leak_ref())) 79 | { 80 | } 81 | 82 | ALWAYS_INLINE NonnullRefPtr(NonnullRefPtr const& other) 83 | : m_ptr(const_cast(other.ptr())) 84 | { 85 | m_ptr->ref(); 86 | } 87 | 88 | template 89 | ALWAYS_INLINE NonnullRefPtr(NonnullRefPtr const& other) requires(IsConvertible) 90 | : m_ptr(const_cast(static_cast(other.ptr()))) 91 | { 92 | m_ptr->ref(); 93 | } 94 | 95 | ALWAYS_INLINE ~NonnullRefPtr() 96 | { 97 | unref_if_not_null(m_ptr); 98 | m_ptr = nullptr; 99 | # ifdef SANITIZE_PTRS 100 | m_ptr = reinterpret_cast(explode_byte(NONNULLREFPTR_SCRUB_BYTE)); 101 | # endif 102 | } 103 | 104 | template 105 | NonnullRefPtr(RefPtr const&) = delete; 106 | template 107 | NonnullRefPtr& operator=(RefPtr const&) = delete; 108 | NonnullRefPtr(RefPtr const&) = delete; 109 | NonnullRefPtr& operator=(RefPtr const&) = delete; 110 | 111 | NonnullRefPtr& operator=(NonnullRefPtr const& other) 112 | { 113 | NonnullRefPtr tmp { other }; 114 | swap(tmp); 115 | return *this; 116 | } 117 | 118 | template 119 | NonnullRefPtr& operator=(NonnullRefPtr const& other) requires(IsConvertible) 120 | { 121 | NonnullRefPtr tmp { other }; 122 | swap(tmp); 123 | return *this; 124 | } 125 | 126 | ALWAYS_INLINE NonnullRefPtr& operator=(NonnullRefPtr&& other) 127 | { 128 | NonnullRefPtr tmp { move(other) }; 129 | swap(tmp); 130 | return *this; 131 | } 132 | 133 | template 134 | NonnullRefPtr& operator=(NonnullRefPtr&& other) requires(IsConvertible) 135 | { 136 | NonnullRefPtr tmp { move(other) }; 137 | swap(tmp); 138 | return *this; 139 | } 140 | 141 | NonnullRefPtr& operator=(T const& object) 142 | { 143 | NonnullRefPtr tmp { object }; 144 | swap(tmp); 145 | return *this; 146 | } 147 | 148 | [[nodiscard]] ALWAYS_INLINE T& leak_ref() 149 | { 150 | T* ptr = exchange(m_ptr, nullptr); 151 | VERIFY(ptr); 152 | return *ptr; 153 | } 154 | 155 | ALWAYS_INLINE RETURNS_NONNULL T* ptr() 156 | { 157 | return as_nonnull_ptr(); 158 | } 159 | ALWAYS_INLINE RETURNS_NONNULL const T* ptr() const 160 | { 161 | return as_nonnull_ptr(); 162 | } 163 | 164 | ALWAYS_INLINE RETURNS_NONNULL T* operator->() 165 | { 166 | return as_nonnull_ptr(); 167 | } 168 | ALWAYS_INLINE RETURNS_NONNULL const T* operator->() const 169 | { 170 | return as_nonnull_ptr(); 171 | } 172 | 173 | ALWAYS_INLINE T& operator*() 174 | { 175 | return *as_nonnull_ptr(); 176 | } 177 | ALWAYS_INLINE const T& operator*() const 178 | { 179 | return *as_nonnull_ptr(); 180 | } 181 | 182 | ALWAYS_INLINE RETURNS_NONNULL operator T*() 183 | { 184 | return as_nonnull_ptr(); 185 | } 186 | ALWAYS_INLINE RETURNS_NONNULL operator const T*() const 187 | { 188 | return as_nonnull_ptr(); 189 | } 190 | 191 | ALWAYS_INLINE operator T&() 192 | { 193 | return *as_nonnull_ptr(); 194 | } 195 | ALWAYS_INLINE operator const T&() const 196 | { 197 | return *as_nonnull_ptr(); 198 | } 199 | 200 | operator bool() const = delete; 201 | bool operator!() const = delete; 202 | 203 | void swap(NonnullRefPtr& other) 204 | { 205 | AK::swap(m_ptr, other.m_ptr); 206 | } 207 | 208 | template 209 | void swap(NonnullRefPtr& other) requires(IsConvertible) 210 | { 211 | AK::swap(m_ptr, other.m_ptr); 212 | } 213 | 214 | // clang-format off 215 | private: 216 | NonnullRefPtr() = delete; 217 | // clang-format on 218 | 219 | ALWAYS_INLINE RETURNS_NONNULL T* as_nonnull_ptr() const 220 | { 221 | VERIFY(m_ptr); 222 | return m_ptr; 223 | } 224 | 225 | T* m_ptr { nullptr }; 226 | }; 227 | 228 | template 229 | inline NonnullRefPtr adopt_ref(T& object) 230 | { 231 | return NonnullRefPtr(NonnullRefPtr::Adopt, object); 232 | } 233 | 234 | template 235 | inline void swap(NonnullRefPtr& a, NonnullRefPtr& b) requires(IsConvertible) 236 | { 237 | a.swap(b); 238 | } 239 | 240 | template 241 | requires(IsConstructible) inline NonnullRefPtr make_ref_counted(Args&&... args) 242 | { 243 | return NonnullRefPtr(NonnullRefPtr::Adopt, *new T(forward(args)...)); 244 | } 245 | 246 | // FIXME: Remove once P0960R3 is available in Clang. 247 | template 248 | inline NonnullRefPtr make_ref_counted(Args&&... args) 249 | { 250 | return NonnullRefPtr(NonnullRefPtr::Adopt, *new T { forward(args)... }); 251 | } 252 | } 253 | 254 | template 255 | struct Traits> : public GenericTraits> { 256 | using PeekType = T*; 257 | using ConstPeekType = const T*; 258 | static unsigned hash(NonnullRefPtr const& p) { return ptr_hash(p.ptr()); } 259 | static bool equals(NonnullRefPtr const& a, NonnullRefPtr const& b) { return a.ptr() == b.ptr(); } 260 | }; 261 | 262 | using AK::adopt_ref; 263 | using AK::make_ref_counted; 264 | using AK::NonnullRefPtr; 265 | 266 | #endif 267 | -------------------------------------------------------------------------------- /runtime/AK/String.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2022, Andreas Kling 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | namespace AK { 15 | 16 | ErrorOr String::copy(StringView view) 17 | { 18 | auto storage = TRY(StringStorage::create(view.characters_without_null_termination(), view.length())); 19 | return String { storage }; 20 | } 21 | 22 | ErrorOr String::vformatted(StringView fmtstr, TypeErasedFormatParams& params) 23 | { 24 | StringBuilder builder; 25 | TRY(vformat(builder, fmtstr, params)); 26 | return builder.to_string(); 27 | } 28 | 29 | bool String::operator==(String const& other) const 30 | { 31 | return m_storage == other.storage() || view() == other.view(); 32 | } 33 | 34 | bool String::operator==(StringView other) const 35 | { 36 | return view() == other; 37 | } 38 | 39 | bool String::operator<(String const& other) const 40 | { 41 | return view() < other.view(); 42 | } 43 | 44 | bool String::operator>(String const& other) const 45 | { 46 | return view() > other.view(); 47 | } 48 | 49 | ErrorOr String::substring(size_t start, size_t length) const 50 | { 51 | if (!length) 52 | return String::empty(); 53 | VERIFY(!Checked::addition_would_overflow(start, length)); 54 | VERIFY(start + length <= m_storage->length()); 55 | return String::copy(StringView { c_string() + start, length }); 56 | } 57 | 58 | ErrorOr> String::split(char separator, bool keep_empty) const 59 | { 60 | return split_limit(separator, 0, keep_empty); 61 | } 62 | 63 | ErrorOr> String::split_limit(char separator, size_t limit, bool keep_empty) const 64 | { 65 | auto v = Array(); 66 | if (is_empty()) 67 | return v; 68 | 69 | size_t substart = 0; 70 | for (size_t i = 0; i < length() && (v.size() + 1) != limit; ++i) { 71 | char ch = c_string()[i]; 72 | if (ch == separator) { 73 | size_t sublen = i - substart; 74 | if (sublen != 0 || keep_empty) 75 | TRY(v.push(TRY(substring(substart, sublen)))); 76 | substart = i + 1; 77 | } 78 | } 79 | size_t taillen = length() - substart; 80 | if (taillen != 0 || keep_empty) 81 | TRY(v.push(TRY(substring(substart, taillen)))); 82 | return v; 83 | } 84 | 85 | template 86 | Optional String::to_int(TrimWhitespace trim_whitespace) const 87 | { 88 | return AK::StringUtils::convert_to_int(view(), trim_whitespace); 89 | } 90 | 91 | template Optional String::to_int(TrimWhitespace) const; 92 | template Optional String::to_int(TrimWhitespace) const; 93 | template Optional String::to_int(TrimWhitespace) const; 94 | template Optional String::to_int(TrimWhitespace) const; 95 | 96 | template 97 | Optional String::to_uint(TrimWhitespace trim_whitespace) const 98 | { 99 | return AK::StringUtils::convert_to_uint(view(), trim_whitespace); 100 | } 101 | 102 | template Optional String::to_uint(TrimWhitespace) const; 103 | template Optional String::to_uint(TrimWhitespace) const; 104 | template Optional String::to_uint(TrimWhitespace) const; 105 | template Optional String::to_uint(TrimWhitespace) const; 106 | template Optional String::to_uint(TrimWhitespace) const; 107 | 108 | bool String::starts_with(StringView str, CaseSensitivity case_sensitivity) const 109 | { 110 | return AK::StringUtils::starts_with(view(), str, case_sensitivity); 111 | } 112 | 113 | bool String::starts_with(char ch) const 114 | { 115 | if (is_empty()) 116 | return false; 117 | return c_string()[0] == ch; 118 | } 119 | 120 | bool String::ends_with(StringView str, CaseSensitivity case_sensitivity) const 121 | { 122 | return AK::StringUtils::ends_with(view(), str, case_sensitivity); 123 | } 124 | 125 | bool String::ends_with(char ch) const 126 | { 127 | if (is_empty()) 128 | return false; 129 | return c_string()[length() - 1] == ch; 130 | } 131 | 132 | ErrorOr String::repeated(char ch, size_t count) 133 | { 134 | if (!count) 135 | return empty(); 136 | char* buffer; 137 | auto storage = TRY(StringStorage::create_uninitialized(count, buffer)); 138 | memset(buffer, ch, count); 139 | return String { *storage }; 140 | } 141 | 142 | bool String::contains(StringView needle, CaseSensitivity case_sensitivity) const 143 | { 144 | return AK::StringUtils::contains(view(), needle, case_sensitivity); 145 | } 146 | 147 | bool String::contains(char needle, CaseSensitivity case_sensitivity) const 148 | { 149 | return AK::StringUtils::contains(view(), StringView(&needle, 1), case_sensitivity); 150 | } 151 | 152 | bool String::equals_ignoring_case(StringView other) const 153 | { 154 | return AK::StringUtils::equals_ignoring_case(view(), other); 155 | } 156 | 157 | bool operator<(char const* characters, String const& string) 158 | { 159 | return string.view() > characters; 160 | } 161 | 162 | bool operator>=(char const* characters, String const& string) 163 | { 164 | return string.view() <= characters; 165 | } 166 | 167 | bool operator>(char const* characters, String const& string) 168 | { 169 | return string.view() < characters; 170 | } 171 | 172 | bool operator<=(char const* characters, String const& string) 173 | { 174 | return string.view() >= characters; 175 | } 176 | 177 | bool String::operator==(char const* c_string) const 178 | { 179 | return view() == c_string; 180 | } 181 | 182 | void StringStorage::operator delete(void* ptr) 183 | { 184 | free(ptr); 185 | } 186 | 187 | static StringStorage* s_the_empty_string_storage = nullptr; 188 | 189 | StringStorage& StringStorage::the_empty_string() 190 | { 191 | if (!s_the_empty_string_storage) { 192 | void* slot = malloc(sizeof(StringStorage) + sizeof(char)); 193 | s_the_empty_string_storage = new (slot) StringStorage(ConstructTheEmptyStringStorage); 194 | } 195 | return *s_the_empty_string_storage; 196 | } 197 | 198 | StringStorage::StringStorage(ConstructWithInlineBufferTag, size_t length) 199 | : m_length(length) 200 | { 201 | } 202 | 203 | StringStorage::~StringStorage() 204 | { 205 | } 206 | 207 | constexpr size_t allocation_size_for_string_storage(size_t length) 208 | { 209 | return sizeof(StringStorage) + (sizeof(char) * length) + sizeof(char); 210 | } 211 | 212 | ErrorOr> StringStorage::create_uninitialized(size_t length, char*& buffer) 213 | { 214 | VERIFY(length); 215 | void* slot = malloc(allocation_size_for_string_storage(length)); 216 | if (!slot) { 217 | return Error::from_errno(ENOMEM); 218 | } 219 | auto new_string_storage = adopt_ref(*new (slot) StringStorage(ConstructWithInlineBuffer, length)); 220 | buffer = const_cast(new_string_storage->c_string()); 221 | buffer[length] = '\0'; 222 | return new_string_storage; 223 | } 224 | 225 | ErrorOr> StringStorage::create(char const* c_string, size_t length) 226 | { 227 | if (!length) 228 | return the_empty_string(); 229 | 230 | VERIFY(c_string); 231 | 232 | char* buffer; 233 | auto new_string_storage = TRY(create_uninitialized(length, buffer)); 234 | memcpy(buffer, c_string, length * sizeof(char)); 235 | 236 | return new_string_storage; 237 | } 238 | 239 | void StringStorage::compute_hash() const 240 | { 241 | if (!length()) 242 | m_hash = 0; 243 | else 244 | m_hash = string_hash(c_string(), m_length); 245 | m_has_hash = true; 246 | } 247 | 248 | } 249 | -------------------------------------------------------------------------------- /runtime/AK/HashMap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2020, Andreas Kling 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | namespace AK { 14 | 15 | template 16 | class HashMap { 17 | private: 18 | struct Entry { 19 | K key; 20 | V value; 21 | }; 22 | 23 | struct EntryTraits { 24 | static unsigned hash(Entry const& entry) { return KeyTraits::hash(entry.key); } 25 | static bool equals(Entry const& a, Entry const& b) { return KeyTraits::equals(a.key, b.key); } 26 | }; 27 | 28 | public: 29 | using KeyType = K; 30 | using ValueType = V; 31 | 32 | HashMap() = default; 33 | 34 | HashMap(std::initializer_list list) 35 | { 36 | MUST(ensure_capacity(list.size())); 37 | for (auto& item : list) 38 | MUST(set(item.key, item.value)); 39 | } 40 | 41 | [[nodiscard]] bool is_empty() const 42 | { 43 | return m_table.is_empty(); 44 | } 45 | [[nodiscard]] size_t size() const { return m_table.size(); } 46 | [[nodiscard]] size_t capacity() const { return m_table.capacity(); } 47 | void clear() { m_table.clear(); } 48 | void clear_with_capacity() { m_table.clear_with_capacity(); } 49 | 50 | ErrorOr set(const K& key, const V& value) { return m_table.try_set({ key, value }); } 51 | ErrorOr set(const K& key, V&& value) { return m_table.try_set({ key, move(value) }); } 52 | ErrorOr set(K&& key, V&& value) { return m_table.try_set({ move(key), move(value) }); } 53 | 54 | bool remove(const K& key) 55 | { 56 | auto it = find(key); 57 | if (it != end()) { 58 | m_table.remove(it); 59 | return true; 60 | } 61 | return false; 62 | } 63 | 64 | template Key> 65 | requires(IsSame>) bool remove(Key const& key) 66 | { 67 | auto it = find(key); 68 | if (it != end()) { 69 | m_table.remove(it); 70 | return true; 71 | } 72 | return false; 73 | } 74 | 75 | template 76 | bool remove_all_matching(TUnaryPredicate predicate) 77 | { 78 | return m_table.template remove_all_matching([&](auto& entry) { 79 | return predicate(entry.key, entry.value); 80 | }); 81 | } 82 | 83 | using HashTableType = HashTable; 84 | using IteratorType = typename HashTableType::Iterator; 85 | using ConstIteratorType = typename HashTableType::ConstIterator; 86 | 87 | [[nodiscard]] IteratorType begin() { return m_table.begin(); } 88 | [[nodiscard]] IteratorType end() { return m_table.end(); } 89 | [[nodiscard]] IteratorType find(const K& key) 90 | { 91 | return m_table.find(KeyTraits::hash(key), [&](auto& entry) { return KeyTraits::equals(key, entry.key); }); 92 | } 93 | template 94 | [[nodiscard]] IteratorType find(unsigned hash, TUnaryPredicate predicate) 95 | { 96 | return m_table.find(hash, predicate); 97 | } 98 | 99 | [[nodiscard]] ConstIteratorType begin() const { return m_table.begin(); } 100 | [[nodiscard]] ConstIteratorType end() const { return m_table.end(); } 101 | [[nodiscard]] ConstIteratorType find(const K& key) const 102 | { 103 | return m_table.find(KeyTraits::hash(key), [&](auto& entry) { return KeyTraits::equals(key, entry.key); }); 104 | } 105 | template 106 | [[nodiscard]] ConstIteratorType find(unsigned hash, TUnaryPredicate predicate) const 107 | { 108 | return m_table.find(hash, predicate); 109 | } 110 | 111 | template Key> 112 | requires(IsSame>) [[nodiscard]] IteratorType find(Key const& key) 113 | { 114 | return m_table.find(Traits::hash(key), [&](auto& entry) { return Traits::equals(key, entry.key); }); 115 | } 116 | 117 | template Key> 118 | requires(IsSame>) [[nodiscard]] ConstIteratorType find(Key const& key) const 119 | { 120 | return m_table.find(Traits::hash(key), [&](auto& entry) { return Traits::equals(key, entry.key); }); 121 | } 122 | 123 | ErrorOr ensure_capacity(size_t capacity) { return m_table.try_ensure_capacity(capacity); } 124 | 125 | Optional::ConstPeekType> get(const K& key) const requires(!IsPointer::PeekType>) 126 | { 127 | auto it = find(key); 128 | if (it == end()) 129 | return {}; 130 | return (*it).value; 131 | } 132 | 133 | Optional::ConstPeekType> get(const K& key) const requires(IsPointer::PeekType>) 134 | { 135 | auto it = find(key); 136 | if (it == end()) 137 | return {}; 138 | return (*it).value; 139 | } 140 | 141 | Optional::PeekType> get(const K& key) requires(!IsConst::PeekType>) 142 | { 143 | auto it = find(key); 144 | if (it == end()) 145 | return {}; 146 | return (*it).value; 147 | } 148 | 149 | template Key> 150 | requires(IsSame>) Optional::PeekType> get(Key const& key) 151 | const requires(!IsPointer::PeekType>) 152 | { 153 | auto it = find(key); 154 | if (it == end()) 155 | return {}; 156 | return (*it).value; 157 | } 158 | 159 | template Key> 160 | requires(IsSame>) Optional::ConstPeekType> get(Key const& key) 161 | const requires(IsPointer::PeekType>) 162 | { 163 | auto it = find(key); 164 | if (it == end()) 165 | return {}; 166 | return (*it).value; 167 | } 168 | 169 | template Key> 170 | requires(IsSame>) Optional::PeekType> get(Key const& key) 171 | requires(!IsConst::PeekType>) 172 | { 173 | auto it = find(key); 174 | if (it == end()) 175 | return {}; 176 | return (*it).value; 177 | } 178 | 179 | [[nodiscard]] bool contains(const K& key) const 180 | { 181 | return find(key) != end(); 182 | } 183 | 184 | template Key> 185 | requires(IsSame>) [[nodiscard]] bool contains(Key const& value) 186 | { 187 | return find(value) != end(); 188 | } 189 | 190 | void remove(IteratorType it) 191 | { 192 | m_table.remove(it); 193 | } 194 | 195 | V& ensure(const K& key) 196 | { 197 | auto it = find(key); 198 | if (it != end()) 199 | return it->value; 200 | auto result = set(key, V()); 201 | VERIFY(result == HashSetResult::InsertedNewEntry); 202 | return find(key)->value; 203 | } 204 | 205 | template 206 | V& ensure(K const& key, Callback initialization_callback) 207 | { 208 | auto it = find(key); 209 | if (it != end()) 210 | return it->value; 211 | auto result = set(key, initialization_callback()); 212 | VERIFY(result == HashSetResult::InsertedNewEntry); 213 | return find(key)->value; 214 | } 215 | 216 | [[nodiscard]] u32 hash() const 217 | { 218 | u32 hash = 0; 219 | for (auto& it : *this) { 220 | auto entry_hash = pair_int_hash(it.key.hash(), it.value.hash()); 221 | hash = pair_int_hash(hash, entry_hash); 222 | } 223 | return hash; 224 | } 225 | 226 | private: 227 | HashTableType m_table; 228 | }; 229 | 230 | } 231 | 232 | using AK::HashMap; 233 | using AK::OrderedHashMap; 234 | -------------------------------------------------------------------------------- /runtime/AK/String.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2022, Andreas Kling 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | namespace AK { 21 | 22 | class StringStorage : public RefCounted { 23 | public: 24 | static ErrorOr> create_uninitialized(size_t length, char*& buffer); 25 | static ErrorOr> create(char const* c_string, size_t length); 26 | 27 | void operator delete(void* ptr); 28 | 29 | static StringStorage& the_empty_string(); 30 | 31 | ~StringStorage(); 32 | 33 | size_t length() const { return m_length; } 34 | 35 | // NOTE: Always includes null terminator. 36 | char const* c_string() const { return &m_inline_buffer[0]; } 37 | 38 | StringView view() const { return { c_string(), length() }; } 39 | 40 | char const& operator[](size_t i) const 41 | { 42 | VERIFY(i < m_length); 43 | return c_string()[i]; 44 | } 45 | 46 | bool operator==(StringStorage const& other) const 47 | { 48 | if (length() != other.length()) 49 | return false; 50 | return __builtin_memcmp(c_string(), other.c_string(), length()) == 0; 51 | } 52 | 53 | unsigned hash() const 54 | { 55 | if (!m_has_hash) 56 | compute_hash(); 57 | return m_hash; 58 | } 59 | 60 | unsigned existing_hash() const 61 | { 62 | return m_hash; 63 | } 64 | 65 | private: 66 | enum ConstructTheEmptyStringStorageTag { 67 | ConstructTheEmptyStringStorage 68 | }; 69 | explicit StringStorage(ConstructTheEmptyStringStorageTag) 70 | { 71 | m_inline_buffer[0] = '\0'; 72 | } 73 | 74 | enum ConstructWithInlineBufferTag { 75 | ConstructWithInlineBuffer 76 | }; 77 | StringStorage(ConstructWithInlineBufferTag, size_t length); 78 | 79 | void compute_hash() const; 80 | 81 | size_t m_length { 0 }; 82 | mutable unsigned m_hash { 0 }; 83 | mutable bool m_has_hash { false }; 84 | char m_inline_buffer[0]; 85 | }; 86 | 87 | inline size_t allocation_size_for_StringStorage(size_t length) 88 | { 89 | return sizeof(StringStorage) + (sizeof(char) * length) + sizeof(char); 90 | } 91 | 92 | class String { 93 | public: 94 | String(String const&) = default; 95 | String(String&&) = default; 96 | String& operator=(String&&) = default; 97 | String& operator=(String const&) = default; 98 | 99 | // FIXME: Remove this constructor! 100 | explicit String(char const* c_string) 101 | : m_storage(MUST(StringStorage::create(c_string, strlen(c_string)))) 102 | { 103 | } 104 | 105 | ~String() = default; 106 | 107 | [[nodiscard]] static String empty() { return String { StringStorage::the_empty_string() }; } 108 | static ErrorOr from_utf8(StringView); 109 | static ErrorOr copy(StringView); 110 | 111 | [[nodiscard]] static ErrorOr vformatted(StringView fmtstr, TypeErasedFormatParams&); 112 | 113 | template 114 | [[nodiscard]] static ErrorOr formatted(StringView&& fmtstr, Parameters const&... parameters) 115 | { 116 | VariadicFormatParams variadic_format_parameters { parameters... }; 117 | return vformatted(fmtstr, variadic_format_parameters); 118 | } 119 | 120 | StringView view() const { return { c_string(), length() }; } 121 | 122 | static ErrorOr repeated(char, size_t count); 123 | 124 | template 125 | Optional to_int(TrimWhitespace = TrimWhitespace::Yes) const; 126 | template 127 | Optional to_uint(TrimWhitespace = TrimWhitespace::Yes) const; 128 | 129 | [[nodiscard]] bool is_whitespace() const; 130 | 131 | [[nodiscard]] bool equals_ignoring_case(StringView) const; 132 | 133 | [[nodiscard]] bool contains(StringView, CaseSensitivity = CaseSensitivity::CaseSensitive) const; 134 | [[nodiscard]] bool contains(char, CaseSensitivity = CaseSensitivity::CaseSensitive) const; 135 | 136 | ErrorOr> split(char separator, bool keep_empty = false) const; 137 | ErrorOr> split_limit(char separator, size_t limit, bool keep_empty) const; 138 | 139 | [[nodiscard]] ErrorOr substring(size_t start, size_t length) const; 140 | 141 | [[nodiscard]] bool is_empty() const { return length() == 0; } 142 | [[nodiscard]] size_t length() const { return m_storage->length(); } 143 | 144 | // Guaranteed to include null terminator. 145 | [[nodiscard]] char const* c_string() const { return m_storage->c_string(); } 146 | 147 | [[nodiscard]] ALWAYS_INLINE char const& operator[](size_t i) const 148 | { 149 | return (*m_storage)[i]; 150 | } 151 | 152 | [[nodiscard]] bool starts_with(StringView, CaseSensitivity = CaseSensitivity::CaseSensitive) const; 153 | [[nodiscard]] bool ends_with(StringView, CaseSensitivity = CaseSensitivity::CaseSensitive) const; 154 | [[nodiscard]] bool starts_with(char) const; 155 | [[nodiscard]] bool ends_with(char) const; 156 | 157 | bool operator==(String const&) const; 158 | bool operator!=(String const& other) const { return !(*this == other); } 159 | 160 | bool operator==(StringView) const; 161 | bool operator!=(StringView other) const { return !(*this == other); } 162 | 163 | bool operator<(String const&) const; 164 | bool operator<(char const*) const; 165 | bool operator>=(String const& other) const { return !(*this < other); } 166 | bool operator>=(char const* other) const { return !(*this < other); } 167 | 168 | bool operator>(String const&) const; 169 | bool operator>(char const*) const; 170 | bool operator<=(String const& other) const { return !(*this > other); } 171 | bool operator<=(char const* other) const { return !(*this > other); } 172 | 173 | bool operator==(char const* cstring) const; 174 | bool operator!=(char const* cstring) const { return !(*this == cstring); } 175 | 176 | [[nodiscard]] StringStorage& storage() { return *m_storage; } 177 | [[nodiscard]] StringStorage const& storage() const { return *m_storage; } 178 | 179 | [[nodiscard]] u32 hash() const 180 | { 181 | return m_storage->hash(); 182 | } 183 | 184 | template 185 | [[nodiscard]] static ErrorOr number(T value) requires IsArithmetic 186 | { 187 | return formatted("{}", value); 188 | } 189 | 190 | private: 191 | String(NonnullRefPtr storage) 192 | : m_storage(move(storage)) 193 | { 194 | } 195 | 196 | NonnullRefPtr m_storage; 197 | }; 198 | template<> 199 | struct Formatter : Formatter { 200 | ErrorOr format(FormatBuilder& builder, StringStorage const& value) 201 | { 202 | return Formatter::format(builder, { value.c_string(), value.length() }); 203 | } 204 | }; 205 | 206 | template<> 207 | struct Traits : public GenericTraits { 208 | static unsigned hash(String const& s) { return s.storage().hash(); } 209 | }; 210 | 211 | template 212 | struct Formatter> : Formatter { 213 | ErrorOr format(FormatBuilder& builder, NonnullRefPtr const& value) 214 | { 215 | auto str = TRY(AK::String::formatted("{}", *value)); 216 | return Formatter::format(builder, str); 217 | } 218 | }; 219 | 220 | template 221 | struct Formatter> : Formatter { 222 | ErrorOr format(FormatBuilder& builder, Optional const& value) 223 | { 224 | if (!value.has_value()) 225 | return Formatter::format(builder, "None"); 226 | auto str = TRY(AK::String::formatted("{}", *value)); 227 | return Formatter::format(builder, str); 228 | } 229 | }; 230 | 231 | } 232 | 233 | using AK::String; 234 | -------------------------------------------------------------------------------- /runtime/AK/Span.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2021, the SerenityOS developers. 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | namespace AK { 16 | 17 | namespace Detail { 18 | 19 | template 20 | class Span { 21 | public: 22 | ALWAYS_INLINE constexpr Span() = default; 23 | 24 | ALWAYS_INLINE constexpr Span(T* values, size_t size) 25 | : m_values(values) 26 | , m_size(size) 27 | { 28 | } 29 | 30 | template 31 | ALWAYS_INLINE constexpr Span(T (&values)[size]) 32 | : m_values(values) 33 | , m_size(size) 34 | { 35 | } 36 | 37 | template 38 | ALWAYS_INLINE constexpr Span(LinearArray& array) 39 | : m_values(array.data()) 40 | , m_size(size) 41 | { 42 | } 43 | 44 | template 45 | requires(IsConst) 46 | ALWAYS_INLINE constexpr Span(LinearArray const& array) 47 | : m_values(array.data()) 48 | , m_size(size) 49 | { 50 | } 51 | 52 | protected: 53 | T* m_values { nullptr }; 54 | size_t m_size { 0 }; 55 | }; 56 | 57 | template<> 58 | class Span { 59 | public: 60 | ALWAYS_INLINE constexpr Span() = default; 61 | 62 | ALWAYS_INLINE constexpr Span(u8* values, size_t size) 63 | : m_values(values) 64 | , m_size(size) 65 | { 66 | } 67 | ALWAYS_INLINE Span(void* values, size_t size) 68 | : m_values(reinterpret_cast(values)) 69 | , m_size(size) 70 | { 71 | } 72 | 73 | protected: 74 | u8* m_values { nullptr }; 75 | size_t m_size { 0 }; 76 | }; 77 | 78 | template<> 79 | class Span { 80 | public: 81 | ALWAYS_INLINE constexpr Span() = default; 82 | 83 | ALWAYS_INLINE constexpr Span(u8 const* values, size_t size) 84 | : m_values(values) 85 | , m_size(size) 86 | { 87 | } 88 | ALWAYS_INLINE Span(void const* values, size_t size) 89 | : m_values(reinterpret_cast(values)) 90 | , m_size(size) 91 | { 92 | } 93 | ALWAYS_INLINE Span(char const* values, size_t size) 94 | : m_values(reinterpret_cast(values)) 95 | , m_size(size) 96 | { 97 | } 98 | 99 | protected: 100 | u8 const* m_values { nullptr }; 101 | size_t m_size { 0 }; 102 | }; 103 | 104 | } 105 | 106 | template 107 | class Span : public Detail::Span { 108 | public: 109 | using Detail::Span::Span; 110 | 111 | constexpr Span() = default; 112 | 113 | [[nodiscard]] ALWAYS_INLINE constexpr T const* data() const { return this->m_values; } 114 | [[nodiscard]] ALWAYS_INLINE constexpr T* data() { return this->m_values; } 115 | 116 | [[nodiscard]] ALWAYS_INLINE constexpr T const* offset_pointer(size_t offset) const { return this->m_values + offset; } 117 | [[nodiscard]] ALWAYS_INLINE constexpr T* offset_pointer(size_t offset) { return this->m_values + offset; } 118 | 119 | using ConstIterator = SimpleIterator; 120 | using Iterator = SimpleIterator; 121 | 122 | constexpr ConstIterator begin() const { return ConstIterator::begin(*this); } 123 | constexpr Iterator begin() { return Iterator::begin(*this); } 124 | 125 | constexpr ConstIterator end() const { return ConstIterator::end(*this); } 126 | constexpr Iterator end() { return Iterator::end(*this); } 127 | 128 | [[nodiscard]] ALWAYS_INLINE constexpr size_t size() const { return this->m_size; } 129 | [[nodiscard]] ALWAYS_INLINE constexpr bool is_null() const { return this->m_values == nullptr; } 130 | [[nodiscard]] ALWAYS_INLINE constexpr bool is_empty() const { return this->m_size == 0; } 131 | 132 | [[nodiscard]] ALWAYS_INLINE constexpr Span slice(size_t start, size_t length) const 133 | { 134 | VERIFY(start + length <= size()); 135 | return { this->m_values + start, length }; 136 | } 137 | [[nodiscard]] ALWAYS_INLINE constexpr Span slice(size_t start) const 138 | { 139 | VERIFY(start <= size()); 140 | return { this->m_values + start, size() - start }; 141 | } 142 | [[nodiscard]] ALWAYS_INLINE constexpr Span slice_from_end(size_t count) const 143 | { 144 | VERIFY(count <= size()); 145 | return { this->m_values + size() - count, count }; 146 | } 147 | 148 | [[nodiscard]] ALWAYS_INLINE constexpr Span trim(size_t length) const 149 | { 150 | return { this->m_values, min(size(), length) }; 151 | } 152 | 153 | [[nodiscard]] ALWAYS_INLINE constexpr T* offset(size_t start) const 154 | { 155 | VERIFY(start < this->m_size); 156 | return this->m_values + start; 157 | } 158 | 159 | ALWAYS_INLINE constexpr void overwrite(size_t offset, void const* data, size_t data_size) 160 | { 161 | // make sure we're not told to write past the end 162 | VERIFY(offset + data_size <= size()); 163 | __builtin_memmove(this->data() + offset, data, data_size); 164 | } 165 | 166 | ALWAYS_INLINE constexpr size_t copy_to(Span> other) const 167 | { 168 | VERIFY(other.size() >= size()); 169 | return TypedTransfer>::copy(other.data(), data(), size()); 170 | } 171 | 172 | ALWAYS_INLINE constexpr size_t copy_trimmed_to(Span> other) const 173 | { 174 | auto const count = min(size(), other.size()); 175 | return TypedTransfer>::copy(other.data(), data(), count); 176 | } 177 | 178 | ALWAYS_INLINE constexpr size_t fill(T const& value) 179 | { 180 | for (size_t idx = 0; idx < size(); ++idx) 181 | data()[idx] = value; 182 | 183 | return size(); 184 | } 185 | 186 | [[nodiscard]] bool constexpr contains_slow(T const& value) const 187 | { 188 | for (size_t i = 0; i < size(); ++i) { 189 | if (at(i) == value) 190 | return true; 191 | } 192 | return false; 193 | } 194 | 195 | [[nodiscard]] bool constexpr starts_with(Span other) const 196 | { 197 | if (size() < other.size()) 198 | return false; 199 | 200 | return TypedTransfer::compare(data(), other.data(), other.size()); 201 | } 202 | 203 | [[nodiscard]] ALWAYS_INLINE constexpr T const& at(size_t index) const 204 | { 205 | VERIFY(index < this->m_size); 206 | return this->m_values[index]; 207 | } 208 | 209 | [[nodiscard]] ALWAYS_INLINE constexpr T& at(size_t index) 210 | { 211 | VERIFY(index < this->m_size); 212 | return this->m_values[index]; 213 | } 214 | 215 | [[nodiscard]] ALWAYS_INLINE constexpr T const& last() const 216 | { 217 | return this->at(this->size() - 1); 218 | } 219 | 220 | [[nodiscard]] ALWAYS_INLINE constexpr T& last() 221 | { 222 | return this->at(this->size() - 1); 223 | } 224 | 225 | [[nodiscard]] ALWAYS_INLINE constexpr T const& operator[](size_t index) const 226 | { 227 | return at(index); 228 | } 229 | 230 | [[nodiscard]] ALWAYS_INLINE constexpr T& operator[](size_t index) 231 | { 232 | return at(index); 233 | } 234 | 235 | constexpr bool operator==(Span const& other) const 236 | { 237 | if (size() != other.size()) 238 | return false; 239 | 240 | return TypedTransfer::compare(data(), other.data(), size()); 241 | } 242 | 243 | ALWAYS_INLINE constexpr operator Span() const 244 | { 245 | return { data(), size() }; 246 | } 247 | }; 248 | 249 | template 250 | struct Traits> : public GenericTraits> { 251 | static unsigned hash(Span const& span) 252 | { 253 | unsigned hash = 0; 254 | for (auto const& value : span) { 255 | auto value_hash = Traits::hash(value); 256 | hash = pair_int_hash(hash, value_hash); 257 | } 258 | return hash; 259 | } 260 | }; 261 | 262 | using ReadonlyBytes = Span; 263 | using Bytes = Span; 264 | 265 | } 266 | 267 | using AK::Bytes; 268 | using AK::ReadonlyBytes; 269 | using AK::Span; 270 | -------------------------------------------------------------------------------- /runtime/AK/Function.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2016 Apple Inc. All rights reserved. 3 | * Copyright (c) 2021, Gunnar Beutner 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * 1. Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * 2. Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in the 12 | * documentation and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 16 | * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS 18 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 24 | * THE POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #pragma once 28 | 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | 37 | namespace AK { 38 | 39 | template 40 | class Function; 41 | 42 | template 43 | inline constexpr bool IsFunctionPointer = (IsPointer && IsFunction>); 44 | 45 | // Not a function pointer, and not an lvalue reference. 46 | template 47 | inline constexpr bool IsFunctionObject = (!IsFunctionPointer && IsRvalueReference); 48 | 49 | template 50 | class Function { 51 | AK_MAKE_NONCOPYABLE(Function); 52 | 53 | public: 54 | Function() = default; 55 | Function(std::nullptr_t) 56 | { 57 | } 58 | 59 | ~Function() 60 | { 61 | clear(false); 62 | } 63 | 64 | template 65 | Function(CallableType&& callable) requires((IsFunctionObject && IsCallableWithArguments && !IsSame, Function>)) 66 | { 67 | init_with_callable(forward(callable)); 68 | } 69 | 70 | template 71 | Function(FunctionType f) requires((IsFunctionPointer && IsCallableWithArguments, In...> && !IsSame, Function>)) 72 | { 73 | init_with_callable(move(f)); 74 | } 75 | 76 | Function(Function&& other) 77 | { 78 | move_from(move(other)); 79 | } 80 | 81 | // Note: Despite this method being const, a mutable lambda _may_ modify its own captures. 82 | Out operator()(In... in) const 83 | { 84 | auto* wrapper = callable_wrapper(); 85 | VERIFY(wrapper); 86 | ++m_call_nesting_level; 87 | ScopeGuard guard([this] { 88 | if (--m_call_nesting_level == 0 && m_deferred_clear) 89 | const_cast(this)->clear(false); 90 | }); 91 | return wrapper->call(forward(in)...); 92 | } 93 | 94 | explicit operator bool() const { return !!callable_wrapper(); } 95 | 96 | template 97 | Function& operator=(CallableType&& callable) requires((IsFunctionObject && IsCallableWithArguments)) 98 | { 99 | clear(); 100 | init_with_callable(forward(callable)); 101 | return *this; 102 | } 103 | 104 | template 105 | Function& operator=(FunctionType f) requires((IsFunctionPointer && IsCallableWithArguments, In...>)) 106 | { 107 | clear(); 108 | if (f) 109 | init_with_callable(move(f)); 110 | return *this; 111 | } 112 | 113 | Function& operator=(std::nullptr_t) 114 | { 115 | clear(); 116 | return *this; 117 | } 118 | 119 | Function& operator=(Function&& other) 120 | { 121 | if (this != &other) { 122 | clear(); 123 | move_from(move(other)); 124 | } 125 | return *this; 126 | } 127 | 128 | private: 129 | class CallableWrapperBase { 130 | public: 131 | virtual ~CallableWrapperBase() = default; 132 | // Note: This is not const to allow storing mutable lambdas. 133 | virtual Out call(In...) = 0; 134 | virtual void destroy() = 0; 135 | virtual void init_and_swap(u8*, size_t) = 0; 136 | }; 137 | 138 | template 139 | class CallableWrapper final : public CallableWrapperBase { 140 | AK_MAKE_NONMOVABLE(CallableWrapper); 141 | AK_MAKE_NONCOPYABLE(CallableWrapper); 142 | 143 | public: 144 | explicit CallableWrapper(CallableType&& callable) 145 | : m_callable(move(callable)) 146 | { 147 | } 148 | 149 | Out call(In... in) final override 150 | { 151 | return m_callable(forward(in)...); 152 | } 153 | 154 | void destroy() final override 155 | { 156 | delete this; 157 | } 158 | 159 | // NOLINTNEXTLINE(readability-non-const-parameter) False positive; destination is used in a placement new expression 160 | void init_and_swap(u8* destination, size_t size) final override 161 | { 162 | VERIFY(size >= sizeof(CallableWrapper)); 163 | new (destination) CallableWrapper { move(m_callable) }; 164 | } 165 | 166 | private: 167 | CallableType m_callable; 168 | }; 169 | 170 | enum class FunctionKind { 171 | NullPointer, 172 | Inline, 173 | Outline, 174 | }; 175 | 176 | CallableWrapperBase* callable_wrapper() const 177 | { 178 | switch (m_kind) { 179 | case FunctionKind::NullPointer: 180 | return nullptr; 181 | case FunctionKind::Inline: 182 | return bit_cast(&m_storage); 183 | case FunctionKind::Outline: 184 | return *bit_cast(&m_storage); 185 | default: 186 | VERIFY_NOT_REACHED(); 187 | } 188 | } 189 | 190 | void clear(bool may_defer = true) 191 | { 192 | bool called_from_inside_function = m_call_nesting_level > 0; 193 | // NOTE: This VERIFY could fail because a Function is destroyed from within itself. 194 | VERIFY(may_defer || !called_from_inside_function); 195 | if (called_from_inside_function && may_defer) { 196 | m_deferred_clear = true; 197 | return; 198 | } 199 | m_deferred_clear = false; 200 | auto* wrapper = callable_wrapper(); 201 | if (m_kind == FunctionKind::Inline) { 202 | VERIFY(wrapper); 203 | wrapper->~CallableWrapperBase(); 204 | } else if (m_kind == FunctionKind::Outline) { 205 | VERIFY(wrapper); 206 | wrapper->destroy(); 207 | } 208 | m_kind = FunctionKind::NullPointer; 209 | } 210 | 211 | template 212 | void init_with_callable(Callable&& callable) 213 | { 214 | VERIFY(m_call_nesting_level == 0); 215 | using WrapperType = CallableWrapper; 216 | if constexpr (sizeof(WrapperType) > inline_capacity) { 217 | *bit_cast(&m_storage) = new WrapperType(forward(callable)); 218 | m_kind = FunctionKind::Outline; 219 | } else { 220 | new (m_storage) WrapperType(forward(callable)); 221 | m_kind = FunctionKind::Inline; 222 | } 223 | } 224 | 225 | void move_from(Function&& other) 226 | { 227 | VERIFY(m_call_nesting_level == 0 && other.m_call_nesting_level == 0); 228 | auto* other_wrapper = other.callable_wrapper(); 229 | switch (other.m_kind) { 230 | case FunctionKind::NullPointer: 231 | break; 232 | case FunctionKind::Inline: 233 | other_wrapper->init_and_swap(m_storage, inline_capacity); 234 | m_kind = FunctionKind::Inline; 235 | break; 236 | case FunctionKind::Outline: 237 | *bit_cast(&m_storage) = other_wrapper; 238 | m_kind = FunctionKind::Outline; 239 | break; 240 | default: 241 | VERIFY_NOT_REACHED(); 242 | } 243 | other.m_kind = FunctionKind::NullPointer; 244 | } 245 | 246 | FunctionKind m_kind { FunctionKind::NullPointer }; 247 | bool m_deferred_clear { false }; 248 | mutable Atomic m_call_nesting_level { 0 }; 249 | // Empirically determined to fit most lambdas and functions. 250 | static constexpr size_t inline_capacity = 4 * sizeof(void*); 251 | alignas(max(alignof(CallableWrapperBase), alignof(CallableWrapperBase*))) u8 m_storage[inline_capacity]; 252 | }; 253 | 254 | } 255 | 256 | using AK::Function; 257 | -------------------------------------------------------------------------------- /runtime/Builtins/Array.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | namespace JaktInternal { 10 | 11 | template 12 | class ArrayStorage : public RefCounted> { 13 | public: 14 | ArrayStorage() { } 15 | 16 | bool is_empty() const { return m_size == 0; } 17 | size_t size() const { return m_size; } 18 | size_t capacity() const { return m_capacity; } 19 | 20 | ErrorOr ensure_capacity(size_t capacity) 21 | { 22 | if (m_capacity >= capacity) { 23 | return {}; 24 | } 25 | if (Checked::multiplication_would_overflow(capacity, sizeof(T))) { 26 | return Error::from_errno(EOVERFLOW); 27 | } 28 | auto* new_elements = static_cast(malloc(capacity * sizeof(T))); 29 | if (!new_elements) { 30 | return Error::from_errno(ENOMEM); 31 | } 32 | for (size_t i = 0; i < m_size; ++i) { 33 | new (&new_elements[i]) T(move(m_elements[i])); 34 | m_elements[i].~T(); 35 | } 36 | free(m_elements); 37 | m_elements = new_elements; 38 | m_capacity = capacity; 39 | return {}; 40 | } 41 | 42 | ErrorOr add_capacity(size_t capacity) 43 | { 44 | if (Checked::addition_would_overflow(m_capacity, capacity)) { 45 | return Error::from_errno(EOVERFLOW); 46 | } 47 | TRY(ensure_capacity(m_capacity + capacity)); 48 | return {}; 49 | } 50 | 51 | bool contains(T const& value) const 52 | { 53 | for (size_t i = 0; i < m_size; ++i) { 54 | if (Traits::equals(m_elements[i], value)) { 55 | return true; 56 | } 57 | } 58 | return false; 59 | } 60 | 61 | ErrorOr add_size(size_t size) 62 | { 63 | if (Checked::addition_would_overflow(m_size, size)) { 64 | return Error::from_errno(EOVERFLOW); 65 | } 66 | TRY(resize(m_size + size)); 67 | return {}; 68 | } 69 | 70 | ErrorOr resize(size_t size) 71 | { 72 | TRY(ensure_capacity(size)); 73 | if (size > m_size) { 74 | for (size_t i = m_size; i < size; ++i) { 75 | new (&m_elements[i]) T(); 76 | } 77 | } else { 78 | for (size_t i = size; i < m_size; ++i) { 79 | m_elements[i].~T(); 80 | } 81 | } 82 | m_size = size; 83 | return {}; 84 | } 85 | 86 | T const& at(size_t index) const 87 | { 88 | VERIFY(index < m_size); 89 | return m_elements[index]; 90 | } 91 | 92 | T& at(size_t index) 93 | { 94 | VERIFY(index < m_size); 95 | return m_elements[index]; 96 | } 97 | 98 | ErrorOr push(T value) 99 | { 100 | TRY(ensure_capacity(m_size + 1)); 101 | new (&m_elements[m_size]) T(move(value)); 102 | ++m_size; 103 | return {}; 104 | } 105 | 106 | ErrorOr push_values(T const* values, size_t count) 107 | { 108 | TRY(add_capacity(count)); 109 | for (size_t i = 0; i < count; ++i) { 110 | new (&m_elements[m_size + i]) T(values[i]); 111 | } 112 | m_size += count; 113 | return {}; 114 | } 115 | 116 | T* unsafe_data() { return m_elements; } 117 | 118 | private: 119 | size_t m_size { 0 }; 120 | size_t m_capacity { 0 }; 121 | T* m_elements { nullptr }; 122 | }; 123 | 124 | template 125 | class ArraySlice { 126 | public: 127 | ArraySlice() = default; 128 | ArraySlice(ArraySlice const&) = default; 129 | ArraySlice(ArraySlice&&) = default; 130 | ArraySlice& operator=(ArraySlice const&) = default; 131 | ArraySlice& operator=(ArraySlice&&) = default; 132 | ~ArraySlice() = default; 133 | 134 | ArraySlice(NonnullRefPtr> storage, size_t offset, size_t size) 135 | : m_storage(move(storage)) 136 | , m_offset(offset) 137 | , m_size(size) 138 | { 139 | VERIFY(m_storage); 140 | VERIFY(m_offset < m_storage->size()); 141 | } 142 | 143 | bool is_empty() const { return size() == 0; } 144 | size_t size() const 145 | { 146 | if (!m_storage) 147 | return 0; 148 | if (m_offset >= m_storage->size()) 149 | return 0; 150 | size_t available_in_storage = m_storage->size() - m_offset; 151 | return max(m_size, available_in_storage); 152 | } 153 | 154 | T const& at(size_t index) const { return m_storage->at(m_offset + index); } 155 | T& at(size_t index) { return m_storage->at(m_offset + index); } 156 | T const& operator[](size_t index) const { return at(index); } 157 | T& operator[](size_t index) { return at(index); } 158 | 159 | private: 160 | RefPtr> m_storage; 161 | size_t m_offset { 0 }; 162 | size_t m_size { 0 }; 163 | }; 164 | 165 | template 166 | class ArrayIterator { 167 | using Storage = ArrayStorage; 168 | 169 | public: 170 | ArrayIterator(NonnullRefPtr storage) 171 | : m_storage(move(storage)) 172 | { 173 | } 174 | 175 | Optional next() 176 | { 177 | if (m_index >= m_storage->size()) { 178 | return {}; 179 | } 180 | auto current = m_storage->at(m_index); 181 | ++m_index; 182 | return current; 183 | } 184 | 185 | private: 186 | NonnullRefPtr m_storage; 187 | size_t m_index { 0 }; 188 | }; 189 | 190 | template 191 | class Array { 192 | public: 193 | Array() = default; 194 | Array(Array const&) = default; 195 | Array(Array&&) = default; 196 | Array& operator=(Array const&) = default; 197 | Array& operator=(Array&&) = default; 198 | ~Array() = default; 199 | 200 | ArrayIterator iterator() const 201 | { 202 | return ArrayIterator { *m_storage }; 203 | } 204 | 205 | Array(std::initializer_list list) requires(!IsLvalueReference) 206 | { 207 | // FIXME: Should not MUST() 208 | MUST(ensure_capacity(list.size())); 209 | for (auto& item : list) 210 | MUST(push(item)); 211 | } 212 | 213 | bool is_empty() const { return !m_storage || m_storage->is_empty(); } 214 | size_t size() const { return m_storage ? m_storage->size() : 0; } 215 | size_t capacity() const { return m_storage ? m_storage->capacity() : 0; } 216 | 217 | ErrorOr push(T value) 218 | { 219 | auto* storage = TRY(ensure_storage()); 220 | TRY(storage->push(move(value))); 221 | return {}; 222 | } 223 | 224 | ErrorOr push_values(T const* values, size_t count) 225 | { 226 | auto* storage = TRY(ensure_storage()); 227 | TRY(storage->push_values(values, count)); 228 | return {}; 229 | } 230 | 231 | T const& at(size_t index) const 232 | { 233 | VERIFY(m_storage); 234 | return m_storage->at(index); 235 | } 236 | 237 | T& at(size_t index) 238 | { 239 | VERIFY(m_storage); 240 | return m_storage->at(index); 241 | } 242 | 243 | bool contains(T const& value) const 244 | { 245 | return m_storage->contains(value); 246 | } 247 | 248 | T const& operator[](size_t index) const { return at(index); } 249 | T& operator[](size_t index) { return at(index); } 250 | 251 | ErrorOr ensure_capacity(size_t capacity) 252 | { 253 | auto* storage = TRY(ensure_storage()); 254 | TRY(storage->ensure_capacity(capacity)); 255 | return {}; 256 | } 257 | 258 | ErrorOr add_capacity(size_t capacity) 259 | { 260 | auto* storage = TRY(ensure_storage()); 261 | TRY(storage->add_capacity(capacity)); 262 | return {}; 263 | } 264 | 265 | ErrorOr add_size(size_t size) 266 | { 267 | auto* storage = TRY(ensure_storage()); 268 | TRY(storage->add_size(size)); 269 | return {}; 270 | } 271 | 272 | ArraySlice slice(size_t offset, size_t size) 273 | { 274 | if (!m_storage) 275 | return {}; 276 | return { *m_storage, offset, size }; 277 | } 278 | 279 | ErrorOr resize(size_t size) 280 | { 281 | if (size != this->size()) { 282 | auto* storage = TRY(ensure_storage()); 283 | TRY(storage->resize(size)); 284 | } 285 | return {}; 286 | } 287 | 288 | Optional pop() 289 | { 290 | if (is_empty()) 291 | return {}; 292 | auto value = move(at(size() - 1)); 293 | static_cast(resize(size() - 1)); 294 | return value; 295 | } 296 | 297 | static ErrorOr filled(size_t size, T value) 298 | { 299 | Array array; 300 | TRY(array.ensure_capacity(size)); 301 | for (size_t i = 0; i < size; ++i) { 302 | TRY(array.push(value)); 303 | } 304 | return array; 305 | } 306 | 307 | T* unsafe_data() 308 | { 309 | if (!m_storage) 310 | return nullptr; 311 | return m_storage->unsafe_data(); 312 | } 313 | 314 | private: 315 | ErrorOr*> ensure_storage() 316 | { 317 | if (!m_storage) { 318 | m_storage = TRY(adopt_nonnull_ref_or_enomem(new (nothrow) ArrayStorage)); 319 | } 320 | return m_storage.ptr(); 321 | } 322 | 323 | RefPtr> m_storage; 324 | }; 325 | 326 | } 327 | 328 | using JaktInternal::Array; 329 | -------------------------------------------------------------------------------- /runtime/AK/Debug.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2020-2022, the SerenityOS developers. 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #ifndef AFLACLOADER_DEBUG 10 | #define AFLACLOADER_DEBUG 0 11 | #endif 12 | 13 | #ifndef AWAVLOADER_DEBUG 14 | #define AWAVLOADER_DEBUG 0 15 | #endif 16 | 17 | #ifndef BMP_DEBUG 18 | #define BMP_DEBUG 0 19 | #endif 20 | 21 | #ifndef CACHE_DEBUG 22 | #define CACHE_DEBUG 0 23 | #endif 24 | 25 | #ifndef CALLBACK_MACHINE_DEBUG 26 | #define CALLBACK_MACHINE_DEBUG 0 27 | #endif 28 | 29 | #ifndef CANVAS_RENDERING_CONTEXT_2D_DEBUG 30 | #define CANVAS_RENDERING_CONTEXT_2D_DEBUG 0 31 | #endif 32 | 33 | #ifndef COMPOSE_DEBUG 34 | #define COMPOSE_DEBUG 0 35 | #endif 36 | 37 | #ifndef COPY_DEBUG 38 | #define COPY_DEBUG 0 39 | #endif 40 | 41 | #ifndef CPP_DEBUG 42 | #define CPP_DEBUG 0 43 | #endif 44 | 45 | #ifndef CPP_LANGUAGE_SERVER_DEBUG 46 | #define CPP_LANGUAGE_SERVER_DEBUG 0 47 | #endif 48 | 49 | #ifndef CRYPTO_DEBUG 50 | #define CRYPTO_DEBUG 0 51 | #endif 52 | 53 | #ifndef CSOCKET_DEBUG 54 | #define CSOCKET_DEBUG 0 55 | #endif 56 | 57 | #ifndef CSS_LOADER_DEBUG 58 | #define CSS_LOADER_DEBUG 0 59 | #endif 60 | 61 | #ifndef CSS_PARSER_DEBUG 62 | #define CSS_PARSER_DEBUG 0 63 | #endif 64 | 65 | #ifndef CSS_TOKENIZER_DEBUG 66 | #define CSS_TOKENIZER_DEBUG 0 67 | #endif 68 | 69 | #ifndef CURSOR_TOOL_DEBUG 70 | #define CURSOR_TOOL_DEBUG 0 71 | #endif 72 | 73 | #ifndef DDS_DEBUG 74 | #define DDS_DEBUG 0 75 | #endif 76 | 77 | #ifndef DEFERRED_INVOKE_DEBUG 78 | #define DEFERRED_INVOKE_DEBUG 0 79 | #endif 80 | 81 | #ifndef DHCPV4_DEBUG 82 | #define DHCPV4_DEBUG 0 83 | #endif 84 | 85 | #ifndef DHCPV4CLIENT_DEBUG 86 | #define DHCPV4CLIENT_DEBUG 0 87 | #endif 88 | 89 | #ifndef DIFF_DEBUG 90 | #define DIFF_DEBUG 0 91 | #endif 92 | 93 | #ifndef DISASM_DUMP_DEBUG 94 | #define DISASM_DUMP_DEBUG 0 95 | #endif 96 | 97 | #ifndef DOUBLECLICK_DEBUG 98 | #define DOUBLECLICK_DEBUG 0 99 | #endif 100 | 101 | #ifndef DRAG_DEBUG 102 | #define DRAG_DEBUG 0 103 | #endif 104 | 105 | #ifndef DWARF_DEBUG 106 | #define DWARF_DEBUG 0 107 | #endif 108 | 109 | #ifndef DYNAMIC_LOAD_DEBUG 110 | #define DYNAMIC_LOAD_DEBUG 0 111 | #endif 112 | 113 | #ifndef EDITOR_DEBUG 114 | #define EDITOR_DEBUG 0 115 | #endif 116 | 117 | #ifndef ELF_IMAGE_DEBUG 118 | #define ELF_IMAGE_DEBUG 0 119 | #endif 120 | 121 | #ifndef EMOJI_DEBUG 122 | #define EMOJI_DEBUG 0 123 | #endif 124 | 125 | #ifndef ESCAPE_SEQUENCE_DEBUG 126 | #define ESCAPE_SEQUENCE_DEBUG 0 127 | #endif 128 | 129 | #ifndef EVENT_DEBUG 130 | #define EVENT_DEBUG 0 131 | #endif 132 | 133 | #ifndef EVENTLOOP_DEBUG 134 | #define EVENTLOOP_DEBUG 0 135 | #endif 136 | 137 | #ifndef FILE_CONTENT_DEBUG 138 | #define FILE_CONTENT_DEBUG 0 139 | #endif 140 | 141 | #ifndef FILL_PATH_DEBUG 142 | #define FILL_PATH_DEBUG 0 143 | #endif 144 | 145 | #ifndef FILE_WATCHER_DEBUG 146 | #define FILE_WATCHER_DEBUG 0 147 | #endif 148 | 149 | #ifndef GEMINI_DEBUG 150 | #define GEMINI_DEBUG 0 151 | #endif 152 | 153 | #ifndef GEMINIJOB_DEBUG 154 | #define GEMINIJOB_DEBUG 0 155 | #endif 156 | 157 | #ifndef GENERATE_DEBUG 158 | #define GENERATE_DEBUG 0 159 | #endif 160 | 161 | #ifndef GHASH_PROCESS_DEBUG 162 | #define GHASH_PROCESS_DEBUG 0 163 | #endif 164 | 165 | #ifndef GIF_DEBUG 166 | #define GIF_DEBUG 0 167 | #endif 168 | 169 | #ifndef GL_DEBUG 170 | #define GL_DEBUG 0 171 | #endif 172 | 173 | #ifndef GLOBAL_DTORS_DEBUG 174 | #define GLOBAL_DTORS_DEBUG 0 175 | #endif 176 | 177 | #ifndef GZIP_DEBUG 178 | #define GZIP_DEBUG 0 179 | #endif 180 | 181 | #ifndef HEAP_DEBUG 182 | #define HEAP_DEBUG 0 183 | #endif 184 | 185 | #ifndef HEARTS_DEBUG 186 | #define HEARTS_DEBUG 0 187 | #endif 188 | 189 | #ifndef HEX_DEBUG 190 | #define HEX_DEBUG 0 191 | #endif 192 | 193 | #ifndef HIGHLIGHT_FOCUSED_FRAME_DEBUG 194 | #define HIGHLIGHT_FOCUSED_FRAME_DEBUG 0 195 | #endif 196 | 197 | #ifndef HTML_SCRIPT_DEBUG 198 | #define HTML_SCRIPT_DEBUG 0 199 | #endif 200 | 201 | #ifndef HTTPJOB_DEBUG 202 | #define HTTPJOB_DEBUG 0 203 | #endif 204 | 205 | #ifndef HTTPSJOB_DEBUG 206 | #define HTTPSJOB_DEBUG 0 207 | #endif 208 | 209 | #ifndef HUNKS_DEBUG 210 | #define HUNKS_DEBUG 0 211 | #endif 212 | 213 | #ifndef ICO_DEBUG 214 | #define ICO_DEBUG 0 215 | #endif 216 | 217 | #ifndef IMAGE_DECODER_DEBUG 218 | #define IMAGE_DECODER_DEBUG 0 219 | #endif 220 | 221 | #ifndef IMAGE_LOADER_DEBUG 222 | #define IMAGE_LOADER_DEBUG 0 223 | #endif 224 | 225 | #ifndef ITEM_RECTS_DEBUG 226 | #define ITEM_RECTS_DEBUG 0 227 | #endif 228 | 229 | #ifndef JOB_DEBUG 230 | #define JOB_DEBUG 0 231 | #endif 232 | 233 | #ifndef JPG_DEBUG 234 | #define JPG_DEBUG 0 235 | #endif 236 | 237 | #ifndef JS_BYTECODE_DEBUG 238 | #define JS_BYTECODE_DEBUG 0 239 | #endif 240 | 241 | #ifndef JS_MODULE_DEBUG 242 | #define JS_MODULE_DEBUG 0 243 | #endif 244 | 245 | #ifndef KEYBOARD_SHORTCUTS_DEBUG 246 | #define KEYBOARD_SHORTCUTS_DEBUG 0 247 | #endif 248 | 249 | #ifndef LANGUAGE_SERVER_DEBUG 250 | #define LANGUAGE_SERVER_DEBUG 0 251 | #endif 252 | 253 | #ifndef LEXER_DEBUG 254 | #define LEXER_DEBUG 0 255 | #endif 256 | 257 | #ifndef LIBWEB_CSS_DEBUG 258 | #define LIBWEB_CSS_DEBUG 0 259 | #endif 260 | 261 | #ifndef LINE_EDITOR_DEBUG 262 | #define LINE_EDITOR_DEBUG 0 263 | #endif 264 | 265 | #ifndef LOG_DEBUG 266 | #define LOG_DEBUG 0 267 | #endif 268 | 269 | #ifndef LOOKUPSERVER_DEBUG 270 | #define LOOKUPSERVER_DEBUG 0 271 | #endif 272 | 273 | #ifndef MALLOC_DEBUG 274 | #define MALLOC_DEBUG 0 275 | #endif 276 | 277 | #ifndef MARKDOWN_DEBUG 278 | #define MARKDOWN_DEBUG 0 279 | #endif 280 | 281 | #ifndef MATROSKA_DEBUG 282 | #define MATROSKA_DEBUG 0 283 | #endif 284 | 285 | #ifndef MATROSKA_TRACE_DEBUG 286 | #define MATROSKA_TRACE_DEBUG 0 287 | #endif 288 | 289 | #ifndef MEMORY_DEBUG 290 | #define MEMORY_DEBUG 0 291 | #endif 292 | 293 | #ifndef MENU_DEBUG 294 | #define MENU_DEBUG 0 295 | #endif 296 | 297 | #ifndef MENUS_DEBUG 298 | #define MENUS_DEBUG 0 299 | #endif 300 | 301 | #ifndef MINIMIZE_ANIMATION_DEBUG 302 | #define MINIMIZE_ANIMATION_DEBUG 0 303 | #endif 304 | 305 | #ifndef MOVE_DEBUG 306 | #define MOVE_DEBUG 0 307 | #endif 308 | 309 | #ifndef NETWORKJOB_DEBUG 310 | #define NETWORKJOB_DEBUG 0 311 | #endif 312 | 313 | #ifndef NT_DEBUG 314 | #define NT_DEBUG 0 315 | #endif 316 | 317 | #ifndef OCCLUSIONS_DEBUG 318 | #define OCCLUSIONS_DEBUG 0 319 | #endif 320 | 321 | #ifndef HTML_PARSER_DEBUG 322 | #define HTML_PARSER_DEBUG 0 323 | #endif 324 | 325 | #ifndef PATH_DEBUG 326 | #define PATH_DEBUG 0 327 | #endif 328 | 329 | #ifndef PDF_DEBUG 330 | #define PDF_DEBUG 0 331 | #endif 332 | 333 | #ifndef PNG_DEBUG 334 | #define PNG_DEBUG 0 335 | #endif 336 | 337 | #ifndef PORTABLE_IMAGE_LOADER_DEBUG 338 | #define PORTABLE_IMAGE_LOADER_DEBUG 0 339 | #endif 340 | 341 | #ifndef PROMISE_DEBUG 342 | #define PROMISE_DEBUG 0 343 | #endif 344 | 345 | #ifndef PTHREAD_DEBUG 346 | #define PTHREAD_DEBUG 0 347 | #endif 348 | 349 | #ifndef REACHABLE_DEBUG 350 | #define REACHABLE_DEBUG 0 351 | #endif 352 | 353 | #ifndef REGEX_DEBUG 354 | #define REGEX_DEBUG 0 355 | #endif 356 | 357 | #ifndef REQUESTSERVER_DEBUG 358 | #define REQUESTSERVER_DEBUG 0 359 | #endif 360 | 361 | #ifndef RESIZE_DEBUG 362 | #define RESIZE_DEBUG 0 363 | #endif 364 | 365 | #ifndef RESOURCE_DEBUG 366 | #define RESOURCE_DEBUG 0 367 | #endif 368 | 369 | #ifndef RSA_PARSE_DEBUG 370 | #define RSA_PARSE_DEBUG 0 371 | #endif 372 | 373 | #ifndef SAFE_SYSCALL_DEBUG 374 | #define SAFE_SYSCALL_DEBUG 0 375 | #endif 376 | 377 | #ifndef SERVICE_DEBUG 378 | #define SERVICE_DEBUG 0 379 | #endif 380 | 381 | #ifndef SH_DEBUG 382 | #define SH_DEBUG 0 383 | #endif 384 | 385 | #ifndef SH_LANGUAGE_SERVER_DEBUG 386 | #define SH_LANGUAGE_SERVER_DEBUG 0 387 | #endif 388 | 389 | #ifndef SHARED_QUEUE_DEBUG 390 | #define SHARED_QUEUE_DEBUG 0 391 | #endif 392 | 393 | #ifndef SHELL_JOB_DEBUG 394 | #define SHELL_JOB_DEBUG 0 395 | #endif 396 | 397 | #ifndef SOLITAIRE_DEBUG 398 | #define SOLITAIRE_DEBUG 0 399 | #endif 400 | 401 | #ifndef SPAM_DEBUG 402 | #define SPAM_DEBUG 0 403 | #endif 404 | 405 | #ifndef SQL_DEBUG 406 | #define SQL_DEBUG 0 407 | #endif 408 | 409 | #ifndef SQLSERVER_DEBUG 410 | #define SQLSERVER_DEBUG 0 411 | #endif 412 | 413 | #ifndef SYNTAX_HIGHLIGHTING_DEBUG 414 | #define SYNTAX_HIGHLIGHTING_DEBUG 0 415 | #endif 416 | 417 | #ifndef SYSCALL_1_DEBUG 418 | #define SYSCALL_1_DEBUG 0 419 | #endif 420 | 421 | #ifndef SYSTEM_MENU_DEBUG 422 | #define SYSTEM_MENU_DEBUG 0 423 | #endif 424 | 425 | #ifndef SYSTEMSERVER_DEBUG 426 | #define SYSTEMSERVER_DEBUG 0 427 | #endif 428 | 429 | #ifndef TERMCAP_DEBUG 430 | #define TERMCAP_DEBUG 0 431 | #endif 432 | 433 | #ifndef TERMINAL_DEBUG 434 | #define TERMINAL_DEBUG 0 435 | #endif 436 | 437 | #ifndef TEXTEDITOR_DEBUG 438 | #define TEXTEDITOR_DEBUG 0 439 | #endif 440 | 441 | #ifndef TLS_DEBUG 442 | #define TLS_DEBUG 0 443 | #endif 444 | 445 | #ifndef TLS_SSL_KEYLOG_DEBUG 446 | #define TLS_SSL_KEYLOG_DEBUG 0 447 | #endif 448 | 449 | #ifndef TOKENIZER_TRACE_DEBUG 450 | #define TOKENIZER_TRACE_DEBUG 0 451 | #endif 452 | 453 | #ifndef UCI_DEBUG 454 | #define UCI_DEBUG 0 455 | #endif 456 | 457 | #ifndef UPDATE_COALESCING_DEBUG 458 | #define UPDATE_COALESCING_DEBUG 0 459 | #endif 460 | 461 | #ifndef URL_PARSER_DEBUG 462 | #define URL_PARSER_DEBUG 0 463 | #endif 464 | 465 | #ifndef UTF8_DEBUG 466 | #define UTF8_DEBUG 0 467 | #endif 468 | 469 | #ifndef WASM_BINPARSER_DEBUG 470 | #define WASM_BINPARSER_DEBUG 0 471 | #endif 472 | 473 | #ifndef WASM_TRACE_DEBUG 474 | #define WASM_TRACE_DEBUG 0 475 | #endif 476 | 477 | #ifndef WASM_VALIDATOR_DEBUG 478 | #define WASM_VALIDATOR_DEBUG 0 479 | #endif 480 | 481 | #ifndef WEBSERVER_DEBUG 482 | #define WEBSERVER_DEBUG 0 483 | #endif 484 | 485 | #ifndef WEB_WORKER_DEBUG 486 | #define WEB_WORKER_DEBUG 0 487 | #endif 488 | 489 | #ifndef WINDOWMANAGER_DEBUG 490 | #define WINDOWMANAGER_DEBUG 0 491 | #endif 492 | 493 | #ifndef WRAPPER_GENERATOR_DEBUG 494 | #define WRAPPER_GENERATOR_DEBUG 0 495 | #endif 496 | 497 | #ifndef WSMESSAGELOOP_DEBUG 498 | #define WSMESSAGELOOP_DEBUG 0 499 | #endif 500 | 501 | #ifndef WSSCREEN_DEBUG 502 | #define WSSCREEN_DEBUG 0 503 | #endif 504 | 505 | #ifndef XML_PARSER_DEBUG 506 | #define XML_PARSER_DEBUG 0 507 | #endif 508 | 509 | -------------------------------------------------------------------------------- /runtime/AK/RefPtr.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2020, Andreas Kling 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #define REFPTR_SCRUB_BYTE 0xe0 10 | 11 | #ifdef KERNEL 12 | # include 13 | #else 14 | 15 | # include 16 | # include 17 | # include 18 | # include 19 | # include 20 | # include 21 | # include 22 | # include 23 | 24 | namespace AK { 25 | 26 | template 27 | class [[nodiscard]] RefPtr { 28 | template 29 | friend class RefPtr; 30 | template 31 | friend class WeakPtr; 32 | 33 | public: 34 | enum AdoptTag { 35 | Adopt 36 | }; 37 | 38 | RefPtr() = default; 39 | RefPtr(T const* ptr) 40 | : m_ptr(const_cast(ptr)) 41 | { 42 | ref_if_not_null(m_ptr); 43 | } 44 | 45 | RefPtr(T const& object) 46 | : m_ptr(const_cast(&object)) 47 | { 48 | m_ptr->ref(); 49 | } 50 | 51 | RefPtr(AdoptTag, T& object) 52 | : m_ptr(&object) 53 | { 54 | } 55 | 56 | RefPtr(RefPtr&& other) 57 | : m_ptr(other.leak_ref()) 58 | { 59 | } 60 | 61 | ALWAYS_INLINE RefPtr(NonnullRefPtr const& other) 62 | : m_ptr(const_cast(other.ptr())) 63 | { 64 | m_ptr->ref(); 65 | } 66 | 67 | template 68 | ALWAYS_INLINE RefPtr(NonnullRefPtr const& other) requires(IsConvertible) 69 | : m_ptr(const_cast(static_cast(other.ptr()))) 70 | { 71 | m_ptr->ref(); 72 | } 73 | 74 | template 75 | ALWAYS_INLINE RefPtr(NonnullRefPtr&& other) requires(IsConvertible) 76 | : m_ptr(static_cast(&other.leak_ref())) 77 | { 78 | } 79 | 80 | template 81 | RefPtr(RefPtr&& other) requires(IsConvertible) 82 | : m_ptr(static_cast(other.leak_ref())) 83 | { 84 | } 85 | 86 | RefPtr(RefPtr const& other) 87 | : m_ptr(other.m_ptr) 88 | { 89 | ref_if_not_null(m_ptr); 90 | } 91 | 92 | template 93 | RefPtr(RefPtr const& other) requires(IsConvertible) 94 | : m_ptr(const_cast(static_cast(other.ptr()))) 95 | { 96 | ref_if_not_null(m_ptr); 97 | } 98 | 99 | ALWAYS_INLINE ~RefPtr() 100 | { 101 | clear(); 102 | # ifdef SANITIZE_PTRS 103 | m_ptr = reinterpret_cast(explode_byte(REFPTR_SCRUB_BYTE)); 104 | # endif 105 | } 106 | 107 | void swap(RefPtr& other) 108 | { 109 | AK::swap(m_ptr, other.m_ptr); 110 | } 111 | 112 | template 113 | void swap(RefPtr& other) requires(IsConvertible) 114 | { 115 | AK::swap(m_ptr, other.m_ptr); 116 | } 117 | 118 | ALWAYS_INLINE RefPtr& operator=(RefPtr&& other) 119 | { 120 | RefPtr tmp { move(other) }; 121 | swap(tmp); 122 | return *this; 123 | } 124 | 125 | template 126 | ALWAYS_INLINE RefPtr& operator=(RefPtr&& other) requires(IsConvertible) 127 | { 128 | RefPtr tmp { move(other) }; 129 | swap(tmp); 130 | return *this; 131 | } 132 | 133 | template 134 | ALWAYS_INLINE RefPtr& operator=(NonnullRefPtr&& other) requires(IsConvertible) 135 | { 136 | RefPtr tmp { move(other) }; 137 | swap(tmp); 138 | return *this; 139 | } 140 | 141 | ALWAYS_INLINE RefPtr& operator=(NonnullRefPtr const& other) 142 | { 143 | RefPtr tmp { other }; 144 | swap(tmp); 145 | return *this; 146 | } 147 | 148 | template 149 | ALWAYS_INLINE RefPtr& operator=(NonnullRefPtr const& other) requires(IsConvertible) 150 | { 151 | RefPtr tmp { other }; 152 | swap(tmp); 153 | return *this; 154 | } 155 | 156 | ALWAYS_INLINE RefPtr& operator=(RefPtr const& other) 157 | { 158 | RefPtr tmp { other }; 159 | swap(tmp); 160 | return *this; 161 | } 162 | 163 | template 164 | ALWAYS_INLINE RefPtr& operator=(RefPtr const& other) requires(IsConvertible) 165 | { 166 | RefPtr tmp { other }; 167 | swap(tmp); 168 | return *this; 169 | } 170 | 171 | ALWAYS_INLINE RefPtr& operator=(T const* ptr) 172 | { 173 | RefPtr tmp { ptr }; 174 | swap(tmp); 175 | return *this; 176 | } 177 | 178 | ALWAYS_INLINE RefPtr& operator=(T const& object) 179 | { 180 | RefPtr tmp { object }; 181 | swap(tmp); 182 | return *this; 183 | } 184 | 185 | RefPtr& operator=(std::nullptr_t) 186 | { 187 | clear(); 188 | return *this; 189 | } 190 | 191 | ALWAYS_INLINE bool assign_if_null(RefPtr&& other) 192 | { 193 | if (this == &other) 194 | return is_null(); 195 | *this = move(other); 196 | return true; 197 | } 198 | 199 | template 200 | ALWAYS_INLINE bool assign_if_null(RefPtr&& other) 201 | { 202 | if (this == &other) 203 | return is_null(); 204 | *this = move(other); 205 | return true; 206 | } 207 | 208 | ALWAYS_INLINE void clear() 209 | { 210 | unref_if_not_null(m_ptr); 211 | m_ptr = nullptr; 212 | } 213 | 214 | bool operator!() const { return !m_ptr; } 215 | 216 | [[nodiscard]] T* leak_ref() 217 | { 218 | return exchange(m_ptr, nullptr); 219 | } 220 | 221 | NonnullRefPtr release_nonnull() 222 | { 223 | auto* ptr = leak_ref(); 224 | VERIFY(ptr); 225 | return NonnullRefPtr(NonnullRefPtr::Adopt, *ptr); 226 | } 227 | 228 | ALWAYS_INLINE T* ptr() { return as_ptr(); } 229 | ALWAYS_INLINE const T* ptr() const { return as_ptr(); } 230 | 231 | ALWAYS_INLINE T* operator->() 232 | { 233 | return as_nonnull_ptr(); 234 | } 235 | 236 | ALWAYS_INLINE const T* operator->() const 237 | { 238 | return as_nonnull_ptr(); 239 | } 240 | 241 | ALWAYS_INLINE T& operator*() 242 | { 243 | return *as_nonnull_ptr(); 244 | } 245 | 246 | ALWAYS_INLINE const T& operator*() const 247 | { 248 | return *as_nonnull_ptr(); 249 | } 250 | 251 | ALWAYS_INLINE operator const T*() const { return as_ptr(); } 252 | ALWAYS_INLINE operator T*() { return as_ptr(); } 253 | 254 | ALWAYS_INLINE operator bool() { return !is_null(); } 255 | 256 | bool operator==(std::nullptr_t) const { return is_null(); } 257 | bool operator!=(std::nullptr_t) const { return !is_null(); } 258 | 259 | bool operator==(RefPtr const& other) const { return as_ptr() == other.as_ptr(); } 260 | bool operator!=(RefPtr const& other) const { return as_ptr() != other.as_ptr(); } 261 | 262 | bool operator==(RefPtr& other) { return as_ptr() == other.as_ptr(); } 263 | bool operator!=(RefPtr& other) { return as_ptr() != other.as_ptr(); } 264 | 265 | bool operator==(const T* other) const { return as_ptr() == other; } 266 | bool operator!=(const T* other) const { return as_ptr() != other; } 267 | 268 | bool operator==(T* other) { return as_ptr() == other; } 269 | bool operator!=(T* other) { return as_ptr() != other; } 270 | 271 | ALWAYS_INLINE bool is_null() const { return !m_ptr; } 272 | 273 | private: 274 | ALWAYS_INLINE T* as_ptr() const 275 | { 276 | return m_ptr; 277 | } 278 | 279 | ALWAYS_INLINE T* as_nonnull_ptr() const 280 | { 281 | VERIFY(m_ptr); 282 | return m_ptr; 283 | } 284 | 285 | T* m_ptr { nullptr }; 286 | }; 287 | 288 | template 289 | struct Formatter> : Formatter { 290 | ErrorOr format(FormatBuilder& builder, RefPtr const& value) 291 | { 292 | return Formatter::format(builder, value.ptr()); 293 | } 294 | }; 295 | 296 | template 297 | struct Traits> : public GenericTraits> { 298 | using PeekType = T*; 299 | using ConstPeekType = const T*; 300 | static unsigned hash(RefPtr const& p) { return ptr_hash(p.ptr()); } 301 | static bool equals(RefPtr const& a, RefPtr const& b) { return a.ptr() == b.ptr(); } 302 | }; 303 | 304 | template 305 | inline NonnullRefPtr static_ptr_cast(NonnullRefPtr const& ptr) 306 | { 307 | return NonnullRefPtr(static_cast(*ptr)); 308 | } 309 | 310 | template 311 | inline RefPtr static_ptr_cast(RefPtr const& ptr) 312 | { 313 | return RefPtr(static_cast(ptr.ptr())); 314 | } 315 | 316 | template 317 | inline void swap(RefPtr& a, RefPtr& b) requires(IsConvertible) 318 | { 319 | a.swap(b); 320 | } 321 | 322 | template 323 | inline RefPtr adopt_ref_if_nonnull(T* object) 324 | { 325 | if (object) 326 | return RefPtr(RefPtr::Adopt, *object); 327 | return {}; 328 | } 329 | 330 | template 331 | requires(IsConstructible) inline ErrorOr> try_make_ref_counted(Args&&... args) 332 | { 333 | return adopt_nonnull_ref_or_enomem(new (nothrow) T(forward(args)...)); 334 | } 335 | 336 | // FIXME: Remove once P0960R3 is available in Clang. 337 | template 338 | inline ErrorOr> try_make_ref_counted(Args&&... args) 339 | { 340 | return adopt_nonnull_ref_or_enomem(new (nothrow) T { forward(args)... }); 341 | } 342 | 343 | template 344 | inline ErrorOr> adopt_nonnull_ref_or_enomem(T* object) 345 | { 346 | auto result = adopt_ref_if_nonnull(object); 347 | if (!result) 348 | return Error::from_errno(ENOMEM); 349 | return result.release_nonnull(); 350 | } 351 | 352 | } 353 | 354 | using AK::adopt_ref_if_nonnull; 355 | using AK::RefPtr; 356 | using AK::static_ptr_cast; 357 | using AK::try_make_ref_counted; 358 | 359 | #endif 360 | -------------------------------------------------------------------------------- /runtime/AK/StringView.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2018-2021, Andreas Kling 3 | * 4 | * SPDX-License-Identifier: BSD-2-Clause 5 | */ 6 | 7 | #pragma once 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | 18 | namespace AK { 19 | 20 | class StringView { 21 | public: 22 | ALWAYS_INLINE constexpr StringView() = default; 23 | ALWAYS_INLINE constexpr StringView(char const* characters, size_t length) 24 | : m_characters(characters) 25 | , m_length(length) 26 | { 27 | if (!is_constant_evaluated()) 28 | VERIFY(!Checked::addition_would_overflow((uintptr_t)characters, length)); 29 | } 30 | ALWAYS_INLINE StringView(unsigned char const* characters, size_t length) 31 | : m_characters((char const*)characters) 32 | , m_length(length) 33 | { 34 | VERIFY(!Checked::addition_would_overflow((uintptr_t)characters, length)); 35 | } 36 | ALWAYS_INLINE constexpr StringView(char const* cstring) 37 | : m_characters(cstring) 38 | , m_length(cstring ? __builtin_strlen(cstring) : 0) 39 | { 40 | } 41 | ALWAYS_INLINE StringView(ReadonlyBytes bytes) 42 | : m_characters(reinterpret_cast(bytes.data())) 43 | , m_length(bytes.size()) 44 | { 45 | } 46 | 47 | #ifndef KERNEL 48 | StringView(String const&); 49 | #endif 50 | 51 | #ifndef KERNEL 52 | explicit StringView(String&&) = delete; 53 | #endif 54 | 55 | [[nodiscard]] constexpr bool is_null() const 56 | { 57 | return m_characters == nullptr; 58 | } 59 | [[nodiscard]] constexpr bool is_empty() const { return m_length == 0; } 60 | 61 | [[nodiscard]] constexpr char const* characters_without_null_termination() const { return m_characters; } 62 | [[nodiscard]] constexpr size_t length() const { return m_length; } 63 | 64 | [[nodiscard]] ReadonlyBytes bytes() const { return { m_characters, m_length }; } 65 | 66 | constexpr char const& operator[](size_t index) const { return m_characters[index]; } 67 | 68 | using ConstIterator = SimpleIterator; 69 | 70 | [[nodiscard]] constexpr ConstIterator begin() const { return ConstIterator::begin(*this); } 71 | [[nodiscard]] constexpr ConstIterator end() const { return ConstIterator::end(*this); } 72 | 73 | [[nodiscard]] constexpr unsigned hash() const 74 | { 75 | if (is_empty()) 76 | return 0; 77 | return string_hash(characters_without_null_termination(), length()); 78 | } 79 | 80 | [[nodiscard]] bool starts_with(StringView, CaseSensitivity = CaseSensitivity::CaseSensitive) const; 81 | [[nodiscard]] bool ends_with(StringView, CaseSensitivity = CaseSensitivity::CaseSensitive) const; 82 | [[nodiscard]] bool starts_with(char) const; 83 | [[nodiscard]] bool ends_with(char) const; 84 | [[nodiscard]] bool contains(char) const; 85 | [[nodiscard]] bool contains(StringView, CaseSensitivity = CaseSensitivity::CaseSensitive) const; 86 | [[nodiscard]] bool equals_ignoring_case(StringView other) const; 87 | 88 | [[nodiscard]] StringView trim(StringView characters, TrimMode mode = TrimMode::Both) const { return StringUtils::trim(*this, characters, mode); } 89 | [[nodiscard]] StringView trim_whitespace(TrimMode mode = TrimMode::Both) const { return StringUtils::trim_whitespace(*this, mode); } 90 | 91 | [[nodiscard]] Optional find(char needle, size_t start = 0) const 92 | { 93 | return StringUtils::find(*this, needle, start); 94 | } 95 | [[nodiscard]] Optional find(StringView needle, size_t start = 0) const { return StringUtils::find(*this, needle, start); } 96 | [[nodiscard]] Optional find_last(char needle) const { return StringUtils::find_last(*this, needle); } 97 | // FIXME: Implement find_last(StringView) for API symmetry. 98 | 99 | [[nodiscard]] ErrorOr> find_all(StringView needle) const; 100 | 101 | using SearchDirection = StringUtils::SearchDirection; 102 | [[nodiscard]] Optional find_any_of(StringView needles, SearchDirection direction = SearchDirection::Forward) const { return StringUtils::find_any_of(*this, needles, direction); } 103 | 104 | [[nodiscard]] constexpr StringView substring_view(size_t start, size_t length) const 105 | { 106 | if (!is_constant_evaluated()) 107 | VERIFY(start + length <= m_length); 108 | return { m_characters + start, length }; 109 | } 110 | 111 | [[nodiscard]] constexpr StringView substring_view(size_t start) const 112 | { 113 | if (!is_constant_evaluated()) 114 | VERIFY(start <= length()); 115 | return substring_view(start, length() - start); 116 | } 117 | 118 | template Callback> 119 | void for_each_split_view(char separator, bool keep_empty, Callback callback) const 120 | { 121 | StringView seperator_view { &separator, 1 }; 122 | for_each_split_view(seperator_view, keep_empty, callback); 123 | } 124 | 125 | template 126 | Optional to_int() const; 127 | template 128 | Optional to_uint() const; 129 | 130 | // Create a new substring view of this string view, starting either at the beginning of 131 | // the given substring view, or after its end, and continuing until the end of this string 132 | // view (that is, for the remaining part of its length). For example, 133 | // 134 | // StringView str { "foobar" }; 135 | // StringView substr = str.substring_view(1, 2); // "oo" 136 | // StringView substr_from = str.substring_view_starting_from_substring(subst); // "oobar" 137 | // StringView substr_after = str.substring_view_starting_after_substring(subst); // "bar" 138 | // 139 | // Note that this only works if the string view passed as an argument is indeed a substring 140 | // view of this string view, such as one created by substring_view() and split_view(). It 141 | // does not work for arbitrary strings; for example declaring substr in the example above as 142 | // 143 | // StringView substr { "oo" }; 144 | // 145 | // would not work. 146 | 147 | constexpr bool operator==(char const* cstring) const 148 | { 149 | if (is_null()) 150 | return cstring == nullptr; 151 | if (!cstring) 152 | return false; 153 | // NOTE: `m_characters` is not guaranteed to be null-terminated, but `cstring` is. 154 | char const* cp = cstring; 155 | for (size_t i = 0; i < m_length; ++i) { 156 | if (*cp == '\0') 157 | return false; 158 | if (m_characters[i] != *(cp++)) 159 | return false; 160 | } 161 | return *cp == '\0'; 162 | } 163 | 164 | constexpr bool operator!=(char const* cstring) const 165 | { 166 | return !(*this == cstring); 167 | } 168 | 169 | #ifndef KERNEL 170 | bool operator==(String const&) const; 171 | #endif 172 | 173 | [[nodiscard]] constexpr int compare(StringView other) const 174 | { 175 | if (m_characters == nullptr) 176 | return other.m_characters ? -1 : 0; 177 | 178 | if (other.m_characters == nullptr) 179 | return 1; 180 | 181 | size_t rlen = min(m_length, other.m_length); 182 | int c = __builtin_memcmp(m_characters, other.m_characters, rlen); 183 | if (c == 0) { 184 | if (length() < other.length()) 185 | return -1; 186 | if (length() == other.length()) 187 | return 0; 188 | return 1; 189 | } 190 | return c; 191 | } 192 | 193 | constexpr bool operator==(StringView other) const 194 | { 195 | return length() == other.length() && compare(other) == 0; 196 | } 197 | 198 | constexpr bool operator!=(StringView other) const 199 | { 200 | return length() != other.length() || compare(other) != 0; 201 | } 202 | 203 | constexpr bool operator<(StringView other) const { return compare(other) < 0; } 204 | 205 | constexpr bool operator<=(StringView other) const { return compare(other) <= 0; } 206 | 207 | constexpr bool operator>(StringView other) const { return compare(other) > 0; } 208 | 209 | constexpr bool operator>=(StringView other) const { return compare(other) >= 0; } 210 | 211 | [[nodiscard]] ErrorOr to_string() const; 212 | 213 | [[nodiscard]] bool is_whitespace() const 214 | { 215 | return StringUtils::is_whitespace(*this); 216 | } 217 | 218 | [[nodiscard]] size_t count(StringView needle) const 219 | { 220 | return StringUtils::count(*this, needle); 221 | } 222 | 223 | template 224 | [[nodiscard]] ALWAYS_INLINE constexpr bool is_one_of(Ts&&... strings) const 225 | { 226 | return (... || this->operator==(forward(strings))); 227 | } 228 | 229 | template 230 | [[nodiscard]] ALWAYS_INLINE constexpr bool is_one_of_ignoring_case(Ts&&... strings) const 231 | { 232 | return (... || 233 | [this, &strings]() -> bool { 234 | if constexpr (requires(Ts a) { a.view()->StringView; }) 235 | return this->equals_ignoring_case(forward(strings.view())); 236 | else 237 | return this->equals_ignoring_case(forward(strings)); 238 | }()); 239 | } 240 | 241 | private: 242 | friend class String; 243 | char const* m_characters { nullptr }; 244 | size_t m_length { 0 }; 245 | }; 246 | 247 | template<> 248 | struct Traits : public GenericTraits { 249 | static unsigned hash(StringView s) { return s.hash(); } 250 | }; 251 | 252 | struct CaseInsensitiveStringViewTraits : public Traits { 253 | static unsigned hash(StringView s) 254 | { 255 | if (s.is_empty()) 256 | return 0; 257 | return case_insensitive_string_hash(s.characters_without_null_termination(), s.length()); 258 | } 259 | }; 260 | 261 | } 262 | 263 | // FIXME: Remove this when clang fully supports consteval (specifically in the context of default parameter initialization). 264 | // See: https://stackoverflow.com/questions/68789984/immediate-function-as-default-function-argument-initializer-in-clang 265 | #if defined(__clang__) 266 | # define AK_STRING_VIEW_LITERAL_CONSTEVAL constexpr 267 | #else 268 | # define AK_STRING_VIEW_LITERAL_CONSTEVAL consteval 269 | #endif 270 | 271 | [[nodiscard]] ALWAYS_INLINE AK_STRING_VIEW_LITERAL_CONSTEVAL AK::StringView operator"" sv(char const* cstring, size_t length) 272 | { 273 | return AK::StringView(cstring, length); 274 | } 275 | 276 | using AK::CaseInsensitiveStringViewTraits; 277 | using AK::StringView; 278 | -------------------------------------------------------------------------------- /runtime/lib.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | #include 41 | #include 42 | #include 43 | #include 44 | #include 45 | #include 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | 52 | #include 53 | #include 54 | #include 55 | #include 56 | #include 57 | #include 58 | #include 59 | 60 | namespace JaktInternal { 61 | template 62 | class Set; 63 | } 64 | 65 | #include 66 | #include 67 | #include 68 | 69 | #include 70 | 71 | #include 72 | 73 | using f32 = float; 74 | using f64 = double; 75 | 76 | template 77 | struct Range { 78 | using IndexType = T; 79 | T start {}; 80 | T end {}; 81 | T current {}; 82 | 83 | Range(T start, T end) 84 | : start(start) 85 | , end(end) 86 | , current(start) 87 | { 88 | } 89 | 90 | Optional next() 91 | { 92 | if (current == end) 93 | return {}; 94 | return current++; 95 | } 96 | }; 97 | 98 | namespace JaktInternal { 99 | 100 | #ifdef JAKT_CONTINUE_ON_PANIC 101 | constexpr auto continue_on_panic = true; 102 | #else 103 | constexpr auto continue_on_panic = false; 104 | #endif 105 | 106 | using OptionalNone = AK::NullOptional; 107 | 108 | ErrorOr main(Array); 109 | 110 | inline void panic(StringView message) 111 | { 112 | warnln("Panic: {}", message); 113 | if (continue_on_panic) 114 | return; 115 | VERIFY_NOT_REACHED(); 116 | } 117 | 118 | template 119 | inline constexpr T checked_add(T value, T other) 120 | { 121 | Checked checked = value; 122 | checked += other; 123 | if (checked.has_overflow()) 124 | panic(MUST(String::formatted("Overflow in checked addition '{} + {}'", value, other))); 125 | return checked.value_unchecked(); 126 | } 127 | 128 | template 129 | inline constexpr T checked_sub(T value, T other) 130 | { 131 | Checked checked = value; 132 | checked -= other; 133 | if (checked.has_overflow()) 134 | panic(MUST(String::formatted("Overflow in checked subtraction '{} - {}'", value, other))); 135 | return checked.value_unchecked(); 136 | } 137 | 138 | template 139 | inline constexpr T checked_mul(T value, T other) 140 | { 141 | Checked checked = value; 142 | checked *= other; 143 | if (checked.has_overflow()) 144 | panic(MUST(String::formatted("Overflow in checked multiplication '{} * {}'", value, other))); 145 | return checked.value_unchecked(); 146 | } 147 | 148 | template 149 | inline constexpr T checked_div(T value, T other) 150 | { 151 | Checked checked = value; 152 | checked /= other; 153 | if (checked.has_overflow()) { 154 | if (other == 0) 155 | panic(MUST(String::formatted("Division by zero in checked division '{} / {}'", value, other))); 156 | else 157 | panic(MUST(String::formatted("Overflow in checked division '{} / {}'", value, other))); 158 | } 159 | return checked.value_unchecked(); 160 | } 161 | 162 | template 163 | inline constexpr T checked_mod(T value, T other) 164 | { 165 | Checked checked = value; 166 | checked %= other; 167 | if (checked.has_overflow()) { 168 | if (other == 0) 169 | panic(MUST(String::formatted("Division by zero in checked modulo '{} % {}'", value, other))); 170 | else 171 | panic(MUST(String::formatted("Overflow in checked modulo '{} % {}'", value, other))); 172 | } 173 | return checked.value_unchecked(); 174 | } 175 | 176 | template 177 | inline constexpr T arithmetic_shift_right(T value, size_t steps) 178 | { 179 | if constexpr (IsSigned) { 180 | if constexpr (sizeof(T) == 1) { 181 | auto sign = (value & 0x80); 182 | // 8-bit variant 183 | return ((value >> steps) | sign); 184 | } else if constexpr (sizeof(T) == 2) { 185 | auto sign = (value & 0x8000); 186 | // 16-bit variant 187 | return ((value >> steps) | sign); 188 | } else if constexpr (sizeof(T) == 4) { 189 | auto sign = (value & 0x80000000); 190 | // 32-bit variant 191 | return ((value >> steps) | sign); 192 | } else if constexpr (sizeof(T) == 8) { 193 | auto sign = (value & 0x8000000000000000); 194 | // 64-bit variant 195 | return ((value >> steps) | sign); 196 | } 197 | } else { 198 | return (value >> steps); 199 | } 200 | } 201 | 202 | template 203 | struct ExplicitValue { 204 | ExplicitValue(Value&& v) 205 | : value(move(v)) 206 | { 207 | } 208 | ExplicitValue(Value const& v) 209 | : value(v) 210 | { 211 | } 212 | 213 | Value value; 214 | }; 215 | 216 | template<> 217 | struct ExplicitValue { 218 | ExplicitValue() 219 | { 220 | } 221 | }; 222 | 223 | template 224 | struct ExplicitValueOrReturn { 225 | template 226 | ExplicitValueOrReturn(ExplicitValue&& v) 227 | : value(ExplicitValue { move(v.value) }) 228 | { 229 | } 230 | 231 | ExplicitValueOrReturn(ExplicitValue&&) 232 | : value(ExplicitValue {}) 233 | { 234 | } 235 | 236 | template 237 | ExplicitValueOrReturn(U&& v) requires(!IsVoid) 238 | : value(Return { forward(v) }) 239 | { 240 | } 241 | 242 | ExplicitValueOrReturn(void) requires(IsVoid) 243 | : value(Empty {}) 244 | { 245 | } 246 | 247 | bool is_return() const 248 | { 249 | return value.template has, Empty, Return>>(); 250 | } 251 | 252 | Return release_return() 253 | { 254 | if constexpr (IsVoid) 255 | return; 256 | else 257 | return move(value).template get(); 258 | } 259 | Value release_value() 260 | 261 | { 262 | if constexpr (IsVoid) 263 | return; 264 | else 265 | return move(value).template get>().value; 266 | } 267 | 268 | Variant, Empty, Return>, ExplicitValue> value; 269 | }; 270 | 271 | #define JAKT_RESOLVE_EXPLICIT_VALUE_OR_RETURN(x) ({ \ 272 | auto&& _jakt_value = x; \ 273 | if (_jakt_value.is_return()) \ 274 | return _jakt_value.release_return(); \ 275 | _jakt_value.release_value(); \ 276 | }) 277 | 278 | template 279 | ALWAYS_INLINE Optional fallible_integer_cast(InputType input) 280 | { 281 | if constexpr (IsEnum) { 282 | return fallible_integer_cast(to_underlying(input)); 283 | } else { 284 | static_assert(IsIntegral); 285 | if (!AK::is_within_range(input)) 286 | return {}; 287 | return static_cast(input); 288 | } 289 | } 290 | 291 | template 292 | void compiletime_fail(Ts...) { } 293 | 294 | template 295 | ALWAYS_INLINE constexpr OutputType infallible_integer_cast(InputType input) 296 | { 297 | if constexpr (IsEnum) { 298 | return infallible_integer_cast(to_underlying(input)); 299 | } else { 300 | static_assert(IsIntegral); 301 | if (is_constant_evaluated()) { 302 | if (!AK::is_within_range(input)) 303 | compiletime_fail("Integer cast out of range"); 304 | } else { 305 | VERIFY(AK::is_within_range(input)); 306 | } 307 | return static_cast(input); 308 | } 309 | } 310 | 311 | template 312 | ALWAYS_INLINE constexpr OutputType as_saturated(InputType input) 313 | { 314 | if constexpr (IsEnum) { 315 | return as_saturated(to_underlying(input)); 316 | } else { 317 | static_assert(IsIntegral); 318 | if (!AK::is_within_range(input)) { 319 | if constexpr (IsSigned) { 320 | if (input < 0) 321 | return NumericLimits::min(); 322 | } 323 | return NumericLimits::max(); 324 | } 325 | return static_cast(input); 326 | } 327 | } 328 | 329 | template 330 | ALWAYS_INLINE constexpr OutputType as_truncated(InputType input) 331 | { 332 | if constexpr (IsEnum) { 333 | return as_truncated(to_underlying(input)); 334 | } else { 335 | static_assert(IsIntegral); 336 | return static_cast(input); 337 | } 338 | } 339 | 340 | template 341 | struct _RemoveRefPtr { 342 | using Type = T; 343 | }; 344 | 345 | template 346 | struct _RemoveRefPtr> { 347 | using Type = T; 348 | }; 349 | 350 | template 351 | using RemoveRefPtr = typename _RemoveRefPtr>::Type; 352 | 353 | template 354 | ALWAYS_INLINE decltype(auto) deref_if_ref_pointer(T&& value) 355 | { 356 | if constexpr (IsSpecializationOf, NonnullRefPtr>) 357 | return static_cast, RemoveRefPtr>&>(*value); 358 | else 359 | return static_cast, RemoveReference, T>>(value); 360 | } 361 | 362 | } 363 | 364 | using JaktInternal::as_saturated; 365 | using JaktInternal::as_truncated; 366 | using JaktInternal::fallible_integer_cast; 367 | using JaktInternal::infallible_integer_cast; 368 | 369 | int main(int argc, char** argv) 370 | { 371 | Array args; 372 | for (int i = 0; i < argc; ++i) { 373 | MUST(args.push(MUST(String::copy(StringView(argv[i]))))); 374 | } 375 | auto result = JaktInternal::main(move(args)); 376 | if (result.is_error()) { 377 | warnln("Runtime error: {}", result.error()); 378 | return 1; 379 | } 380 | return result.value(); 381 | } 382 | --------------------------------------------------------------------------------