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;

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

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

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

 63:     Level: developer

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

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

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

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

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

117:   PetscCall(PetscObjectReference(obj));
118:   PetscCall(PetscStrncpy(olist->name, name, sizeof(olist->name)));

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

128: /*@C
129:     PetscObjectListDestroy - Destroy a list of objects

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

134:     Level: developer

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

142:   PetscFunctionBegin;
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 - givn a name, find the matching object

158:     Input Parameters:
159: +   fl   - pointer to list
160: -   name - name string

162:     Output Parameter:
163: .   obj - the PETSc object

165:     Level: developer

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

170:     The reference count of the object is not increased

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

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

194:     Input Parameters:
195: +   fl   - pointer to list
196: -   obj - the PETSc object

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

202:     Level: developer

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

207:     The reference count of the object is not increased

209: .seealso: `PetscObjectListDestroy()`, `PetscObjectListAdd()`, `PetscObjectListDuplicate()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`
210: @*/
211: PetscErrorCode PetscObjectListReverseFind(PetscObjectList fl, PetscObject obj, char **name, PetscBool *skipdereference)
212: {
213:   PetscFunctionBegin;
216:   *name = NULL;
217:   while (fl) {
218:     if (fl->obj == obj) {
219:       *name = fl->name;
220:       if (skipdereference) *skipdereference = fl->skipdereference;
221:       break;
222:     }
223:     fl = fl->next;
224:   }
225:   PetscFunctionReturn(PETSC_SUCCESS);
226: }

228: /*@C
229:     PetscObjectListDuplicate - Creates a new list from a given object list.

231:     Input Parameter:
232: .   fl   - pointer to list

234:     Output Parameter:
235: .   nl - the new list (should point to 0 to start, otherwise appends)

237:     Level: developer

239: .seealso: `PetscObjectListDestroy()`, `PetscObjectListAdd()`, `PetscObjectListReverseFind()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`
240: @*/
241: PetscErrorCode PetscObjectListDuplicate(PetscObjectList fl, PetscObjectList *nl)
242: {
243:   PetscFunctionBegin;
245:   while (fl) {
246:     PetscCall(PetscObjectListAdd(nl, fl->name, fl->obj));
247:     fl = fl->next;
248:   }
249:   PetscFunctionReturn(PETSC_SUCCESS);
250: }