xref: /petsc/src/sys/objects/olist.c (revision fbf9dbe564678ed6eff1806adbc4c4f01b9743f4)
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 Note:
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()`, `PetscObjectListDuplicate()`,
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()`, `PetscObjectListDuplicate()`,
72           `PetscObject`, `PetscObjectList`
73 @*/
74 PetscErrorCode PetscObjectListAdd(PetscObjectList *fl, const char name[], PetscObject obj)
75 {
76   PetscObjectList olist, nlist, prev;
77   PetscBool       match;
78 
79   PetscFunctionBegin;
80   PetscValidPointer(fl, 1);
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   }
113 
114   /* add it to list, because it was not already there */
115   PetscCall(PetscNew(&olist));
116   olist->next = NULL;
117   olist->obj  = obj;
118 
119   PetscCall(PetscObjectReference(obj));
120   PetscCall(PetscStrncpy(olist->name, name, sizeof(olist->name)));
121 
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 }
129 
130 /*@C
131     PetscObjectListDestroy - Destroy a list of objects
132 
133     Input Parameter:
134 .   ifl   - pointer to list
135 
136     Level: developer
137 
138 .seealso: `PetscObjectList`, `PetscObject`, `PetscObjectListAdd()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`,
139           `PetscObjectListReverseFind()`, `PetscObjectListDuplicate()`, `PetscObject`
140 @*/
141 PetscErrorCode PetscObjectListDestroy(PetscObjectList *ifl)
142 {
143   PetscObjectList tmp, fl;
144 
145   PetscFunctionBegin;
146   PetscValidPointer(ifl, 1);
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 }
157 
158 /*@C
159     PetscObjectListFind - givn a name, find the matching object in a list
160 
161     Input Parameters:
162 +   fl   - pointer to list
163 -   name - name string
164 
165     Output Parameter:
166 .   obj - the PETSc object
167 
168     Level: developer
169 
170     Notes:
171     The name must have been registered with the `PetscObjectListAdd()` before calling this routine.
172 
173     The reference count of the object is not increased
174 
175 .seealso: `PetscObjectListDestroy()`, `PetscObjectListAdd()`, `PetscObjectListDuplicate()`, `PetscObjectListReverseFind()`, `PetscObjectListDuplicate()`,
176           `PetscObjectList`
177 @*/
178 PetscErrorCode PetscObjectListFind(PetscObjectList fl, const char name[], PetscObject *obj)
179 {
180   PetscFunctionBegin;
181   PetscValidPointer(obj, 3);
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 }
194 
195 /*@C
196     PetscObjectListReverseFind - given a object, find the matching name if it exists
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()`, `PetscObjectListDuplicate()`,
214           `PetscObjectList`
215 @*/
216 PetscErrorCode PetscObjectListReverseFind(PetscObjectList fl, PetscObject obj, char **name, PetscBool *skipdereference)
217 {
218   PetscFunctionBegin;
219   PetscValidPointer(name, 3);
220   if (skipdereference) PetscValidBoolPointer(skipdereference, 4);
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 }
232 
233 /*@C
234     PetscObjectListDuplicate - Creates a new list from a given object list.
235 
236     Input Parameter:
237 .   fl   - pointer to list
238 
239     Output Parameter:
240 .   nl - the new list (should point to `NULL` to start, otherwise appends)
241 
242     Level: developer
243 
244 .seealso: `PetscObjectListDestroy()`, `PetscObjectListAdd()`, `PetscObjectListReverseFind()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`,
245           `PetscObjectList`
246 @*/
247 PetscErrorCode PetscObjectListDuplicate(PetscObjectList fl, PetscObjectList *nl)
248 {
249   PetscFunctionBegin;
250   PetscValidPointer(nl, 2);
251   while (fl) {
252     PetscCall(PetscObjectListAdd(nl, fl->name, fl->obj));
253     fl = fl->next;
254   }
255   PetscFunctionReturn(PETSC_SUCCESS);
256 }
257