/****************************************************************************** * vlc_diffutil.h ****************************************************************************** * Copyright (C) 2022 VLC authors and VideoLAN * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation; either version 2.1 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ #ifndef VLC_DIFFUTIL_H #define VLC_DIFFUTIL_H #include #include /** * this structure defines callback to access and compare elements from * the old and the new list */ typedef struct { /// return the size of the old list @a list uint32_t (*getOldSize)(const void* list); /// return the size of the new list @a list uint32_t (*getNewSize)(const void* list); /// compare 2 elements bool (*isSame)(const void* listOld, uint32_t oldIndex, const void* listNew, uint32_t newIndex); } vlc_diffutil_callback_t; typedef struct { /** * notify that the item from @a listNew at position @a posNew is inserted in list @a listOld at position @a posOld * * @param opaque user data from function vlc_diffutil_walk_snake * @param listOld pointer to the old model * @param posOld position of the element inserted in the old model (before removal) * @param listNew pointer to the new model * @param posNew position of the element inserted in the new model */ void (*insert)(void* opaque, const void* listOld, uint32_t posOld, const void* listNew, uint32_t posNew); /** * notify that the item from @a listOld at position @a posOld is removed * @param opaque user data from function vlc_diffutil_walk_snake * @param listOld pointer to the old model * @param posOld position of the element removed in the old model * @param listNew pointer to the new model * @param posNew position of the element removed in the new model (before removal) */ void (*remove)(void* opaque, const void* listOld, uint32_t posOld, const void* listNew, uint32_t posNew); /** * notify that the item as @a posOld from the old list @a listOld is unchanged, the respective item * position in the new list is at the position @a posNew in @a listNew */ void (*equal)(void* opaque, const void* listOld, uint32_t posOld, const void* listNew, uint32_t posNew); } vlc_diffutil_snake_callback_t; typedef struct diffutil_snake_t diffutil_snake_t; enum vlc_diffutil_op_type { ///items have been added to the list VLC_DIFFUTIL_OP_INSERT, ///items have been removed from the list VLC_DIFFUTIL_OP_REMOVE, ///items have been moved within the list VLC_DIFFUTIL_OP_MOVE, ///current change should be ignored VLC_DIFFUTIL_OP_IGNORE, }; /** * The data positioned at newModel[ y ] is inserted at position index * in the current model. * * @code * model = "abcdefg" * newModel[3] = 'X' * after operation insert(y=3, index = 3), model will be * model = "abcXdefg" * @endcode */ struct vlc_diffutil_insert { /// data position in the old model uint32_t x; /// data position in the new model uint32_t y; /// insertion position in the updated model uint32_t index; }; /** * The data positioned at oldModel[ y ] is removed at position index * in the current model. * * @code * model = "abCdefg" * oldModel[4] = 'C' * after operation remove(x=4, index = 2), model will be * model = "abdefg" * @endcode */ struct vlc_diffutil_remove { /// data position in the old model uint32_t x; /// data position in the new model uint32_t y; /// removal position in the updated model uint32_t index; }; /** * Moves the data from position model[ from ] to model[ to ] * the data is available either at newModel[ y ] or oldModel[ x ] * * the positions @a from and @a to are given in the referenrial before the operation * * @code * model = "aBCdefg" * after operation move(from=1, to=5, count=2), model will be * model = "adeCBfg" * @endcode */ struct vlc_diffutil_move { /// move origin uint32_t from; /// move destination uint32_t to; /// data position in the old model uint32_t x; /// data position in the new model uint32_t y; }; /** * represent a change to the model, each change assumes that previous changes * have already been applied * * for instance with a model "aBcDef", the operations [remove(index=1, count=1), remove(index=2, count=1)] * will result in "acef" (with "acDef" as intermediary step) */ typedef struct { union { struct vlc_diffutil_insert insert; struct vlc_diffutil_remove remove; struct vlc_diffutil_move move; } op; /// type of change operation enum vlc_diffutil_op_type type; /// number of elements to be inserted/removed/moved uint32_t count; } vlc_diffutil_change_t; typedef struct VLC_VECTOR(vlc_diffutil_change_t) vlc_diffutil_changelist_t; enum vlc_diffutil_result_flag { /// try to transform an insertion with a matching suppression into a move operation VLC_DIFFUTIL_RESULT_MOVE = 0x1, /** * aggregate similar consecutive operations into a single operation * for instance this: * [{INSERT, i=5}{INSERT, x=6}{REMOVE, i=10}{REMOVE, i=10}{REMOVE, i=10}] * would be transformed into: * [{INSERT, i=5, count=2}{REMOVE, i=10, count=3}] */ VLC_DIFFUTIL_RESULT_AGGREGATE = 0x2, }; /** * vlc_diffutil_build_snake compute a diff model * between the @a dataOld model and the @a dataNew model. This model can be * processed manually using vlc_diffutil_walk_snake or translated into a change list using * vlc_diffutil_build_change_list * * @param diffOp callback to compare the elements from the old and new model * @param dataOld old model * @param dataNew new model * @return the diff model, NULL on error */ VLC_API struct diffutil_snake_t* vlc_diffutil_build_snake(const vlc_diffutil_callback_t* diffOp, const void* dataOld, const void* dataNew); /// free the snake created by vlc_diffutil_build_snake VLC_API void vlc_diffutil_free_snake(struct diffutil_snake_t* snake); /** * iterate over the changelist and callback user on each operation (keep/insert/remove) * * @param snake the snake created with vlc_diffutil_build_snake * @param snakeOp snake callback * @param cbData user data for snake callbacks * @param diffOp callbacks used in vlc_diffutil_build_snake * @param dataOld old model * @param dataNew new model * @return false on error * * @warning @a dataOld and @a dataNew should not be altered during the operation */ VLC_API bool vlc_diffutil_walk_snake( const diffutil_snake_t* snake, const vlc_diffutil_snake_callback_t* snakeOp, void* cbData, const vlc_diffutil_callback_t* diffOp, const void* dataOld, const void* dataNew); /** * vlc_diffutil_build_change_list creates a list of changes to apply to transform @a dataOld into @a dataNew * * @param snake the snake created with vlc_diffutil_build_snake * @param diffOp callbacks used in vlc_diffutil_build_snake * @param dataOld old model * @param dataNew new model * @param flags vlc_diffutil_result_flag flags * @return the list of changes, NULL on error */ VLC_API vlc_diffutil_changelist_t* vlc_diffutil_build_change_list( const struct diffutil_snake_t* snake, const vlc_diffutil_callback_t* diffOp, const void* dataOld, const void* dataNew, int flags); /// free the changelist created by vlc_diffutil_build_change_list VLC_API void vlc_diffutil_free_change_list(vlc_diffutil_changelist_t* changelist); #endif // VLC_DIFFUTIL_H