1
Fork 0
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:
Andreas Kling 2018-10-10 11:53:07 +02:00
commit 5a30055157
67 changed files with 8836 additions and 0 deletions

1
AK/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
akit-test

15
AK/Assertions.h Normal file
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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
View 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;
}