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