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