Actual source code: olist.c
1: /*
2: Provides a general mechanism to maintain a linked list of PETSc objects.
3: This is used to allow PETSc objects to carry a list of "composed" objects
4: */
5: #include <petsc/private/petscimpl.h>
7: /*@C
8: PetscObjectListRemoveReference - Calls `PetscObjectDereference()` on an object in the list immediately but keeps a pointer to the object in the list.
10: Input Parameters:
11: + fl - the object list
12: - name - the name to use for the object
14: Level: developer
16: Notes:
17: Use `PetscObjectListAdd`(`PetscObjectList`,const char name[],NULL) to truly remove the object from the list
19: Use this routine ONLY if you know that the object referenced will remain in existence until the pointing object is destroyed
21: Developer Notes:
22: This is to handle some cases that otherwise would result in having circular references so reference counts never got to zero
24: .seealso: `PetscObjectListDestroy()`,`PetscObjectListFind()`,`PetscObjectListDuplicate()`,`PetscObjectListReverseFind()`,
25: `PetscObject`, `PetscObjectListAdd()`
26: @*/
27: PetscErrorCode PetscObjectListRemoveReference(PetscObjectList *fl, const char name[])
28: {
29: PetscObjectList nlist;
30: PetscBool match;
32: PetscFunctionBegin;
33: PetscAssertPointer(fl, 1);
34: PetscAssertPointer(name, 2);
35: nlist = *fl;
36: while (nlist) {
37: PetscCall(PetscStrcmp(name, nlist->name, &match));
38: if (match) { /* found it in the list */
39: if (!nlist->skipdereference) PetscCall(PetscObjectDereference(nlist->obj));
40: nlist->skipdereference = PETSC_TRUE;
41: PetscFunctionReturn(PETSC_SUCCESS);
42: }
43: nlist = nlist->next;
44: }
45: PetscFunctionReturn(PETSC_SUCCESS);
46: }
48: /*@C
49: PetscObjectListAdd - Adds a new object to an `PetscObjectList`
51: Input Parameters:
52: + fl - the object list
53: . name - the name to use for the object
54: - obj - the object to attach
56: Level: developer
58: Notes:
59: Replaces item if it is already in list. Removes item if you pass in a `NULL` object.
61: Use `PetscObjectListFind()` or `PetscObjectListReverseFind()` to get the object back
63: .seealso: `PetscObjectListDestroy()`,`PetscObjectListFind()`,`PetscObjectListDuplicate()`,`PetscObjectListReverseFind()`, `PetscObject`, `PetscObjectList`
64: @*/
65: PetscErrorCode PetscObjectListAdd(PetscObjectList *fl, const char name[], PetscObject obj)
66: {
67: PetscObjectList olist, nlist, prev;
68: PetscBool match;
70: PetscFunctionBegin;
71: PetscAssertPointer(fl, 1);
72: if (!obj) { /* this means remove from list if it is there */
73: nlist = *fl;
74: prev = NULL;
75: while (nlist) {
76: PetscCall(PetscStrcmp(name, nlist->name, &match));
77: if (match) { /* found it already in the list */
78: /* Remove it first to prevent circular derefs */
79: if (prev) prev->next = nlist->next;
80: else if (nlist->next) *fl = nlist->next;
81: else *fl = NULL;
82: if (!nlist->skipdereference) PetscCall(PetscObjectDereference(nlist->obj));
83: PetscCall(PetscFree(nlist));
84: PetscFunctionReturn(PETSC_SUCCESS);
85: }
86: prev = nlist;
87: nlist = nlist->next;
88: }
89: PetscFunctionReturn(PETSC_SUCCESS); /* did not find it to remove */
90: }
91: /* look for it already in list */
92: nlist = *fl;
93: while (nlist) {
94: PetscCall(PetscStrcmp(name, nlist->name, &match));
95: if (match) { /* found it in the list */
96: PetscCall(PetscObjectReference(obj));
97: if (!nlist->skipdereference) PetscCall(PetscObjectDereference(nlist->obj));
98: nlist->skipdereference = PETSC_FALSE;
99: nlist->obj = obj;
100: PetscFunctionReturn(PETSC_SUCCESS);
101: }
102: nlist = nlist->next;
103: }
105: /* add it to list, because it was not already there */
106: PetscCall(PetscNew(&olist));
107: olist->next = NULL;
108: olist->obj = obj;
110: PetscCall(PetscObjectReference(obj));
111: PetscCall(PetscStrncpy(olist->name, name, sizeof(olist->name)));
113: if (!*fl) *fl = olist;
114: else { /* go to end of list */ nlist = *fl;
115: while (nlist->next) nlist = nlist->next;
116: nlist->next = olist;
117: }
118: PetscFunctionReturn(PETSC_SUCCESS);
119: }
121: /*@C
122: PetscObjectListDestroy - Destroy a list of objects
124: Input Parameter:
125: . ifl - pointer to list
127: Level: developer
129: .seealso: `PetscObjectList`, `PetscObject`, `PetscObjectListAdd()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`,
130: `PetscObjectListReverseFind()`
131: @*/
132: PetscErrorCode PetscObjectListDestroy(PetscObjectList *ifl)
133: {
134: PetscObjectList tmp, fl;
136: PetscFunctionBegin;
137: PetscAssertPointer(ifl, 1);
138: fl = *ifl;
139: while (fl) {
140: tmp = fl->next;
141: if (!fl->skipdereference) PetscCall(PetscObjectDereference(fl->obj));
142: PetscCall(PetscFree(fl));
143: fl = tmp;
144: }
145: *ifl = NULL;
146: PetscFunctionReturn(PETSC_SUCCESS);
147: }
149: /*@C
150: PetscObjectListFind - given a name, find the matching object in a list
152: Input Parameters:
153: + fl - pointer to list
154: - name - name string
156: Output Parameter:
157: . obj - the PETSc object
159: Level: developer
161: Notes:
162: The name must have been registered with the `PetscObjectListAdd()` before calling this routine.
164: The reference count of the object is not increased
166: .seealso: `PetscObjectListDestroy()`,`PetscObjectListAdd()`,`PetscObjectListDuplicate()`,`PetscObjectListReverseFind()`, `PetscObjectList`
167: @*/
168: PetscErrorCode PetscObjectListFind(PetscObjectList fl, const char name[], PetscObject *obj)
169: {
170: PetscFunctionBegin;
171: PetscAssertPointer(obj, 3);
172: *obj = NULL;
173: while (fl) {
174: PetscBool match;
175: PetscCall(PetscStrcmp(name, fl->name, &match));
176: if (match) {
177: *obj = fl->obj;
178: break;
179: }
180: fl = fl->next;
181: }
182: PetscFunctionReturn(PETSC_SUCCESS);
183: }
185: /*@C
186: PetscObjectListReverseFind - given a object, find the matching name if it exists
188: Input Parameters:
189: + fl - pointer to list
190: - obj - the PETSc object
192: Output Parameters:
193: + name - name string
194: - skipdereference - if the object is in list but does not have the increased reference count for a circular dependency
196: Level: developer
198: Notes:
199: The name must have been registered with the `PetscObjectListAdd()` before calling this routine.
201: The reference count of the object is not increased
203: .seealso: `PetscObjectListDestroy()`,`PetscObjectListAdd()`,`PetscObjectListDuplicate()`,`PetscObjectListFind()`, `PetscObjectList`
204: @*/
205: PetscErrorCode PetscObjectListReverseFind(PetscObjectList fl, PetscObject obj, char **name, PetscBool *skipdereference)
206: {
207: PetscFunctionBegin;
208: PetscAssertPointer(name, 3);
209: if (skipdereference) PetscAssertPointer(skipdereference, 4);
210: *name = NULL;
211: while (fl) {
212: if (fl->obj == obj) {
213: *name = fl->name;
214: if (skipdereference) *skipdereference = fl->skipdereference;
215: break;
216: }
217: fl = fl->next;
218: }
219: PetscFunctionReturn(PETSC_SUCCESS);
220: }
222: /*@C
223: PetscObjectListDuplicate - Creates a new list from a given object list.
225: Input Parameter:
226: . fl - pointer to list
228: Output Parameter:
229: . nl - the new list (should point to `NULL` to start, otherwise appends)
231: Level: developer
233: .seealso: `PetscObjectListDestroy()`, `PetscObjectListAdd()`, `PetscObjectListReverseFind()`,
234: `PetscObjectListFind()`, `PetscObjectList`
235: @*/
236: PetscErrorCode PetscObjectListDuplicate(PetscObjectList fl, PetscObjectList *nl)
237: {
238: PetscFunctionBegin;
239: PetscAssertPointer(nl, 2);
240: while (fl) {
241: PetscCall(PetscObjectListAdd(nl, fl->name, fl->obj));
242: fl = fl->next;
243: }
244: PetscFunctionReturn(PETSC_SUCCESS);
245: }