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 Notes: 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()`, 33 `PetscObject`, `PetscObjectListAdd()` 34 @*/ 35 PetscErrorCode PetscObjectListRemoveReference(PetscObjectList *fl, const char name[]) 36 { 37 PetscObjectList nlist; 38 PetscBool match; 39 40 PetscFunctionBegin; 41 PetscValidPointer(fl, 1); 42 PetscValidCharPointer(name, 2); 43 nlist = *fl; 44 while (nlist) { 45 PetscCall(PetscStrcmp(name, nlist->name, &match)); 46 if (match) { /* found it in the list */ 47 if (!nlist->skipdereference) PetscCall(PetscObjectDereference(nlist->obj)); 48 nlist->skipdereference = PETSC_TRUE; 49 PetscFunctionReturn(PETSC_SUCCESS); 50 } 51 nlist = nlist->next; 52 } 53 PetscFunctionReturn(PETSC_SUCCESS); 54 } 55 56 /*@C 57 PetscObjectListAdd - Adds a new object to an `PetscObjectList` 58 59 Input Parameters: 60 + fl - the object list 61 . name - the name to use for the object 62 - obj - the object to attach 63 64 Level: developer 65 66 Notes: 67 Replaces item if it is already in list. Removes item if you pass in a `NULL` object. 68 69 Use `PetscObjectListFind()` or `PetscObjectListReverseFind()` to get the object back 70 71 .seealso: `PetscObjectListDestroy()`,`PetscObjectListFind()`,`PetscObjectListDuplicate()`,`PetscObjectListReverseFind()`, `PetscObject`, `PetscObjectList` 72 @*/ 73 PetscErrorCode PetscObjectListAdd(PetscObjectList *fl, const char name[], PetscObject obj) 74 { 75 PetscObjectList olist, nlist, prev; 76 PetscBool match; 77 78 PetscFunctionBegin; 79 PetscValidPointer(fl, 1); 80 if (!obj) { /* this means remove from list if it is there */ 81 nlist = *fl; 82 prev = NULL; 83 while (nlist) { 84 PetscCall(PetscStrcmp(name, nlist->name, &match)); 85 if (match) { /* found it already in the list */ 86 /* Remove it first to prevent circular derefs */ 87 if (prev) prev->next = nlist->next; 88 else if (nlist->next) *fl = nlist->next; 89 else *fl = NULL; 90 if (!nlist->skipdereference) PetscCall(PetscObjectDereference(nlist->obj)); 91 PetscCall(PetscFree(nlist)); 92 PetscFunctionReturn(PETSC_SUCCESS); 93 } 94 prev = nlist; 95 nlist = nlist->next; 96 } 97 PetscFunctionReturn(PETSC_SUCCESS); /* did not find it to remove */ 98 } 99 /* look for it already in list */ 100 nlist = *fl; 101 while (nlist) { 102 PetscCall(PetscStrcmp(name, nlist->name, &match)); 103 if (match) { /* found it in the list */ 104 PetscCall(PetscObjectReference(obj)); 105 if (!nlist->skipdereference) PetscCall(PetscObjectDereference(nlist->obj)); 106 nlist->skipdereference = PETSC_FALSE; 107 nlist->obj = obj; 108 PetscFunctionReturn(PETSC_SUCCESS); 109 } 110 nlist = nlist->next; 111 } 112 113 /* add it to list, because it was not already there */ 114 PetscCall(PetscNew(&olist)); 115 olist->next = NULL; 116 olist->obj = obj; 117 118 PetscCall(PetscObjectReference(obj)); 119 PetscCall(PetscStrncpy(olist->name, name, sizeof(olist->name))); 120 121 if (!*fl) *fl = olist; 122 else { /* go to end of list */ nlist = *fl; 123 while (nlist->next) nlist = nlist->next; 124 nlist->next = olist; 125 } 126 PetscFunctionReturn(PETSC_SUCCESS); 127 } 128 129 /*@C 130 PetscObjectListDestroy - Destroy a list of objects 131 132 Input Parameter: 133 . ifl - pointer to list 134 135 Level: developer 136 137 .seealso: `PetscObjectList`, `PetscObject`, `PetscObjectListAdd()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`, 138 `PetscObjectListReverseFind()` 139 @*/ 140 PetscErrorCode PetscObjectListDestroy(PetscObjectList *ifl) 141 { 142 PetscObjectList tmp, fl; 143 144 PetscFunctionBegin; 145 PetscValidPointer(ifl, 1); 146 fl = *ifl; 147 while (fl) { 148 tmp = fl->next; 149 if (!fl->skipdereference) PetscCall(PetscObjectDereference(fl->obj)); 150 PetscCall(PetscFree(fl)); 151 fl = tmp; 152 } 153 *ifl = NULL; 154 PetscFunctionReturn(PETSC_SUCCESS); 155 } 156 157 /*@C 158 PetscObjectListFind - given a name, find the matching object in a list 159 160 Input Parameters: 161 + fl - pointer to list 162 - name - name string 163 164 Output Parameter: 165 . obj - the PETSc object 166 167 Level: developer 168 169 Notes: 170 The name must have been registered with the `PetscObjectListAdd()` before calling this routine. 171 172 The reference count of the object is not increased 173 174 .seealso: `PetscObjectListDestroy()`,`PetscObjectListAdd()`,`PetscObjectListDuplicate()`,`PetscObjectListReverseFind()`, `PetscObjectList` 175 @*/ 176 PetscErrorCode PetscObjectListFind(PetscObjectList fl, const char name[], PetscObject *obj) 177 { 178 PetscFunctionBegin; 179 PetscValidPointer(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 } 192 193 /*@C 194 PetscObjectListReverseFind - given a object, find the matching name if it exists 195 196 Input Parameters: 197 + fl - pointer to list 198 - obj - the PETSc object 199 200 Output Parameters: 201 + name - name string 202 - skipdereference - if the object is in list but does not have the increased reference count for a circular dependency 203 204 Level: developer 205 206 Notes: 207 The name must have been registered with the `PetscObjectListAdd()` before calling this routine. 208 209 The reference count of the object is not increased 210 211 .seealso: `PetscObjectListDestroy()`,`PetscObjectListAdd()`,`PetscObjectListDuplicate()`,`PetscObjectListFind()`, `PetscObjectList` 212 @*/ 213 PetscErrorCode PetscObjectListReverseFind(PetscObjectList fl, PetscObject obj, char **name, PetscBool *skipdereference) 214 { 215 PetscFunctionBegin; 216 PetscValidPointer(name, 3); 217 if (skipdereference) PetscValidBoolPointer(skipdereference, 4); 218 *name = NULL; 219 while (fl) { 220 if (fl->obj == obj) { 221 *name = fl->name; 222 if (skipdereference) *skipdereference = fl->skipdereference; 223 break; 224 } 225 fl = fl->next; 226 } 227 PetscFunctionReturn(PETSC_SUCCESS); 228 } 229 230 /*@C 231 PetscObjectListDuplicate - Creates a new list from a given object list. 232 233 Input Parameter: 234 . fl - pointer to list 235 236 Output Parameter: 237 . nl - the new list (should point to `NULL` to start, otherwise appends) 238 239 Level: developer 240 241 .seealso: `PetscObjectListDestroy()`, `PetscObjectListAdd()`, `PetscObjectListReverseFind()`, 242 `PetscObjectListFind()`, `PetscObjectListDuplicate()`, `PetscObjectList` 243 @*/ 244 PetscErrorCode PetscObjectListDuplicate(PetscObjectList fl, PetscObjectList *nl) 245 { 246 PetscFunctionBegin; 247 PetscValidPointer(nl, 2); 248 while (fl) { 249 PetscCall(PetscObjectListAdd(nl, fl->name, fl->obj)); 250 fl = fl->next; 251 } 252 PetscFunctionReturn(PETSC_SUCCESS); 253 } 254