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()`,
 33:           `PetscObject`, `PetscObjectListAdd()`
 34: @*/
 35: PetscErrorCode PetscObjectListRemoveReference(PetscObjectList *fl, const char name[])
 36: {
 37:   PetscObjectList nlist;
 38:   PetscBool       match;

 40:   PetscFunctionBegin;
 43:   nlist = *fl;
 44:   while (nlist) {
 45:     PetscCall(PetscStrcmp(name, nlist->name, &match));
 46:     if (match) { /* found it in the list */
 47:       if (!nlist->skipdereference) PetscCall(PetscObjectDereference(nlist->obj));
 48:       nlist->skipdereference = PETSC_TRUE;
 49:       PetscFunctionReturn(PETSC_SUCCESS);
 50:     }
 51:     nlist = nlist->next;
 52:   }
 53:   PetscFunctionReturn(PETSC_SUCCESS);
 54: }

 56: /*@C
 57:      PetscObjectListAdd - Adds a new object to an `PetscObjectList`

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

 64:     Level: developer

 66:     Notes:
 67:     Replaces item if it is already in list. Removes item if you pass in a `NULL` object.

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

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

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

114:   /* add it to list, because it was not already there */
115:   PetscCall(PetscNew(&olist));
116:   olist->next = NULL;
117:   olist->obj  = obj;

119:   PetscCall(PetscObjectReference(obj));
120:   PetscCall(PetscStrncpy(olist->name, name, sizeof(olist->name)));

122:   if (!*fl) *fl = olist;
123:   else { /* go to end of list */ nlist = *fl;
124:     while (nlist->next) nlist = nlist->next;
125:     nlist->next = olist;
126:   }
127:   PetscFunctionReturn(PETSC_SUCCESS);
128: }

130: /*@C
131:     PetscObjectListDestroy - Destroy a list of objects

133:     Input Parameter:
134: .   ifl   - pointer to list

136:     Level: developer

138: .seealso: `PetscObjectList`, `PetscObject`, `PetscObjectListAdd()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`,
139:           `PetscObjectListReverseFind()`, `PetscObjectListDuplicate()`, `PetscObject`
140: @*/
141: PetscErrorCode PetscObjectListDestroy(PetscObjectList *ifl)
142: {
143:   PetscObjectList tmp, fl;

145:   PetscFunctionBegin;
147:   fl = *ifl;
148:   while (fl) {
149:     tmp = fl->next;
150:     if (!fl->skipdereference) PetscCall(PetscObjectDereference(fl->obj));
151:     PetscCall(PetscFree(fl));
152:     fl = tmp;
153:   }
154:   *ifl = NULL;
155:   PetscFunctionReturn(PETSC_SUCCESS);
156: }

158: /*@C
159:     PetscObjectListFind - givn a name, find the matching object in a list

161:     Input Parameters:
162: +   fl   - pointer to list
163: -   name - name string

165:     Output Parameter:
166: .   obj - the PETSc object

168:     Level: developer

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

173:     The reference count of the object is not increased

175: .seealso: `PetscObjectListDestroy()`, `PetscObjectListAdd()`, `PetscObjectListDuplicate()`, `PetscObjectListReverseFind()`, `PetscObjectListDuplicate()`,
176:           `PetscObjectList`
177: @*/
178: PetscErrorCode PetscObjectListFind(PetscObjectList fl, const char name[], PetscObject *obj)
179: {
180:   PetscFunctionBegin;
182:   *obj = NULL;
183:   while (fl) {
184:     PetscBool match;
185:     PetscCall(PetscStrcmp(name, fl->name, &match));
186:     if (match) {
187:       *obj = fl->obj;
188:       break;
189:     }
190:     fl = fl->next;
191:   }
192:   PetscFunctionReturn(PETSC_SUCCESS);
193: }

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

198:     Input Parameters:
199: +   fl   - pointer to list
200: -   obj - the PETSc object

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

206:     Level: developer

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

211:     The reference count of the object is not increased

213: .seealso: `PetscObjectListDestroy()`, `PetscObjectListAdd()`, `PetscObjectListDuplicate()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`,
214:           `PetscObjectList`
215: @*/
216: PetscErrorCode PetscObjectListReverseFind(PetscObjectList fl, PetscObject obj, char **name, PetscBool *skipdereference)
217: {
218:   PetscFunctionBegin;
221:   *name = NULL;
222:   while (fl) {
223:     if (fl->obj == obj) {
224:       *name = fl->name;
225:       if (skipdereference) *skipdereference = fl->skipdereference;
226:       break;
227:     }
228:     fl = fl->next;
229:   }
230:   PetscFunctionReturn(PETSC_SUCCESS);
231: }

233: /*@C
234:     PetscObjectListDuplicate - Creates a new list from a given object list.

236:     Input Parameter:
237: .   fl   - pointer to list

239:     Output Parameter:
240: .   nl - the new list (should point to `NULL` to start, otherwise appends)

242:     Level: developer

244: .seealso: `PetscObjectListDestroy()`, `PetscObjectListAdd()`, `PetscObjectListReverseFind()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`,
245:           `PetscObjectList`
246: @*/
247: PetscErrorCode PetscObjectListDuplicate(PetscObjectList fl, PetscObjectList *nl)
248: {
249:   PetscFunctionBegin;
251:   while (fl) {
252:     PetscCall(PetscObjectListAdd(nl, fl->name, fl->obj));
253:     fl = fl->next;
254:   }
255:   PetscFunctionReturn(PETSC_SUCCESS);
256: }