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