Serenity Operating System
at master 126 lines 3.4 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#pragma once 8 9#include <AK/Badge.h> 10#include <AK/RefCounted.h> 11#include <AK/RefPtr.h> 12#include <AK/Span.h> 13#include <AK/Types.h> 14#include <AK/kmalloc.h> 15 16namespace AK { 17 18enum ShouldChomp { 19 NoChomp, 20 Chomp 21}; 22 23size_t allocation_size_for_stringimpl(size_t length); 24 25class StringImpl : public RefCounted<StringImpl> { 26public: 27 static NonnullRefPtr<StringImpl const> create_uninitialized(size_t length, char*& buffer); 28 static RefPtr<StringImpl const> create(char const* cstring, ShouldChomp = NoChomp); 29 static RefPtr<StringImpl const> create(char const* cstring, size_t length, ShouldChomp = NoChomp); 30 static RefPtr<StringImpl const> create(ReadonlyBytes, ShouldChomp = NoChomp); 31 static RefPtr<StringImpl const> create_lowercased(char const* cstring, size_t length); 32 static RefPtr<StringImpl const> create_uppercased(char const* cstring, size_t length); 33 34 NonnullRefPtr<StringImpl const> to_lowercase() const; 35 NonnullRefPtr<StringImpl const> to_uppercase() const; 36 37 void operator delete(void* ptr) 38 { 39 kfree_sized(ptr, allocation_size_for_stringimpl(static_cast<StringImpl*>(ptr)->m_length)); 40 } 41 42 static StringImpl& the_empty_stringimpl(); 43 44 ~StringImpl(); 45 46 size_t length() const { return m_length; } 47 // Includes NUL-terminator. 48 char const* characters() const { return &m_inline_buffer[0]; } 49 50 ALWAYS_INLINE ReadonlyBytes bytes() const { return { characters(), length() }; } 51 ALWAYS_INLINE StringView view() const { return { characters(), length() }; } 52 53 char const& operator[](size_t i) const 54 { 55 VERIFY(i < m_length); 56 return characters()[i]; 57 } 58 59 bool operator==(StringImpl const& other) const 60 { 61 if (length() != other.length()) 62 return false; 63 return __builtin_memcmp(characters(), other.characters(), length()) == 0; 64 } 65 66 unsigned hash() const 67 { 68 if (!m_has_hash) 69 compute_hash(); 70 return m_hash; 71 } 72 73 unsigned existing_hash() const 74 { 75 return m_hash; 76 } 77 78 unsigned case_insensitive_hash() const; 79 80 bool is_fly() const { return m_fly; } 81 void set_fly(Badge<DeprecatedFlyString>, bool fly) const { m_fly = fly; } 82 83private: 84 enum ConstructTheEmptyStringImplTag { 85 ConstructTheEmptyStringImpl 86 }; 87 explicit StringImpl(ConstructTheEmptyStringImplTag) 88 : m_fly(true) 89 { 90 m_inline_buffer[0] = '\0'; 91 } 92 93 enum ConstructWithInlineBufferTag { 94 ConstructWithInlineBuffer 95 }; 96 StringImpl(ConstructWithInlineBufferTag, size_t length); 97 98 void compute_hash() const; 99 100 size_t m_length { 0 }; 101 mutable unsigned m_hash { 0 }; 102 mutable bool m_has_hash { false }; 103 mutable bool m_fly { false }; 104 char m_inline_buffer[0]; 105}; 106 107inline size_t allocation_size_for_stringimpl(size_t length) 108{ 109 return sizeof(StringImpl) + (sizeof(char) * length) + sizeof(char); 110} 111 112template<> 113struct Formatter<StringImpl> : Formatter<StringView> { 114 ErrorOr<void> format(FormatBuilder& builder, StringImpl const& value) 115 { 116 return Formatter<StringView>::format(builder, { value.characters(), value.length() }); 117 } 118}; 119 120} 121 122#if USING_AK_GLOBALLY 123using AK::Chomp; 124using AK::NoChomp; 125using AK::StringImpl; 126#endif