This commit is contained in:
2026-07-28 02:57:13 +01:00
parent 737c6c1d20
commit 57dda2589e
14 changed files with 369 additions and 84 deletions
+1 -1
View File
@@ -44,7 +44,7 @@ UNICODE_OBJ := $(patsubst libs/unicode_width/%.c,$(OBJ_DIR)/unicode_width/%.o,$(
LIBS := $(PCRE_LIBS) $(LIBGRAPHEME_LIBS) $(MRUBY_LIBS)
SRC := $(wildcard $(SRC_DIR)/**/*.cc) $(wildcard $(SRC_DIR)/*.cc)
SRC := $(shell find $(SRC_DIR) -type f -name '*.cc')
OBJ_DEBUG := $(patsubst $(SRC_DIR)/%.cc,$(OBJ_DIR)/debug/%.o,$(SRC))
OBJ_RELEASE := $(patsubst $(SRC_DIR)/%.cc,$(OBJ_DIR)/release/%.o,$(SRC))
+2
View File
@@ -58,6 +58,7 @@
gnumake
xxd
bash
findutils
];
buildInputs = with pkgs; [
@@ -100,6 +101,7 @@
hostPkgs.xxd
hostPkgs.gdb
hostPkgs.binutils
hostPkgs.findutils
pkgs.libgrapheme
pkgs.pcre2
+40
View File
@@ -0,0 +1,40 @@
#pragma once
#include "pch.h"
inline int read_file(const char *path, char **text, uint32_t *len) {
FILE *f = fopen(path, "rb");
if (!f)
return 0;
fseek(f, 0, SEEK_END);
long size = ftell(f);
fseek(f, 0, SEEK_SET);
if (size < 0 || size > UINT32_MAX) {
fclose(f);
return 0;
}
*len = (uint32_t)size;
*text = (char *)malloc(*len + 1);
if (!*text) {
fclose(f);
return 0;
}
size_t read = fread(*text, 1, *len, f);
fclose(f);
if (read != *len) {
free(*text);
*text = NULL;
*len = 0;
return 0;
}
(*text)[*len] = '\0'; // handy if treating it as a C string
return 1;
}
+1
View File
@@ -30,6 +30,7 @@ extern "C" {
#include <fstream>
#include <functional>
#include <immintrin.h>
#include <iostream>
#include <limits.h>
#include <map>
#include <mutex>
@@ -1,9 +1,12 @@
#pragma once
#include "buffer.h"
#include "pch.h"
#include <cstdint>
struct AppendBuffer {
struct AppendBuffer : Buffer {
static constexpr uint32_t CHUNK_SIZE = 1 << 16;
using TChunk = char[CHUNK_SIZE];
std::vector<TChunk *> buf;
TChunk *t_current;
@@ -22,9 +25,14 @@ struct AppendBuffer {
inline void key(char c);
void append(const char *text, uint32_t length);
const char *read(uint32_t pos, uint32_t *out_len);
uint32_t count_lines(uint32_t pos, uint32_t length);
private:
inline void new_text_chunk();
inline void new_line_chunk();
inline uint32_t find_newline(uint32_t target, uint32_t low, uint32_t high);
inline void _append(const char *text, uint32_t length);
};
+10
View File
@@ -0,0 +1,10 @@
#pragma once
#include "pch.h"
struct Buffer {
virtual const char *read(uint32_t pos, uint32_t *out_len) = 0;
virtual uint32_t count_lines(uint32_t pos, uint32_t length) = 0;
virtual ~Buffer() = default;
};
@@ -1,8 +1,9 @@
#pragma once
#include "buffer.h"
#include "pch.h"
struct OriginalBuffer {
struct OriginalBuffer : Buffer {
char *buf;
uint32_t length;
std::vector<uint32_t> newlines;
@@ -23,4 +24,7 @@ struct OriginalBuffer {
~OriginalBuffer() {
free(buf);
}
const char *read(uint32_t pos, uint32_t *out_len);
uint32_t count_lines(uint32_t pos, uint32_t length);
};
+9 -7
View File
@@ -1,5 +1,6 @@
#pragma once
#include "buffer/buffer.h"
#include "pch.h"
struct Shard {
@@ -14,7 +15,7 @@ struct Shard {
std::atomic_uint32_t refs;
Shard(ShardKind kind, uint32_t length, uint32_t lines)
: kind(kind), length(length), lines(lines) {};
: kind(kind), length(length), lines(lines), refs(0) {};
};
struct ShardPtr {
@@ -53,17 +54,18 @@ struct Branch : Shard {
Branch(Shard *l, Shard *r)
: Shard(ShardKind::Branch, l->length + r->length, l->lines + r->lines),
left(ShardPtr(l)), right(ShardPtr(r)) {};
left(l), right(r) {};
};
struct Petal : Shard {
enum struct Kind {
Original,
Append
} source;
Buffer *source;
uint32_t pos;
Petal(uint32_t length, uint32_t lines, Kind source, uint32_t pos)
Petal(uint32_t length, uint32_t lines, Buffer *source, uint32_t pos)
: Shard(ShardKind::Petal, length, lines), source(source), pos(pos) {};
};
std::pair<ShardPtr, ShardPtr> split(Shard *n, uint32_t offset);
void print_shard(const Shard *shard, int depth = 0);
+3 -3
View File
@@ -1,7 +1,7 @@
#pragma once
#include "append_buffer.h"
#include "original_buffer.h"
#include "buffer/append.h"
#include "buffer/original.h"
#include "pch.h"
#include "shard.h"
@@ -21,7 +21,7 @@ struct Vase {
root = new Petal(
length,
original.newlines.size(),
Petal::Kind::Original,
&original,
0
);
}
+14
View File
@@ -1,5 +1,19 @@
#include "io/file.h"
#include "pch.h"
#include "vase/shard.h"
#include "vase/vase.h"
int main() {
char *text;
uint32_t len;
int s = read_file("./flake.nix", &text, &len);
if (!s)
return 1;
Vase vase = Vase(text, len);
print_shard(vase.root.ptr);
return 0;
}
-71
View File
@@ -1,71 +0,0 @@
#include "vase/append_buffer.h"
AppendBuffer::AppendBuffer() {
new_text_chunk();
new_line_chunk();
}
AppendBuffer::~AppendBuffer() {
for (auto p : buf)
free(p);
for (auto p : newlines)
free(p);
}
inline void AppendBuffer::key(char c) {
if (t_offset == CHUNK_SIZE)
new_text_chunk();
(*t_current)[t_offset++] = c;
if (c == '\n') {
if (l_offset == CHUNK_SIZE)
new_line_chunk();
(*l_current)[l_offset++] = current_offset;
}
++current_offset;
}
void AppendBuffer::append(const char *text, uint32_t length) {
while (length) {
uint32_t space = CHUNK_SIZE - t_offset;
if (space == 0) {
new_text_chunk();
space = CHUNK_SIZE;
}
uint32_t copy = length < space ? length : space;
_append(text, copy);
text += copy;
length -= copy;
}
}
inline void AppendBuffer::new_text_chunk() {
t_current = (TChunk *)malloc(sizeof(TChunk));
buf.push_back(t_current);
t_offset = 0;
}
inline void AppendBuffer::new_line_chunk() {
l_current = (LChunk *)malloc(sizeof(LChunk));
newlines.push_back(l_current);
l_offset = 0;
}
inline void AppendBuffer::_append(const char *text, uint32_t length) {
memcpy((*t_current) + t_offset, text, length);
const char *p = text;
const char *end = text + length;
while (p < end) {
p = (const char *)memchr(p, '\n', end - p);
if (!p)
break;
if (l_offset == CHUNK_SIZE)
new_line_chunk();
(*l_current)[l_offset++] = current_offset + uint32_t(p - text);
p++;
}
t_offset += length;
current_offset += length;
}
+148
View File
@@ -0,0 +1,148 @@
#include "vase/buffer/append.h"
#include <cstdint>
AppendBuffer::AppendBuffer() {
new_text_chunk();
new_line_chunk();
}
AppendBuffer::~AppendBuffer() {
for (auto p : buf)
free(p);
for (auto p : newlines)
free(p);
}
inline void AppendBuffer::key(char c) {
if (t_offset == CHUNK_SIZE)
new_text_chunk();
(*t_current)[t_offset++] = c;
if (c == '\n') {
if (l_offset == CHUNK_SIZE)
new_line_chunk();
(*l_current)[l_offset++] = current_offset;
}
++current_offset;
}
void AppendBuffer::append(const char *text, uint32_t length) {
while (length) {
uint32_t space = CHUNK_SIZE - t_offset;
if (space == 0) {
new_text_chunk();
space = CHUNK_SIZE;
}
uint32_t copy = length < space ? length : space;
_append(text, copy);
text += copy;
length -= copy;
}
}
const char *AppendBuffer::read(uint32_t pos, uint32_t *out_len) {
if (pos >= current_offset)
return nullptr;
uint32_t local_offset = pos % CHUNK_SIZE;
if (out_len) {
uint32_t remaining = current_offset - pos;
uint32_t until_chunk_end = CHUNK_SIZE - local_offset;
*out_len = std::min(remaining, until_chunk_end);
}
return &(*buf[pos / CHUNK_SIZE])[local_offset];
}
uint32_t AppendBuffer::find_newline(uint32_t target, uint32_t low, uint32_t high) {
if (low >= high)
return low;
uint32_t first_chunk = low / CHUNK_SIZE;
uint32_t last_chunk = (high - 1) / CHUNK_SIZE;
uint32_t left = first_chunk;
uint32_t right = last_chunk;
while (left < right) {
uint32_t mid = left + (right - left) / 2;
uint32_t first_value = (*newlines[mid])[0];
if (first_value < target)
left = mid + 1;
else
right = mid;
}
uint32_t chunk = left;
if (chunk > first_chunk) {
LChunk &prev = *newlines[chunk - 1];
uint32_t prev_size =
(chunk - 1 == newlines.size() - 1) ? l_offset : CHUNK_SIZE;
if (prev[prev_size - 1] >= target)
chunk--;
}
LChunk &c = *newlines[chunk];
uint32_t chunk_size =
(chunk == newlines.size() - 1) ? l_offset : CHUNK_SIZE;
uint32_t l = 0;
uint32_t r = chunk_size;
while (l < r) {
uint32_t m = l + (r - l) / 2;
if (c[m] < target)
l = m + 1;
else
r = m;
}
return chunk * CHUNK_SIZE + l;
}
uint32_t AppendBuffer::count_lines(uint32_t pos, uint32_t length) {
if (newlines.empty())
return 0;
uint32_t total_newlines = CHUNK_SIZE * (newlines.size() - 1) + l_offset;
uint32_t pos_index = find_newline(pos, 0, total_newlines);
uint32_t end_index = find_newline(pos + length, pos_index, total_newlines);
return end_index - pos_index;
}
inline void AppendBuffer::new_text_chunk() {
t_current = (TChunk *)malloc(sizeof(TChunk));
buf.push_back(t_current);
t_offset = 0;
}
inline void AppendBuffer::new_line_chunk() {
l_current = (LChunk *)malloc(sizeof(LChunk));
newlines.push_back(l_current);
l_offset = 0;
}
inline void AppendBuffer::_append(const char *text, uint32_t length) {
memcpy((*t_current) + t_offset, text, length);
const char *p = text;
const char *end = text + length;
while (p < end) {
p = (const char *)memchr(p, '\n', end - p);
if (!p)
break;
if (l_offset == CHUNK_SIZE)
new_line_chunk();
(*l_current)[l_offset++] = current_offset + uint32_t(p - text);
p++;
}
t_offset += length;
current_offset += length;
}
+24
View File
@@ -0,0 +1,24 @@
#include "vase/buffer/original.h"
const char *OriginalBuffer::read(uint32_t pos, uint32_t *out_len) {
if (pos >= length)
return nullptr;
*out_len = length - pos;
return buf + pos;
}
uint32_t OriginalBuffer::count_lines(uint32_t pos, uint32_t length) {
auto start = std::lower_bound(
newlines.begin(),
newlines.end(),
pos
);
auto end = std::lower_bound(
start,
newlines.end(),
pos + length
);
return (uint32_t)(end - start);
}
+103
View File
@@ -0,0 +1,103 @@
#include "vase/shard.h"
std::pair<ShardPtr, ShardPtr> split(Shard *n, uint32_t offset) {
if (!n)
return {nullptr, nullptr};
if (offset == 0)
return {nullptr, ShardPtr(n)};
if (offset == n->length)
return {ShardPtr(n), nullptr};
if (n->kind == Shard::ShardKind::Branch) {
Branch *b = static_cast<Branch *>(n);
if (offset < b->left.ptr->length) {
auto [a, b2] = split(b->left.ptr, offset);
return {
a,
ShardPtr(new Branch(
b2.ptr,
b->right.ptr
))
};
} else {
auto [a, b2] = split(
b->right.ptr,
offset - b->left.ptr->length
);
return {
ShardPtr(new Branch(
b->left.ptr,
a.ptr
)),
b2
};
}
}
Petal *p = static_cast<Petal *>(n);
auto left = new Petal(
offset,
p->source->count_lines(0, offset),
p->source,
p->pos
);
auto right = new Petal(
p->length - offset,
p->source->count_lines(offset, p->length),
p->source,
p->pos + offset
);
return {
ShardPtr(left),
ShardPtr(right)
};
}
void print_shard(const Shard *shard, int depth) {
if (!shard) {
std::cout << std::string(depth * 2, ' ') << "<null>\n";
return;
}
std::string indent(depth * 2, ' ');
std::cout << indent;
if (shard->kind == Shard::ShardKind::Branch) {
auto *branch = static_cast<const Branch *>(shard);
std::cout
<< "Branch"
<< " @" << shard
<< " len=" << shard->length
<< " lines=" << shard->lines
<< " refs=" << shard->refs.load()
<< "\n";
std::cout << indent << "├─ left:\n";
print_shard(branch->left.ptr, depth + 2);
std::cout << indent << "└─ right:\n";
print_shard(branch->right.ptr, depth + 2);
} else {
auto *petal = static_cast<const Petal *>(shard);
std::cout
<< "Petal"
<< " @" << shard
<< " len=" << shard->length
<< " lines=" << shard->lines
<< " refs=" << shard->refs.load()
<< " source=@" << petal->source
<< " pos=" << petal->pos
<< "\n";
}
}