diff options
-rw-r--r-- | source/blender/editors/curve/editfont_undo.c | 201 |
1 files changed, 199 insertions, 2 deletions
diff --git a/source/blender/editors/curve/editfont_undo.c b/source/blender/editors/curve/editfont_undo.c index b2a265a415b..a0453f9694d 100644 --- a/source/blender/editors/curve/editfont_undo.c +++ b/source/blender/editors/curve/editfont_undo.c @@ -40,13 +40,175 @@ #include "ED_curve.h" #include "ED_util.h" +#define USE_ARRAY_STORE + +#ifdef USE_ARRAY_STORE +// # define DEBUG_PRINT +# include "BLI_array_store.h" +# include "BLI_array_store_utils.h" +# include "BLI_listbase.h" +# define ARRAY_CHUNK_SIZE 32 +#endif + typedef struct UndoFont { wchar_t *textbuf; struct CharInfo *textbufinfo; int len, pos; + +#ifdef USE_ARRAY_STORE + struct { + BArrayState *textbuf; + BArrayState *textbufinfo; + } store; +#endif } UndoFont; + +#ifdef USE_ARRAY_STORE + +/** \name Array Store + * \{ */ + +static struct { + struct BArrayStore_AtSize bs_stride; + int users; + + /* We could have the undo API pass in the previous state, for now store a local list */ + ListBase local_links; + +} uf_arraystore = {NULL}; + +/** + * \param create: When false, only free the arrays. + * This is done since when reading from an undo state, they must be temporarily expanded. + * then discarded afterwards, having this argument avoids having 2x code paths. + */ +static void uf_arraystore_compact_ex( + UndoFont *uf, const UndoFont *uf_ref, + bool create) +{ +#define STATE_COMPACT(uf, id, len) \ + if ((uf)->id) { \ + BLI_assert(create == ((uf)->store.id == NULL)); \ + if (create) { \ + BArrayState *state_reference = uf_ref ? uf_ref->store.id : NULL; \ + const size_t stride = sizeof(*(uf)->id); \ + BArrayStore *bs = BLI_array_store_at_size_ensure(&uf_arraystore.bs_stride, stride, ARRAY_CHUNK_SIZE); \ + (uf)->store.id = BLI_array_store_state_add( \ + bs, (uf)->id, (size_t)(len) * stride, state_reference); \ + } \ + /* keep uf->len for validation */ \ + MEM_freeN((uf)->id); \ + (uf)->id = NULL; \ + } ((void)0) + + STATE_COMPACT(uf, textbuf, uf->len + 1); + STATE_COMPACT(uf, textbufinfo, uf->len + 1); + +#undef STATE_COMPACT + + if (create) { + uf_arraystore.users += 1; + } +} + +/** + * Move data from allocated arrays to de-duplicated states and clear arrays. + */ +static void uf_arraystore_compact(UndoFont *um, const UndoFont *uf_ref) +{ + uf_arraystore_compact_ex(um, uf_ref, true); +} + +static void uf_arraystore_compact_with_info(UndoFont *um, const UndoFont *uf_ref) +{ +#ifdef DEBUG_PRINT + size_t size_expanded_prev, size_compacted_prev; + BLI_array_store_at_size_calc_memory_usage(&uf_arraystore.bs_stride, &size_expanded_prev, &size_compacted_prev); +#endif + + uf_arraystore_compact(um, uf_ref); + +#ifdef DEBUG_PRINT + { + size_t size_expanded, size_compacted; + BLI_array_store_at_size_calc_memory_usage(&uf_arraystore.bs_stride, &size_expanded, &size_compacted); + + const double percent_total = size_expanded ? + (((double)size_compacted / (double)size_expanded) * 100.0) : -1.0; + + size_t size_expanded_step = size_expanded - size_expanded_prev; + size_t size_compacted_step = size_compacted - size_compacted_prev; + const double percent_step = size_expanded_step ? + (((double)size_compacted_step / (double)size_expanded_step) * 100.0) : -1.0; + + printf("overall memory use: %.8f%% of expanded size\n", percent_total); + printf("step memory use: %.8f%% of expanded size\n", percent_step); + } +#endif +} + +/** + * Remove data we only expanded for temporary use. + */ +static void uf_arraystore_expand_clear(UndoFont *um) +{ + uf_arraystore_compact_ex(um, NULL, false); +} + +static void uf_arraystore_expand(UndoFont *uf) +{ +#define STATE_EXPAND(uf, id, len) \ + if ((uf)->store.id) { \ + const size_t stride = sizeof(*(uf)->id); \ + BArrayState *state = (uf)->store.id; \ + size_t state_len; \ + (uf)->id = BLI_array_store_state_data_get_alloc(state, &state_len); \ + BLI_assert((len) == (state_len / stride)); \ + UNUSED_VARS_NDEBUG(stride); \ + } ((void)0) + + STATE_EXPAND(uf, textbuf, uf->len + 1); + STATE_EXPAND(uf, textbufinfo, uf->len + 1); + +#undef STATE_EXPAND +} + +static void uf_arraystore_free(UndoFont *uf) +{ +#define STATE_FREE(uf, id) \ + if ((uf)->store.id) { \ + const size_t stride = sizeof(*(uf)->id); \ + BArrayStore *bs = BLI_array_store_at_size_get(&uf_arraystore.bs_stride, stride); \ + BArrayState *state = (uf)->store.id; \ + BLI_array_store_state_remove(bs, state); \ + (uf)->store.id = NULL; \ + } ((void)0) + + STATE_FREE(uf, textbuf); + STATE_FREE(uf, textbufinfo); + +#undef STATE_FREE + + uf_arraystore.users -= 1; + + BLI_assert(uf_arraystore.users >= 0); + + if (uf_arraystore.users == 0) { +#ifdef DEBUG_PRINT + printf("editfont undo store: freeing all data!\n"); +#endif + + BLI_array_store_at_size_clear(&uf_arraystore.bs_stride); + } + +} + +/** \} */ + +#endif /* USE_ARRAY_STORE */ + static void undoFont_to_editFont(void *uf_v, void *ecu, void *UNUSED(obdata)) { Curve *cu = (Curve *)ecu; @@ -55,6 +217,10 @@ static void undoFont_to_editFont(void *uf_v, void *ecu, void *UNUSED(obdata)) size_t final_size; +#ifdef USE_ARRAY_STORE + uf_arraystore_expand(uf_v); +#endif + final_size = sizeof(wchar_t) * (uf->len + 1); memcpy(ef->textbuf, uf->textbuf, final_size); @@ -65,6 +231,10 @@ static void undoFont_to_editFont(void *uf_v, void *ecu, void *UNUSED(obdata)) ef->len = uf->len; ef->selstart = ef->selend = 0; + +#ifdef USE_ARRAY_STORE + uf_arraystore_expand_clear(uf_v); +#endif } static void *editFont_to_undoFont(void *ecu, void *UNUSED(obdata)) @@ -87,14 +257,41 @@ static void *editFont_to_undoFont(void *ecu, void *UNUSED(obdata)) uf->pos = ef->pos; uf->len = ef->len; +#ifdef USE_ARRAY_STORE + { + const UndoFont *uf_ref = uf_arraystore.local_links.last ? + ((LinkData *)uf_arraystore.local_links.last)->data : NULL; + + /* add oursrlves */ + BLI_addtail(&uf_arraystore.local_links, BLI_genericNodeN(uf)); + + uf_arraystore_compact_with_info(uf, uf_ref); + } +#endif + return uf; } static void free_undoFont(void *uf_v) { UndoFont *uf = uf_v; - MEM_freeN(uf->textbuf); - MEM_freeN(uf->textbufinfo); + +#ifdef USE_ARRAY_STORE + { + LinkData *link = BLI_findptr(&uf_arraystore.local_links, uf, offsetof(LinkData, data)); + BLI_remlink(&uf_arraystore.local_links, link); + MEM_freeN(link); + } + uf_arraystore_free(uf); +#endif + + if (uf->textbuf) { + MEM_freeN(uf->textbuf); + } + if (uf->textbufinfo) { + MEM_freeN(uf->textbufinfo); + } + MEM_freeN(uf); } |