ktrs_parser/builder/
pool.rs1use std::cell::RefCell;
6
7use ktrs_lexer::Token;
8use ktrs_syntax::SyntaxKind;
9
10use super::production::{MarkerData, Production};
11use super::psi_builder::PsiBuilder;
12
13const MAX_POOLED: usize = 16;
15const MAX_POOLED_LEXEMES: usize = 1 << 18;
17
18thread_local! {
19 static POOL: RefCell<Vec<Buffers>> = const { RefCell::new(Vec::new()) };
20}
21
22#[derive(Default)]
23struct Buffers {
24 text: String,
25 lex_starts: Vec<u32>,
26 lex_types: Vec<SyntaxKind>,
27 orig_types: Vec<SyntaxKind>,
28 markers: Vec<MarkerData>,
29 list: Vec<i32>,
30 skipped_errors: Vec<bool>,
31}
32
33impl Buffers {
34 fn take() -> Buffers {
35 POOL.with(|pool| pool.borrow_mut().pop()).unwrap_or_default()
36 }
37
38 fn give_back(mut self) {
39 if self.lex_types.capacity() > MAX_POOLED_LEXEMES || self.markers.capacity() > 4 * MAX_POOLED_LEXEMES {
40 return;
41 }
42 self.text.clear();
43 self.lex_starts.clear();
44 self.lex_types.clear();
45 self.orig_types.clear();
46 self.markers.clear();
47 self.list.clear();
48 self.skipped_errors.clear();
49 POOL.with(|pool| {
50 let mut pool = pool.borrow_mut();
51 if pool.len() < MAX_POOLED {
52 pool.push(self);
53 }
54 });
55 }
56}
57
58impl PsiBuilder {
59 pub fn new(text: &str, tokens: &[Token]) -> PsiBuilder {
61 PsiBuilder::from_tokens(text, tokens.iter().copied())
62 }
63
64 pub(crate) fn lex_kotlin(text: &str) -> PsiBuilder {
66 PsiBuilder::from_tokens(text, ktrs_lexer::tokens_of(text))
67 }
68
69 fn from_tokens(text: &str, tokens: impl Iterator<Item = Token>) -> PsiBuilder {
70 let mut buffers = Buffers::take();
71 let mut offset = 0u32;
72 for token in tokens {
73 buffers.lex_starts.push(offset);
74 buffers.lex_types.push(token.kind);
75 offset += token.len;
76 }
77 buffers.lex_starts.push(offset);
78 PsiBuilder::from_buffers(text, buffers)
79 }
80
81 pub(crate) fn from_lexemes(text: &str, starts: &[u32], kinds: &[SyntaxKind]) -> PsiBuilder {
84 let mut buffers = Buffers::take();
85 let base = starts[0];
86 buffers.lex_starts.extend(starts.iter().map(|s| s - base));
87 buffers.lex_types.extend_from_slice(kinds);
88 PsiBuilder::from_buffers(text, buffers)
89 }
90
91 fn from_buffers(text: &str, buffers: Buffers) -> PsiBuilder {
92 let Buffers { text: mut own_text, lex_starts, lex_types, mut orig_types, markers, list, skipped_errors } =
93 buffers;
94 assert_eq!(lex_starts.last().copied(), Some(text.len() as u32), "token lengths must sum to the text length");
95 own_text.push_str(text);
96 orig_types.extend_from_slice(&lex_types);
97 PsiBuilder {
98 text: own_text,
99 lex_starts,
100 lex_types,
101 orig_types,
102 current_lexeme: 0,
103 token_type_checked: false,
104 production: Production::from_vecs(markers, list),
105 skipped_errors,
106 }
107 }
108}
109
110impl Drop for PsiBuilder {
111 fn drop(&mut self) {
112 let (markers, list) = self.production.take_vecs();
113 Buffers {
114 text: std::mem::take(&mut self.text),
115 lex_starts: std::mem::take(&mut self.lex_starts),
116 lex_types: std::mem::take(&mut self.lex_types),
117 orig_types: std::mem::take(&mut self.orig_types),
118 markers,
119 list,
120 skipped_errors: std::mem::take(&mut self.skipped_errors),
121 }
122 .give_back();
123 }
124}