Cleanup
This commit is contained in:
@@ -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))
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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);
|
||||
};
|
||||
@@ -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
@@ -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
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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";
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user