Actual source code: olist.c


  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>

  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: };

 15: /*@C
 16:      PetscObjectListRemoveReference - Calls `PetscObjectDereference()` on an object in the list immediately but keeps a pointer to the object in the list.

 18:     Input Parameters:
 19: +     fl - the object list
 20: -     name - the name to use for the object

 22:     Level: developer

 24:     Notes:
 25:     Use `PetscObjectListAdd`(`PetscObjectList`,const char name[],NULL) to truly remove the object from the list

 27:     Use this routine ONLY if you know that the object referenced will remain in existence until the pointing object is destroyed

 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

 32: .seealso: `PetscObjectListDestroy()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`, `PetscObjectListReverseFind()`, `PetscObjectListDuplicate()`, `PetscObjectListAdd()`
 33: @*/
 34: PetscErrorCode PetscObjectListRemoveReference(PetscObjectList *fl, const char name[])
 35: {
 36:   PetscObjectList nlist;
 37:   PetscBool       match;

 41:   nlist = *fl;
 42:   while (nlist) {
 43:     PetscStrcmp(name, nlist->name, &match);
 44:     if (match) { /* found it in the list */
 45:       if (!nlist->skipdereference) PetscObjectDereference(nlist->obj);
 46:       nlist->skipdereference = PETSC_TRUE;
 47:       return 0;
 48:     }
 49:     nlist = nlist->next;
 50:   }
 51:   return 0;
 52: }

 54: /*@C
 55:      PetscObjectListAdd - Adds a new object to an `PetscObjectList`

 57:     Input Parameters:
 58: +     fl - the object list
 59: .     name - the name to use for the object
 60: -     obj - the object to attach

 62:     Level: developer

 64:     Notes:
 65:     Replaces item if it is already in list. Removes item if you pass in a NULL object.

 67:     Use `PetscObjectListFind()` or `PetscObjectListReverseFind()` to get the object back

 69: .seealso: `PetscObjectListDestroy()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`, `PetscObjectListReverseFind()`, `PetscObjectListDuplicate()`
 70: @*/
 71: PetscErrorCode PetscObjectListAdd(PetscObjectList *fl, const char name[], PetscObject obj)
 72: {
 73:   PetscObjectList olist, nlist, prev;
 74:   PetscBool       match;

 77:   if (!obj) { /* this means remove from list if it is there */
 78:     nlist = *fl;
 79:     prev  = NULL;
 80:     while (nlist) {
 81:       PetscStrcmp(name, nlist->name, &match);
 82:       if (match) { /* found it already in the list */
 83:         /* Remove it first to prevent circular derefs */
 84:         if (prev) prev->next = nlist->next;
 85:         else if (nlist->next) *fl = nlist->next;
 86:         else *fl = NULL;
 87:         if (!nlist->skipdereference) PetscObjectDereference(nlist->obj);
 88:         PetscFree(nlist);
 89:         return 0;
 90:       }
 91:       prev  = nlist;
 92:       nlist = nlist->next;
 93:     }
 94:     return 0; /* did not find it to remove */
 95:   }
 96:   /* look for it already in list */
 97:   nlist = *fl;
 98:   while (nlist) {
 99:     PetscStrcmp(name, nlist->name, &match);
100:     if (match) { /* found it in the list */
101:       PetscObjectReference(obj);
102:       if (!nlist->skipdereference) PetscObjectDereference(nlist->obj);
103:       nlist->skipdereference = PETSC_FALSE;
104:       nlist->obj             = obj;
105:       return 0;
106:     }
107:     nlist = nlist->next;
108:   }

110:   /* add it to list, because it was not already there */
111:   PetscNew(&olist);
112:   olist->next = NULL;
113:   olist->obj  = obj;

115:   PetscObjectReference(obj);
116:   PetscStrcpy(olist->name, name);

118:   if (!*fl) *fl = olist;
119:   else { /* go to end of list */ nlist = *fl;
120:     while (nlist->next) nlist = nlist->next;
121:     nlist->next = olist;
122:   }
123:   return 0;
124: }

126: /*@C
127:     PetscObjectListDestroy - Destroy a list of objects

129:     Input Parameter:
130: .   ifl   - pointer to list

132:     Level: developer

134: .seealso: `PetscObjectListAdd()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`, `PetscObjectListReverseFind()`, `PetscObjectListDuplicate()`
135: @*/
136: PetscErrorCode PetscObjectListDestroy(PetscObjectList *ifl)
137: {
138:   PetscObjectList tmp, fl;

141:   fl = *ifl;
142:   while (fl) {
143:     tmp = fl->next;
144:     if (!fl->skipdereference) PetscObjectDereference(fl->obj);
145:     PetscFree(fl);
146:     fl = tmp;
147:   }
148:   *ifl = NULL;
149:   return 0;
150: }

152: /*@C
153:     PetscObjectListFind - givn a name, find the matching object

155:     Input Parameters:
156: +   fl   - pointer to list
157: -   name - name string

159:     Output Parameters:
160: .   obj - the PETSc object

162:     Level: developer

164:     Notes:
165:     The name must have been registered with the `PetscObjectListAdd()` before calling this routine.

167:     The reference count of the object is not increased

169: .seealso: `PetscObjectListDestroy()`, `PetscObjectListAdd()`, `PetscObjectListDuplicate()`, `PetscObjectListReverseFind()`, `PetscObjectListDuplicate()`
170: @*/
171: PetscErrorCode PetscObjectListFind(PetscObjectList fl, const char name[], PetscObject *obj)
172: {
174:   *obj = NULL;
175:   while (fl) {
176:     PetscBool match;
177:     PetscStrcmp(name, fl->name, &match);
178:     if (match) {
179:       *obj = fl->obj;
180:       break;
181:     }
182:     fl = fl->next;
183:   }
184:   return 0;
185: }

187: /*@C
188:     PetscObjectListReverseFind - given a object, find the matching name if it exists

190:     Input Parameters:
191: +   fl   - pointer to list
192: -   obj - the PETSc object

194:     Output Parameters:
195: +  name - name string
196: -  skipdereference - if the object is in list but does not have the increased reference count for a circular dependency

198:     Level: developer

200:     Notes:
201:     The name must have been registered with the `PetscObjectListAdd()` before calling this routine.

203:     The reference count of the object is not increased

205: .seealso: `PetscObjectListDestroy()`, `PetscObjectListAdd()`, `PetscObjectListDuplicate()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`
206: @*/
207: PetscErrorCode PetscObjectListReverseFind(PetscObjectList fl, PetscObject obj, char **name, PetscBool *skipdereference)
208: {
211:   *name = NULL;
212:   while (fl) {
213:     if (fl->obj == obj) {
214:       *name = fl->name;
215:       if (skipdereference) *skipdereference = fl->skipdereference;
216:       break;
217:     }
218:     fl = fl->next;
219:   }
220:   return 0;
221: }

223: /*@C
224:     PetscObjectListDuplicate - Creates a new list from a given object list.

226:     Input Parameters:
227: .   fl   - pointer to list

229:     Output Parameters:
230: .   nl - the new list (should point to 0 to start, otherwise appends)

232:     Level: developer

234: .seealso: `PetscObjectListDestroy()`, `PetscObjectListAdd()`, `PetscObjectListReverseFind()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`
235: @*/
236: PetscErrorCode PetscObjectListDuplicate(PetscObjectList fl, PetscObjectList *nl)
237: {
239:   while (fl) {
240:     PetscObjectListAdd(nl, fl->name, fl->obj);
241:     fl = fl->next;
242:   }
243:   return 0;
244: }