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