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 { 36 PetscObjectList nlist; 37 PetscBool match; 38 39 PetscFunctionBegin; 40 PetscValidPointer(fl, 1); 41 PetscValidCharPointer(name, 2); 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(0); 49 } 50 nlist = nlist->next; 51 } 52 PetscFunctionReturn(0); 53 } 54 55 /*@C 56 PetscObjectListAdd - Adds a new object to an `PetscObjectList` 57 58 Input Parameters: 59 + fl - the object list 60 . name - the name to use for the object 61 - obj - the object to attach 62 63 Level: developer 64 65 Notes: 66 Replaces item if it is already in list. Removes item if you pass in a NULL object. 67 68 Use `PetscObjectListFind()` or `PetscObjectListReverseFind()` to get the object back 69 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; 76 77 PetscFunctionBegin; 78 PetscValidPointer(fl, 1); 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(0); 92 } 93 prev = nlist; 94 nlist = nlist->next; 95 } 96 PetscFunctionReturn(0); /* 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(0); 108 } 109 nlist = nlist->next; 110 } 111 112 /* add it to list, because it was not already there */ 113 PetscCall(PetscNew(&olist)); 114 olist->next = NULL; 115 olist->obj = obj; 116 117 PetscCall(PetscObjectReference(obj)); 118 PetscCall(PetscStrcpy(olist->name, name)); 119 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(0); 126 } 127 128 /*@C 129 PetscObjectListDestroy - Destroy a list of objects 130 131 Input Parameter: 132 . ifl - pointer to list 133 134 Level: developer 135 136 .seealso: `PetscObjectListAdd()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`, `PetscObjectListReverseFind()`, `PetscObjectListDuplicate()` 137 @*/ 138 PetscErrorCode PetscObjectListDestroy(PetscObjectList *ifl) 139 { 140 PetscObjectList tmp, fl; 141 142 PetscFunctionBegin; 143 PetscValidPointer(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(0); 153 } 154 155 /*@C 156 PetscObjectListFind - givn a name, find the matching object 157 158 Input Parameters: 159 + fl - pointer to list 160 - name - name string 161 162 Output Parameters: 163 . obj - the PETSc object 164 165 Level: developer 166 167 Notes: 168 The name must have been registered with the `PetscObjectListAdd()` before calling this routine. 169 170 The reference count of the object is not increased 171 172 .seealso: `PetscObjectListDestroy()`, `PetscObjectListAdd()`, `PetscObjectListDuplicate()`, `PetscObjectListReverseFind()`, `PetscObjectListDuplicate()` 173 @*/ 174 PetscErrorCode PetscObjectListFind(PetscObjectList fl, const char name[], PetscObject *obj) 175 { 176 PetscFunctionBegin; 177 PetscValidPointer(obj, 3); 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(0); 189 } 190 191 /*@C 192 PetscObjectListReverseFind - given a object, find the matching name if it exists 193 194 Input Parameters: 195 + fl - pointer to list 196 - obj - the PETSc object 197 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 201 202 Level: developer 203 204 Notes: 205 The name must have been registered with the `PetscObjectListAdd()` before calling this routine. 206 207 The reference count of the object is not increased 208 209 .seealso: `PetscObjectListDestroy()`, `PetscObjectListAdd()`, `PetscObjectListDuplicate()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()` 210 @*/ 211 PetscErrorCode PetscObjectListReverseFind(PetscObjectList fl, PetscObject obj, char **name, PetscBool *skipdereference) 212 { 213 PetscFunctionBegin; 214 PetscValidPointer(name, 3); 215 if (skipdereference) PetscValidBoolPointer(skipdereference, 4); 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(0); 226 } 227 228 /*@C 229 PetscObjectListDuplicate - Creates a new list from a given object list. 230 231 Input Parameters: 232 . fl - pointer to list 233 234 Output Parameters: 235 . nl - the new list (should point to 0 to start, otherwise appends) 236 237 Level: developer 238 239 .seealso: `PetscObjectListDestroy()`, `PetscObjectListAdd()`, `PetscObjectListReverseFind()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()` 240 @*/ 241 PetscErrorCode PetscObjectListDuplicate(PetscObjectList fl, PetscObjectList *nl) 242 { 243 PetscFunctionBegin; 244 PetscValidPointer(nl, 2); 245 while (fl) { 246 PetscCall(PetscObjectListAdd(nl, fl->name, fl->obj)); 247 fl = fl->next; 248 } 249 PetscFunctionReturn(0); 250 } 251