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