1 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> 7 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 }; 14 15 /*@C 16 PetscObjectListRemoveReference - Calls `PetscObjectDereference()` on an object in the list immediately but keeps a pointer to the object in the list. 17 18 Input Parameters: 19 + fl - the object list 20 - name - the name to use for the object 21 22 Level: developer 23 24 Notes: 25 Use `PetscObjectListAdd`(`PetscObjectList`,const char name[],NULL) to truly remove the object from the list 26 27 Use this routine ONLY if you know that the object referenced will remain in existence until the pointing object is destroyed 28 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 31 32 .seealso: `PetscObjectListDestroy()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`, `PetscObjectListReverseFind()`, `PetscObjectListDuplicate()`, `PetscObjectListAdd()` 33 @*/ 34 PetscErrorCode PetscObjectListRemoveReference(PetscObjectList *fl, const char name[]) { 35 PetscObjectList nlist; 36 PetscBool match; 37 38 PetscFunctionBegin; 39 PetscValidPointer(fl, 1); 40 PetscValidCharPointer(name, 2); 41 nlist = *fl; 42 while (nlist) { 43 PetscCall(PetscStrcmp(name, nlist->name, &match)); 44 if (match) { /* found it in the list */ 45 if (!nlist->skipdereference) PetscCall(PetscObjectDereference(nlist->obj)); 46 nlist->skipdereference = PETSC_TRUE; 47 PetscFunctionReturn(0); 48 } 49 nlist = nlist->next; 50 } 51 PetscFunctionReturn(0); 52 } 53 54 /*@C 55 PetscObjectListAdd - Adds a new object to an `PetscObjectList` 56 57 Input Parameters: 58 + fl - the object list 59 . name - the name to use for the object 60 - obj - the object to attach 61 62 Level: developer 63 64 Notes: 65 Replaces item if it is already in list. Removes item if you pass in a NULL object. 66 67 Use `PetscObjectListFind()` or `PetscObjectListReverseFind()` to get the object back 68 69 .seealso: `PetscObjectListDestroy()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`, `PetscObjectListReverseFind()`, `PetscObjectListDuplicate()` 70 @*/ 71 PetscErrorCode PetscObjectListAdd(PetscObjectList *fl, const char name[], PetscObject obj) { 72 PetscObjectList olist, nlist, prev; 73 PetscBool match; 74 75 PetscFunctionBegin; 76 PetscValidPointer(fl, 1); 77 if (!obj) { /* this means remove from list if it is there */ 78 nlist = *fl; 79 prev = NULL; 80 while (nlist) { 81 PetscCall(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) PetscCall(PetscObjectDereference(nlist->obj)); 88 PetscCall(PetscFree(nlist)); 89 PetscFunctionReturn(0); 90 } 91 prev = nlist; 92 nlist = nlist->next; 93 } 94 PetscFunctionReturn(0); /* did not find it to remove */ 95 } 96 /* look for it already in list */ 97 nlist = *fl; 98 while (nlist) { 99 PetscCall(PetscStrcmp(name, nlist->name, &match)); 100 if (match) { /* found it in the list */ 101 PetscCall(PetscObjectReference(obj)); 102 if (!nlist->skipdereference) PetscCall(PetscObjectDereference(nlist->obj)); 103 nlist->skipdereference = PETSC_FALSE; 104 nlist->obj = obj; 105 PetscFunctionReturn(0); 106 } 107 nlist = nlist->next; 108 } 109 110 /* add it to list, because it was not already there */ 111 PetscCall(PetscNew(&olist)); 112 olist->next = NULL; 113 olist->obj = obj; 114 115 PetscCall(PetscObjectReference(obj)); 116 PetscCall(PetscStrcpy(olist->name, name)); 117 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 PetscFunctionReturn(0); 124 } 125 126 /*@C 127 PetscObjectListDestroy - Destroy a list of objects 128 129 Input Parameter: 130 . ifl - pointer to list 131 132 Level: developer 133 134 .seealso: `PetscObjectListAdd()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`, `PetscObjectListReverseFind()`, `PetscObjectListDuplicate()` 135 @*/ 136 PetscErrorCode PetscObjectListDestroy(PetscObjectList *ifl) { 137 PetscObjectList tmp, fl; 138 139 PetscFunctionBegin; 140 PetscValidPointer(ifl, 1); 141 fl = *ifl; 142 while (fl) { 143 tmp = fl->next; 144 if (!fl->skipdereference) PetscCall(PetscObjectDereference(fl->obj)); 145 PetscCall(PetscFree(fl)); 146 fl = tmp; 147 } 148 *ifl = NULL; 149 PetscFunctionReturn(0); 150 } 151 152 /*@C 153 PetscObjectListFind - givn a name, find the matching object 154 155 Input Parameters: 156 + fl - pointer to list 157 - name - name string 158 159 Output Parameters: 160 . obj - the PETSc object 161 162 Level: developer 163 164 Notes: 165 The name must have been registered with the `PetscObjectListAdd()` before calling this routine. 166 167 The reference count of the object is not increased 168 169 .seealso: `PetscObjectListDestroy()`, `PetscObjectListAdd()`, `PetscObjectListDuplicate()`, `PetscObjectListReverseFind()`, `PetscObjectListDuplicate()` 170 @*/ 171 PetscErrorCode PetscObjectListFind(PetscObjectList fl, const char name[], PetscObject *obj) { 172 PetscFunctionBegin; 173 PetscValidPointer(obj, 3); 174 *obj = NULL; 175 while (fl) { 176 PetscBool match; 177 PetscCall(PetscStrcmp(name, fl->name, &match)); 178 if (match) { 179 *obj = fl->obj; 180 break; 181 } 182 fl = fl->next; 183 } 184 PetscFunctionReturn(0); 185 } 186 187 /*@C 188 PetscObjectListReverseFind - given a object, find the matching name if it exists 189 190 Input Parameters: 191 + fl - pointer to list 192 - obj - the PETSc object 193 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 197 198 Level: developer 199 200 Notes: 201 The name must have been registered with the `PetscObjectListAdd()` before calling this routine. 202 203 The reference count of the object is not increased 204 205 .seealso: `PetscObjectListDestroy()`, `PetscObjectListAdd()`, `PetscObjectListDuplicate()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()` 206 @*/ 207 PetscErrorCode PetscObjectListReverseFind(PetscObjectList fl, PetscObject obj, char **name, PetscBool *skipdereference) { 208 PetscFunctionBegin; 209 PetscValidPointer(name, 3); 210 if (skipdereference) PetscValidBoolPointer(skipdereference, 4); 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 PetscFunctionReturn(0); 221 } 222 223 /*@C 224 PetscObjectListDuplicate - Creates a new list from a given object list. 225 226 Input Parameters: 227 . fl - pointer to list 228 229 Output Parameters: 230 . nl - the new list (should point to 0 to start, otherwise appends) 231 232 Level: developer 233 234 .seealso: `PetscObjectListDestroy()`, `PetscObjectListAdd()`, `PetscObjectListReverseFind()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()` 235 @*/ 236 PetscErrorCode PetscObjectListDuplicate(PetscObjectList fl, PetscObjectList *nl) { 237 PetscFunctionBegin; 238 PetscValidPointer(nl, 2); 239 while (fl) { 240 PetscCall(PetscObjectListAdd(nl, fl->name, fl->obj)); 241 fl = fl->next; 242 } 243 PetscFunctionReturn(0); 244 } 245