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