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()`, `PetscObjectListAdd()`
33: @*/
34: PetscErrorCode PetscObjectListRemoveReference(PetscObjectList *fl, const char name[])
35: {
36: PetscObjectList nlist;
37: PetscBool match;
39: PetscFunctionBegin;
42: nlist = *fl;
43: while (nlist) {
44: PetscCall(PetscStrcmp(name, nlist->name, &match));
45: if (match) { /* found it in the list */
46: if (!nlist->skipdereference) PetscCall(PetscObjectDereference(nlist->obj));
47: nlist->skipdereference = PETSC_TRUE;
48: PetscFunctionReturn(PETSC_SUCCESS);
49: }
50: nlist = nlist->next;
51: }
52: PetscFunctionReturn(PETSC_SUCCESS);
53: }
55: /*@C
56: PetscObjectListAdd - Adds a new object to an `PetscObjectList`
58: Input Parameters:
59: + fl - the object list
60: . name - the name to use for the object
61: - obj - the object to attach
63: Level: developer
65: Notes:
66: Replaces item if it is already in list. Removes item if you pass in a NULL object.
68: Use `PetscObjectListFind()` or `PetscObjectListReverseFind()` to get the object back
70: .seealso: `PetscObjectListDestroy()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`, `PetscObjectListReverseFind()`, `PetscObjectListDuplicate()`
71: @*/
72: PetscErrorCode PetscObjectListAdd(PetscObjectList *fl, const char name[], PetscObject obj)
73: {
74: PetscObjectList olist, nlist, prev;
75: PetscBool match;
77: PetscFunctionBegin;
79: if (!obj) { /* this means remove from list if it is there */
80: nlist = *fl;
81: prev = NULL;
82: while (nlist) {
83: PetscCall(PetscStrcmp(name, nlist->name, &match));
84: if (match) { /* found it already in the list */
85: /* Remove it first to prevent circular derefs */
86: if (prev) prev->next = nlist->next;
87: else if (nlist->next) *fl = nlist->next;
88: else *fl = NULL;
89: if (!nlist->skipdereference) PetscCall(PetscObjectDereference(nlist->obj));
90: PetscCall(PetscFree(nlist));
91: PetscFunctionReturn(PETSC_SUCCESS);
92: }
93: prev = nlist;
94: nlist = nlist->next;
95: }
96: PetscFunctionReturn(PETSC_SUCCESS); /* did not find it to remove */
97: }
98: /* look for it already in list */
99: nlist = *fl;
100: while (nlist) {
101: PetscCall(PetscStrcmp(name, nlist->name, &match));
102: if (match) { /* found it in the list */
103: PetscCall(PetscObjectReference(obj));
104: if (!nlist->skipdereference) PetscCall(PetscObjectDereference(nlist->obj));
105: nlist->skipdereference = PETSC_FALSE;
106: nlist->obj = obj;
107: PetscFunctionReturn(PETSC_SUCCESS);
108: }
109: nlist = nlist->next;
110: }
112: /* add it to list, because it was not already there */
113: PetscCall(PetscNew(&olist));
114: olist->next = NULL;
115: olist->obj = obj;
117: PetscCall(PetscObjectReference(obj));
118: PetscCall(PetscStrcpy(olist->name, name));
120: if (!*fl) *fl = olist;
121: else { /* go to end of list */ nlist = *fl;
122: while (nlist->next) nlist = nlist->next;
123: nlist->next = olist;
124: }
125: PetscFunctionReturn(PETSC_SUCCESS);
126: }
128: /*@C
129: PetscObjectListDestroy - Destroy a list of objects
131: Input Parameter:
132: . ifl - pointer to list
134: Level: developer
136: .seealso: `PetscObjectListAdd()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`, `PetscObjectListReverseFind()`, `PetscObjectListDuplicate()`
137: @*/
138: PetscErrorCode PetscObjectListDestroy(PetscObjectList *ifl)
139: {
140: PetscObjectList tmp, fl;
142: PetscFunctionBegin;
144: fl = *ifl;
145: while (fl) {
146: tmp = fl->next;
147: if (!fl->skipdereference) PetscCall(PetscObjectDereference(fl->obj));
148: PetscCall(PetscFree(fl));
149: fl = tmp;
150: }
151: *ifl = NULL;
152: PetscFunctionReturn(PETSC_SUCCESS);
153: }
155: /*@C
156: PetscObjectListFind - givn a name, find the matching object
158: Input Parameters:
159: + fl - pointer to list
160: - name - name string
162: Output Parameters:
163: . obj - the PETSc object
165: Level: developer
167: Notes:
168: The name must have been registered with the `PetscObjectListAdd()` before calling this routine.
170: The reference count of the object is not increased
172: .seealso: `PetscObjectListDestroy()`, `PetscObjectListAdd()`, `PetscObjectListDuplicate()`, `PetscObjectListReverseFind()`, `PetscObjectListDuplicate()`
173: @*/
174: PetscErrorCode PetscObjectListFind(PetscObjectList fl, const char name[], PetscObject *obj)
175: {
176: PetscFunctionBegin;
178: *obj = NULL;
179: while (fl) {
180: PetscBool match;
181: PetscCall(PetscStrcmp(name, fl->name, &match));
182: if (match) {
183: *obj = fl->obj;
184: break;
185: }
186: fl = fl->next;
187: }
188: PetscFunctionReturn(PETSC_SUCCESS);
189: }
191: /*@C
192: PetscObjectListReverseFind - given a object, find the matching name if it exists
194: Input Parameters:
195: + fl - pointer to list
196: - obj - the PETSc object
198: Output Parameters:
199: + name - name string
200: - skipdereference - if the object is in list but does not have the increased reference count for a circular dependency
202: Level: developer
204: Notes:
205: The name must have been registered with the `PetscObjectListAdd()` before calling this routine.
207: The reference count of the object is not increased
209: .seealso: `PetscObjectListDestroy()`, `PetscObjectListAdd()`, `PetscObjectListDuplicate()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`
210: @*/
211: PetscErrorCode PetscObjectListReverseFind(PetscObjectList fl, PetscObject obj, char **name, PetscBool *skipdereference)
212: {
213: PetscFunctionBegin;
216: *name = NULL;
217: while (fl) {
218: if (fl->obj == obj) {
219: *name = fl->name;
220: if (skipdereference) *skipdereference = fl->skipdereference;
221: break;
222: }
223: fl = fl->next;
224: }
225: PetscFunctionReturn(PETSC_SUCCESS);
226: }
228: /*@C
229: PetscObjectListDuplicate - Creates a new list from a given object list.
231: Input Parameters:
232: . fl - pointer to list
234: Output Parameters:
235: . nl - the new list (should point to 0 to start, otherwise appends)
237: Level: developer
239: .seealso: `PetscObjectListDestroy()`, `PetscObjectListAdd()`, `PetscObjectListReverseFind()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`
240: @*/
241: PetscErrorCode PetscObjectListDuplicate(PetscObjectList fl, PetscObjectList *nl)
242: {
243: PetscFunctionBegin;
245: while (fl) {
246: PetscCall(PetscObjectListAdd(nl, fl->name, fl->obj));
247: fl = fl->next;
248: }
249: PetscFunctionReturn(PETSC_SUCCESS);
250: }