xref: /petsc/src/sys/objects/olist.c (revision 8fb5bd83c3955fefcf33a54e3bb66920a9fa884b)
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 {
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 @*/
73 PetscErrorCode  PetscObjectListAdd(PetscObjectList *fl,const char name[],PetscObject obj)
74 {
75   PetscObjectList olist,nlist,prev;
76   PetscBool       match;
77 
78   PetscFunctionBegin;
79   PetscValidPointer(fl,1);
80   if (!obj) { /* this means remove from list if it is there */
81     nlist = *fl; 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 */
122     nlist = *fl;
123     while (nlist->next) nlist = nlist->next;
124     nlist->next = olist;
125   }
126   PetscFunctionReturn(0);
127 }
128 
129 /*@C
130     PetscObjectListDestroy - Destroy a list of objects
131 
132     Input Parameter:
133 .   ifl   - pointer to list
134 
135     Level: developer
136 
137 .seealso: `PetscObjectListAdd()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`, `PetscObjectListReverseFind()`, `PetscObjectListDuplicate()`
138 
139 @*/
140 PetscErrorCode  PetscObjectListDestroy(PetscObjectList *ifl)
141 {
142   PetscObjectList tmp,fl;
143 
144   PetscFunctionBegin;
145   PetscValidPointer(ifl,1);
146   fl = *ifl;
147   while (fl) {
148     tmp = fl->next;
149     if (!fl->skipdereference) PetscCall(PetscObjectDereference(fl->obj));
150     PetscCall(PetscFree(fl));
151     fl   = tmp;
152   }
153   *ifl = NULL;
154   PetscFunctionReturn(0);
155 }
156 
157 /*@C
158     PetscObjectListFind - givn a name, find the matching object
159 
160     Input Parameters:
161 +   fl   - pointer to list
162 -   name - name string
163 
164     Output Parameters:
165 .   obj - the PETSc object
166 
167     Level: developer
168 
169     Notes:
170     The name must have been registered with the PetscObjectListAdd() before calling this routine.
171 
172     The reference count of the object is not increased
173 
174 .seealso: `PetscObjectListDestroy()`, `PetscObjectListAdd()`, `PetscObjectListDuplicate()`, `PetscObjectListReverseFind()`, `PetscObjectListDuplicate()`
175 
176 @*/
177 PetscErrorCode  PetscObjectListFind(PetscObjectList fl,const char name[],PetscObject *obj)
178 {
179   PetscFunctionBegin;
180   PetscValidPointer(obj,3);
181   *obj = NULL;
182   while (fl) {
183     PetscBool match;
184     PetscCall(PetscStrcmp(name,fl->name,&match));
185     if (match) {
186       *obj = fl->obj;
187       break;
188     }
189     fl = fl->next;
190   }
191   PetscFunctionReturn(0);
192 }
193 
194 /*@C
195     PetscObjectListReverseFind - given a object, find the matching name if it exists
196 
197     Input Parameters:
198 +   fl   - pointer to list
199 -   obj - the PETSc object
200 
201     Output Parameters:
202 +  name - name string
203 -  skipdereference - if the object is in list but does not have the increased reference count for a circular dependency
204 
205     Level: developer
206 
207     Notes:
208     The name must have been registered with the PetscObjectListAdd() before calling this routine.
209 
210     The reference count of the object is not increased
211 
212 .seealso: `PetscObjectListDestroy()`, `PetscObjectListAdd()`, `PetscObjectListDuplicate()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`
213 
214 @*/
215 PetscErrorCode  PetscObjectListReverseFind(PetscObjectList fl,PetscObject obj,char **name,PetscBool *skipdereference)
216 {
217   PetscFunctionBegin;
218   PetscValidPointer(name,3);
219   if (skipdereference) PetscValidBoolPointer(skipdereference,4);
220   *name = NULL;
221   while (fl) {
222     if (fl->obj == obj) {
223       *name = fl->name;
224       if (skipdereference) *skipdereference = fl->skipdereference;
225       break;
226     }
227     fl = fl->next;
228   }
229   PetscFunctionReturn(0);
230 }
231 
232 /*@C
233     PetscObjectListDuplicate - Creates a new list from a given object list.
234 
235     Input Parameters:
236 .   fl   - pointer to list
237 
238     Output Parameters:
239 .   nl - the new list (should point to 0 to start, otherwise appends)
240 
241     Level: developer
242 
243 .seealso: `PetscObjectListDestroy()`, `PetscObjectListAdd()`, `PetscObjectListReverseFind()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`
244 
245 @*/
246 PetscErrorCode  PetscObjectListDuplicate(PetscObjectList fl,PetscObjectList *nl)
247 {
248   PetscFunctionBegin;
249   PetscValidPointer(nl,2);
250   while (fl) {
251     PetscCall(PetscObjectListAdd(nl,fl->name,fl->obj));
252     fl = fl->next;
253   }
254   PetscFunctionReturn(0);
255 }
256