This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/blenlib/BLI_listbase.h

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

376 lines
13 KiB
C++
Raw Normal View History

/* SPDX-License-Identifier: GPL-2.0-or-later
* Copyright 2001-2002 NaN Holding BV. All rights reserved. */
#pragma once
/** \file
* \ingroup bli
*/
#include "BLI_compiler_attrs.h"
#include "BLI_utildefines.h"
#include "DNA_listBase.h"
// struct ListBase;
// struct LinkData;
#ifdef __cplusplus
extern "C" {
#endif
/**
* Returns the position of \a vlink within \a listbase, numbering from 0, or -1 if not found.
*/
int BLI_findindex(const struct ListBase *listbase, const void *vlink) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
/**
* Returns the 0-based index of the first element of listbase which contains the specified
* null-terminated string at the specified offset, or -1 if not found.
*/
int BLI_findstringindex(const struct ListBase *listbase,
const char *id,
int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* Return a ListBase representing the entire list the given Link is in.
*/
ListBase BLI_listbase_from_link(struct Link *some_link);
/* Find forwards. */
/**
* Returns the nth element of \a listbase, numbering from 0.
*/
void *BLI_findlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
GPencil: Update-on-write using update cache This implements the update cache described in T95401. The cache is currently only used for drawing strokes and sculpting (using the push brush). **Note: Making use of the cache throughout grease pencil will have to be done incrementally in other patches. ** The update cache stores what elements have changed in the original data-block since the last time the eval object was updated. Additionally, the update cache can store multiple updates to the data and minimizes the number of elements that need to be copied. Elements can be tagged using `BKE_gpencil_tag_full_update` and `BKE_gpencil_tag_light_update`. A full update means that the element itself will be copied but also all of the content inside. E.g. when a layer is tagged for a full update, the layer, all the frames inside the layer and all the strokes inside the frames will be copied. A light update means that only the properties of the element are copied without any of the content. E.g. if a layer is tagged with a light update, it will copy the layer name, opacity, transform, etc. When the update cache is in use (e.g. elements have been tagged) then the depsgraph will not trigger a copy-on-write, but an update-on-write. This means that the update cache will be used to determine what elements have changed and then only those elements will be copied over to the eval object. If the update cache is empty or the data block was tagged with a full update, we always fall back to a copy-on-write. Currently, the update cache is only used by the active depsgraph. This is because we need to free the update cache after an update-on-write so it's reset and we need to make sure it is not freed or read by other depsgraphs. Co-authored-by: @yann-lty This patch was contributed by The SPA Studios. Reviewed By: sergey, antoniov, #dependency_graph, pepeland, mendio Maniphest Tasks: T95401 Differential Revision: https://developer.blender.org/D13984
2022-02-10 11:34:12 +01:00
/**
* Returns the nth element after \a link, numbering from 0.
*/
void *BLI_findlinkfrom(struct Link *start, int number) ATTR_WARN_UNUSED_RESULT;
/**
* Finds the first element of \a listbase which contains the null-terminated
* string \a id at the specified offset, returning NULL if not found.
*/
void *BLI_findstring(const struct ListBase *listbase,
const char *id,
int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* Finds the first element of \a listbase which contains a pointer to the
* null-terminated string \a id at the specified offset, returning NULL if not found.
*/
void *BLI_findstring_ptr(const struct ListBase *listbase,
const char *id,
int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* Finds the first element of listbase which contains the specified pointer value
* at the specified offset, returning NULL if not found.
*/
void *BLI_findptr(const struct ListBase *listbase,
const void *ptr,
int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* Finds the first element of listbase which contains the specified bytes
* at the specified offset, returning NULL if not found.
*/
void *BLI_listbase_bytes_find(const ListBase *listbase,
const void *bytes,
size_t bytes_size,
int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
/**
* Find the first item in the list that matches the given string, or the given index as fallback.
*
* \note The string is only used is non-NULL and non-empty.
*
* \return The found item, or NULL.
*/
void *BLI_listbase_string_or_index_find(const struct ListBase *listbase,
const char *string,
size_t string_offset,
int index) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/* Find backwards. */
/**
* Returns the nth-last element of \a listbase, numbering from 0.
*/
void *BLI_rfindlink(const struct ListBase *listbase, int number) ATTR_WARN_UNUSED_RESULT
ATTR_NONNULL(1);
/**
* Finds the last element of \a listbase which contains the
* null-terminated string \a id at the specified offset, returning NULL if not found.
*/
void *BLI_rfindstring(const struct ListBase *listbase,
const char *id,
int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* Finds the last element of \a listbase which contains a pointer to the
* null-terminated string \a id at the specified offset, returning NULL if not found.
*/
void *BLI_rfindstring_ptr(const struct ListBase *listbase,
const char *id,
int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* Finds the last element of listbase which contains the specified pointer value
* at the specified offset, returning NULL if not found.
*/
void *BLI_rfindptr(const struct ListBase *listbase,
const void *ptr,
int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* Finds the last element of listbase which contains the specified bytes
* at the specified offset, returning NULL if not found.
*/
void *BLI_listbase_bytes_rfind(const ListBase *listbase,
const void *bytes,
size_t bytes_size,
int offset) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1, 2);
/**
* Removes and disposes of the entire contents of \a listbase using guardedalloc.
*/
void BLI_freelistN(struct ListBase *listbase) ATTR_NONNULL(1);
/**
* Appends \a vlink (assumed to begin with a Link) onto listbase.
*/
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
/**
* Removes \a vlink from \a listbase. Assumes it is linked into there!
*/
void BLI_remlink(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
/**
* Checks that \a vlink is linked into listbase, removing it from there if so.
*/
bool BLI_remlink_safe(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
/**
* Removes the head from \a listbase and returns it.
*/
void *BLI_pophead(ListBase *listbase) ATTR_NONNULL(1);
/**
* Removes the tail from \a listbase and returns it.
*/
void *BLI_poptail(ListBase *listbase) ATTR_NONNULL(1);
/**
* Prepends \a vlink (assumed to begin with a Link) onto listbase.
*/
void BLI_addhead(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
/**
* Inserts \a vnewlink immediately preceding \a vnextlink in listbase.
* Or, if \a vnextlink is NULL, puts \a vnewlink at the end of the list.
*/
void BLI_insertlinkbefore(struct ListBase *listbase, void *vnextlink, void *vnewlink)
ATTR_NONNULL(1);
/**
* Inserts \a vnewlink immediately following \a vprevlink in \a listbase.
* Or, if \a vprevlink is NULL, puts \a vnewlink at the front of the list.
*/
void BLI_insertlinkafter(struct ListBase *listbase, void *vprevlink, void *vnewlink)
ATTR_NONNULL(1);
/**
* Insert a link in place of another, without changing its position in the list.
*
* Puts `vnewlink` in the position of `vreplacelink`, removing `vreplacelink`.
* - `vreplacelink` *must* be in the list.
* - `vnewlink` *must not* be in the list.
*/
void BLI_insertlinkreplace(ListBase *listbase, void *vreplacelink, void *vnewlink)
ATTR_NONNULL(1, 2, 3);
/**
* Sorts the elements of listbase into the order defined by cmp
* (which should return 1 if its first arg should come after its second arg).
* This uses insertion sort, so NOT ok for large list.
*/
void BLI_listbase_sort(struct ListBase *listbase, int (*cmp)(const void *, const void *))
ATTR_NONNULL(1, 2);
void BLI_listbase_sort_r(ListBase *listbase,
int (*cmp)(void *, const void *, const void *),
void *thunk) ATTR_NONNULL(1, 2);
/**
* Reinsert \a vlink relative to its current position but offset by \a step. Doesn't move
* item if new position would exceed list (could optionally move to head/tail).
*
* \param step: Absolute value defines step size, sign defines direction. E.g pass -1
* to move \a vlink before previous, or 1 to move behind next.
* \return If position of \a vlink has changed.
*/
bool BLI_listbase_link_move(ListBase *listbase, void *vlink, int step) ATTR_NONNULL();
/**
* Move the link at the index \a from to the position at index \a to.
*
* \return If the move was successful.
*/
bool BLI_listbase_move_index(ListBase *listbase, int from, int to) ATTR_NONNULL();
/**
* Removes and disposes of the entire contents of listbase using direct free(3).
*/
void BLI_freelist(struct ListBase *listbase) ATTR_NONNULL(1);
/**
* Returns the number of elements in \a listbase, up until (and including count_max)
*
* \note Use to avoid redundant looping.
*/
int BLI_listbase_count_at_most(const struct ListBase *listbase,
int count_max) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* Returns the number of elements in \a listbase.
*/
int BLI_listbase_count(const struct ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1);
/**
* Removes \a vlink from listbase and disposes of it. Assumes it is linked into there!
*/
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1);
/**
* Swaps \a vlinka and \a vlinkb in the list. Assumes they are both already in the list!
*/
void BLI_listbase_swaplinks(struct ListBase *listbase, void *vlinka, void *vlinkb)
ATTR_NONNULL(1, 2);
/**
* Swaps \a vlinka and \a vlinkb from their respective lists.
* Assumes they are both already in their \a listbasea!
*/
2017-11-14 16:10:48 +11:00
void BLI_listbases_swaplinks(struct ListBase *listbasea,
struct ListBase *listbaseb,
void *vlinka,
void *vlinkb) ATTR_NONNULL(2, 3);
/**
* Moves the entire contents of \a src onto the end of \a dst.
*/
void BLI_movelisttolist(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1, 2);
/**
* Moves the entire contents of \a src at the beginning of \a dst.
*/
void BLI_movelisttolist_reverse(struct ListBase *dst, struct ListBase *src) ATTR_NONNULL(1, 2);
/**
* Sets dst to a duplicate of the entire contents of src. dst may be the same as src.
*/
void BLI_duplicatelist(struct ListBase *dst, const struct ListBase *src) ATTR_NONNULL(1, 2);
void BLI_listbase_reverse(struct ListBase *lb) ATTR_NONNULL(1);
/**
* \param vlink: Link to make first.
*/
2014-07-30 15:01:16 +10:00
void BLI_listbase_rotate_first(struct ListBase *lb, void *vlink) ATTR_NONNULL(1, 2);
/**
* \param vlink: Link to make last.
*/
2014-07-30 15:01:16 +10:00
void BLI_listbase_rotate_last(struct ListBase *lb, void *vlink) ATTR_NONNULL(1, 2);
/**
* Utility functions to avoid first/last references inline all over.
*/
BLI_INLINE bool BLI_listbase_is_single(const struct ListBase *lb)
{
return (lb->first && lb->first == lb->last);
}
2014-02-08 08:09:49 +11:00
BLI_INLINE bool BLI_listbase_is_empty(const struct ListBase *lb)
{
return (lb->first == (void *)0);
}
BLI_INLINE void BLI_listbase_clear(struct ListBase *lb)
{
lb->first = lb->last = (void *)0;
}
/**
* Equality check for ListBase.
*
* This only shallowly compares the ListBase itself (so the first/last
* pointers), and does not do any equality checks on the list items.
*/
BLI_INLINE bool BLI_listbase_equal(const struct ListBase *a, const struct ListBase *b)
{
if (a == NULL) {
return b == NULL;
}
if (b == NULL) {
return false;
}
return a->first == b->first && a->last == b->last;
}
/**
* Create a generic list node containing link to provided data.
*/
struct LinkData *BLI_genericNodeN(void *data);
/**
* Does a full loop on the list, with any value acting as first
* (handy for cycling items)
*
* \code{.c}
*
* LISTBASE_CIRCULAR_FORWARD_BEGIN(type, listbase, item, item_init)
* {
* ...operate on marker...
* }
* LISTBASE_CIRCULAR_FORWARD_END (type, listbase, item, item_init);
*
* \endcode
*/
#define LISTBASE_CIRCULAR_FORWARD_BEGIN(type, lb, lb_iter, lb_init) \
if ((lb)->first && (lb_init || (lb_init = (type)(lb)->first))) { \
lb_iter = (type)(lb_init); \
do {
#define LISTBASE_CIRCULAR_FORWARD_END(type, lb, lb_iter, lb_init) \
} \
while ((lb_iter = (lb_iter)->next ? (type)(lb_iter)->next : (type)(lb)->first), \
(lb_iter != lb_init)) \
; \
} \
((void)0)
#define LISTBASE_CIRCULAR_BACKWARD_BEGIN(type, lb, lb_iter, lb_init) \
if ((lb)->last && (lb_init || (lb_init = (type)(lb)->last))) { \
lb_iter = lb_init; \
do {
#define LISTBASE_CIRCULAR_BACKWARD_END(type, lb, lb_iter, lb_init) \
} \
while ((lb_iter = (lb_iter)->prev ? (lb_iter)->prev : (type)(lb)->last), (lb_iter != lb_init)) \
; \
} \
((void)0)
#define LISTBASE_FOREACH(type, var, list) \
for (type var = (type)((list)->first); var != NULL; var = (type)(((Link *)(var))->next))
/**
* A version of #LISTBASE_FOREACH that supports incrementing an index variable at every step.
* Including this in the macro helps prevent mistakes where "continue" mistakenly skips the
* incrementation.
*/
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var) \
for (type var = (((void)(index_var = 0)), (type)((list)->first)); var != NULL; \
var = (type)(((Link *)(var))->next), index_var++)
#define LISTBASE_FOREACH_BACKWARD(type, var, list) \
for (type var = (type)((list)->last); var != NULL; var = (type)(((Link *)(var))->prev))
/**
* A version of #LISTBASE_FOREACH that supports removing the item we're looping over.
*/
#define LISTBASE_FOREACH_MUTABLE(type, var, list) \
for (type var = (type)((list)->first), *var##_iter_next; \
((var != NULL) ? ((void)(var##_iter_next = (type)(((Link *)(var))->next)), 1) : 0); \
var = var##_iter_next)
/**
* A version of #LISTBASE_FOREACH_BACKWARD that supports removing the item we're looping over.
*/
#define LISTBASE_FOREACH_BACKWARD_MUTABLE(type, var, list) \
for (type var = (type)((list)->last), *var##_iter_prev; \
((var != NULL) ? ((void)(var##_iter_prev = (type)(((Link *)(var))->prev)), 1) : 0); \
var = var##_iter_prev)
#ifdef __cplusplus
}
#endif
#ifdef __cplusplus
BLI_INLINE bool operator==(const ListBase &a, const ListBase &b)
{
return BLI_listbase_equal(&a, &b);
}
#endif