Serene Runtime 1.0.0-dev
C runtime for the Serene programming language
Loading...
Searching...
No Matches
source_manager.h
Go to the documentation of this file.
1/* -*- C -*-
2 * Serene programming language
3 * Copyright (C) 2019-2026 Sameer Rahmani <lxsameer@lxsameer.com>
4 *
5 * This library is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this library. If not, see <https://www.gnu.org/licenses/>.
17 */
18
19#pragma once
20
21/** @file
22Source manager is what that read the source files and own the buffer that contains the data.
23Notes:
24- We use manual memory management for buffers since the size of buffers are not known in advance and
25they might be bigger than block sizes, also the lifecycle of buffers are known and we can avoidarena
26allocation completely.
27
28- Each buffer is assigned a stable integer ID on first load. That ID is the canonical handle for all
29later references and never changes for a given file path.
30
31- A hashmap from file path to ID prevents duplicate reads. Passing an already loaded path to
32`srn_sm_read_buffer_file` returns the existing ID without reopening the file.
33- When `reread` is true, the freshly read buffer is prepended to the existing buffer's chain rather
34than replacing it. The slot ID stays the same. The previous buffer remains reachable via
35`buffer->next` this way expressions that are previously loaded will continue to have valid
36locations.
37
38- An empty file produces a valid buffer slot with `data == nullptr` and `len == 0`. Callers must
39treat a null `data` field as a valid zero length source rather than an error.
40
41- File content is read through `srn_fiber_read`, so the call suspends the current fiber instead of
42blocking the OS thread.
43
44- A single write lock serialises all insertions and updates. A new file is read outside the lock
45and the map is checked again under it before the slot is inserted, so two fibers loading the same
46path end up sharing one slot. The path lookup snapshots the map under the lock; `srn_sm_get_buffer`
47is unsynchronised, callers must not call it concurrently with a write.
48
49- The source manager itself is allocated in the immortal pool and lives for the entire lifetime of
50the context.
51 */
52
53#include <stddef.h>
54
59#include "serene/utils.h"
60
61#define SRN_SM_NO_ID UINTPTR_MAX
62
63#define SM_TRACEPOINT(...) SRN_TRACEPOINT_WITH_GROUP(source_manager __VA_OPT__(, ) __VA_ARGS__)
64
65typedef struct srn_context_t srn_context_t;
66typedef size_t srn_sm_buffer_id_t;
67
72
73typedef struct srn_sm_buffer_t {
74 const char *filename;
75 /// nullptr when the source file was empty (no mapping exists)
76 unsigned char *data;
77 size_t len;
80
85
94
95/**
96 * Initialize the source manager, as an immortal data structure. The buffers
97 * themselves will NOT be managed by the the memory manager.
98 */
99[[gnu::nonnull(1)]]
101
102/**
103 * Shutdown the source manager freeing all the buffers. After this call all the
104 * pointers into the buffers will be invalid.
105 */
106[[gnu::nonnull(1)]]
108
109/**
110 * Return the buffer pointer of the given `id`, `nullptr` if the id does not exists.
111 */
112[[gnu::nonnull(1)]]
114
115/**
116 * Read and buffer the given `filepath` into the source manager and return the buffer id.
117 * If the file already exists, it will just return the buffer id, unless the `reread` is true,
118 * which will reread the file and populate the buffer. It will NOT overwrite the old buffer.
119 */
120[[gnu::nonnull(1, 2)]]
121srn_sm_maybe_id_t srn_sm_read_buffer_file(srn_sm_t *sm, const char *filepath, bool reread);
122
123/**
124 * Read and buffer the given `filepath` into the source manager and return a `srn_sm_maybe_buffer_t`
125 * which either fails or has a pointer to the buffer containing the content of the file. A `nullptr`
126 * for the buffer means an empty file.
127 */
128[[gnu::nonnull(1, 2)]]
129srn_sm_maybe_buffer_t srn_sm_buffer_file(srn_sm_t *sm, const char *filepath, bool reread);
130
131static inline const unsigned char *srn_sm_buffer_data(srn_sm_buffer_t *buf) { return buf->data; }
132static inline size_t srn_sm_buffer_len(srn_sm_buffer_t *buf) { return buf->len; }
A bit-partitioned trie with a tail buffer, used as a growable indexed sequence in the runtime.
This is an implementation of Compressed Hash-Array Mapped Prefix-tree, which is a bit-partitioned,...
A fiber blocking mutex.
static size_t srn_sm_buffer_len(srn_sm_buffer_t *buf)
srn_sm_maybe_buffer_t srn_sm_buffer_file(srn_sm_t *sm, const char *filepath, bool reread)
Read and buffer the given filepath into the source manager and return a srn_sm_maybe_buffer_t which e...
void srn_sm_shutdown(srn_sm_t *sm)
Shutdown the source manager freeing all the buffers.
srn_sm_t * srn_sm_init(srn_context_t *ctx)
Initialize the source manager, as an immortal data structure.
srn_sm_buffer_t * srn_sm_get_buffer(srn_sm_t *sm, srn_sm_buffer_id_t id)
Return the buffer pointer of the given id, nullptr if the id does not exists.
static const unsigned char * srn_sm_buffer_data(srn_sm_buffer_t *buf)
srn_sm_maybe_id_t srn_sm_read_buffer_file(srn_sm_t *sm, const char *filepath, bool reread)
Read and buffer the given filepath into the source manager and return the buffer id.
size_t srn_sm_buffer_id_t
srn_sm_t * sm
unsigned char * data
nullptr when the source file was empty (no mapping exists)
const char * filename
struct srn_sm_buffer_t * next
srn_sm_buffer_t * buffer
srn_sm_buffer_id_t id
srn_fiber_mutex_t write_lock
srn_context_t * ctx
size_t buffer_counts
array_list_t buffers
hmap_t file_to_id_map
srn_thread_t, srn_mutex_t, and srn_cond_t model the thread-level operations the runtime needs,...