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