99#include "lineops.h"
1010#include "charsets.h"
1111#include <structmember.h>
12+ #include "ringbuf.h"
1213
1314extern PyTypeObject Line_Type ;
1415#define SEGMENT_SIZE 2048
@@ -61,42 +62,37 @@ alloc_pagerhist(size_t pagerhist_sz) {
6162 if (!pagerhist_sz ) return NULL ;
6263 ph = PyMem_Calloc (1 , sizeof (PagerHistoryBuf ));
6364 if (!ph ) return NULL ;
64- ph -> max_sz = pagerhist_sz ;
65- ph -> buffer_size = MIN ( 1024u * 1024u , ph -> max_sz );
66- ph -> buffer = PyMem_Malloc (ph -> buffer_size );
67- if (! ph -> buffer ) { PyMem_Free ( ph ); return NULL ; }
65+ size_t sz = MIN ( 1024u * 1024u , pagerhist_sz ) ;
66+ ph -> ringbuf = ringbuf_new ( sz );
67+ if (! ph -> ringbuf ) { PyMem_Free (ph ); return NULL ; }
68+ ph -> maximum_size = pagerhist_sz ;
6869 return ph ;
6970}
7071
7172static inline void
7273free_pagerhist (HistoryBuf * self ) {
73- if (self -> pagerhist ) PyMem_Free ( self -> pagerhist -> buffer );
74+ if (self -> pagerhist && self -> pagerhist -> ringbuf ) ringbuf_free (( ringbuf_t * ) & self -> pagerhist -> ringbuf );
7475 PyMem_Free (self -> pagerhist );
7576 self -> pagerhist = NULL ;
7677}
7778
7879static inline bool
7980pagerhist_extend (PagerHistoryBuf * ph , size_t minsz ) {
80- if (ph -> buffer_size >= ph -> max_sz ) return false;
81- size_t newsz = MIN (ph -> max_sz , ph -> buffer_size + MAX (1024u * 1024u , minsz ));
82- uint8_t * newbuf = PyMem_Malloc (newsz );
81+ size_t buffer_size = ringbuf_capacity (ph -> ringbuf );
82+ if (buffer_size >= ph -> maximum_size ) return false;
83+ size_t newsz = MIN (ph -> maximum_size , buffer_size + MAX (1024u * 1024u , minsz ));
84+ ringbuf_t newbuf = ringbuf_new (newsz );
8385 if (!newbuf ) return false;
84- size_t copied = MIN (ph -> length , ph -> buffer_size - ph -> start );
85- if (copied ) memcpy (newbuf , ph -> buffer + ph -> start , copied );
86- if (copied < ph -> length ) memcpy (newbuf + copied , ph -> buffer , (ph -> length - copied ));
87- PyMem_Free (ph -> buffer );
88- ph -> start = 0 ;
89- ph -> buffer = newbuf ;
90- ph -> buffer_size = newsz ;
86+ size_t count = ringbuf_bytes_used (ph -> ringbuf );
87+ if (count ) ringbuf_copy (newbuf , ph -> ringbuf , count );
88+ ringbuf_free ((ringbuf_t * )& ph -> ringbuf );
89+ ph -> ringbuf = newbuf ;
9190 return true;
9291}
9392
9493static inline void
9594pagerhist_clear (HistoryBuf * self ) {
96- if (!self -> pagerhist || !self -> pagerhist -> max_sz ) return ;
97- index_type pagerhist_sz = self -> pagerhist -> max_sz ;
98- free_pagerhist (self );
99- self -> pagerhist = alloc_pagerhist (pagerhist_sz );
95+ if (self -> pagerhist && self -> pagerhist -> ringbuf ) ringbuf_reset (self -> pagerhist -> ringbuf );
10096}
10197
10298static HistoryBuf *
@@ -188,36 +184,28 @@ historybuf_clear(HistoryBuf *self) {
188184
189185static inline bool
190186pagerhist_write_bytes (PagerHistoryBuf * ph , const uint8_t * buf , size_t sz ) {
191- if (sz > ph -> max_sz ) return false;
187+ if (sz > ph -> maximum_size ) return false;
192188 if (!sz ) return true;
193- if (sz > ph -> buffer_size - ph -> length ) pagerhist_extend (ph , sz );
194- if (sz > ph -> buffer_size ) return false;
195- size_t start_writing_at = (ph -> start + ph -> length ) % ph -> buffer_size ;
196- size_t available_space = ph -> buffer_size - ph -> length ;
197- size_t overlap = available_space < sz ? sz - available_space : 0 ;
198- size_t copied = MIN (sz , ph -> buffer_size - start_writing_at );
199- ph -> length += sz - overlap ;
200- ph -> start = (ph -> start + overlap ) % ph -> buffer_size ;
201- if (copied ) memcpy (ph -> buffer + start_writing_at , buf , copied );
202- if (copied < sz ) memcpy (ph -> buffer , buf + copied , (sz - copied ));
189+ size_t space_in_ringbuf = ringbuf_bytes_free (ph -> ringbuf );
190+ if (sz > space_in_ringbuf ) pagerhist_extend (ph , sz );
191+ ringbuf_memcpy_into (ph -> ringbuf , buf , sz );
203192 return true;
204193}
205194
206195static inline bool
207196pagerhist_ensure_start_is_valid_utf8 (PagerHistoryBuf * ph ) {
197+ uint8_t scratch [8 ];
198+ size_t num = ringbuf_memcpy_from (scratch , ph -> ringbuf , arraysz (scratch ));
208199 uint32_t state = UTF8_ACCEPT , codep ;
209- size_t pos = ph -> start , count = 0 ;
200+ size_t count = 0 ;
210201 size_t last_reject_at = 0 ;
211- while (count < ph -> length ) {
212- decode_utf8 (& state , & codep , ph -> buffer [pos ]);
213- count ++ ;
202+ while (count < num ) {
203+ decode_utf8 (& state , & codep , scratch [count ++ ]);
214204 if (state == UTF8_ACCEPT ) break ;
215205 if (state == UTF8_REJECT ) { state = UTF8_ACCEPT ; last_reject_at = count ; }
216- pos = pos == ph -> buffer_size - 1 ? 0 : pos + 1 ;
217206 }
218207 if (last_reject_at ) {
219- ph -> start = (ph -> start + last_reject_at ) % ph -> buffer_size ;
220- ph -> length -= last_reject_at ;
208+ ringbuf_memmove_from (scratch , ph -> ringbuf , last_reject_at );
221209 return true;
222210 }
223211 return false;
@@ -241,7 +229,7 @@ pagerhist_push(HistoryBuf *self, ANSIBuf *as_ansi_buf) {
241229 Line l = {.xnum = self -> xnum };
242230 init_line (self , self -> start_of_data , & l );
243231 line_as_ansi (& l , as_ansi_buf , & prev_cell );
244- if (ph -> length != 0 && !l .continued ) pagerhist_write_bytes (ph , (const uint8_t * )"\n" , 1 );
232+ if (ringbuf_bytes_used ( ph -> ringbuf ) && !l .continued ) pagerhist_write_bytes (ph , (const uint8_t * )"\n" , 1 );
245233 pagerhist_write_bytes (ph , (const uint8_t * )"\x1b[m" , 3 );
246234 if (pagerhist_write_ucs4 (ph , as_ansi_buf -> buf , as_ansi_buf -> len )) pagerhist_write_bytes (ph , (const uint8_t * )"\r" , 1 );
247235}
@@ -335,30 +323,28 @@ static inline Line*
335323get_line (HistoryBuf * self , index_type y , Line * l ) { init_line (self , index_of (self , self -> count - y - 1 ), l ); return l ; }
336324
337325static inline char_type
338- pagerhist_read_char (PagerHistoryBuf * ph , size_t pos , unsigned * count , uint8_t record [8 ]) {
326+ pagerhist_remove_char (PagerHistoryBuf * ph , unsigned * count , uint8_t record [8 ]) {
339327 uint32_t codep , state = UTF8_ACCEPT ;
340328 * count = 0 ;
341- while (true) {
342- decode_utf8 (& state , & codep , ph -> buffer [pos ]);
343- record [(* count )++ ] = ph -> buffer [pos ];
329+ while (ringbuf_bytes_used (ph -> ringbuf )) {
330+ ringbuf_memmove_from (& record [* count ], ph -> ringbuf , 1 );
331+ decode_utf8 (& state , & codep , record [* count ]);
332+ * count += 1 ;
344333 if (state == UTF8_REJECT ) { codep = 0 ; break ; }
345334 if (state == UTF8_ACCEPT ) break ;
346- pos = pos == ph -> buffer_size - 1 ? 0 : (pos + 1 );
347335 }
348336 return codep ;
349337}
350338
351339static void
352340pagerhist_rewrap_to (HistoryBuf * self , index_type cells_in_line ) {
353341 PagerHistoryBuf * ph = self -> pagerhist ;
354- if (!ph -> length ) return ;
342+ if (!ph -> ringbuf || ! ringbuf_bytes_used ( ph -> ringbuf ) ) return ;
355343 PagerHistoryBuf * nph = PyMem_Calloc (sizeof (PagerHistoryBuf ), 1 );
356344 if (!nph ) return ;
357- nph -> buffer_size = ph -> buffer_size ;
358- nph -> max_sz = ph -> max_sz ;
359- nph -> buffer = PyMem_Malloc (nph -> buffer_size );
360- if (!nph -> buffer ) { PyMem_Free (nph ); return ; }
361- size_t i = 0 , pos ;
345+ nph -> maximum_size = ph -> maximum_size ;
346+ nph -> ringbuf = ringbuf_new (MIN (ph -> maximum_size , ringbuf_capacity (ph -> ringbuf ) + 4096 ));
347+ if (!nph -> ringbuf ) { PyMem_Free (nph ); return ; }
362348 ssize_t ch_width = 0 ;
363349 unsigned count ;
364350 uint8_t record [8 ];
@@ -367,11 +353,6 @@ pagerhist_rewrap_to(HistoryBuf *self, index_type cells_in_line) {
367353 WCSState wcs_state ;
368354 initialize_wcs_state (& wcs_state );
369355
370- #define READ_CHAR (ch ) { \
371- ch = pagerhist_read_char(ph, pos, &count, record); \
372- i += count; pos += count; \
373- if (pos >= ph->buffer_size) pos = pos - ph->buffer_size; \
374- }
375356#define WRITE_CHAR () { \
376357 if (num_in_current_line + ch_width > cells_in_line) { \
377358 pagerhist_write_bytes(nph, (const uint8_t*)"\r", 1); \
@@ -381,10 +362,8 @@ pagerhist_rewrap_to(HistoryBuf *self, index_type cells_in_line) {
381362 pagerhist_write_bytes(nph, record, count); \
382363}
383364
384- for (i = 0 ; i < ph -> length ;) {
385- pos = ph -> start + i ;
386- if (pos >= ph -> buffer_size ) pos = pos - ph -> buffer_size ;
387- READ_CHAR (ch );
365+ while (ringbuf_bytes_used (ph -> ringbuf )) {
366+ ch = pagerhist_remove_char (ph , & count , record );
388367 if (ch == '\n' ) {
389368 initialize_wcs_state (& wcs_state );
390369 ch_width = 1 ;
@@ -397,12 +376,12 @@ pagerhist_rewrap_to(HistoryBuf *self, index_type cells_in_line) {
397376 }
398377 free_pagerhist (self );
399378 self -> pagerhist = nph ;
400- #undef READ_CHAR
379+ #undef WRITE_CHAR
401380}
402381
403382static PyObject *
404383pagerhist_write (HistoryBuf * self , PyObject * what ) {
405- if (self -> pagerhist && self -> pagerhist -> max_sz ) {
384+ if (self -> pagerhist && self -> pagerhist -> maximum_size ) {
406385 if (PyBytes_Check (what )) pagerhist_write_bytes (self -> pagerhist , (const uint8_t * )PyBytes_AS_STRING (what ), PyBytes_GET_SIZE (what ));
407386 else if (PyUnicode_Check (what ) && PyUnicode_READY (what ) == 0 ) {
408387 Py_UCS4 * buf = PyUnicode_AsUCS4Copy (what );
@@ -418,19 +397,17 @@ pagerhist_write(HistoryBuf *self, PyObject *what) {
418397static PyObject *
419398pagerhist_as_bytes (HistoryBuf * self , PyObject * args UNUSED ) {
420399 PagerHistoryBuf * ph = self -> pagerhist ;
421- if (!ph || !ph -> length ) return PyBytes_FromStringAndSize ("" , 0 );
400+ if (!ph || !ringbuf_bytes_used ( ph -> ringbuf ) ) return PyBytes_FromStringAndSize ("" , 0 );
422401 pagerhist_ensure_start_is_valid_utf8 (ph );
423402 if (ph -> rewrap_needed ) pagerhist_rewrap_to (self , self -> xnum );
424403
425404 Line l = {.xnum = self -> xnum }; get_line (self , 0 , & l );
426- size_t sz = ph -> length ;
405+ size_t sz = ringbuf_bytes_used ( ph -> ringbuf ) ;
427406 if (!l .continued ) sz += 1 ;
428407 PyObject * ans = PyBytes_FromStringAndSize (NULL , sz );
429408 if (!ans ) return NULL ;
430409 uint8_t * buf = (uint8_t * )PyBytes_AS_STRING (ans );
431- size_t copied = MIN (ph -> length , ph -> buffer_size - ph -> start );
432- if (copied ) memcpy (buf , ph -> buffer + ph -> start , copied );
433- if (copied < ph -> length ) memcpy (buf + copied , ph -> buffer , (ph -> length - copied ));
410+ ringbuf_memcpy_from (buf , ph -> ringbuf , sz );
434411 if (!l .continued ) buf [sz - 1 ] = '\n' ;
435412 return ans ;
436413}
@@ -561,7 +538,7 @@ void historybuf_rewrap(HistoryBuf *self, HistoryBuf *other, ANSIBuf *as_ansi_buf
561538 other -> count = self -> count ; other -> start_of_data = self -> start_of_data ;
562539 return ;
563540 }
564- if (other -> pagerhist && other -> xnum != self -> xnum && other -> pagerhist -> length )
541+ if (other -> pagerhist && other -> xnum != self -> xnum && ringbuf_bytes_used ( other -> pagerhist -> ringbuf ) )
565542 other -> pagerhist -> rewrap_needed = true;
566543 other -> count = 0 ; other -> start_of_data = 0 ;
567544 index_type x = 0 , y = 0 ;
0 commit comments