mirror of
https://github.com/RGBCube/serenity
synced 2025-07-29 01:07:35 +00:00
Import all this stuff into a single repo called Serenity.
This commit is contained in:
commit
5a30055157
67 changed files with 8836 additions and 0 deletions
1
AK/.gitignore
vendored
Normal file
1
AK/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
akit-test
|
15
AK/Assertions.h
Normal file
15
AK/Assertions.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include <assert.h>
|
||||
|
||||
#define ASSERT(x) assert(x)
|
||||
#define ASSERT_NOT_REACHED() assert(false)
|
||||
|
||||
namespace AK {
|
||||
|
||||
inline void notImplemented() { assert(false); }
|
||||
|
||||
}
|
||||
|
||||
using AK::notImplemented;
|
||||
|
71
AK/Bitmap.h
Normal file
71
AK/Bitmap.h
Normal file
|
@ -0,0 +1,71 @@
|
|||
#pragma once
|
||||
|
||||
#include "StdLib.h"
|
||||
#include "Types.h"
|
||||
#include "kmalloc.h"
|
||||
|
||||
namespace AK {
|
||||
|
||||
class Bitmap {
|
||||
public:
|
||||
// NOTE: A wrapping Bitmap won't try to free the wrapped data.
|
||||
static Bitmap wrap(byte* data, unsigned size)
|
||||
{
|
||||
return Bitmap(data, size);
|
||||
}
|
||||
|
||||
static Bitmap create(unsigned size)
|
||||
{
|
||||
return Bitmap(size);
|
||||
}
|
||||
|
||||
~Bitmap()
|
||||
{
|
||||
if (m_owned)
|
||||
kfree(m_data);
|
||||
m_data = nullptr;
|
||||
}
|
||||
|
||||
unsigned size() const { return m_size; }
|
||||
bool get(unsigned index) const
|
||||
{
|
||||
ASSERT(index < m_size);
|
||||
return 0 != (m_data[index / 8] & (1u << (index % 8)));
|
||||
}
|
||||
void set(unsigned index, bool value) const
|
||||
{
|
||||
ASSERT(index < m_size);
|
||||
if (value)
|
||||
m_data[index / 8] |= static_cast<byte>((1u << (index % 8)));
|
||||
else
|
||||
m_data[index / 8] &= static_cast<byte>(~(1u << (index % 8)));
|
||||
}
|
||||
|
||||
byte* data() { return m_data; }
|
||||
const byte* data() const { return m_data; }
|
||||
|
||||
private:
|
||||
explicit Bitmap(unsigned size)
|
||||
: m_size(size)
|
||||
, m_owned(true)
|
||||
{
|
||||
ASSERT(m_size != 0);
|
||||
m_data = reinterpret_cast<byte*>(kmalloc(ceilDiv(size, 8u)));
|
||||
}
|
||||
|
||||
Bitmap(byte* data, unsigned size)
|
||||
: m_data(data)
|
||||
, m_size(size)
|
||||
, m_owned(false)
|
||||
{
|
||||
}
|
||||
|
||||
byte* m_data { nullptr };
|
||||
unsigned m_size { 0 };
|
||||
bool m_owned { false };
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
using AK::Bitmap;
|
||||
|
120
AK/Buffer.h
Normal file
120
AK/Buffer.h
Normal file
|
@ -0,0 +1,120 @@
|
|||
#pragma once
|
||||
|
||||
#include "Assertions.h"
|
||||
#include "Retainable.h"
|
||||
#include "RetainPtr.h"
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include "kmalloc.h"
|
||||
|
||||
namespace AK {
|
||||
|
||||
template<typename T>
|
||||
class Buffer : public Retainable<Buffer<T>> {
|
||||
public:
|
||||
static RetainPtr<Buffer> createUninitialized(size_t count);
|
||||
static RetainPtr<Buffer> copy(const T*, size_t count);
|
||||
static RetainPtr<Buffer> wrap(T*, size_t count);
|
||||
static RetainPtr<Buffer> adopt(T*, size_t count);
|
||||
|
||||
~Buffer() { clear(); }
|
||||
|
||||
void clear()
|
||||
{
|
||||
if (!m_elements)
|
||||
return;
|
||||
kfree(m_elements);
|
||||
m_elements = nullptr;
|
||||
}
|
||||
|
||||
T& operator[](size_t i) { ASSERT(i < m_size); return m_elements[i]; }
|
||||
const T& operator[](size_t i) const { ASSERT(i < m_size); return m_elements[i]; }
|
||||
bool isEmpty() const { return !m_size; }
|
||||
size_t size() const { return m_size; }
|
||||
|
||||
T* pointer() { return m_elements; }
|
||||
const T* pointer() const { return m_elements; }
|
||||
|
||||
T* offsetPointer(size_t offset) { return m_elements + offset; }
|
||||
const T* offsetPointer(size_t offset) const { return m_elements + offset; }
|
||||
|
||||
const void* endPointer() const { return m_elements + m_size; }
|
||||
|
||||
// NOTE: trim() does not reallocate.
|
||||
void trim(size_t size)
|
||||
{
|
||||
ASSERT(size <= m_size);
|
||||
m_size = size;
|
||||
}
|
||||
|
||||
private:
|
||||
enum ConstructionMode { Uninitialized, Copy, Wrap, Adopt };
|
||||
explicit Buffer(size_t); // For ConstructionMode=Uninitialized
|
||||
Buffer(const T*, size_t, ConstructionMode); // For ConstructionMode=Copy
|
||||
Buffer(T*, size_t, ConstructionMode); // For ConstructionMode=Wrap/Adopt
|
||||
Buffer() { }
|
||||
|
||||
T* m_elements { nullptr };
|
||||
size_t m_size { 0 };
|
||||
bool m_owned { false };
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline Buffer<T>::Buffer(size_t size)
|
||||
: m_size(size)
|
||||
{
|
||||
m_elements = static_cast<T*>(kmalloc(size * sizeof(T)));
|
||||
m_owned = true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline Buffer<T>::Buffer(const T* elements, size_t size, ConstructionMode mode)
|
||||
: m_size(size)
|
||||
{
|
||||
ASSERT(mode == Copy);
|
||||
m_elements = static_cast<T*>(kmalloc(size * sizeof(T)));
|
||||
memcpy(m_elements, elements, size * sizeof(T));
|
||||
m_owned = true;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline Buffer<T>::Buffer(T* elements, size_t size, ConstructionMode mode)
|
||||
: m_elements(elements)
|
||||
, m_size(size)
|
||||
{
|
||||
if (mode == Adopt) {
|
||||
m_owned = true;
|
||||
} else if (mode == Wrap) {
|
||||
m_owned = false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline RetainPtr<Buffer<T>> Buffer<T>::createUninitialized(size_t size)
|
||||
{
|
||||
return ::adopt(*new Buffer<T>(size));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline RetainPtr<Buffer<T>> Buffer<T>::copy(const T* elements, size_t size)
|
||||
{
|
||||
return ::adopt(*new Buffer<T>(elements, size, Copy));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline RetainPtr<Buffer<T>> Buffer<T>::wrap(T* elements, size_t size)
|
||||
{
|
||||
return ::adopt(*new Buffer<T>(elements, size, Wrap));
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline RetainPtr<Buffer<T>> Buffer<T>::adopt(T* elements, size_t size)
|
||||
{
|
||||
return ::adopt(*new Buffer<T>(elements, size, Adopt));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
using AK::Buffer;
|
||||
|
85
AK/ByteBuffer.h
Normal file
85
AK/ByteBuffer.h
Normal file
|
@ -0,0 +1,85 @@
|
|||
#pragma once
|
||||
|
||||
#include "Buffer.h"
|
||||
#include "Types.h"
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
|
||||
namespace AK {
|
||||
|
||||
class ByteBuffer {
|
||||
public:
|
||||
ByteBuffer() { }
|
||||
ByteBuffer(std::nullptr_t) { }
|
||||
ByteBuffer(const ByteBuffer& other)
|
||||
: m_impl(other.m_impl.copyRef())
|
||||
{
|
||||
}
|
||||
ByteBuffer(ByteBuffer&& other)
|
||||
: m_impl(std::move(other.m_impl))
|
||||
{
|
||||
}
|
||||
ByteBuffer& operator=(ByteBuffer&& other)
|
||||
{
|
||||
if (this != &other)
|
||||
m_impl = std::move(other.m_impl);
|
||||
return *this;
|
||||
}
|
||||
|
||||
static ByteBuffer createUninitialized(size_t size) { return ByteBuffer(Buffer<byte>::createUninitialized(size)); }
|
||||
static ByteBuffer copy(const byte* data, size_t size) { return ByteBuffer(Buffer<byte>::copy(data, size)); }
|
||||
static ByteBuffer wrap(byte* data, size_t size) { return ByteBuffer(Buffer<byte>::wrap(data, size)); }
|
||||
static ByteBuffer adopt(byte* data, size_t size) { return ByteBuffer(Buffer<byte>::adopt(data, size)); }
|
||||
|
||||
~ByteBuffer() { clear(); }
|
||||
void clear() { m_impl = nullptr; }
|
||||
|
||||
operator bool() const { return !isNull(); }
|
||||
bool operator!() const { return isNull(); }
|
||||
bool isNull() const { return m_impl == nullptr; }
|
||||
|
||||
byte& operator[](size_t i) { ASSERT(m_impl); return (*m_impl)[i]; }
|
||||
byte operator[](size_t i) const { ASSERT(m_impl); return (*m_impl)[i]; }
|
||||
bool isEmpty() const { return !m_impl || m_impl->isEmpty(); }
|
||||
size_t size() const { return m_impl ? m_impl->size() : 0; }
|
||||
|
||||
byte* pointer() { return m_impl ? m_impl->pointer() : nullptr; }
|
||||
const byte* pointer() const { return m_impl ? m_impl->pointer() : nullptr; }
|
||||
|
||||
byte* offsetPointer(size_t offset) { return m_impl ? m_impl->offsetPointer(offset) : nullptr; }
|
||||
const byte* offsetPointer(size_t offset) const { return m_impl ? m_impl->offsetPointer(offset) : nullptr; }
|
||||
|
||||
const void* endPointer() const { return m_impl ? m_impl->endPointer() : nullptr; }
|
||||
|
||||
// NOTE: trim() does not reallocate.
|
||||
void trim(size_t size)
|
||||
{
|
||||
if (m_impl)
|
||||
m_impl->trim(size);
|
||||
}
|
||||
|
||||
ByteBuffer slice(size_t offset, size_t size) const
|
||||
{
|
||||
if (isNull())
|
||||
return { };
|
||||
if (offset >= this->size())
|
||||
return { };
|
||||
if (offset + size >= this->size())
|
||||
size = this->size() - offset;
|
||||
return copy(offsetPointer(offset), size);
|
||||
}
|
||||
|
||||
private:
|
||||
explicit ByteBuffer(RetainPtr<Buffer<byte>>&& impl)
|
||||
: m_impl(std::move(impl))
|
||||
{
|
||||
}
|
||||
|
||||
RetainPtr<Buffer<byte>> m_impl;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
using AK::ByteBuffer;
|
||||
|
95
AK/HashMap.h
Normal file
95
AK/HashMap.h
Normal file
|
@ -0,0 +1,95 @@
|
|||
#pragma once
|
||||
|
||||
#include "HashTable.h"
|
||||
#include <utility>
|
||||
|
||||
namespace AK {
|
||||
|
||||
template<typename K, typename V>
|
||||
class HashMap {
|
||||
private:
|
||||
struct Entry {
|
||||
K key;
|
||||
V value;
|
||||
|
||||
bool operator==(const Entry& other)
|
||||
{
|
||||
return key == other.key;
|
||||
}
|
||||
};
|
||||
|
||||
struct EntryTraits {
|
||||
static unsigned hash(const Entry& entry) { return Traits<K>::hash(entry.key); }
|
||||
static void dump(const Entry& entry)
|
||||
{
|
||||
printf("key=");
|
||||
Traits<K>::dump(entry.key);
|
||||
printf(" value=");
|
||||
Traits<V>::dump(entry.value);
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
HashMap() { }
|
||||
|
||||
HashMap(HashMap&& other)
|
||||
: m_table(std::move(other.m_table))
|
||||
{
|
||||
}
|
||||
|
||||
HashMap& operator=(HashMap&& other)
|
||||
{
|
||||
if (this != &other) {
|
||||
m_table = std::move(other.m_table);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool isEmpty() const { return m_table.isEmpty(); }
|
||||
unsigned size() const { return m_table.size(); }
|
||||
unsigned capacity() const { return m_table.capacity(); }
|
||||
|
||||
void set(const K&, V&&);
|
||||
|
||||
typedef HashTable<Entry, EntryTraits> HashTableType;
|
||||
typedef typename HashTableType::Iterator IteratorType;
|
||||
typedef typename HashTableType::ConstIterator ConstIteratorType;
|
||||
|
||||
IteratorType begin() { return m_table.begin(); }
|
||||
IteratorType end() { return m_table.end(); }
|
||||
IteratorType find(const K&);
|
||||
|
||||
ConstIteratorType begin() const { return m_table.begin(); }
|
||||
ConstIteratorType end() const { return m_table.end(); }
|
||||
ConstIteratorType find(const K&) const;
|
||||
|
||||
void dump() const { m_table.dump(); }
|
||||
|
||||
private:
|
||||
HashTable<Entry, EntryTraits> m_table;
|
||||
};
|
||||
|
||||
template<typename K, typename V>
|
||||
void HashMap<K, V>::set(const K& key, V&& value)
|
||||
{
|
||||
m_table.set(Entry{key, std::move(value)});
|
||||
}
|
||||
|
||||
template<typename K, typename V>
|
||||
auto HashMap<K, V>::find(const K& key) -> IteratorType
|
||||
{
|
||||
Entry dummy { key, V() };
|
||||
return m_table.find(dummy);
|
||||
}
|
||||
|
||||
template<typename K, typename V>
|
||||
auto HashMap<K, V>::find(const K& key) const -> ConstIteratorType
|
||||
{
|
||||
Entry dummy { key, V() };
|
||||
return m_table.find(dummy);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
using AK::HashMap;
|
||||
|
360
AK/HashTable.h
Normal file
360
AK/HashTable.h
Normal file
|
@ -0,0 +1,360 @@
|
|||
#pragma once
|
||||
|
||||
#include "Assertions.h"
|
||||
#include "SinglyLinkedList.h"
|
||||
#include "Traits.h"
|
||||
#include <cstdlib>
|
||||
#include <utility>
|
||||
|
||||
//#define HASHTABLE_DEBUG
|
||||
|
||||
namespace AK {
|
||||
|
||||
template<typename T, typename = Traits<T>> class HashTable;
|
||||
|
||||
template<typename T, typename TraitsForT>
|
||||
class HashTable {
|
||||
private:
|
||||
struct Bucket {
|
||||
SinglyLinkedList<T> chain;
|
||||
};
|
||||
|
||||
public:
|
||||
HashTable() { }
|
||||
explicit HashTable(HashTable&& other)
|
||||
: m_buckets(other.m_buckets)
|
||||
, m_size(other.m_size)
|
||||
, m_capacity(other.m_capacity)
|
||||
{
|
||||
other.m_size = 0;
|
||||
other.m_capacity = 0;
|
||||
other.m_buckets = nullptr;
|
||||
}
|
||||
HashTable& operator=(HashTable&& other)
|
||||
{
|
||||
if (this != &other) {
|
||||
m_buckets = other.m_buckets;
|
||||
m_size = other.m_size;
|
||||
m_capacity = other.m_capacity;
|
||||
other.m_size = 0;
|
||||
other.m_capacity = 0;
|
||||
other.m_buckets = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
~HashTable() { clear(); }
|
||||
bool isEmpty() const { return !m_size; }
|
||||
unsigned size() const { return m_size; }
|
||||
unsigned capacity() const { return m_capacity; }
|
||||
|
||||
void set(T&&);
|
||||
bool contains(const T&) const;
|
||||
void clear();
|
||||
|
||||
void dump() const;
|
||||
|
||||
class Iterator {
|
||||
public:
|
||||
bool operator!=(const Iterator& other)
|
||||
{
|
||||
if (m_isEnd && other.m_isEnd)
|
||||
return false;
|
||||
return &m_table != &other.m_table
|
||||
|| m_isEnd != other.m_isEnd
|
||||
|| m_bucketIndex != other.m_bucketIndex
|
||||
|| m_bucketIterator != other.m_bucketIterator;
|
||||
}
|
||||
T& operator*()
|
||||
{
|
||||
#ifdef HASHTABLE_DEBUG
|
||||
printf("retrieve { bucketIndex: %u, isEnd: %u }\n", m_bucketIndex, m_isEnd);
|
||||
#endif
|
||||
return *m_bucketIterator;
|
||||
}
|
||||
Iterator& operator++()
|
||||
{
|
||||
skipToNext();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void skipToNext()
|
||||
{
|
||||
#ifdef HASHTABLE_DEBUG
|
||||
unsigned pass = 0;
|
||||
#endif
|
||||
while (!m_isEnd) {
|
||||
#ifdef HASHTABLE_DEBUG
|
||||
++pass;
|
||||
printf("skipToNext pass %u, m_bucketIndex=%u\n", pass, m_bucketIndex);
|
||||
#endif
|
||||
if (m_bucketIterator.isEnd()) {
|
||||
++m_bucketIndex;
|
||||
if (m_bucketIndex >= m_table.capacity()) {
|
||||
m_isEnd = true;
|
||||
return;
|
||||
}
|
||||
m_bucketIterator = m_table.m_buckets[m_bucketIndex].chain.begin();
|
||||
} else {
|
||||
++m_bucketIterator;
|
||||
}
|
||||
if (!m_bucketIterator.isEnd())
|
||||
return;
|
||||
}
|
||||
}
|
||||
private:
|
||||
friend class HashTable;
|
||||
explicit Iterator(HashTable& table, bool isEnd, typename SinglyLinkedList<T>::Iterator bucketIterator = SinglyLinkedList<T>::Iterator::universalEnd())
|
||||
: m_table(table)
|
||||
, m_isEnd(isEnd)
|
||||
, m_bucketIterator(bucketIterator)
|
||||
{
|
||||
if (!isEnd && !m_table.isEmpty() && !(m_bucketIterator != SinglyLinkedList<T>::Iterator::universalEnd())) {
|
||||
#ifdef HASHTABLE_DEBUG
|
||||
printf("bucket iterator init!\n");
|
||||
#endif
|
||||
m_bucketIterator = m_table.m_buckets[0].chain.begin();
|
||||
if (m_bucketIterator.isEnd())
|
||||
skipToNext();
|
||||
}
|
||||
}
|
||||
|
||||
HashTable& m_table;
|
||||
unsigned m_bucketIndex { 0 };
|
||||
bool m_isEnd { false };
|
||||
typename SinglyLinkedList<T>::Iterator m_bucketIterator;
|
||||
};
|
||||
|
||||
Iterator begin() { return Iterator(*this, false); }
|
||||
Iterator end() { return Iterator(*this, true); }
|
||||
|
||||
class ConstIterator {
|
||||
public:
|
||||
bool operator!=(const ConstIterator& other)
|
||||
{
|
||||
if (m_isEnd && other.m_isEnd)
|
||||
return false;
|
||||
return &m_table != &other.m_table
|
||||
|| m_isEnd != other.m_isEnd
|
||||
|| m_bucketIndex != other.m_bucketIndex
|
||||
|| m_bucketIterator != other.m_bucketIterator;
|
||||
}
|
||||
const T& operator*() const
|
||||
{
|
||||
#ifdef HASHTABLE_DEBUG
|
||||
printf("retrieve { bucketIndex: %u, isEnd: %u }\n", m_bucketIndex, m_isEnd);
|
||||
#endif
|
||||
return *m_bucketIterator;
|
||||
}
|
||||
ConstIterator& operator++()
|
||||
{
|
||||
skipToNext();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void skipToNext()
|
||||
{
|
||||
#ifdef HASHTABLE_DEBUG
|
||||
unsigned pass = 0;
|
||||
#endif
|
||||
while (!m_isEnd) {
|
||||
#ifdef HASHTABLE_DEBUG
|
||||
++pass;
|
||||
printf("skipToNext pass %u, m_bucketIndex=%u\n", pass, m_bucketIndex);
|
||||
#endif
|
||||
if (m_bucketIterator.isEnd()) {
|
||||
++m_bucketIndex;
|
||||
if (m_bucketIndex >= m_table.capacity()) {
|
||||
m_isEnd = true;
|
||||
return;
|
||||
}
|
||||
const SinglyLinkedList<T>& chain = m_table.m_buckets[m_bucketIndex].chain;
|
||||
m_bucketIterator = chain.begin();
|
||||
} else {
|
||||
++m_bucketIterator;
|
||||
}
|
||||
if (!m_bucketIterator.isEnd())
|
||||
return;
|
||||
}
|
||||
}
|
||||
private:
|
||||
friend class HashTable;
|
||||
ConstIterator(const HashTable& table, bool isEnd, typename SinglyLinkedList<T>::ConstIterator bucketIterator = SinglyLinkedList<T>::ConstIterator::universalEnd())
|
||||
: m_table(table)
|
||||
, m_isEnd(isEnd)
|
||||
, m_bucketIterator(bucketIterator)
|
||||
{
|
||||
if (!isEnd && !m_table.isEmpty() && !(m_bucketIterator != SinglyLinkedList<T>::ConstIterator::universalEnd())) {
|
||||
#ifdef HASHTABLE_DEBUG
|
||||
printf("bucket iterator init!\n");
|
||||
#endif
|
||||
const SinglyLinkedList<T>& chain = m_table.m_buckets[0].chain;
|
||||
m_bucketIterator = chain.begin();
|
||||
|
||||
skipToNext();
|
||||
}
|
||||
}
|
||||
|
||||
const HashTable& m_table;
|
||||
unsigned m_bucketIndex { 0 };
|
||||
bool m_isEnd { false };
|
||||
typename SinglyLinkedList<T>::ConstIterator m_bucketIterator;
|
||||
};
|
||||
|
||||
ConstIterator begin() const { return ConstIterator(*this, false); }
|
||||
ConstIterator end() const { return ConstIterator(*this, true); }
|
||||
|
||||
Iterator find(const T&);
|
||||
ConstIterator find(const T&) const;
|
||||
|
||||
private:
|
||||
Bucket& lookup(const T&);
|
||||
const Bucket& lookup(const T&) const;
|
||||
void rehash(unsigned capacity);
|
||||
void insert(T&&);
|
||||
|
||||
Bucket* m_buckets { nullptr };
|
||||
|
||||
unsigned m_size { 0 };
|
||||
unsigned m_capacity { 0 };
|
||||
};
|
||||
|
||||
template<typename T, typename TraitsForT>
|
||||
void HashTable<T, TraitsForT>::set(T&& value)
|
||||
{
|
||||
if (!m_capacity)
|
||||
rehash(1);
|
||||
auto& bucket = lookup(value);
|
||||
for (auto& e : bucket.chain) {
|
||||
if (e == value)
|
||||
return;
|
||||
}
|
||||
if (size() >= capacity()) {
|
||||
rehash(size() + 1);
|
||||
insert(std::move(value));
|
||||
} else {
|
||||
bucket.chain.append(std::move(value));
|
||||
}
|
||||
m_size++;
|
||||
}
|
||||
|
||||
template<typename T, typename TraitsForT>
|
||||
void HashTable<T, TraitsForT>::rehash(unsigned newCapacity)
|
||||
{
|
||||
newCapacity *= 2;
|
||||
#ifdef HASHTABLE_DEBUG
|
||||
printf("rehash to %u buckets\n", newCapacity);
|
||||
#endif
|
||||
auto* newBuckets = new Bucket[newCapacity];
|
||||
auto* oldBuckets = m_buckets;
|
||||
unsigned oldCapacity = m_capacity;
|
||||
m_buckets = newBuckets;
|
||||
m_capacity = newCapacity;
|
||||
|
||||
#ifdef HASHTABLE_DEBUG
|
||||
printf("reinsert %u buckets\n", oldCapacity);
|
||||
#endif
|
||||
for (unsigned i = 0; i < oldCapacity; ++i) {
|
||||
for (auto& value : oldBuckets[i].chain) {
|
||||
insert(std::move(value));
|
||||
}
|
||||
}
|
||||
|
||||
delete [] oldBuckets;
|
||||
}
|
||||
|
||||
template<typename T, typename TraitsForT>
|
||||
void HashTable<T, TraitsForT>::clear()
|
||||
{
|
||||
delete [] m_buckets;
|
||||
m_capacity = 0;
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
template<typename T, typename TraitsForT>
|
||||
void HashTable<T, TraitsForT>::insert(T&& value)
|
||||
{
|
||||
auto& bucket = lookup(value);
|
||||
bucket.chain.append(std::move(value));
|
||||
}
|
||||
|
||||
template<typename T, typename TraitsForT>
|
||||
bool HashTable<T, TraitsForT>::contains(const T& value) const
|
||||
{
|
||||
if (isEmpty())
|
||||
return false;
|
||||
auto& bucket = lookup(value);
|
||||
for (auto& e : bucket.chain) {
|
||||
if (e == value)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename T, typename TraitsForT>
|
||||
auto HashTable<T, TraitsForT>::find(const T& value) -> Iterator
|
||||
{
|
||||
if (isEmpty())
|
||||
return end();
|
||||
auto& bucket = lookup(value);
|
||||
auto bucketIterator = bucket.chain.find(value);
|
||||
if (bucketIterator != bucket.chain.end())
|
||||
return Iterator(*this, false, bucketIterator);
|
||||
return end();
|
||||
}
|
||||
|
||||
template<typename T, typename TraitsForT>
|
||||
auto HashTable<T, TraitsForT>::find(const T& value) const -> ConstIterator
|
||||
{
|
||||
if (isEmpty())
|
||||
return end();
|
||||
auto& bucket = lookup(value);
|
||||
auto bucketIterator = bucket.chain.find(value);
|
||||
if (bucketIterator != bucket.chain.end())
|
||||
return ConstIterator(*this, false, bucketIterator);
|
||||
return end();
|
||||
}
|
||||
|
||||
template<typename T, typename TraitsForT>
|
||||
typename HashTable<T, TraitsForT>::Bucket& HashTable<T, TraitsForT>::lookup(const T& value)
|
||||
{
|
||||
unsigned hash = TraitsForT::hash(value);
|
||||
#ifdef HASHTABLE_DEBUG
|
||||
printf("hash for ");
|
||||
TraitsForT::dump(value);
|
||||
printf(" is %u\n", hash);
|
||||
#endif
|
||||
return m_buckets[hash % m_capacity];
|
||||
}
|
||||
|
||||
template<typename T, typename TraitsForT>
|
||||
const typename HashTable<T, TraitsForT>::Bucket& HashTable<T, TraitsForT>::lookup(const T& value) const
|
||||
{
|
||||
unsigned hash = TraitsForT::hash(value);
|
||||
#ifdef HASHTABLE_DEBUG
|
||||
printf("hash for ");
|
||||
TraitsForT::dump(value);
|
||||
printf(" is %u\n", hash);
|
||||
#endif
|
||||
return m_buckets[hash % m_capacity];
|
||||
}
|
||||
|
||||
template<typename T, typename TraitsForT>
|
||||
void HashTable<T, TraitsForT>::dump() const
|
||||
{
|
||||
printf("HashTable{%p} m_size=%u, m_capacity=%u, m_buckets=%p\n", this, m_size, m_capacity, m_buckets);
|
||||
for (unsigned i = 0; i < m_capacity; ++i) {
|
||||
auto& bucket = m_buckets[i];
|
||||
printf("Bucket %u\n", i);
|
||||
for (auto& e : bucket.chain) {
|
||||
printf(" > ");
|
||||
TraitsForT::dump(e);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
using AK::HashTable;
|
||||
|
18
AK/Makefile
Normal file
18
AK/Makefile
Normal file
|
@ -0,0 +1,18 @@
|
|||
PROGRAM = akit-test
|
||||
OBJS = StringImpl.o String.o MappedFile.o TemporaryFile.o SimpleMalloc.o kmalloc.o test.o
|
||||
|
||||
CXXFLAGS = -std=c++17 -O0 -W -Wall -ggdb3
|
||||
|
||||
all: $(PROGRAM)
|
||||
|
||||
test.o: Vector.h String.h StringImpl.h MappedFile.h HashTable.h SinglyLinkedList.h Traits.h HashMap.h TemporaryFile.h Buffer.h
|
||||
|
||||
.cpp.o:
|
||||
$(CXX) $(CXXFLAGS) -o $@ -c $<
|
||||
|
||||
clean:
|
||||
rm -f $(OBJS) $(PROGRAM)
|
||||
|
||||
$(PROGRAM): $(OBJS)
|
||||
$(CXX) $(LDFLAGS) -o $@ $(OBJS)
|
||||
|
48
AK/MappedFile.cpp
Normal file
48
AK/MappedFile.cpp
Normal file
|
@ -0,0 +1,48 @@
|
|||
#include "MappedFile.h"
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <cstdio>
|
||||
|
||||
namespace AK {
|
||||
|
||||
MappedFile::MappedFile(String&& fileName)
|
||||
: m_fileName(std::move(fileName))
|
||||
{
|
||||
m_fileLength = 1024;
|
||||
m_fd = open(m_fileName.characters(), O_RDONLY);
|
||||
|
||||
if (m_fd != -1) {
|
||||
struct stat st;
|
||||
fstat(m_fd, &st);
|
||||
m_fileLength = st.st_size;
|
||||
m_map = mmap(nullptr, m_fileLength, PROT_READ, MAP_SHARED, m_fd, 0);
|
||||
|
||||
if (m_map == MAP_FAILED)
|
||||
perror("");
|
||||
}
|
||||
|
||||
printf("MappedFile{%s} := { m_fd=%d, m_fileLength=%u, m_map=%p }\n", m_fileName.characters(), m_fd, m_fileLength, m_map);
|
||||
}
|
||||
|
||||
MappedFile::~MappedFile()
|
||||
{
|
||||
if (m_map != (void*)-1) {
|
||||
ASSERT(m_fd != -1);
|
||||
munmap(m_map, m_fileLength);
|
||||
}
|
||||
}
|
||||
|
||||
MappedFile::MappedFile(MappedFile&& other)
|
||||
: m_fileName(std::move(other.m_fileName))
|
||||
, m_fileLength(other.m_fileLength)
|
||||
, m_fd(other.m_fd)
|
||||
, m_map(other.m_map)
|
||||
{
|
||||
other.m_fileLength = 0;
|
||||
other.m_fd = -1;
|
||||
other.m_map = (void*)-1;
|
||||
}
|
||||
|
||||
}
|
||||
|
30
AK/MappedFile.h
Normal file
30
AK/MappedFile.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
#pragma once
|
||||
|
||||
#include "String.h"
|
||||
|
||||
namespace AK {
|
||||
|
||||
class MappedFile {
|
||||
public:
|
||||
MappedFile() { }
|
||||
explicit MappedFile(String&& fileName);
|
||||
MappedFile(MappedFile&&);
|
||||
~MappedFile();
|
||||
|
||||
bool isValid() const { return m_map != (void*)-1; }
|
||||
|
||||
void* pointer() { return m_map; }
|
||||
const void* pointer() const { return m_map; }
|
||||
size_t fileLength() const { return m_fileLength; }
|
||||
|
||||
private:
|
||||
String m_fileName;
|
||||
size_t m_fileLength { 0 };
|
||||
int m_fd { -1 };
|
||||
void* m_map { (void*)-1 };
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
using AK::MappedFile;
|
||||
|
94
AK/OwnPtr.h
Normal file
94
AK/OwnPtr.h
Normal file
|
@ -0,0 +1,94 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
namespace AK {
|
||||
|
||||
template<typename T>
|
||||
class OwnPtr {
|
||||
public:
|
||||
OwnPtr() { }
|
||||
explicit OwnPtr(T* ptr) : m_ptr(ptr) { }
|
||||
OwnPtr(OwnPtr&& other) : m_ptr(other.leakPtr()) { }
|
||||
template<typename U> OwnPtr(OwnPtr<U>&& other) : m_ptr(static_cast<T*>(other.leakPtr())) { }
|
||||
~OwnPtr() { clear(); }
|
||||
OwnPtr(std::nullptr_t) { };
|
||||
|
||||
OwnPtr& operator=(OwnPtr&& other)
|
||||
{
|
||||
if (this != &other) {
|
||||
delete m_ptr;
|
||||
m_ptr = other.leakPtr();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
OwnPtr& operator=(OwnPtr<U>&& other)
|
||||
{
|
||||
if (this != static_cast<void*>(&other)) {
|
||||
delete m_ptr;
|
||||
m_ptr = other.leakPtr();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
OwnPtr& operator=(T* ptr)
|
||||
{
|
||||
if (m_ptr != ptr)
|
||||
delete m_ptr;
|
||||
m_ptr = ptr;
|
||||
return *this;
|
||||
}
|
||||
|
||||
OwnPtr& operator=(std::nullptr_t)
|
||||
{
|
||||
clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
delete m_ptr;
|
||||
m_ptr = nullptr;
|
||||
}
|
||||
|
||||
bool operator!() const { return !m_ptr; }
|
||||
|
||||
typedef T* OwnPtr::*UnspecifiedBoolType;
|
||||
operator UnspecifiedBoolType() const { return m_ptr ? &OwnPtr::m_ptr : nullptr; }
|
||||
|
||||
T* leakPtr()
|
||||
{
|
||||
T* leakedPtr = m_ptr;
|
||||
m_ptr = nullptr;
|
||||
return leakedPtr;
|
||||
}
|
||||
|
||||
T* ptr() { return m_ptr; }
|
||||
const T* ptr() const { return m_ptr; }
|
||||
|
||||
T* operator->() { return m_ptr; }
|
||||
const T* operator->() const { return m_ptr; }
|
||||
|
||||
T& operator*() { return *m_ptr; }
|
||||
const T& operator*() const { return *m_ptr; }
|
||||
|
||||
operator bool() { return !!m_ptr; }
|
||||
|
||||
private:
|
||||
T* m_ptr = nullptr;
|
||||
};
|
||||
|
||||
template<class T, class... Args> inline OwnPtr<T>
|
||||
make(Args&&... args)
|
||||
{
|
||||
return OwnPtr<T>(new T(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
using AK::OwnPtr;
|
||||
using AK::make;
|
||||
|
128
AK/RetainPtr.h
Normal file
128
AK/RetainPtr.h
Normal file
|
@ -0,0 +1,128 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <utility>
|
||||
|
||||
namespace AK {
|
||||
|
||||
template<typename T>
|
||||
inline void retainIfNotNull(T* ptr)
|
||||
{
|
||||
if (ptr)
|
||||
ptr->retain();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline void releaseIfNotNull(T* ptr)
|
||||
{
|
||||
if (ptr)
|
||||
ptr->release();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
class RetainPtr {
|
||||
public:
|
||||
enum AdoptTag { Adopt };
|
||||
|
||||
RetainPtr() { }
|
||||
RetainPtr(const T* ptr) : m_ptr(const_cast<T*>(ptr)) { retainIfNotNull(m_ptr); }
|
||||
RetainPtr(T* ptr) : m_ptr(ptr) { retainIfNotNull(m_ptr); }
|
||||
RetainPtr(T& object) : m_ptr(&object) { m_ptr->retain(); }
|
||||
RetainPtr(AdoptTag, T& object) : m_ptr(&object) { }
|
||||
RetainPtr(RetainPtr&& other) : m_ptr(other.leakRef()) { }
|
||||
template<typename U> RetainPtr(RetainPtr<U>&& other) : m_ptr(static_cast<T*>(other.leakRef())) { }
|
||||
~RetainPtr() { clear(); }
|
||||
RetainPtr(std::nullptr_t) { }
|
||||
|
||||
RetainPtr& operator=(RetainPtr&& other)
|
||||
{
|
||||
if (this != &other) {
|
||||
releaseIfNotNull(m_ptr);
|
||||
m_ptr = other.leakRef();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename U>
|
||||
RetainPtr& operator=(RetainPtr<U>&& other)
|
||||
{
|
||||
if (this != static_cast<void*>(&other)) {
|
||||
releaseIfNotNull(m_ptr);
|
||||
m_ptr = other.leakRef();
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
RetainPtr& operator=(T* ptr)
|
||||
{
|
||||
if (m_ptr != ptr)
|
||||
releaseIfNotNull(m_ptr);
|
||||
m_ptr = ptr;
|
||||
retainIfNotNull(m_ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
RetainPtr& operator=(T& object)
|
||||
{
|
||||
if (m_ptr != &object)
|
||||
releaseIfNotNull(m_ptr);
|
||||
m_ptr = &object;
|
||||
retainIfNotNull(m_ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
RetainPtr& operator=(std::nullptr_t)
|
||||
{
|
||||
clear();
|
||||
return *this;
|
||||
}
|
||||
|
||||
RetainPtr copyRef() const
|
||||
{
|
||||
return RetainPtr(m_ptr);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
releaseIfNotNull(m_ptr);
|
||||
m_ptr = nullptr;
|
||||
}
|
||||
|
||||
bool operator!() const { return !m_ptr; }
|
||||
|
||||
typedef T* RetainPtr::*UnspecifiedBoolType;
|
||||
operator UnspecifiedBoolType() const { return m_ptr ? &RetainPtr::m_ptr : nullptr; }
|
||||
|
||||
T* leakRef()
|
||||
{
|
||||
T* leakedPtr = m_ptr;
|
||||
m_ptr = nullptr;
|
||||
return leakedPtr;
|
||||
}
|
||||
|
||||
T* ptr() { return m_ptr; }
|
||||
const T* ptr() const { return m_ptr; }
|
||||
|
||||
T* operator->() { return m_ptr; }
|
||||
const T* operator->() const { return m_ptr; }
|
||||
|
||||
T& operator*() { return *m_ptr; }
|
||||
const T& operator*() const { return *m_ptr; }
|
||||
|
||||
operator bool() { return !!m_ptr; }
|
||||
|
||||
private:
|
||||
T* m_ptr = nullptr;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
inline RetainPtr<T> adopt(T& object)
|
||||
{
|
||||
return RetainPtr<T>(RetainPtr<T>::Adopt, object);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
using AK::RetainPtr;
|
||||
using AK::adopt;
|
||||
|
43
AK/Retainable.h
Normal file
43
AK/Retainable.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
#pragma once
|
||||
|
||||
#include "Assertions.h"
|
||||
|
||||
namespace AK {
|
||||
|
||||
template<typename T>
|
||||
class Retainable {
|
||||
public:
|
||||
Retainable() { }
|
||||
|
||||
void retain()
|
||||
{
|
||||
ASSERT(m_retainCount);
|
||||
++m_retainCount;
|
||||
}
|
||||
|
||||
void release()
|
||||
{
|
||||
assert(m_retainCount);
|
||||
if (!--m_retainCount)
|
||||
delete static_cast<const T*>(this);
|
||||
}
|
||||
|
||||
int retainCount() const
|
||||
{
|
||||
return m_retainCount;
|
||||
}
|
||||
|
||||
protected:
|
||||
~Retainable()
|
||||
{
|
||||
ASSERT(!m_retainCount);
|
||||
}
|
||||
|
||||
private:
|
||||
int m_retainCount { 1 };
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
using AK::Retainable;
|
||||
|
254
AK/SimpleMalloc.cpp
Normal file
254
AK/SimpleMalloc.cpp
Normal file
|
@ -0,0 +1,254 @@
|
|||
#include "SimpleMalloc.h"
|
||||
#include "Assertions.h"
|
||||
#include "Types.h"
|
||||
#include <sys/mman.h>
|
||||
#include <cstring>
|
||||
#include <cstdio>
|
||||
|
||||
namespace SimpleMalloc {
|
||||
|
||||
class AllocationBitmap {
|
||||
public:
|
||||
static AllocationBitmap wrap(byte* data, unsigned size)
|
||||
{
|
||||
return AllocationBitmap(data, size);
|
||||
}
|
||||
|
||||
~AllocationBitmap()
|
||||
{
|
||||
}
|
||||
|
||||
unsigned size() const { return m_size; }
|
||||
bool get(unsigned index) const
|
||||
{
|
||||
ASSERT(index < m_size);
|
||||
return 0 != (m_data[index / 8] & (1u << (index % 8)));
|
||||
}
|
||||
void set(unsigned index, bool value) const
|
||||
{
|
||||
ASSERT(index < m_size);
|
||||
if (value)
|
||||
m_data[index / 8] |= static_cast<byte>((1u << (index % 8)));
|
||||
else
|
||||
m_data[index / 8] &= static_cast<byte>(~(1u << (index % 8)));
|
||||
}
|
||||
|
||||
private:
|
||||
AllocationBitmap(byte* data, unsigned size)
|
||||
: m_data(data)
|
||||
, m_size(size)
|
||||
{
|
||||
}
|
||||
|
||||
byte* m_data { nullptr };
|
||||
unsigned m_size { 0 };
|
||||
};
|
||||
|
||||
template<dword chunkSize>
|
||||
class ChunkAllocator {
|
||||
public:
|
||||
void initialize(byte* base)
|
||||
{
|
||||
m_base = base;
|
||||
m_free = capacityInAllocations();
|
||||
dump();
|
||||
}
|
||||
|
||||
static constexpr dword capacityInAllocations()
|
||||
{
|
||||
return 1048576 / chunkSize;
|
||||
}
|
||||
|
||||
static constexpr dword capacityInBytes()
|
||||
{
|
||||
return capacityInAllocations() * chunkSize;
|
||||
}
|
||||
|
||||
byte* allocate()
|
||||
{
|
||||
auto bitmap = this->bitmap();
|
||||
for (dword i = 0; i < capacityInAllocations(); ++i) {
|
||||
if (!bitmap.get(i)) {
|
||||
bitmap.set(i, true);
|
||||
--m_free;
|
||||
return pointerToChunk(i);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void dump() const
|
||||
{
|
||||
printf("ChunkAllocator<%u> @ %p, free: %u\n", chunkSize, m_base, m_free);
|
||||
}
|
||||
|
||||
void free(byte* ptr)
|
||||
{
|
||||
ASSERT(isInAllocator(ptr));
|
||||
auto bitmap = this->bitmap();
|
||||
auto chunkIndex = chunkIndexFromPointer(ptr);
|
||||
ASSERT(bitmap.get(chunkIndex));
|
||||
bitmap.set(chunkIndex, false);
|
||||
++m_free;
|
||||
}
|
||||
|
||||
bool isInAllocator(byte* ptr)
|
||||
{
|
||||
return ptr >= pointerToChunk(0) && ptr <= addressAfterThisAllocator();
|
||||
}
|
||||
|
||||
dword chunkIndexFromPointer(byte* ptr)
|
||||
{
|
||||
return (ptr - pointerToChunk(0)) / chunkSize;
|
||||
}
|
||||
|
||||
byte* pointerToChunk(dword index)
|
||||
{
|
||||
return m_base + sizeOfAllocationBitmapInBytes() + (index * chunkSize);
|
||||
}
|
||||
|
||||
AllocationBitmap bitmap()
|
||||
{
|
||||
return AllocationBitmap::wrap(m_base, capacityInAllocations());
|
||||
}
|
||||
|
||||
static constexpr dword sizeOfAllocationBitmapInBytes()
|
||||
{
|
||||
return capacityInAllocations() / 8;
|
||||
}
|
||||
|
||||
byte* addressAfterThisAllocator() const
|
||||
{
|
||||
return m_base + sizeOfAllocationBitmapInBytes() + capacityInBytes();
|
||||
}
|
||||
|
||||
dword numberOfFreeChunks() const
|
||||
{
|
||||
return m_free;
|
||||
}
|
||||
|
||||
private:
|
||||
byte* m_base { nullptr };
|
||||
dword m_free { capacityInAllocations() };
|
||||
};
|
||||
|
||||
struct Allocator {
|
||||
void initialize();
|
||||
void initializeIfNeeded();
|
||||
void dump();
|
||||
|
||||
ChunkAllocator<8> alloc8;
|
||||
ChunkAllocator<16> alloc16;
|
||||
ChunkAllocator<4096> alloc4096;
|
||||
ChunkAllocator<16384> alloc16384;
|
||||
|
||||
byte* space;
|
||||
bool initialized { false };
|
||||
};
|
||||
|
||||
static Allocator allocator;
|
||||
|
||||
void Allocator::initializeIfNeeded()
|
||||
{
|
||||
if (initialized)
|
||||
return;
|
||||
initialize();
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
void Allocator::initialize()
|
||||
{
|
||||
space = (byte*)mmap((void*)0x20000000, 32 * MB, PROT_WRITE | PROT_READ | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
ASSERT(space != MAP_FAILED);
|
||||
alloc8.initialize(space + 0x10000);
|
||||
alloc16.initialize(alloc8.addressAfterThisAllocator());
|
||||
alloc4096.initialize(alloc16.addressAfterThisAllocator());
|
||||
alloc16384.initialize(alloc4096.addressAfterThisAllocator());
|
||||
}
|
||||
|
||||
void Allocator::dump()
|
||||
{
|
||||
alloc8.dump();
|
||||
alloc16.dump();
|
||||
alloc4096.dump();
|
||||
alloc16384.dump();
|
||||
}
|
||||
|
||||
void initialize()
|
||||
{
|
||||
allocator.initialize();
|
||||
}
|
||||
|
||||
void dump()
|
||||
{
|
||||
allocator.dump();
|
||||
}
|
||||
|
||||
byte* allocate(dword size)
|
||||
{
|
||||
if (!size)
|
||||
return nullptr;
|
||||
allocator.initializeIfNeeded();
|
||||
if (size <= 8) {
|
||||
if (auto* ptr = allocator.alloc8.allocate())
|
||||
return ptr;
|
||||
}
|
||||
if (size <= 16) {
|
||||
if (auto* ptr = allocator.alloc16.allocate())
|
||||
return ptr;
|
||||
}
|
||||
if (size <= 4096) {
|
||||
if (auto* ptr = allocator.alloc4096.allocate())
|
||||
return ptr;
|
||||
}
|
||||
if (size <= 16384) {
|
||||
if (auto* ptr = allocator.alloc16384.allocate())
|
||||
return ptr;
|
||||
}
|
||||
printf("SimpleMalloc: unsupported alloc size: %u\n", size);
|
||||
ASSERT_NOT_REACHED();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
byte* allocateZeroed(dword size)
|
||||
{
|
||||
auto* ptr = allocate(size);
|
||||
if (!ptr)
|
||||
return nullptr;
|
||||
memset(ptr, 0, size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
byte* reallocate(byte* ptr, dword size)
|
||||
{
|
||||
// FIXME;
|
||||
ASSERT_NOT_REACHED();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void free(byte* ptr)
|
||||
{
|
||||
if (!ptr)
|
||||
return;
|
||||
allocator.initializeIfNeeded();
|
||||
if (allocator.alloc8.isInAllocator(ptr)) {
|
||||
allocator.alloc8.free(ptr);
|
||||
return;
|
||||
}
|
||||
if (allocator.alloc16.isInAllocator(ptr)) {
|
||||
allocator.alloc16.free(ptr);
|
||||
return;
|
||||
}
|
||||
if (allocator.alloc4096.isInAllocator(ptr)) {
|
||||
allocator.alloc4096.free(ptr);
|
||||
return;
|
||||
}
|
||||
if (allocator.alloc16384.isInAllocator(ptr)) {
|
||||
allocator.alloc16384.free(ptr);
|
||||
return;
|
||||
}
|
||||
ASSERT_NOT_REACHED();
|
||||
}
|
||||
|
||||
}
|
||||
|
15
AK/SimpleMalloc.h
Normal file
15
AK/SimpleMalloc.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#pragma once
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
namespace SimpleMalloc {
|
||||
|
||||
void initialize();
|
||||
void dump();
|
||||
byte* allocate(dword);
|
||||
byte* allocateZeroed(dword);
|
||||
void free(byte*);
|
||||
byte* reallocate(byte*, dword);
|
||||
|
||||
}
|
||||
|
114
AK/SinglyLinkedList.h
Normal file
114
AK/SinglyLinkedList.h
Normal file
|
@ -0,0 +1,114 @@
|
|||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace AK {
|
||||
|
||||
template<typename T>
|
||||
class SinglyLinkedList {
|
||||
private:
|
||||
struct Node {
|
||||
T value;
|
||||
Node* next { nullptr };
|
||||
};
|
||||
|
||||
public:
|
||||
SinglyLinkedList() { }
|
||||
~SinglyLinkedList() { }
|
||||
|
||||
bool isEmpty() const { return !head(); }
|
||||
|
||||
T& first() { ASSERT(head()); return head()->value; }
|
||||
const T& first() const { ASSERT(head()); return head()->value; }
|
||||
T& last() { ASSERT(head()); return tail()->value; }
|
||||
const T& last() const { ASSERT(head()); return tail()->value; }
|
||||
|
||||
void append(T&& value)
|
||||
{
|
||||
auto* node = new Node;
|
||||
node->value = std::move(value);
|
||||
if (!m_head) {
|
||||
m_head = node;
|
||||
m_tail = node;
|
||||
return;
|
||||
}
|
||||
m_tail->next = node;
|
||||
m_tail = node;
|
||||
}
|
||||
|
||||
bool containsSlow(const T& value) const
|
||||
{
|
||||
for (auto* node = m_head; node; node = node->next) {
|
||||
if (node->value == value)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
class Iterator {
|
||||
public:
|
||||
bool operator!=(const Iterator& other) { return m_node != other.m_node; }
|
||||
Iterator& operator++() { m_node = m_node->next; return *this; }
|
||||
T& operator*() { return m_node->value; }
|
||||
bool isEnd() const { return !m_node; }
|
||||
static Iterator universalEnd() { return Iterator(nullptr); }
|
||||
private:
|
||||
friend class SinglyLinkedList;
|
||||
explicit Iterator(SinglyLinkedList::Node* node) : m_node(node) { }
|
||||
SinglyLinkedList::Node* m_node;
|
||||
};
|
||||
|
||||
Iterator begin() { return Iterator(m_head); }
|
||||
Iterator end() { return Iterator::universalEnd(); }
|
||||
|
||||
class ConstIterator {
|
||||
public:
|
||||
bool operator!=(const ConstIterator& other) { return m_node != other.m_node; }
|
||||
ConstIterator& operator++() { m_node = m_node->next; return *this; }
|
||||
const T& operator*() const { return m_node->value; }
|
||||
bool isEnd() const { return !m_node; }
|
||||
static ConstIterator universalEnd() { return ConstIterator(nullptr); }
|
||||
private:
|
||||
friend class SinglyLinkedList;
|
||||
explicit ConstIterator(const SinglyLinkedList::Node* node) : m_node(node) { }
|
||||
const SinglyLinkedList::Node* m_node;
|
||||
};
|
||||
|
||||
ConstIterator begin() const { return ConstIterator(m_head); }
|
||||
ConstIterator end() const { return ConstIterator::universalEnd(); }
|
||||
|
||||
ConstIterator find(const T& value) const
|
||||
{
|
||||
for (auto* node = m_head; node; node = node->next) {
|
||||
if (node->value == value)
|
||||
return ConstIterator(node);
|
||||
}
|
||||
return end();
|
||||
}
|
||||
|
||||
Iterator find(const T& value)
|
||||
{
|
||||
for (auto* node = m_head; node; node = node->next) {
|
||||
if (node->value == value)
|
||||
return Iterator(node);
|
||||
}
|
||||
return end();
|
||||
}
|
||||
|
||||
private:
|
||||
friend class Iterator;
|
||||
|
||||
Node* head() { return m_head; }
|
||||
const Node* head() const { return m_head; }
|
||||
|
||||
Node* tail() { return m_tail; }
|
||||
const Node* tail() const { return m_tail; }
|
||||
|
||||
Node* m_head { nullptr };
|
||||
Node* m_tail { nullptr };
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
using AK::SinglyLinkedList;
|
||||
|
33
AK/StdLib.h
Normal file
33
AK/StdLib.h
Normal file
|
@ -0,0 +1,33 @@
|
|||
#pragma once
|
||||
|
||||
namespace AK {
|
||||
|
||||
template<typename T>
|
||||
inline T min(const T& a, const T& b)
|
||||
{
|
||||
return a < b ? a : b;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
inline T max(const T& a, const T& b)
|
||||
{
|
||||
return a < b ? b : a;
|
||||
}
|
||||
|
||||
|
||||
template<typename T>
|
||||
static inline T ceilDiv(T a, T b)
|
||||
{
|
||||
T result = a / b;
|
||||
if ((a % b) != 0)
|
||||
++result;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
using AK::min;
|
||||
using AK::max;
|
||||
using AK::ceilDiv;
|
||||
|
56
AK/String.cpp
Normal file
56
AK/String.cpp
Normal file
|
@ -0,0 +1,56 @@
|
|||
#include "String.h"
|
||||
#include <cstring>
|
||||
|
||||
namespace AK {
|
||||
|
||||
bool String::operator==(const String& other) const
|
||||
{
|
||||
if (!m_impl)
|
||||
return !other.m_impl;
|
||||
|
||||
if (!other.m_impl)
|
||||
return false;
|
||||
|
||||
if (length() != other.length())
|
||||
return false;
|
||||
|
||||
return !memcmp(characters(), other.characters(), length());
|
||||
}
|
||||
|
||||
String String::empty()
|
||||
{
|
||||
return StringImpl::theEmptyStringImpl();
|
||||
}
|
||||
|
||||
Vector<String> String::split(const char separator) const
|
||||
{
|
||||
if (isEmpty())
|
||||
return { };
|
||||
|
||||
Vector<String> parts;
|
||||
|
||||
auto* characters = this->characters();
|
||||
unsigned startOfPart = 0;
|
||||
unsigned i = 0;
|
||||
for (i = 0; i < length(); ++i) {
|
||||
char ch = characters[i];
|
||||
if (ch == separator) {
|
||||
if (i != startOfPart) {
|
||||
parts.append(String(characters + startOfPart, i - startOfPart));
|
||||
}
|
||||
startOfPart = i + 1;
|
||||
}
|
||||
}
|
||||
if (startOfPart != length())
|
||||
parts.append(String(characters + startOfPart, i - startOfPart));
|
||||
return parts;
|
||||
}
|
||||
|
||||
ByteBuffer String::toByteBuffer() const
|
||||
{
|
||||
if (!m_impl)
|
||||
return nullptr;
|
||||
return ByteBuffer::copy(reinterpret_cast<const byte*>(characters()), length());
|
||||
}
|
||||
|
||||
}
|
98
AK/String.h
Normal file
98
AK/String.h
Normal file
|
@ -0,0 +1,98 @@
|
|||
#pragma once
|
||||
|
||||
#include "ByteBuffer.h"
|
||||
#include "RetainPtr.h"
|
||||
#include "StringImpl.h"
|
||||
#include "Traits.h"
|
||||
#include "Vector.h"
|
||||
#include <cstdio>
|
||||
|
||||
namespace AK {
|
||||
|
||||
class String {
|
||||
public:
|
||||
~String() { }
|
||||
|
||||
String() { }
|
||||
String(const String& other)
|
||||
: m_impl(const_cast<String&>(other).m_impl.copyRef())
|
||||
{
|
||||
}
|
||||
|
||||
String(String&& other)
|
||||
: m_impl(std::move(other.m_impl))
|
||||
{
|
||||
}
|
||||
|
||||
String(const char* cstring)
|
||||
: m_impl(StringImpl::create(cstring))
|
||||
{
|
||||
}
|
||||
|
||||
String(const char* cstring, size_t length)
|
||||
: m_impl(StringImpl::create(cstring, length))
|
||||
{
|
||||
}
|
||||
|
||||
String(const StringImpl& impl)
|
||||
: m_impl(const_cast<StringImpl&>(impl))
|
||||
{
|
||||
}
|
||||
|
||||
String(RetainPtr<StringImpl>&& impl)
|
||||
: m_impl(std::move(impl))
|
||||
{
|
||||
}
|
||||
|
||||
String toLowercase() const
|
||||
{
|
||||
if (!m_impl)
|
||||
return String();
|
||||
return m_impl->toLowercase();
|
||||
}
|
||||
|
||||
String toUppercase() const
|
||||
{
|
||||
if (!m_impl)
|
||||
return String();
|
||||
return m_impl->toUppercase();
|
||||
}
|
||||
|
||||
Vector<String> split(char separator) const;
|
||||
|
||||
bool isEmpty() const { return length() == 0; }
|
||||
unsigned length() const { return m_impl ? m_impl->length() : 0; }
|
||||
const char* characters() const { return m_impl ? m_impl->characters() : nullptr; }
|
||||
char operator[](unsigned i) const { ASSERT(m_impl); return (*m_impl)[i]; }
|
||||
|
||||
bool operator==(const String&) const;
|
||||
bool operator!=(const String& other) const { return !(*this == other); }
|
||||
|
||||
static String empty();
|
||||
|
||||
StringImpl* impl() { return m_impl.ptr(); }
|
||||
const StringImpl* impl() const { return m_impl.ptr(); }
|
||||
|
||||
String& operator=(String&& other)
|
||||
{
|
||||
if (this != &other) {
|
||||
m_impl = std::move(other.m_impl);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
ByteBuffer toByteBuffer() const;
|
||||
|
||||
private:
|
||||
RetainPtr<StringImpl> m_impl;
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Traits<String> {
|
||||
static unsigned hash(const String& s) { return s.impl() ? s.impl()->hash() : 0; }
|
||||
static void dump(const String& s) { printf("%s", s.characters()); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
using AK::String;
|
25
AK/StringBuilder.cpp
Normal file
25
AK/StringBuilder.cpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
#include "StringBuilder.h"
|
||||
|
||||
namespace AK {
|
||||
|
||||
void StringBuilder::append(String&& str)
|
||||
{
|
||||
m_strings.append(std::move(str));
|
||||
}
|
||||
|
||||
void StringBuilder::append(char ch)
|
||||
{
|
||||
m_strings.append(StringImpl::create(&ch, 1));
|
||||
}
|
||||
|
||||
String StringBuilder::build()
|
||||
{
|
||||
auto strings = std::move(m_strings);
|
||||
if (strings.isEmpty())
|
||||
return String::empty();
|
||||
|
||||
return String();
|
||||
}
|
||||
|
||||
}
|
||||
|
25
AK/StringBuilder.h
Normal file
25
AK/StringBuilder.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include "String.h"
|
||||
#include "Vector.h"
|
||||
|
||||
namespace AK {
|
||||
|
||||
class StringBuilder {
|
||||
public:
|
||||
StringBuilder() { }
|
||||
~StringBuilder() { }
|
||||
|
||||
void append(String&&);
|
||||
void append(char);
|
||||
|
||||
String build();
|
||||
|
||||
private:
|
||||
Vector<String> m_strings;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
using AK::StringBuilder;
|
||||
|
149
AK/StringImpl.cpp
Normal file
149
AK/StringImpl.cpp
Normal file
|
@ -0,0 +1,149 @@
|
|||
#include "StringImpl.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <new>
|
||||
#include "kmalloc.h"
|
||||
|
||||
namespace AK {
|
||||
|
||||
StringImpl& StringImpl::theEmptyStringImpl()
|
||||
{
|
||||
static StringImpl* s = new StringImpl(ConstructTheEmptyStringImpl);
|
||||
return *s;
|
||||
}
|
||||
|
||||
StringImpl::~StringImpl()
|
||||
{
|
||||
}
|
||||
|
||||
static inline size_t allocationSizeForStringImpl(unsigned length)
|
||||
{
|
||||
return sizeof(StringImpl) + (sizeof(char) * length) + sizeof(char);
|
||||
}
|
||||
|
||||
RetainPtr<StringImpl> StringImpl::createUninitialized(unsigned length, char*& buffer)
|
||||
{
|
||||
if (!length)
|
||||
return theEmptyStringImpl();
|
||||
|
||||
void* slot = kmalloc(allocationSizeForStringImpl(length));
|
||||
if (!slot)
|
||||
return nullptr;
|
||||
|
||||
auto newStringImpl = adopt(*new (slot) StringImpl(ConstructWithInlineBuffer, length));
|
||||
buffer = const_cast<char*>(newStringImpl->m_characters);
|
||||
buffer[length] = '\0';
|
||||
return newStringImpl;
|
||||
}
|
||||
|
||||
RetainPtr<StringImpl> StringImpl::create(const char* cstring, size_t length)
|
||||
{
|
||||
if (!cstring)
|
||||
return nullptr;
|
||||
|
||||
if (!*cstring)
|
||||
return theEmptyStringImpl();
|
||||
|
||||
char* buffer;
|
||||
auto newStringImpl = createUninitialized(length, buffer);
|
||||
memcpy(buffer, cstring, length * sizeof(char));
|
||||
|
||||
return newStringImpl;
|
||||
}
|
||||
|
||||
RetainPtr<StringImpl> StringImpl::create(const char* cstring)
|
||||
{
|
||||
if (!cstring)
|
||||
return nullptr;
|
||||
|
||||
return create(cstring, strlen(cstring));
|
||||
}
|
||||
|
||||
static inline bool isASCIILowercase(char c)
|
||||
{
|
||||
return c >= 'a' && c <= 'z';
|
||||
}
|
||||
|
||||
static inline bool isASCIIUppercase(char c)
|
||||
{
|
||||
return c >= 'A' && c <= 'Z';
|
||||
}
|
||||
|
||||
static inline char toASCIILowercase(char c)
|
||||
{
|
||||
if (isASCIIUppercase(c))
|
||||
return c | 0x20;
|
||||
return c;
|
||||
}
|
||||
|
||||
static inline char toASCIIUppercase(char c)
|
||||
{
|
||||
if (isASCIILowercase(c))
|
||||
return c & ~0x20;
|
||||
return c;
|
||||
}
|
||||
|
||||
RetainPtr<StringImpl> StringImpl::toLowercase() const
|
||||
{
|
||||
if (!m_length)
|
||||
return const_cast<StringImpl*>(this);
|
||||
|
||||
for (unsigned i = 0; i < m_length; ++i) {
|
||||
if (!isASCIILowercase(m_characters[i]))
|
||||
goto slowPath;
|
||||
}
|
||||
return const_cast<StringImpl*>(this);
|
||||
|
||||
slowPath:
|
||||
char* buffer;
|
||||
auto lowercased = createUninitialized(m_length, buffer);
|
||||
for (unsigned i = 0; i < m_length; ++i) {
|
||||
buffer[i] = toASCIILowercase(m_characters[i]);
|
||||
}
|
||||
|
||||
return lowercased;
|
||||
}
|
||||
|
||||
RetainPtr<StringImpl> StringImpl::toUppercase() const
|
||||
{
|
||||
if (!m_length)
|
||||
return const_cast<StringImpl*>(this);
|
||||
|
||||
for (unsigned i = 0; i < m_length; ++i) {
|
||||
if (!isASCIIUppercase(m_characters[i]))
|
||||
goto slowPath;
|
||||
}
|
||||
return const_cast<StringImpl*>(this);
|
||||
|
||||
slowPath:
|
||||
char* buffer;
|
||||
auto uppercased = createUninitialized(m_length, buffer);
|
||||
for (unsigned i = 0; i < m_length; ++i) {
|
||||
buffer[i] = toASCIIUppercase(m_characters[i]);
|
||||
}
|
||||
|
||||
return uppercased;
|
||||
}
|
||||
|
||||
void StringImpl::computeHash() const
|
||||
{
|
||||
if (!length()) {
|
||||
m_hash = 0;
|
||||
} else {
|
||||
unsigned hash = 0;
|
||||
for (unsigned i = 0; i < m_length; ++i) {
|
||||
hash += m_characters[i];
|
||||
hash += (hash << 10);
|
||||
hash ^= (hash >> 6);
|
||||
}
|
||||
hash += hash << 3;
|
||||
hash ^= hash >> 11;
|
||||
hash += hash << 15;
|
||||
m_hash = hash;
|
||||
}
|
||||
m_hasHash = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
50
AK/StringImpl.h
Normal file
50
AK/StringImpl.h
Normal file
|
@ -0,0 +1,50 @@
|
|||
#pragma once
|
||||
|
||||
#include "Retainable.h"
|
||||
#include "RetainPtr.h"
|
||||
|
||||
namespace AK {
|
||||
|
||||
class StringImpl : public Retainable<StringImpl> {
|
||||
public:
|
||||
static RetainPtr<StringImpl> createUninitialized(unsigned length, char*& buffer);
|
||||
static RetainPtr<StringImpl> create(const char* cstring);
|
||||
static RetainPtr<StringImpl> create(const char* cstring, size_t length);
|
||||
RetainPtr<StringImpl> toLowercase() const;
|
||||
RetainPtr<StringImpl> toUppercase() const;
|
||||
|
||||
static StringImpl& theEmptyStringImpl();
|
||||
|
||||
~StringImpl();
|
||||
|
||||
unsigned length() const { return m_length; }
|
||||
const char* characters() const { return m_characters; }
|
||||
char operator[](unsigned i) const { ASSERT(i < m_length); return m_characters[i]; }
|
||||
|
||||
unsigned hash() const
|
||||
{
|
||||
if (!m_hasHash)
|
||||
computeHash();
|
||||
return m_hash;
|
||||
}
|
||||
|
||||
private:
|
||||
enum ConstructTheEmptyStringImplTag { ConstructTheEmptyStringImpl };
|
||||
explicit StringImpl(ConstructTheEmptyStringImplTag) : m_characters("") { }
|
||||
|
||||
enum ConstructWithInlineBufferTag { ConstructWithInlineBuffer };
|
||||
explicit StringImpl(ConstructWithInlineBufferTag, unsigned length) : m_length(length), m_characters(m_inlineBuffer) { }
|
||||
|
||||
void computeHash() const;
|
||||
|
||||
unsigned m_length { 0 };
|
||||
bool m_ownsBuffer { true };
|
||||
mutable bool m_hasHash { false };
|
||||
const char* m_characters { nullptr };
|
||||
mutable unsigned m_hash { 0 };
|
||||
char m_inlineBuffer[0];
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
using AK::StringImpl;
|
33
AK/TemporaryFile.cpp
Normal file
33
AK/TemporaryFile.cpp
Normal file
|
@ -0,0 +1,33 @@
|
|||
#include "TemporaryFile.h"
|
||||
#include <fcntl.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
|
||||
namespace AK {
|
||||
|
||||
TemporaryFile::TemporaryFile()
|
||||
{
|
||||
char nameBuffer[] = "/tmp/AKTemporaryFile.XXXXXX";
|
||||
int fd = mkstemp(nameBuffer);
|
||||
if (fd != -1) {
|
||||
m_stream = fdopen(fd, "w+");
|
||||
m_fileName = nameBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
TemporaryFile::~TemporaryFile()
|
||||
{
|
||||
if (isValid()) {
|
||||
unlink(m_fileName.characters());
|
||||
fclose(m_stream);
|
||||
}
|
||||
}
|
||||
|
||||
void TemporaryFile::sync()
|
||||
{
|
||||
if (m_stream)
|
||||
fflush(m_stream);
|
||||
}
|
||||
|
||||
}
|
||||
|
26
AK/TemporaryFile.h
Normal file
26
AK/TemporaryFile.h
Normal file
|
@ -0,0 +1,26 @@
|
|||
#pragma once
|
||||
|
||||
#include "String.h"
|
||||
#include <stdio.h>
|
||||
|
||||
namespace AK {
|
||||
|
||||
class TemporaryFile {
|
||||
public:
|
||||
TemporaryFile();
|
||||
~TemporaryFile();
|
||||
|
||||
bool isValid() const { return m_stream; }
|
||||
FILE* stream() { return m_stream; }
|
||||
String fileName() const { return m_fileName; }
|
||||
void sync();
|
||||
|
||||
private:
|
||||
FILE* m_stream { nullptr };
|
||||
String m_fileName;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
using AK::TemporaryFile;
|
||||
|
25
AK/Traits.h
Normal file
25
AK/Traits.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdio>
|
||||
|
||||
namespace AK {
|
||||
|
||||
template<typename T>
|
||||
struct Traits
|
||||
{
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Traits<int> {
|
||||
static unsigned hash(int i) { return i; }
|
||||
static void dump(int i) { printf("%d", i); }
|
||||
};
|
||||
|
||||
template<>
|
||||
struct Traits<unsigned> {
|
||||
static unsigned hash(unsigned u) { return u; }
|
||||
static void dump(unsigned u) { printf("%u", u); }
|
||||
};
|
||||
|
||||
}
|
||||
|
17
AK/Types.h
Normal file
17
AK/Types.h
Normal file
|
@ -0,0 +1,17 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef uint8_t byte;
|
||||
typedef uint16_t word;
|
||||
typedef uint32_t dword;
|
||||
typedef uint64_t qword;
|
||||
|
||||
typedef int8_t signed_byte;
|
||||
typedef int16_t signed_word;
|
||||
typedef int32_t signed_dword;
|
||||
typedef int64_t signed_qword;
|
||||
|
||||
constexpr unsigned KB = 1024;
|
||||
constexpr unsigned MB = KB * KB;
|
||||
constexpr unsigned GB = KB * KB * KB;
|
169
AK/Vector.h
Normal file
169
AK/Vector.h
Normal file
|
@ -0,0 +1,169 @@
|
|||
#pragma once
|
||||
|
||||
#include "Assertions.h"
|
||||
#include "OwnPtr.h"
|
||||
#include <new>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <algorithm>
|
||||
|
||||
namespace AK {
|
||||
|
||||
template<typename T> class Vector;
|
||||
|
||||
template<typename T>
|
||||
class VectorImpl {
|
||||
public:
|
||||
~VectorImpl() { }
|
||||
static OwnPtr<VectorImpl> create(unsigned capacity)
|
||||
{
|
||||
size_t size = sizeof(VectorImpl) + sizeof(T) * capacity;
|
||||
void* slot = kmalloc(size);
|
||||
return OwnPtr<VectorImpl>(new (slot) VectorImpl(capacity));
|
||||
}
|
||||
|
||||
unsigned size() const { return m_size; }
|
||||
unsigned capacity() const { return m_capacity; }
|
||||
|
||||
T& at(unsigned i) { return *slot(i); }
|
||||
const T& at(unsigned i) const { return *slot(i); }
|
||||
|
||||
private:
|
||||
friend class Vector<T>;
|
||||
|
||||
VectorImpl(unsigned capacity) : m_capacity(capacity) { }
|
||||
|
||||
T* tail() { return reinterpret_cast<T*>(this + 1); }
|
||||
T* slot(unsigned i) { return &tail()[i]; }
|
||||
|
||||
const T* tail() const { return reinterpret_cast<const T*>(this + 1); }
|
||||
const T* slot(unsigned i) const { return &tail()[i]; }
|
||||
|
||||
unsigned m_size { 0 };
|
||||
unsigned m_capacity;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
class Vector {
|
||||
public:
|
||||
Vector() { }
|
||||
~Vector() { clear(); }
|
||||
|
||||
Vector(Vector&& other)
|
||||
: m_impl(std::move(other.m_impl))
|
||||
{
|
||||
}
|
||||
|
||||
Vector& operator=(Vector&& other)
|
||||
{
|
||||
if (this != &other)
|
||||
m_impl = std::move(other.m_impl);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
for (unsigned i = 0; i < size(); ++i) {
|
||||
at(i).~T();
|
||||
}
|
||||
m_impl = nullptr;
|
||||
}
|
||||
|
||||
bool isEmpty() const { return size() == 0; }
|
||||
unsigned size() const { return m_impl ? m_impl->size() : 0; }
|
||||
unsigned capacity() const { return m_impl ? m_impl->capacity() : 0; }
|
||||
|
||||
const T& at(unsigned i) const { return m_impl->at(i); }
|
||||
T& at(unsigned i) { return m_impl->at(i); }
|
||||
|
||||
const T& operator[](unsigned i) const { return at(i); }
|
||||
T& operator[](unsigned i) { return at(i); }
|
||||
|
||||
const T& first() const { return at(0); }
|
||||
T& first() { return at(0); }
|
||||
|
||||
const T& last() const { return at(size() - 1); }
|
||||
T& last() { return at(size() - 1); }
|
||||
|
||||
T takeLast()
|
||||
{
|
||||
ASSERT(!isEmpty());
|
||||
T value = std::move(last());
|
||||
last().~T();
|
||||
--m_impl->m_size;
|
||||
return value;
|
||||
}
|
||||
|
||||
void append(T&& value)
|
||||
{
|
||||
ensureCapacity(size() + 1);
|
||||
new (m_impl->slot(m_impl->m_size)) T(std::move(value));
|
||||
++m_impl->m_size;
|
||||
}
|
||||
|
||||
void append(const T& value)
|
||||
{
|
||||
ensureCapacity(size() + 1);
|
||||
new (m_impl->slot(m_impl->m_size)) T(value);
|
||||
++m_impl->m_size;
|
||||
}
|
||||
|
||||
void ensureCapacity(unsigned neededCapacity)
|
||||
{
|
||||
if (capacity() >= neededCapacity)
|
||||
return;
|
||||
size_t newCapacity = paddedCapacity(neededCapacity);
|
||||
auto newImpl = VectorImpl<T>::create(newCapacity);
|
||||
if (m_impl) {
|
||||
newImpl->m_size = m_impl->m_size;
|
||||
for (unsigned i = 0; i < size(); ++i) {
|
||||
new (newImpl->slot(i)) T(std::move(m_impl->at(i)));
|
||||
m_impl->at(i).~T();
|
||||
}
|
||||
}
|
||||
m_impl = std::move(newImpl);
|
||||
}
|
||||
|
||||
class Iterator {
|
||||
public:
|
||||
bool operator!=(const Iterator& other) { return m_index != other.m_index; }
|
||||
Iterator& operator++() { ++m_index; return *this; }
|
||||
T& operator*() { return m_vector[m_index]; }
|
||||
private:
|
||||
friend class Vector;
|
||||
Iterator(Vector& vector, unsigned index) : m_vector(vector), m_index(index) { }
|
||||
Vector& m_vector;
|
||||
unsigned m_index { 0 };
|
||||
};
|
||||
|
||||
Iterator begin() { return Iterator(*this, 0); }
|
||||
Iterator end() { return Iterator(*this, size()); }
|
||||
|
||||
class ConstIterator {
|
||||
public:
|
||||
bool operator!=(const ConstIterator& other) { return m_index != other.m_index; }
|
||||
ConstIterator& operator++() { ++m_index; return *this; }
|
||||
const T& operator*() const { return m_vector[m_index]; }
|
||||
private:
|
||||
friend class Vector;
|
||||
ConstIterator(const Vector& vector, const unsigned index) : m_vector(vector), m_index(index) { }
|
||||
const Vector& m_vector;
|
||||
unsigned m_index { 0 };
|
||||
};
|
||||
|
||||
ConstIterator begin() const { return Iterator(*this, 0); }
|
||||
ConstIterator end() const { return Iterator(*this, size()); }
|
||||
|
||||
private:
|
||||
static unsigned paddedCapacity(unsigned capacity)
|
||||
{
|
||||
return std::max(4u, capacity + (capacity / 4) + 4);
|
||||
}
|
||||
|
||||
OwnPtr<VectorImpl<T>> m_impl;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
using AK::Vector;
|
||||
|
66
AK/kmalloc.cpp
Normal file
66
AK/kmalloc.cpp
Normal file
|
@ -0,0 +1,66 @@
|
|||
#include <cstdio>
|
||||
#include "SimpleMalloc.h"
|
||||
#include <new>
|
||||
|
||||
extern "C" {
|
||||
|
||||
void* kcalloc(dword nmemb, dword size)
|
||||
{
|
||||
if (!nmemb || !size)
|
||||
return nullptr;
|
||||
return SimpleMalloc::allocateZeroed(nmemb * size);
|
||||
}
|
||||
|
||||
void* kmalloc(dword size)
|
||||
{
|
||||
if (!size)
|
||||
return nullptr;
|
||||
return SimpleMalloc::allocate(size);
|
||||
}
|
||||
|
||||
void kfree(void* ptr)
|
||||
{
|
||||
if (!ptr)
|
||||
return;
|
||||
SimpleMalloc::free((byte*)ptr);
|
||||
}
|
||||
|
||||
void* krealloc(void* ptr, dword size)
|
||||
{
|
||||
if (!ptr)
|
||||
return ptr;
|
||||
return SimpleMalloc::reallocate((byte*)ptr, size);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void* operator new(std::size_t size)
|
||||
{
|
||||
return kmalloc(size);
|
||||
}
|
||||
|
||||
void* operator new[](std::size_t size)
|
||||
{
|
||||
return kmalloc(size);
|
||||
}
|
||||
|
||||
void operator delete(void* ptr)
|
||||
{
|
||||
return kfree(ptr);
|
||||
}
|
||||
|
||||
void operator delete[](void* ptr)
|
||||
{
|
||||
return kfree(ptr);
|
||||
}
|
||||
|
||||
void operator delete(void* ptr, size_t)
|
||||
{
|
||||
return kfree(ptr);
|
||||
}
|
||||
|
||||
void operator delete[](void* ptr, size_t)
|
||||
{
|
||||
return kfree(ptr);
|
||||
}
|
||||
|
13
AK/kmalloc.h
Normal file
13
AK/kmalloc.h
Normal file
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
#include "Types.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
void* kcalloc(dword nmemb, dword size);
|
||||
void* kmalloc(dword size);
|
||||
void kfree(void* ptr);
|
||||
void* krealloc(void* ptr, dword size);
|
||||
|
||||
}
|
||||
|
131
AK/test.cpp
Normal file
131
AK/test.cpp
Normal file
|
@ -0,0 +1,131 @@
|
|||
#include "String.h"
|
||||
//#include "StringBuilder.h"
|
||||
#include "Vector.h"
|
||||
#include <stdio.h>
|
||||
#include "HashTable.h"
|
||||
#include "SinglyLinkedList.h"
|
||||
#include "HashMap.h"
|
||||
#include "TemporaryFile.h"
|
||||
#include "Buffer.h"
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
String empty = "";
|
||||
|
||||
char* buffer;
|
||||
auto test = StringImpl::createUninitialized(3, buffer);
|
||||
auto hello = String("hello");
|
||||
auto Hello = String("Hello");
|
||||
|
||||
printf("hello: '%s'\n", hello.characters());
|
||||
printf("Hello: '%s'\n", Hello.characters());
|
||||
printf("'Hello'.lower(): '%s'\n", Hello.toLowercase().characters());
|
||||
printf("'hello'.upper(): '%s'\n", Hello.toUppercase().characters());
|
||||
|
||||
Vector<String> strings;
|
||||
strings.append("a");
|
||||
strings.append("b");
|
||||
strings.append("c");
|
||||
strings.append("d");
|
||||
strings.append("e");
|
||||
strings.append("f");
|
||||
strings.append("g");
|
||||
|
||||
auto g = strings.takeLast();
|
||||
|
||||
for (unsigned i = 0; i < strings.size(); ++i) {
|
||||
printf("[%u]: '%s'\n", i, strings[i].characters());
|
||||
}
|
||||
|
||||
printf("snodde sista: '%s'\n", g.characters());
|
||||
printf("kvar:\n");
|
||||
|
||||
for (auto& s : strings) {
|
||||
printf(" > %s\n", s.characters());
|
||||
}
|
||||
|
||||
#if 0
|
||||
StringBuilder builder;
|
||||
builder.append("HEJ");
|
||||
builder.append(' ');
|
||||
builder.append("KAJ");
|
||||
|
||||
printf("byggd: '%s'\n", builder.build().characters());
|
||||
#endif
|
||||
|
||||
#if 1
|
||||
HashTable<int> ints;
|
||||
ints.set(10);
|
||||
ints.set(20);
|
||||
ints.set(30);
|
||||
ints.dump();
|
||||
|
||||
ASSERT(ints.size() == 3);
|
||||
ASSERT(ints.contains(10));
|
||||
ASSERT(ints.contains(20));
|
||||
ASSERT(ints.contains(30));
|
||||
ASSERT(!ints.contains(0));
|
||||
ASSERT(!ints.contains(40));
|
||||
|
||||
HashTable<String> sss;
|
||||
sss.set("foo");
|
||||
sss.set("bar");
|
||||
sss.set("baz");
|
||||
sss.set("bee");
|
||||
ASSERT(sss.size() == 4);
|
||||
sss.dump();
|
||||
ASSERT(sss.contains("foo"));
|
||||
ASSERT(sss.contains("bar"));
|
||||
ASSERT(sss.contains("baz"));
|
||||
ASSERT(sss.contains("bee"));
|
||||
ASSERT(!sss.contains("boo"));
|
||||
ASSERT(!sss.contains(""));
|
||||
ASSERT(!sss.contains(String()));
|
||||
|
||||
printf(">>> iterate Hash:\n");
|
||||
for (auto& s : sss) {
|
||||
printf("+ %s\n", s.characters());
|
||||
}
|
||||
printf("<<<\n");
|
||||
#endif
|
||||
|
||||
SinglyLinkedList<int> list;
|
||||
list.append(3);
|
||||
list.append(6);
|
||||
list.append(9);
|
||||
ASSERT(!list.isEmpty());
|
||||
ASSERT(list.first() == 3);
|
||||
ASSERT(list.last() == 9);
|
||||
|
||||
for (int i : list) {
|
||||
printf("Iterated to %d\n", i);
|
||||
}
|
||||
|
||||
HashMap<String, int> map;
|
||||
map.set("lol", 100);
|
||||
map.set("kek", 500);
|
||||
map.set("zoo", 300);
|
||||
ASSERT(map.size() == 3);
|
||||
map.dump();
|
||||
for (auto& it : map) {
|
||||
printf("[%s] := %d\n", it.key.characters(), it.value);
|
||||
}
|
||||
|
||||
auto found = map.find("kek");
|
||||
if (found != map.end()) {
|
||||
printf("found 'kek', key: %s, value: %d\n", (*found).key.characters(), (*found).value);
|
||||
} else {
|
||||
printf("not found\n");
|
||||
}
|
||||
|
||||
auto charbuf = Buffer<char>::createUninitialized(1024);
|
||||
printf("charbuf.size() = %u\n", charbuf->size());
|
||||
|
||||
{
|
||||
Vector<String> problem;
|
||||
for (int i = 0; i < 256; ++i)
|
||||
problem.append("test");
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue