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:   Input Parameters:
 11: + fl   - the object list
 12: - name - the name to use for the object

 14:   Level: developer

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

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

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

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

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

 48: /*@C
 49:   PetscObjectListAdd - Adds a new object to an `PetscObjectList`

 51:   Input Parameters:
 52: + fl   - the object list
 53: . name - the name to use for the object
 54: - obj  - the object to attach

 56:   Level: developer

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

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

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

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

105:   /* add it to list, because it was not already there */
106:   PetscCall(PetscNew(&olist));
107:   olist->next = NULL;
108:   olist->obj  = obj;

110:   PetscCall(PetscObjectReference(obj));
111:   PetscCall(PetscStrncpy(olist->name, name, sizeof(olist->name)));

113:   if (!*fl) *fl = olist;
114:   else { /* go to end of list */ nlist = *fl;
115:     while (nlist->next) nlist = nlist->next;
116:     nlist->next = olist;
117:   }
118:   PetscFunctionReturn(PETSC_SUCCESS);
119: }

121: /*@C
122:   PetscObjectListDestroy - Destroy a list of objects

124:   Input Parameter:
125: . ifl - pointer to list

127:   Level: developer

129: .seealso: `PetscObjectList`, `PetscObject`, `PetscObjectListAdd()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`,
130:           `PetscObjectListReverseFind()`
131: @*/
132: PetscErrorCode PetscObjectListDestroy(PetscObjectList *ifl)
133: {
134:   PetscObjectList tmp, fl;

136:   PetscFunctionBegin;
137:   PetscAssertPointer(ifl, 1);
138:   fl = *ifl;
139:   while (fl) {
140:     tmp = fl->next;
141:     if (!fl->skipdereference) PetscCall(PetscObjectDereference(fl->obj));
142:     PetscCall(PetscFree(fl));
143:     fl = tmp;
144:   }
145:   *ifl = NULL;
146:   PetscFunctionReturn(PETSC_SUCCESS);
147: }

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

152:   Input Parameters:
153: + fl   - pointer to list
154: - name - name string

156:   Output Parameter:
157: . obj - the PETSc object

159:   Level: developer

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

164:   The reference count of the object is not increased

166: .seealso: `PetscObjectListDestroy()`,`PetscObjectListAdd()`,`PetscObjectListDuplicate()`,`PetscObjectListReverseFind()`, `PetscObjectList`
167: @*/
168: PetscErrorCode PetscObjectListFind(PetscObjectList fl, const char name[], PetscObject *obj)
169: {
170:   PetscFunctionBegin;
171:   PetscAssertPointer(obj, 3);
172:   *obj = NULL;
173:   while (fl) {
174:     PetscBool match;
175:     PetscCall(PetscStrcmp(name, fl->name, &match));
176:     if (match) {
177:       *obj = fl->obj;
178:       break;
179:     }
180:     fl = fl->next;
181:   }
182:   PetscFunctionReturn(PETSC_SUCCESS);
183: }

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

188:   Input Parameters:
189: + fl  - pointer to list
190: - obj - the PETSc object

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

196:   Level: developer

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

201:   The reference count of the object is not increased

203: .seealso: `PetscObjectListDestroy()`,`PetscObjectListAdd()`,`PetscObjectListDuplicate()`,`PetscObjectListFind()`, `PetscObjectList`
204: @*/
205: PetscErrorCode PetscObjectListReverseFind(PetscObjectList fl, PetscObject obj, char **name, PetscBool *skipdereference)
206: {
207:   PetscFunctionBegin;
208:   PetscAssertPointer(name, 3);
209:   if (skipdereference) PetscAssertPointer(skipdereference, 4);
210:   *name = NULL;
211:   while (fl) {
212:     if (fl->obj == obj) {
213:       *name = fl->name;
214:       if (skipdereference) *skipdereference = fl->skipdereference;
215:       break;
216:     }
217:     fl = fl->next;
218:   }
219:   PetscFunctionReturn(PETSC_SUCCESS);
220: }

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

225:   Input Parameter:
226: . fl - pointer to list

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

231:   Level: developer

233: .seealso: `PetscObjectListDestroy()`, `PetscObjectListAdd()`, `PetscObjectListReverseFind()`,
234: `PetscObjectListFind()`, `PetscObjectList`
235: @*/
236: PetscErrorCode PetscObjectListDuplicate(PetscObjectList fl, PetscObjectList *nl)
237: {
238:   PetscFunctionBegin;
239:   PetscAssertPointer(nl, 2);
240:   while (fl) {
241:     PetscCall(PetscObjectListAdd(nl, fl->name, fl->obj));
242:     fl = fl->next;
243:   }
244:   PetscFunctionReturn(PETSC_SUCCESS);
245: }