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>
6
7 /*@C
8 PetscObjectListRemoveReference - Calls `PetscObjectDereference()` on an object in the list immediately but keeps a pointer to the object in the list.
9
10 No Fortran Support
11
12 Input Parameters:
13 + fl - the object list
14 - name - the name to use for the object
15
16 Level: developer
17
18 Notes:
19 Use `PetscObjectListAdd`(`PetscObjectList`,const char name[],NULL) to truly remove the object from the list
20
21 Use this routine ONLY if you know that the object referenced will remain in existence until the pointing object is destroyed
22
23 Developer Notes:
24 This is to handle some cases that otherwise would result in having circular references so reference counts never got to zero
25
26 .seealso: `PetscObjectListDestroy()`,`PetscObjectListFind()`,`PetscObjectListDuplicate()`,`PetscObjectListReverseFind()`,
27 `PetscObject`, `PetscObjectListAdd()`
28 @*/
PetscObjectListRemoveReference(PetscObjectList * fl,const char name[])29 PetscErrorCode PetscObjectListRemoveReference(PetscObjectList *fl, const char name[])
30 {
31 PetscObjectList nlist;
32 PetscBool match;
33
34 PetscFunctionBegin;
35 PetscAssertPointer(fl, 1);
36 PetscAssertPointer(name, 2);
37 nlist = *fl;
38 while (nlist) {
39 PetscCall(PetscStrcmp(name, nlist->name, &match));
40 if (match) { /* found it in the list */
41 if (!nlist->skipdereference) PetscCall(PetscObjectDereference(nlist->obj));
42 nlist->skipdereference = PETSC_TRUE;
43 PetscFunctionReturn(PETSC_SUCCESS);
44 }
45 nlist = nlist->next;
46 }
47 PetscFunctionReturn(PETSC_SUCCESS);
48 }
49
50 /*@C
51 PetscObjectListAdd - Adds a new object to an `PetscObjectList`
52
53 No Fortran Support
54
55 Input Parameters:
56 + fl - the object list
57 . name - the name to use for the object
58 - obj - the object to attach
59
60 Level: developer
61
62 Notes:
63 Replaces item if it is already in list. Removes item if you pass in a `NULL` object.
64
65 Use `PetscObjectListFind()` or `PetscObjectListReverseFind()` to get the object back
66
67 .seealso: `PetscObjectListDestroy()`,`PetscObjectListFind()`,`PetscObjectListDuplicate()`,`PetscObjectListReverseFind()`, `PetscObject`, `PetscObjectList`
68 @*/
PetscObjectListAdd(PetscObjectList * fl,const char name[],PetscObject obj)69 PetscErrorCode PetscObjectListAdd(PetscObjectList *fl, const char name[], PetscObject obj)
70 {
71 PetscObjectList olist, nlist, prev;
72 PetscBool match;
73
74 PetscFunctionBegin;
75 PetscAssertPointer(fl, 1);
76 if (!obj) { /* this means remove from list if it is there */
77 nlist = *fl;
78 prev = NULL;
79 while (nlist) {
80 PetscCall(PetscStrcmp(name, nlist->name, &match));
81 if (match) { /* found it already in the list */
82 /* Remove it first to prevent circular derefs */
83 if (prev) prev->next = nlist->next;
84 else if (nlist->next) *fl = nlist->next;
85 else *fl = NULL;
86 if (!nlist->skipdereference) PetscCall(PetscObjectDereference(nlist->obj));
87 PetscCall(PetscFree(nlist));
88 PetscFunctionReturn(PETSC_SUCCESS);
89 }
90 prev = nlist;
91 nlist = nlist->next;
92 }
93 PetscFunctionReturn(PETSC_SUCCESS); /* did not find it to remove */
94 }
95 /* look for it already in list */
96 nlist = *fl;
97 while (nlist) {
98 PetscCall(PetscStrcmp(name, nlist->name, &match));
99 if (match) { /* found it in the list */
100 PetscCall(PetscObjectReference(obj));
101 if (!nlist->skipdereference) PetscCall(PetscObjectDereference(nlist->obj));
102 nlist->skipdereference = PETSC_FALSE;
103 nlist->obj = obj;
104 PetscFunctionReturn(PETSC_SUCCESS);
105 }
106 nlist = nlist->next;
107 }
108
109 /* add it to list, because it was not already there */
110 PetscCall(PetscNew(&olist));
111 olist->next = NULL;
112 olist->obj = obj;
113
114 PetscCall(PetscObjectReference(obj));
115 PetscCall(PetscStrncpy(olist->name, name, sizeof(olist->name)));
116
117 if (!*fl) *fl = olist;
118 else { /* go to end of list */ nlist = *fl;
119 while (nlist->next) nlist = nlist->next;
120 nlist->next = olist;
121 }
122 PetscFunctionReturn(PETSC_SUCCESS);
123 }
124
125 /*@C
126 PetscObjectListDestroy - Destroy a list of objects
127
128 No Fortran Support
129
130 Input Parameter:
131 . ifl - pointer to list
132
133 Level: developer
134
135 .seealso: `PetscObjectList`, `PetscObject`, `PetscObjectListAdd()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`,
136 `PetscObjectListReverseFind()`
137 @*/
PetscObjectListDestroy(PetscObjectList * ifl)138 PetscErrorCode PetscObjectListDestroy(PetscObjectList *ifl)
139 {
140 PetscObjectList tmp, fl;
141
142 PetscFunctionBegin;
143 PetscAssertPointer(ifl, 1);
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 }
154
155 /*@C
156 PetscObjectListFind - given a name, find the matching object in a list
157
158 No Fortran Support
159
160 Input Parameters:
161 + fl - pointer to list
162 - name - name string
163
164 Output Parameter:
165 . obj - the PETSc object
166
167 Level: developer
168
169 Notes:
170 The name must have been registered with the `PetscObjectListAdd()` before calling this routine.
171
172 The reference count of the object is not increased
173
174 .seealso: `PetscObjectListDestroy()`,`PetscObjectListAdd()`,`PetscObjectListDuplicate()`,`PetscObjectListReverseFind()`, `PetscObjectList`
175 @*/
PetscObjectListFind(PetscObjectList fl,const char name[],PetscObject * obj)176 PetscErrorCode PetscObjectListFind(PetscObjectList fl, const char name[], PetscObject *obj)
177 {
178 PetscFunctionBegin;
179 PetscAssertPointer(obj, 3);
180 *obj = NULL;
181 while (fl) {
182 PetscBool match;
183 PetscCall(PetscStrcmp(name, fl->name, &match));
184 if (match) {
185 *obj = fl->obj;
186 break;
187 }
188 fl = fl->next;
189 }
190 PetscFunctionReturn(PETSC_SUCCESS);
191 }
192
193 /*@C
194 PetscObjectListReverseFind - given a object, find the matching name if it exists
195
196 No Fortran Support
197
198 Input Parameters:
199 + fl - pointer to list
200 - obj - the PETSc object
201
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
205
206 Level: developer
207
208 Notes:
209 The name must have been registered with the `PetscObjectListAdd()` before calling this routine.
210
211 The reference count of the object is not increased
212
213 .seealso: `PetscObjectListDestroy()`,`PetscObjectListAdd()`,`PetscObjectListDuplicate()`,`PetscObjectListFind()`, `PetscObjectList`
214 @*/
PetscObjectListReverseFind(PetscObjectList fl,PetscObject obj,const char * name[],PetscBool * skipdereference)215 PetscErrorCode PetscObjectListReverseFind(PetscObjectList fl, PetscObject obj, const char *name[], PetscBool *skipdereference)
216 {
217 PetscFunctionBegin;
218 PetscAssertPointer(name, 3);
219 if (skipdereference) PetscAssertPointer(skipdereference, 4);
220 *name = NULL;
221 while (fl) {
222 if (fl->obj == obj) {
223 *name = fl->name;
224 if (skipdereference) *skipdereference = fl->skipdereference;
225 break;
226 }
227 fl = fl->next;
228 }
229 PetscFunctionReturn(PETSC_SUCCESS);
230 }
231
232 /*@C
233 PetscObjectListDuplicate - Creates a new list from a given object list.
234
235 No Fortran Support
236
237 Input Parameter:
238 . fl - pointer to list
239
240 Output Parameter:
241 . nl - the new list (should point to `NULL` to start, otherwise appends)
242
243 Level: developer
244
245 .seealso: `PetscObjectListDestroy()`, `PetscObjectListAdd()`, `PetscObjectListReverseFind()`,
246 `PetscObjectListFind()`, `PetscObjectList`
247 @*/
PetscObjectListDuplicate(PetscObjectList fl,PetscObjectList * nl)248 PetscErrorCode PetscObjectListDuplicate(PetscObjectList fl, PetscObjectList *nl)
249 {
250 PetscFunctionBegin;
251 PetscAssertPointer(nl, 2);
252 while (fl) {
253 PetscCall(PetscObjectListAdd(nl, fl->name, fl->obj));
254 fl = fl->next;
255 }
256 PetscFunctionReturn(PETSC_SUCCESS);
257 }
258