Actual source code: olist.c
2: /*
3: Provides a general mechanism to maintain a linked list of PETSc objects.
4: This is used to allow PETSc objects to carry a list of "composed" objects
5: */
6: #include <petsc/private/petscimpl.h>
8: struct _n_PetscObjectList {
9: char name[256];
10: PetscBool skipdereference; /* when the PetscObjectList is destroyed do not call PetscObjectDereference() on this object */
11: PetscObject obj;
12: PetscObjectList next;
13: };
15: /*@C
16: PetscObjectListRemoveReference - Calls `PetscObjectDereference()` on an object in the list immediately but keeps a pointer to the object in the list.
18: Input Parameters:
19: + fl - the object list
20: - name - the name to use for the object
22: Level: developer
24: Notes:
25: Use `PetscObjectListAdd`(`PetscObjectList`,const char name[],NULL) to truly remove the object from the list
27: Use this routine ONLY if you know that the object referenced will remain in existence until the pointing object is destroyed
29: Developer Note:
30: This is to handle some cases that otherwise would result in having circular references so reference counts never got to zero
32: .seealso: `PetscObjectListDestroy()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`, `PetscObjectListReverseFind()`, `PetscObjectListDuplicate()`,
33: `PetscObject`, `PetscObjectListAdd()`
34: @*/
35: PetscErrorCode PetscObjectListRemoveReference(PetscObjectList *fl, const char name[])
36: {
37: PetscObjectList nlist;
38: PetscBool match;
40: PetscFunctionBegin;
43: nlist = *fl;
44: while (nlist) {
45: PetscCall(PetscStrcmp(name, nlist->name, &match));
46: if (match) { /* found it in the list */
47: if (!nlist->skipdereference) PetscCall(PetscObjectDereference(nlist->obj));
48: nlist->skipdereference = PETSC_TRUE;
49: PetscFunctionReturn(PETSC_SUCCESS);
50: }
51: nlist = nlist->next;
52: }
53: PetscFunctionReturn(PETSC_SUCCESS);
54: }
56: /*@C
57: PetscObjectListAdd - Adds a new object to an `PetscObjectList`
59: Input Parameters:
60: + fl - the object list
61: . name - the name to use for the object
62: - obj - the object to attach
64: Level: developer
66: Notes:
67: Replaces item if it is already in list. Removes item if you pass in a `NULL` object.
69: Use `PetscObjectListFind()` or `PetscObjectListReverseFind()` to get the object back
71: .seealso: `PetscObjectListDestroy()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`, `PetscObjectListReverseFind()`, `PetscObjectListDuplicate()`,
72: `PetscObject`, `PetscObjectList`
73: @*/
74: PetscErrorCode PetscObjectListAdd(PetscObjectList *fl, const char name[], PetscObject obj)
75: {
76: PetscObjectList olist, nlist, prev;
77: PetscBool match;
79: PetscFunctionBegin;
81: if (!obj) { /* this means remove from list if it is there */
82: nlist = *fl;
83: prev = NULL;
84: while (nlist) {
85: PetscCall(PetscStrcmp(name, nlist->name, &match));
86: if (match) { /* found it already in the list */
87: /* Remove it first to prevent circular derefs */
88: if (prev) prev->next = nlist->next;
89: else if (nlist->next) *fl = nlist->next;
90: else *fl = NULL;
91: if (!nlist->skipdereference) PetscCall(PetscObjectDereference(nlist->obj));
92: PetscCall(PetscFree(nlist));
93: PetscFunctionReturn(PETSC_SUCCESS);
94: }
95: prev = nlist;
96: nlist = nlist->next;
97: }
98: PetscFunctionReturn(PETSC_SUCCESS); /* did not find it to remove */
99: }
100: /* look for it already in list */
101: nlist = *fl;
102: while (nlist) {
103: PetscCall(PetscStrcmp(name, nlist->name, &match));
104: if (match) { /* found it in the list */
105: PetscCall(PetscObjectReference(obj));
106: if (!nlist->skipdereference) PetscCall(PetscObjectDereference(nlist->obj));
107: nlist->skipdereference = PETSC_FALSE;
108: nlist->obj = obj;
109: PetscFunctionReturn(PETSC_SUCCESS);
110: }
111: nlist = nlist->next;
112: }
114: /* add it to list, because it was not already there */
115: PetscCall(PetscNew(&olist));
116: olist->next = NULL;
117: olist->obj = obj;
119: PetscCall(PetscObjectReference(obj));
120: PetscCall(PetscStrncpy(olist->name, name, sizeof(olist->name)));
122: if (!*fl) *fl = olist;
123: else { /* go to end of list */ nlist = *fl;
124: while (nlist->next) nlist = nlist->next;
125: nlist->next = olist;
126: }
127: PetscFunctionReturn(PETSC_SUCCESS);
128: }
130: /*@C
131: PetscObjectListDestroy - Destroy a list of objects
133: Input Parameter:
134: . ifl - pointer to list
136: Level: developer
138: .seealso: `PetscObjectList`, `PetscObject`, `PetscObjectListAdd()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`,
139: `PetscObjectListReverseFind()`, `PetscObjectListDuplicate()`, `PetscObject`
140: @*/
141: PetscErrorCode PetscObjectListDestroy(PetscObjectList *ifl)
142: {
143: PetscObjectList tmp, fl;
145: PetscFunctionBegin;
147: fl = *ifl;
148: while (fl) {
149: tmp = fl->next;
150: if (!fl->skipdereference) PetscCall(PetscObjectDereference(fl->obj));
151: PetscCall(PetscFree(fl));
152: fl = tmp;
153: }
154: *ifl = NULL;
155: PetscFunctionReturn(PETSC_SUCCESS);
156: }
158: /*@C
159: PetscObjectListFind - givn a name, find the matching object in a list
161: Input Parameters:
162: + fl - pointer to list
163: - name - name string
165: Output Parameter:
166: . obj - the PETSc object
168: Level: developer
170: Notes:
171: The name must have been registered with the `PetscObjectListAdd()` before calling this routine.
173: The reference count of the object is not increased
175: .seealso: `PetscObjectListDestroy()`, `PetscObjectListAdd()`, `PetscObjectListDuplicate()`, `PetscObjectListReverseFind()`, `PetscObjectListDuplicate()`,
176: `PetscObjectList`
177: @*/
178: PetscErrorCode PetscObjectListFind(PetscObjectList fl, const char name[], PetscObject *obj)
179: {
180: PetscFunctionBegin;
182: *obj = NULL;
183: while (fl) {
184: PetscBool match;
185: PetscCall(PetscStrcmp(name, fl->name, &match));
186: if (match) {
187: *obj = fl->obj;
188: break;
189: }
190: fl = fl->next;
191: }
192: PetscFunctionReturn(PETSC_SUCCESS);
193: }
195: /*@C
196: PetscObjectListReverseFind - given a object, find the matching name if it exists
198: Input Parameters:
199: + fl - pointer to list
200: - obj - the PETSc object
202: Output Parameters:
203: + name - name string
204: - skipdereference - if the object is in list but does not have the increased reference count for a circular dependency
206: Level: developer
208: Notes:
209: The name must have been registered with the `PetscObjectListAdd()` before calling this routine.
211: The reference count of the object is not increased
213: .seealso: `PetscObjectListDestroy()`, `PetscObjectListAdd()`, `PetscObjectListDuplicate()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`,
214: `PetscObjectList`
215: @*/
216: PetscErrorCode PetscObjectListReverseFind(PetscObjectList fl, PetscObject obj, char **name, PetscBool *skipdereference)
217: {
218: PetscFunctionBegin;
221: *name = NULL;
222: while (fl) {
223: if (fl->obj == obj) {
224: *name = fl->name;
225: if (skipdereference) *skipdereference = fl->skipdereference;
226: break;
227: }
228: fl = fl->next;
229: }
230: PetscFunctionReturn(PETSC_SUCCESS);
231: }
233: /*@C
234: PetscObjectListDuplicate - Creates a new list from a given object list.
236: Input Parameter:
237: . fl - pointer to list
239: Output Parameter:
240: . nl - the new list (should point to `NULL` to start, otherwise appends)
242: Level: developer
244: .seealso: `PetscObjectListDestroy()`, `PetscObjectListAdd()`, `PetscObjectListReverseFind()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`,
245: `PetscObjectList`
246: @*/
247: PetscErrorCode PetscObjectListDuplicate(PetscObjectList fl, PetscObjectList *nl)
248: {
249: PetscFunctionBegin;
251: while (fl) {
252: PetscCall(PetscObjectListAdd(nl, fl->name, fl->obj));
253: fl = fl->next;
254: }
255: PetscFunctionReturn(PETSC_SUCCESS);
256: }