Actual source code: olist.c

  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>

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

 10:   No Fortran Support

 12:   Input Parameters:
 13: + fl   - the object list
 14: - name - the name to use for the object

 16:   Level: developer

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

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

 23:   Developer Notes:
 24:   This is to handle some cases that otherwise would result in having circular references so reference counts never got to zero

 26: .seealso: `PetscObjectListDestroy()`,`PetscObjectListFind()`,`PetscObjectListDuplicate()`,`PetscObjectListReverseFind()`,
 27: `PetscObject`, `PetscObjectListAdd()`
 28: @*/
 29: PetscErrorCode PetscObjectListRemoveReference(PetscObjectList *fl, const char name[])
 30: {
 31:   PetscObjectList nlist;
 32:   PetscBool       match;

 34:   PetscFunctionBegin;
 35:   PetscAssertPointer(fl, 1);
 36:   PetscAssertPointer(name, 2);
 37:   nlist = *fl;
 38:   while (nlist) {
 39:     PetscCall(PetscStrcmp(name, nlist->name, &match));
 40:     if (match) { /* found it in the list */
 41:       if (!nlist->skipdereference) PetscCall(PetscObjectDereference(nlist->obj));
 42:       nlist->skipdereference = PETSC_TRUE;
 43:       PetscFunctionReturn(PETSC_SUCCESS);
 44:     }
 45:     nlist = nlist->next;
 46:   }
 47:   PetscFunctionReturn(PETSC_SUCCESS);
 48: }

 50: /*@C
 51:   PetscObjectListAdd - Adds a new object to an `PetscObjectList`

 53:   No Fortran Support

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

 60:   Level: developer

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

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

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

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

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

114:   PetscCall(PetscObjectReference(obj));
115:   PetscCall(PetscStrncpy(olist->name, name, sizeof(olist->name)));

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

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

128:   No Fortran Support

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

133:   Level: developer

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

142:   PetscFunctionBegin;
143:   PetscAssertPointer(ifl, 1);
144:   fl = *ifl;
145:   while (fl) {
146:     tmp = fl->next;
147:     if (!fl->skipdereference) PetscCall(PetscObjectDereference(fl->obj));
148:     PetscCall(PetscFree(fl));
149:     fl = tmp;
150:   }
151:   *ifl = NULL;
152:   PetscFunctionReturn(PETSC_SUCCESS);
153: }

155: /*@C
156:   PetscObjectListFind - given a name, find the matching object in a list

158:   No Fortran Support

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

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

167:   Level: developer

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

172:   The reference count of the object is not increased

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

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

196:   No Fortran Support

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()`, `PetscObjectList`
214: @*/
215: PetscErrorCode PetscObjectListReverseFind(PetscObjectList fl, PetscObject obj, char *name[], PetscBool *skipdereference)
216: {
217:   PetscFunctionBegin;
218:   PetscAssertPointer(name, 3);
219:   if (skipdereference) PetscAssertPointer(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(PETSC_SUCCESS);
230: }

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

235:   No Fortran Support

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

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

243:   Level: developer

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