From b0f7f369950084ef06f271c36847a951a900e5b6 Mon Sep 17 00:00:00 2001 From: nick black Date: Sun, 2 Aug 2020 23:25:19 -0400 Subject: [PATCH] egc inlining #830 --- include/notcurses/notcurses.h | 13 ++++++++----- src/lib/egcpool.h | 2 +- src/lib/internal.h | 2 +- src/lib/notcurses.c | 33 ++++++++++++++------------------- src/lib/render.c | 16 ++++++---------- 5 files changed, 30 insertions(+), 36 deletions(-) diff --git a/include/notcurses/notcurses.h b/include/notcurses/notcurses.h index ccb895b70..30f17e538 100644 --- a/include/notcurses/notcurses.h +++ b/include/notcurses/notcurses.h @@ -485,7 +485,7 @@ channels_set_bg_default(uint64_t* channels){ // // Each cell occupies 16 static bytes (128 bits). The surface is thus ~1.6MB // for a (pretty large) 500x200 terminal. At 80x43, it's less than 64KB. -// Dynamic requirements (the egcpool) can add up to 32MB to an ncplane, but +// Dynamic requirements (the egcpool) can add up to 16MB to an ncplane, but // such large pools are unlikely in common use. // // We implement some small alpha compositing. Foreground and background both @@ -506,9 +506,12 @@ channels_set_bg_default(uint64_t* channels){ // RGB is used if neither default terminal colors nor palette indexing are in // play, and fully supports all transparency options. typedef struct cell { - // These 32 bits are either a single-byte, single-character grapheme cluster - // (values 0--0x7f), or an offset into a per-ncplane attached pool of - // varying-length UTF-8 grapheme clusters. This pool may thus be up to 32MB. + // These 32 bits are either a complete grapheme cluster in 4 bytes or less, + // or 0x01000000 plus an offset into a per-ncplane attached pool of varying- + // length UTF-8 EGCs (an egcpool). This pool may thus be up to 16MB. + // Obviously, this implies that EGCs beginning with 0x01 are disallowed; such + // an EGC, if we wanted to support them, could be spilled to the egcpool. If + // the EGC is less than four bytes, it will be padded with zeroes. uint32_t gcluster; // 4B -> 4B // 8 bits of zero + 8 reserved bits + NCSTYLE_* attributes (16 bits). // (attrword & 0xff000000): reserved, *must be zero* @@ -648,7 +651,7 @@ cell_wide_left_p(const cell* c){ // Is the cell simple (a lone ASCII character, encoded as such)? static inline bool cell_simple_p(const cell* c){ - return c->gcluster < 0x80; + return (c->gcluster >> 24u) != 0x01; } // return a pointer to the NUL-terminated EGC referenced by 'c'. this pointer diff --git a/src/lib/egcpool.h b/src/lib/egcpool.h index 793ae4f57..603d87ba1 100644 --- a/src/lib/egcpool.h +++ b/src/lib/egcpool.h @@ -249,7 +249,7 @@ egcpool_dump(egcpool* pool){ // unsafe results if called on a simple cell. static inline uint32_t cell_egc_idx(const cell* c){ - return c->gcluster - 0x80; + return c->gcluster & 0x00fffffflu; } __attribute__ ((__returns_nonnull__)) static inline const char* diff --git a/src/lib/internal.h b/src/lib/internal.h index 3a72e2414..5addbac11 100644 --- a/src/lib/internal.h +++ b/src/lib/internal.h @@ -608,7 +608,7 @@ cell_duplicate_far(egcpool* tpool, cell* targ, const ncplane* splane, const cell if(eoffset < 0){ return -1; } - targ->gcluster = eoffset + 0x80; + targ->gcluster = 0x01000000ul + eoffset; return ulen; } diff --git a/src/lib/notcurses.c b/src/lib/notcurses.c index a0283f452..177d1aa36 100644 --- a/src/lib/notcurses.c +++ b/src/lib/notcurses.c @@ -1364,36 +1364,30 @@ cell_load_direct(ncplane* n, cell* c, const char* gcluster, int bytes, int cols) if(bytes < 0 || cols < 0){ return -1; } - if(bytes <= 1){ - assert(cols < 2); - cell_release(n, c); - c->channels &= ~(CELL_WIDEASIAN_MASK | CELL_NOBACKGROUND_MASK); - c->gcluster = *gcluster; - return bytes; - } - if(!cell_simple_p(c)){ - if(strcmp(gcluster, cell_extended_gcluster(n, c)) == 0){ - return bytes; // reduce, reuse, recycle - }else{ - cell_release(n, c); - } - } - if(cols > 1){ - c->channels |= CELL_WIDEASIAN_MASK; - }else{ + if(cols < 2){ c->channels &= ~CELL_WIDEASIAN_MASK; + }else{ + c->channels |= CELL_WIDEASIAN_MASK; } - // FIXME also shaded blocks! ░ etc + // FIXME also shaded blocks! ░ etc. are there combined EGCs involving these? if(strncmp(gcluster, "\xe2\x96\x88", 3)){ c->channels &= ~CELL_NOBACKGROUND_MASK; }else{ c->channels |= CELL_NOBACKGROUND_MASK; } + if(bytes <= 4){ + cell_release(n, c); + c->channels &= ~CELL_WIDEASIAN_MASK; + c->gcluster = 0; + memcpy(&c->gcluster, gcluster, bytes); + return bytes; + } int eoffset = egcpool_stash(&n->pool, gcluster, bytes); if(eoffset < 0){ return -1; } - c->gcluster = eoffset + 0x80; + cell_release(n, c); + c->gcluster = 0x01000000ul + eoffset; return bytes; } @@ -1452,6 +1446,7 @@ int ncplane_putegc_yx(ncplane* n, int y, int x, const char* gclust, int* sbytes) if(cell_load_direct(n, targ, gclust, bytes, cols) < 0){ return -1; } +//fprintf(stderr, "%08x %d %d\n", targ->gcluster, bytes, cols); targ->attrword = n->attrword; targ->channels = channels; if(wide){ // must set our right wide, and check for further damage diff --git a/src/lib/render.c b/src/lib/render.c index 399e94f49..4dabe1dd3 100644 --- a/src/lib/render.c +++ b/src/lib/render.c @@ -500,16 +500,12 @@ ncfputc(char c, FILE* out){ static int term_putc(FILE* out, const egcpool* e, const cell* c){ if(cell_simple_p(c)){ - if(c->gcluster == 0 || iscntrl(c->gcluster)){ -// fprintf(stderr, "[ ]\n"); - if(ncfputc(' ', out) == EOF){ - return -1; - } - }else{ -//fprintf(stderr, "[%c]\n", c->gcluster); - if(ncfputc(c->gcluster, out) == EOF){ - return -1; - } + char egc[5]; + memset(egc, 0, sizeof(egc)); + memcpy(egc, &c->gcluster, sizeof(c->gcluster)); +//fprintf(stderr, "[%ls]\n", egc); + if(ncfputs(egc, out) == EOF){ + return -1; } }else{ const char* ext = egcpool_extended_gcluster(e, c);