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