1 /* 2 Provides a general mechanism to maintain a linked list of PETSc objects. 3 This is used to allow PETSc objects to carry a list of "composed" objects 4 */ 5 #include <petsc/private/petscimpl.h> 6 7 /*@C 8 PetscObjectListRemoveReference - Calls `PetscObjectDereference()` on an object in the list immediately but keeps a pointer to the object in the list. 9 10 Input Parameters: 11 + fl - the object list 12 - name - the name to use for the object 13 14 Level: developer 15 16 Notes: 17 Use `PetscObjectListAdd`(`PetscObjectList`,const char name[],NULL) to truly remove the object from the list 18 19 Use this routine ONLY if you know that the object referenced will remain in existence until the pointing object is destroyed 20 21 Developer Notes: 22 This is to handle some cases that otherwise would result in having circular references so reference counts never got to zero 23 24 .seealso: `PetscObjectListDestroy()`,`PetscObjectListFind()`,`PetscObjectListDuplicate()`,`PetscObjectListReverseFind()`, 25 `PetscObject`, `PetscObjectListAdd()` 26 @*/ 27 PetscErrorCode PetscObjectListRemoveReference(PetscObjectList *fl, const char name[]) 28 { 29 PetscObjectList nlist; 30 PetscBool match; 31 32 PetscFunctionBegin; 33 PetscAssertPointer(fl, 1); 34 PetscAssertPointer(name, 2); 35 nlist = *fl; 36 while (nlist) { 37 PetscCall(PetscStrcmp(name, nlist->name, &match)); 38 if (match) { /* found it in the list */ 39 if (!nlist->skipdereference) PetscCall(PetscObjectDereference(nlist->obj)); 40 nlist->skipdereference = PETSC_TRUE; 41 PetscFunctionReturn(PETSC_SUCCESS); 42 } 43 nlist = nlist->next; 44 } 45 PetscFunctionReturn(PETSC_SUCCESS); 46 } 47 48 /*@C 49 PetscObjectListAdd - Adds a new object to an `PetscObjectList` 50 51 Input Parameters: 52 + fl - the object list 53 . name - the name to use for the object 54 - obj - the object to attach 55 56 Level: developer 57 58 Notes: 59 Replaces item if it is already in list. Removes item if you pass in a `NULL` object. 60 61 Use `PetscObjectListFind()` or `PetscObjectListReverseFind()` to get the object back 62 63 .seealso: `PetscObjectListDestroy()`,`PetscObjectListFind()`,`PetscObjectListDuplicate()`,`PetscObjectListReverseFind()`, `PetscObject`, `PetscObjectList` 64 @*/ 65 PetscErrorCode PetscObjectListAdd(PetscObjectList *fl, const char name[], PetscObject obj) 66 { 67 PetscObjectList olist, nlist, prev; 68 PetscBool match; 69 70 PetscFunctionBegin; 71 PetscAssertPointer(fl, 1); 72 if (!obj) { /* this means remove from list if it is there */ 73 nlist = *fl; 74 prev = NULL; 75 while (nlist) { 76 PetscCall(PetscStrcmp(name, nlist->name, &match)); 77 if (match) { /* found it already in the list */ 78 /* Remove it first to prevent circular derefs */ 79 if (prev) prev->next = nlist->next; 80 else if (nlist->next) *fl = nlist->next; 81 else *fl = NULL; 82 if (!nlist->skipdereference) PetscCall(PetscObjectDereference(nlist->obj)); 83 PetscCall(PetscFree(nlist)); 84 PetscFunctionReturn(PETSC_SUCCESS); 85 } 86 prev = nlist; 87 nlist = nlist->next; 88 } 89 PetscFunctionReturn(PETSC_SUCCESS); /* did not find it to remove */ 90 } 91 /* look for it already in list */ 92 nlist = *fl; 93 while (nlist) { 94 PetscCall(PetscStrcmp(name, nlist->name, &match)); 95 if (match) { /* found it in the list */ 96 PetscCall(PetscObjectReference(obj)); 97 if (!nlist->skipdereference) PetscCall(PetscObjectDereference(nlist->obj)); 98 nlist->skipdereference = PETSC_FALSE; 99 nlist->obj = obj; 100 PetscFunctionReturn(PETSC_SUCCESS); 101 } 102 nlist = nlist->next; 103 } 104 105 /* add it to list, because it was not already there */ 106 PetscCall(PetscNew(&olist)); 107 olist->next = NULL; 108 olist->obj = obj; 109 110 PetscCall(PetscObjectReference(obj)); 111 PetscCall(PetscStrncpy(olist->name, name, sizeof(olist->name))); 112 113 if (!*fl) *fl = olist; 114 else { /* go to end of list */ nlist = *fl; 115 while (nlist->next) nlist = nlist->next; 116 nlist->next = olist; 117 } 118 PetscFunctionReturn(PETSC_SUCCESS); 119 } 120 121 /*@C 122 PetscObjectListDestroy - Destroy a list of objects 123 124 Input Parameter: 125 . ifl - pointer to list 126 127 Level: developer 128 129 .seealso: `PetscObjectList`, `PetscObject`, `PetscObjectListAdd()`, `PetscObjectListFind()`, `PetscObjectListDuplicate()`, 130 `PetscObjectListReverseFind()` 131 @*/ 132 PetscErrorCode PetscObjectListDestroy(PetscObjectList *ifl) 133 { 134 PetscObjectList tmp, fl; 135 136 PetscFunctionBegin; 137 PetscAssertPointer(ifl, 1); 138 fl = *ifl; 139 while (fl) { 140 tmp = fl->next; 141 if (!fl->skipdereference) PetscCall(PetscObjectDereference(fl->obj)); 142 PetscCall(PetscFree(fl)); 143 fl = tmp; 144 } 145 *ifl = NULL; 146 PetscFunctionReturn(PETSC_SUCCESS); 147 } 148 149 /*@C 150 PetscObjectListFind - given a name, find the matching object in a list 151 152 Input Parameters: 153 + fl - pointer to list 154 - name - name string 155 156 Output Parameter: 157 . obj - the PETSc object 158 159 Level: developer 160 161 Notes: 162 The name must have been registered with the `PetscObjectListAdd()` before calling this routine. 163 164 The reference count of the object is not increased 165 166 .seealso: `PetscObjectListDestroy()`,`PetscObjectListAdd()`,`PetscObjectListDuplicate()`,`PetscObjectListReverseFind()`, `PetscObjectList` 167 @*/ 168 PetscErrorCode PetscObjectListFind(PetscObjectList fl, const char name[], PetscObject *obj) 169 { 170 PetscFunctionBegin; 171 PetscAssertPointer(obj, 3); 172 *obj = NULL; 173 while (fl) { 174 PetscBool match; 175 PetscCall(PetscStrcmp(name, fl->name, &match)); 176 if (match) { 177 *obj = fl->obj; 178 break; 179 } 180 fl = fl->next; 181 } 182 PetscFunctionReturn(PETSC_SUCCESS); 183 } 184 185 /*@C 186 PetscObjectListReverseFind - given a object, find the matching name if it exists 187 188 Input Parameters: 189 + fl - pointer to list 190 - obj - the PETSc object 191 192 Output Parameters: 193 + name - name string 194 - skipdereference - if the object is in list but does not have the increased reference count for a circular dependency 195 196 Level: developer 197 198 Notes: 199 The name must have been registered with the `PetscObjectListAdd()` before calling this routine. 200 201 The reference count of the object is not increased 202 203 .seealso: `PetscObjectListDestroy()`,`PetscObjectListAdd()`,`PetscObjectListDuplicate()`,`PetscObjectListFind()`, `PetscObjectList` 204 @*/ 205 PetscErrorCode PetscObjectListReverseFind(PetscObjectList fl, PetscObject obj, char **name, PetscBool *skipdereference) 206 { 207 PetscFunctionBegin; 208 PetscAssertPointer(name, 3); 209 if (skipdereference) PetscAssertPointer(skipdereference, 4); 210 *name = NULL; 211 while (fl) { 212 if (fl->obj == obj) { 213 *name = fl->name; 214 if (skipdereference) *skipdereference = fl->skipdereference; 215 break; 216 } 217 fl = fl->next; 218 } 219 PetscFunctionReturn(PETSC_SUCCESS); 220 } 221 222 /*@C 223 PetscObjectListDuplicate - Creates a new list from a given object list. 224 225 Input Parameter: 226 . fl - pointer to list 227 228 Output Parameter: 229 . nl - the new list (should point to `NULL` to start, otherwise appends) 230 231 Level: developer 232 233 .seealso: `PetscObjectListDestroy()`, `PetscObjectListAdd()`, `PetscObjectListReverseFind()`, 234 `PetscObjectListFind()`, `PetscObjectList` 235 @*/ 236 PetscErrorCode PetscObjectListDuplicate(PetscObjectList fl, PetscObjectList *nl) 237 { 238 PetscFunctionBegin; 239 PetscAssertPointer(nl, 2); 240 while (fl) { 241 PetscCall(PetscObjectListAdd(nl, fl->name, fl->obj)); 242 fl = fl->next; 243 } 244 PetscFunctionReturn(PETSC_SUCCESS); 245 } 246