summaryrefslogtreecommitdiffstats
path: root/src/H5Iint.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/H5Iint.c')
-rw-r--r--src/H5Iint.c1476
1 files changed, 1476 insertions, 0 deletions
diff --git a/src/H5Iint.c b/src/H5Iint.c
new file mode 100644
index 0000000..fa08253
--- /dev/null
+++ b/src/H5Iint.c
@@ -0,0 +1,1476 @@
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+ * Copyright by The HDF Group. *
+ * Copyright by the Board of Trustees of the University of Illinois. *
+ * All rights reserved. *
+ * *
+ * This file is part of HDF5. The full HDF5 copyright notice, including *
+ * terms governing use, modification, and redistribution, is contained in *
+ * the COPYING file, which can be found at the root of the source code *
+ * distribution tree, or in https://support.hdfgroup.org/ftp/HDF5/releases. *
+ * If you do not have access to either file, you may request a copy from *
+ * help@hdfgroup.org. *
+ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+/*
+ * H5Iint.c - Private routines for handling IDs
+ */
+
+/****************/
+/* Module Setup */
+/****************/
+
+#include "H5Imodule.h" /* This source code file is part of the H5I module */
+
+/***********/
+/* Headers */
+/***********/
+#include "H5private.h" /* Generic Functions */
+#include "H5Eprivate.h" /* Error handling */
+#include "H5FLprivate.h" /* Free Lists */
+#include "H5Ipkg.h" /* IDs */
+#include "H5MMprivate.h" /* Memory management */
+#include "H5SLprivate.h" /* Skip Lists */
+#include "H5Tprivate.h" /* Datatypes */
+#include "H5VLprivate.h" /* Virtual Object Layer */
+
+/****************/
+/* Local Macros */
+/****************/
+
+/* Combine a Type number and an ID index into an ID */
+#define H5I_MAKE(g, i) ((((hid_t)(g)&TYPE_MASK) << ID_BITS) | ((hid_t)(i)&ID_MASK))
+
+/******************/
+/* Local Typedefs */
+/******************/
+
+/* User data for iterator callback for retrieving an ID corresponding to an object pointer */
+typedef struct {
+ const void *object; /* object pointer to search for */
+ H5I_type_t obj_type; /* type of object we are searching for */
+ hid_t ret_id; /* ID returned */
+} H5I_get_id_ud_t;
+
+/* User data for iterator callback for ID iteration */
+typedef struct {
+ H5I_search_func_t user_func; /* 'User' function to invoke */
+ void * user_udata; /* User data to pass to 'user' function */
+ hbool_t app_ref; /* Whether this is an appl. ref. call */
+ H5I_type_t obj_type; /* Type of object we are iterating over */
+} H5I_iterate_ud_t;
+
+/* User data for H5I__clear_type_cb */
+typedef struct {
+ H5I_type_info_t *type_info; /* Pointer to the type's info to be cleared */
+ hbool_t force; /* Whether to always remove the ID */
+ hbool_t app_ref; /* Whether this is an appl. ref. call */
+} H5I_clear_type_ud_t;
+
+/********************/
+/* Package Typedefs */
+/********************/
+
+/********************/
+/* Local Prototypes */
+/********************/
+
+static void * H5I__unwrap(void *object, H5I_type_t type);
+static htri_t H5I__clear_type_cb(void *_id, void *key, void *udata);
+static void * H5I__remove_common(H5I_type_info_t *type_info, hid_t id);
+static int H5I__find_id_cb(void *_item, void *_key, void *_udata);
+
+/*********************/
+/* Package Variables */
+/*********************/
+
+/* Package initialization variable */
+hbool_t H5_PKG_INIT_VAR = FALSE;
+
+/* Declared extern in H5Ipkg.h and documented there */
+H5I_type_info_t *H5I_type_info_array_g[H5I_MAX_NUM_TYPES];
+int H5I_next_type_g = (int)H5I_NTYPES;
+
+/* Declare a free list to manage the H5I_id_info_t struct */
+H5FL_DEFINE_STATIC(H5I_id_info_t);
+
+/*****************************/
+/* Library Private Variables */
+/*****************************/
+
+/*******************/
+/* Local Variables */
+/*******************/
+
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_term_package
+ *
+ * Purpose: Terminate the H5I interface: release all memory, reset all
+ * global variables to initial values. This only happens if all
+ * types have been destroyed from other interfaces.
+ *
+ * Return: Success: Positive if any action was taken that might
+ * affect some other interface; zero otherwise.
+ *
+ * Failure: Negative
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5I_term_package(void)
+{
+ int in_use = 0; /* Number of ID types still in use */
+
+ FUNC_ENTER_NOAPI_NOINIT_NOERR
+
+ if (H5_PKG_INIT_VAR) {
+ H5I_type_info_t *type_info = NULL; /* Pointer to ID type */
+ int i;
+
+ /* Count the number of types still in use */
+ for (i = 0; i < H5I_next_type_g; i++)
+ if ((type_info = H5I_type_info_array_g[i]) && type_info->ids)
+ in_use++;
+
+ /* If no types are still being used then clean up */
+ if (0 == in_use) {
+ for (i = 0; i < H5I_next_type_g; i++) {
+ type_info = H5I_type_info_array_g[i];
+ if (type_info) {
+ HDassert(NULL == type_info->ids);
+ type_info = H5MM_xfree(type_info);
+ H5I_type_info_array_g[i] = NULL;
+ in_use++;
+ }
+ }
+
+ /* Mark interface closed */
+ if (0 == in_use)
+ H5_PKG_INIT_VAR = FALSE;
+ }
+ }
+
+ FUNC_LEAVE_NOAPI(in_use)
+} /* end H5I_term_package() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_register_type
+ *
+ * Purpose: Creates a new type of ID's to give out.
+ * The class is initialized or its reference count is incremented
+ * (if it is already initialized).
+ *
+ * Return: SUCCEED/FAIL
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5I_register_type(const H5I_class_t *cls)
+{
+ H5I_type_info_t *type_info = NULL; /* Pointer to the ID type*/
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Sanity check */
+ HDassert(cls);
+ HDassert(cls->type > 0 && (int)cls->type < H5I_MAX_NUM_TYPES);
+
+ /* Initialize the type */
+ if (NULL == H5I_type_info_array_g[cls->type]) {
+ /* Allocate the type information for new type */
+ if (NULL == (type_info = (H5I_type_info_t *)H5MM_calloc(sizeof(H5I_type_info_t))))
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTALLOC, FAIL, "ID type allocation failed")
+ H5I_type_info_array_g[cls->type] = type_info;
+ }
+ else {
+ /* Get the pointer to the existing type */
+ type_info = H5I_type_info_array_g[cls->type];
+ }
+
+ /* Initialize the ID type structure for new types */
+ if (type_info->init_count == 0) {
+ type_info->cls = cls;
+ type_info->id_count = 0;
+ type_info->nextid = cls->reserved;
+ type_info->last_id_info = NULL;
+ if (NULL == (type_info->ids = H5SL_create(H5SL_TYPE_HID, NULL)))
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTCREATE, FAIL, "skip list creation failed")
+ }
+
+ /* Increment the count of the times this type has been initialized */
+ type_info->init_count++;
+
+done:
+ /* Clean up on error */
+ if (ret_value < 0) {
+ if (type_info) {
+ if (type_info->ids)
+ H5SL_close(type_info->ids);
+ H5MM_free(type_info);
+ }
+ }
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_register_type() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_nmembers
+ *
+ * Purpose: Returns the number of members in a type.
+ *
+ * Return: Success: Number of members; zero if the type is empty
+ * or has been deleted.
+ *
+ * Failure: Negative
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, March 24, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+int64_t
+H5I_nmembers(H5I_type_t type)
+{
+ H5I_type_info_t *type_info = NULL; /* Pointer to the ID type */
+ int64_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI((-1))
+
+ /* Validate parameter */
+ if (type <= H5I_BADID || (int)type >= H5I_next_type_g)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number")
+ if (NULL == (type_info = H5I_type_info_array_g[type]) || type_info->init_count <= 0)
+ HGOTO_DONE(0);
+
+ /* Set return value */
+ H5_CHECKED_ASSIGN(ret_value, int64_t, type_info->id_count, uint64_t);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_nmembers() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5I__unwrap
+ *
+ * Purpose: Unwraps the object pointer for the 'item' that corresponds
+ * to an ID.
+ *
+ * Return: Pointer to the unwrapped pointer (can't fail)
+ *
+ * Programmer: Quincey Koziol
+ * Friday, October 19, 2018
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5I__unwrap(void *object, H5I_type_t type)
+{
+ void *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(object);
+
+ /* The stored object pointer might be an H5VL_object_t, in which
+ * case we'll need to get the wrapped object struct (H5F_t *, etc.).
+ */
+ if (H5I_FILE == type || H5I_GROUP == type || H5I_DATASET == type || H5I_ATTR == type) {
+ const H5VL_object_t *vol_obj;
+
+ vol_obj = (const H5VL_object_t *)object;
+ ret_value = H5VL_object_data(vol_obj);
+ }
+ else if (H5I_DATATYPE == type) {
+ H5T_t *dt = (H5T_t *)object;
+
+ ret_value = (void *)H5T_get_actual_type(dt);
+ }
+ else
+ ret_value = object;
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I__unwrap() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_clear_type
+ *
+ * Purpose: Removes all objects from the type, calling the free
+ * function for each object regardless of the reference count.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Robb Matzke
+ * Wednesday, March 24, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5I_clear_type(H5I_type_t type, hbool_t force, hbool_t app_ref)
+{
+ H5I_clear_type_ud_t udata; /* udata struct for callback */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Validate parameters */
+ if (type <= H5I_BADID || (int)type >= H5I_next_type_g)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number")
+
+ udata.type_info = H5I_type_info_array_g[type];
+ if (udata.type_info == NULL || udata.type_info->init_count <= 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, FAIL, "invalid type")
+
+ /* Finish constructing udata */
+ udata.force = force;
+ udata.app_ref = app_ref;
+
+ /* Attempt to free all ids in the type */
+ if (H5SL_try_free_safe(udata.type_info->ids, H5I__clear_type_cb, &udata) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTDELETE, FAIL, "can't free ids in type")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_clear_type() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5I__clear_type_cb
+ *
+ * Purpose: Attempts to free the specified ID, calling the free
+ * function for the object.
+ *
+ * Return: TRUE/FALSE/FAIL
+ *
+ * Programmer: Neil Fortner
+ * Friday, July 10, 2015
+ *
+ *-------------------------------------------------------------------------
+ */
+static htri_t
+H5I__clear_type_cb(void *_info, void H5_ATTR_UNUSED *key, void *_udata)
+{
+ H5I_id_info_t * info = (H5I_id_info_t *)_info; /* Current ID info being worked with */
+ H5I_clear_type_ud_t *udata = (H5I_clear_type_ud_t *)_udata; /* udata struct */
+ htri_t ret_value = FALSE; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity checks */
+ HDassert(info);
+ HDassert(udata);
+ HDassert(udata->type_info);
+
+ /* Do nothing to the object if the reference count is larger than
+ * one and forcing is off.
+ */
+ if (udata->force || (info->count - (!udata->app_ref * info->app_count)) <= 1) {
+ /* Check for a 'free' function and call it, if it exists */
+ H5_GCC_DIAG_OFF("cast-qual")
+ if (udata->type_info->cls->free_func &&
+ (udata->type_info->cls->free_func)((void *)info->object) < 0) { /* (Casting away const OK -QAK) */
+ if (udata->force) {
+#ifdef H5I_DEBUG
+ if (H5DEBUG(I)) {
+ HDfprintf(H5DEBUG(I),
+ "H5I: free type=%d obj=0x%08lx "
+ "failure ignored\n",
+ (int)udata->type_info->cls->type, (unsigned long)(info->object));
+ }
+#endif /* H5I_DEBUG */
+
+ /* Indicate node should be removed from list */
+ ret_value = TRUE;
+ }
+ }
+ else {
+ /* Indicate node should be removed from list */
+ ret_value = TRUE;
+ }
+ H5_GCC_DIAG_ON("cast-qual")
+
+ /* Remove ID if requested */
+ if (ret_value) {
+ /* Free ID info */
+ info = H5FL_FREE(H5I_id_info_t, info);
+
+ /* Decrement the number of IDs in the type */
+ udata->type_info->id_count--;
+ }
+ }
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I__clear_type_cb() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5I__destroy_type
+ *
+ * Purpose: Destroys a type along with all IDs in that type
+ * regardless of their reference counts. Destroying IDs
+ * involves calling the free-func for each ID's object and
+ * then adding the ID struct to the ID free list.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ * Programmer: Nathaniel Furrer
+ * James Laird
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5I__destroy_type(H5I_type_t type)
+{
+ H5I_type_info_t *type_info = NULL; /* Pointer to the ID type */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_PACKAGE
+
+ /* Validate parameter */
+ if (type <= H5I_BADID || (int)type >= H5I_next_type_g)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number")
+
+ type_info = H5I_type_info_array_g[type];
+ if (type_info == NULL || type_info->init_count <= 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, FAIL, "invalid type")
+
+ /* Close/clear/destroy all IDs for this type */
+ H5E_BEGIN_TRY {
+ H5I_clear_type(type, TRUE, FALSE);
+ } H5E_END_TRY /* don't care about errors */
+
+ /* Check if we should release the ID class */
+ if (type_info->cls->flags & H5I_CLASS_IS_APPLICATION)
+ type_info->cls = H5MM_xfree_const(type_info->cls);
+
+ if (H5SL_close(type_info->ids) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTCLOSEOBJ, FAIL, "can't close skip list")
+ type_info->ids = NULL;
+
+ type_info = H5MM_xfree(type_info);
+
+ H5I_type_info_array_g[type] = NULL;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I__destroy_type() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_register
+ *
+ * Purpose: Registers an OBJECT in a TYPE and returns an ID for it.
+ * This routine does _not_ check for unique-ness of the objects,
+ * if you register an object twice, you will get two different
+ * IDs for it. This routine does make certain that each ID in a
+ * type is unique. IDs are created by getting a unique number
+ * for the type the ID is in and incorporating the type into
+ * the ID which is returned to the user.
+ *
+ * Return: Success: New object ID
+ * Failure: H5I_INVALID_HID
+ *
+ *-------------------------------------------------------------------------
+ */
+hid_t
+H5I_register(H5I_type_t type, const void *object, hbool_t app_ref)
+{
+ H5I_type_info_t *type_info = NULL; /* Pointer to the type */
+ H5I_id_info_t *info = NULL; /* Pointer to the new ID information */
+ hid_t new_id = H5I_INVALID_HID; /* New ID */
+ hid_t ret_value = H5I_INVALID_HID; /* Return value */
+
+ FUNC_ENTER_NOAPI(H5I_INVALID_HID)
+
+ /* Check arguments */
+ if (type <= H5I_BADID || (int)type >= H5I_next_type_g)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, H5I_INVALID_HID, "invalid type number")
+ type_info = H5I_type_info_array_g[type];
+ if ((NULL == type_info) || (type_info->init_count <= 0))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, H5I_INVALID_HID, "invalid type")
+ if (NULL == (info = H5FL_MALLOC(H5I_id_info_t)))
+ HGOTO_ERROR(H5E_ATOM, H5E_NOSPACE, H5I_INVALID_HID, "memory allocation failed")
+
+ /* Create the struct & its ID */
+ new_id = H5I_MAKE(type, type_info->nextid);
+ info->id = new_id;
+ info->count = 1; /* initial reference count */
+ info->app_count = !!app_ref;
+ info->object = object;
+
+ /* Insert into the type */
+ if (H5SL_insert(type_info->ids, info, &info->id) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTINSERT, H5I_INVALID_HID, "can't insert ID node into skip list")
+ type_info->id_count++;
+ type_info->nextid++;
+
+ /* Sanity check for the 'nextid' getting too large and wrapping around */
+ HDassert(type_info->nextid <= ID_MASK);
+
+ /* Set the most recent ID to this object */
+ type_info->last_id_info = info;
+
+ /* Set return value */
+ ret_value = new_id;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_register() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_register_using_existing_id
+ *
+ * Purpose: Registers an OBJECT in a TYPE with the supplied ID for it.
+ * This routine will check to ensure the supplied ID is not already
+ * in use, and ensure that it is a valid ID for the given type,
+ * but will NOT check to ensure the OBJECT is not already
+ * registered (thus, it is possible to register one object under
+ * multiple IDs).
+ *
+ * NOTE: Intended for use in refresh calls, where we have to close
+ * and re-open the underlying data, then hook the object back
+ * up to the original ID.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5I_register_using_existing_id(H5I_type_t type, void *object, hbool_t app_ref, hid_t existing_id)
+{
+ H5I_type_info_t *type_info = NULL; /* Pointer to the type */
+ H5I_id_info_t *info = NULL; /* Pointer to the new ID information */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments */
+ HDassert(object);
+
+ /* Make sure ID is not already in use */
+ if (NULL != (info = H5I__find_id(existing_id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADRANGE, FAIL, "ID already in use")
+
+ /* Make sure type number is valid */
+ if (type <= H5I_BADID || (int)type >= H5I_next_type_g)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number")
+
+ /* Get type pointer from list of types */
+ type_info = H5I_type_info_array_g[type];
+
+ if (NULL == type_info || type_info->init_count <= 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, FAIL, "invalid type")
+
+ /* Make sure requested ID belongs to object's type */
+ if (H5I_TYPE(existing_id) != type)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADRANGE, FAIL, "invalid type for provided ID")
+
+ /* Allocate new structure to house this ID */
+ if (NULL == (info = H5FL_MALLOC(H5I_id_info_t)))
+ HGOTO_ERROR(H5E_ATOM, H5E_NOSPACE, FAIL, "memory allocation failed")
+
+ /* Create the struct & insert requested ID */
+ info->id = existing_id;
+ info->count = 1; /* initial reference count*/
+ info->app_count = !!app_ref;
+ info->object = object;
+
+ /* Insert into the type */
+ if (H5SL_insert(type_info->ids, info, &info->id) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTINSERT, FAIL, "can't insert ID node into skip list")
+ type_info->id_count++;
+
+ /* Set the most recent ID to this object */
+ type_info->last_id_info = info;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_register_using_existing_id() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_subst
+ *
+ * Purpose: Substitute a new object pointer for the specified ID.
+ *
+ * Return: Success: Non-NULL previous object pointer associated
+ * with the specified ID.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Saturday, February 27, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5I_subst(hid_t id, const void *new_object)
+{
+ H5I_id_info_t *info = NULL; /* Pointer to the ID's info */
+ void * ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* General lookup of the ID */
+ if (NULL == (info = H5I__find_id(id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_NOTFOUND, NULL, "can't get ID ref count")
+
+ /* Get the old object pointer to return */
+ H5_GCC_DIAG_OFF("cast-qual")
+ ret_value = (void *)info->object; /* (Casting away const OK -QAK) */
+ H5_GCC_DIAG_ON("cast-qual")
+
+ /* Set the new object pointer for the ID */
+ info->object = new_object;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_subst() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_object
+ *
+ * Purpose: Find an object pointer for the specified ID.
+ *
+ * Return: Success: Non-NULL object pointer associated with the
+ * specified ID
+ *
+ * Failure: NULL
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5I_object(hid_t id)
+{
+ H5I_id_info_t *info = NULL; /* Pointer to the ID info */
+ void * ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOERR
+
+ /* General lookup of the ID */
+ if (NULL != (info = H5I__find_id(id))) {
+ /* Get the object pointer to return */
+ H5_GCC_DIAG_OFF("cast-qual")
+ ret_value = (void *)info->object; /* (Casting away const OK -QAK) */
+ H5_GCC_DIAG_ON("cast-qual")
+ }
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_object() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_object_verify
+ *
+ * Purpose: Find an object pointer for the specified ID, verifying that
+ * its in a particular type.
+ *
+ * Return: Success: Non-NULL object pointer associated with the
+ * specified ID.
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * Wednesday, July 31, 2002
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5I_object_verify(hid_t id, H5I_type_t type)
+{
+ H5I_id_info_t *info = NULL; /* Pointer to the ID info */
+ void * ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOERR
+
+ HDassert(type >= 1 && (int)type < H5I_next_type_g);
+
+ /* Verify that the type of the ID is correct & lookup the ID */
+ if (type == H5I_TYPE(id) && NULL != (info = H5I__find_id(id))) {
+ /* Get the object pointer to return */
+ H5_GCC_DIAG_OFF("cast-qual")
+ ret_value = (void *)info->object; /* (Casting away const OK -QAK) */
+ H5_GCC_DIAG_ON("cast-qual")
+ }
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* H5I_object_verify() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_get_type
+ *
+ * Purpose: Given an object ID return the type to which it
+ * belongs. The ID need not be the ID of an object which
+ * currently exists because the type number is encoded
+ * in the object ID.
+ *
+ * Return: Success: A positive integer (corresponding to an H5I_type_t
+ * enum value for library ID types, but not for user
+ * ID types).
+ * Failure: H5I_BADID
+ *
+ * Programmer: Robb Matzke
+ * Friday, February 19, 1999
+ *
+ *-------------------------------------------------------------------------
+ */
+H5I_type_t
+H5I_get_type(hid_t id)
+{
+ H5I_type_t ret_value = H5I_BADID; /* Return value */
+
+ FUNC_ENTER_NOAPI_NOERR
+
+ if (id > 0)
+ ret_value = H5I_TYPE(id);
+
+ HDassert(ret_value >= H5I_BADID && (int)ret_value < H5I_next_type_g);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_get_type() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_is_file_object
+ *
+ * Purpose: Convenience function to determine if an ID represents
+ * a file object.
+ *
+ * In H5O calls, you can't use object_verify to ensure
+ * the ID was of the correct class since there's no
+ * H5I_OBJECT ID class.
+ *
+ * Return: Success: TRUE/FALSE
+ * Failure: FAIL
+ *
+ *-------------------------------------------------------------------------
+ */
+htri_t
+H5I_is_file_object(hid_t id)
+{
+ H5I_type_t type = H5I_get_type(id);
+ htri_t ret_value = FAIL;
+
+ FUNC_ENTER_NOAPI(FAIL);
+
+ /* Fail if the ID type is out of range */
+ if (type < 1 || type >= H5I_NTYPES)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "ID type out of range");
+
+ /* Return TRUE if the ID is a file object (dataset, group, map, or committed
+ * datatype), FALSE otherwise.
+ */
+ if (H5I_DATASET == type || H5I_GROUP == type || H5I_MAP == type)
+ ret_value = TRUE;
+ else if (H5I_DATATYPE == type) {
+
+ H5T_t *dt = NULL;
+
+ if (NULL == (dt = (H5T_t *)H5I_object(id)))
+ HGOTO_ERROR(H5E_ARGS, H5E_BADTYPE, FAIL, "unable to get underlying datatype struct");
+
+ ret_value = H5T_is_named(dt);
+ }
+ else
+ ret_value = FALSE;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value);
+} /* H5I_is_file_object() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5I__remove_verify
+ *
+ * Purpose: Removes the specified ID from its type, first checking that
+ * the ID's type is the same as the ID type supplied as an argument
+ *
+ * Return: Success: A pointer to the object that was removed, the
+ * same pointer which would have been found by
+ * calling H5I_object().
+ * Failure: NULL
+ *
+ * Programmer: James Laird
+ * Nat Furrer
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5I__remove_verify(hid_t id, H5I_type_t type)
+{
+ void *ret_value = NULL; /*return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Argument checking will be performed by H5I_remove() */
+
+ /* Verify that the type of the ID is correct */
+ if (type == H5I_TYPE(id))
+ ret_value = H5I_remove(id);
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I__remove_verify() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5I__remove_common
+ *
+ * Purpose: Common code to remove a specified ID from its type.
+ *
+ * Return: Success: A pointer to the object that was removed, the
+ * same pointer which would have been found by
+ * calling H5I_object().
+ * Failure: NULL
+ *
+ * Programmer: Quincey Koziol
+ * October 3, 2013
+ *
+ *-------------------------------------------------------------------------
+ */
+static void *
+H5I__remove_common(H5I_type_info_t *type_info, hid_t id)
+{
+ H5I_id_info_t *info = NULL; /* Pointer to the current ID */
+ void * ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(type_info);
+
+ /* Get the ID node for the ID */
+ if (NULL == (info = (H5I_id_info_t *)H5SL_remove(type_info->ids, &id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTDELETE, NULL, "can't remove ID node from skip list")
+
+ /* Check if this ID was the last one accessed */
+ if (type_info->last_id_info == info)
+ type_info->last_id_info = NULL;
+
+ H5_GCC_DIAG_OFF("cast-qual")
+ ret_value = (void *)info->object; /* (Casting away const OK -QAK) */
+ H5_GCC_DIAG_ON("cast-qual")
+
+ info = H5FL_FREE(H5I_id_info_t, info);
+
+ /* Decrement the number of IDs in the type */
+ (type_info->id_count)--;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I__remove_common() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_remove
+ *
+ * Purpose: Removes the specified ID from its type.
+ *
+ * Return: Success: A pointer to the object that was removed, the
+ * same pointer which would have been found by
+ * calling H5I_object().
+ * Failure: NULL
+ *
+ *-------------------------------------------------------------------------
+ */
+void *
+H5I_remove(hid_t id)
+{
+ H5I_type_info_t *type_info = NULL; /* Pointer to the ID type */
+ H5I_type_t type = H5I_BADID; /* ID's type */
+ void * ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_NOAPI(NULL)
+
+ /* Check arguments */
+ type = H5I_TYPE(id);
+ if (type <= H5I_BADID || (int)type >= H5I_next_type_g)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, NULL, "invalid type number")
+ type_info = H5I_type_info_array_g[type];
+ if (type_info == NULL || type_info->init_count <= 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, NULL, "invalid type")
+
+ /* Remove the node from the type */
+ if (NULL == (ret_value = H5I__remove_common(type_info, id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTDELETE, NULL, "can't remove ID node")
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_remove() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_dec_ref
+ *
+ * Purpose: Decrements the number of references outstanding for an ID.
+ * This will fail if the type is not a reference counted type.
+ * The ID type's 'free' function will be called for the ID
+ * if the reference count for the ID reaches 0 and a free
+ * function has been defined at type creation time.
+ *
+ * Return: Success: New reference count
+ *
+ * Failure: -1
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5I_dec_ref(hid_t id)
+{
+ H5I_id_info_t *info = NULL; /* Pointer to the ID */
+ int ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI((-1))
+
+ /* Sanity check */
+ HDassert(id >= 0);
+
+ /* General lookup of the ID */
+ if (NULL == (info = H5I__find_id(id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, (-1), "can't locate ID")
+
+ /* If this is the last reference to the object then invoke the type's
+ * free method on the object. If the free method is undefined or
+ * successful then remove the object from the type; otherwise leave
+ * the object in the type without decrementing the reference
+ * count. If the reference count is more than one then decrement the
+ * reference count without calling the free method.
+ *
+ * Beware: the free method may call other H5I functions.
+ *
+ * If an object is closing, we can remove the ID even though the free
+ * method might fail. This can happen when a mandatory filter fails to
+ * write when a dataset is closed and the chunk cache is flushed to the
+ * file. We have to close the dataset anyway. (SLU - 2010/9/7)
+ */
+ if (1 == info->count) {
+ H5I_type_info_t *type_info; /*ptr to the type */
+
+ /* Get the ID's type */
+ type_info = H5I_type_info_array_g[H5I_TYPE(id)];
+
+ H5_GCC_DIAG_OFF("cast-qual")
+ /* (Casting away const OK -QAK) */
+ if (!type_info->cls->free_func || (type_info->cls->free_func)((void *)info->object) >= 0) {
+ /* Remove the node from the type */
+ if (NULL == H5I__remove_common(type_info, id))
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTDELETE, (-1), "can't remove ID node")
+ ret_value = 0;
+ }
+ else
+ ret_value = -1;
+ H5_GCC_DIAG_ON("cast-qual")
+ }
+ else {
+ --(info->count);
+ ret_value = (int)info->count;
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_dec_ref() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_dec_app_ref
+ *
+ * Purpose: H5I_dec_ref wrapper for case of modifying the application ref.
+ * count for an ID as well as normal reference count.
+ *
+ * Return: Success: New app. reference count
+ * Failure: -1
+ *
+ * Programmer: Quincey Koziol
+ * Sept 16, 2010
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5I_dec_app_ref(hid_t id)
+{
+ H5I_id_info_t *info = NULL; /* Pointer to the ID info */
+ int ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI((-1))
+
+ /* Sanity check */
+ HDassert(id >= 0);
+
+ /* Call regular decrement reference count routine */
+ if ((ret_value = H5I_dec_ref(id)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTDEC, (-1), "can't decrement ID ref count")
+
+ /* Check if the ID still exists */
+ if (ret_value > 0) {
+ /* General lookup of the ID */
+ if (NULL == (info = H5I__find_id(id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, (-1), "can't locate ID")
+
+ /* Adjust app_ref */
+ --(info->app_count);
+ HDassert(info->count >= info->app_count);
+
+ /* Set return value */
+ ret_value = (int)info->app_count;
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_dec_app_ref() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_dec_app_ref_always_close
+ *
+ * Purpose: H5I_dec_app_ref wrapper for case of always closing the ID,
+ * even when the free routine fails
+ *
+ * Return: Success: New app. reference count
+ * Failure: -1
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5I_dec_app_ref_always_close(hid_t id)
+{
+ int ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI((-1))
+
+ /* Sanity check */
+ HDassert(id >= 0);
+
+ /* Call application decrement reference count routine */
+ ret_value = H5I_dec_app_ref(id);
+
+ /* Check for failure */
+ if (ret_value < 0) {
+ /*
+ * If an object is closing, we can remove the ID even though the free
+ * method might fail. This can happen when a mandatory filter fails to
+ * write when a dataset is closed and the chunk cache is flushed to the
+ * file. We have to close the dataset anyway. (SLU - 2010/9/7)
+ */
+ H5I_remove(id);
+
+ HGOTO_ERROR(H5E_ATOM, H5E_CANTDEC, (-1), "can't decrement ID ref count")
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_dec_app_ref_always_close() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_inc_ref
+ *
+ * Purpose: Increment the reference count for an object.
+ *
+ * Return: Success: The new reference count
+ * Failure: -1
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5I_inc_ref(hid_t id, hbool_t app_ref)
+{
+ H5I_id_info_t *info = NULL; /* Pointer to the ID info */
+ int ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI((-1))
+
+ /* Sanity check */
+ HDassert(id >= 0);
+
+ /* General lookup of the ID */
+ if (NULL == (info = H5I__find_id(id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, (-1), "can't locate ID")
+
+ /* Adjust reference counts */
+ ++(info->count);
+ if (app_ref)
+ ++(info->app_count);
+
+ /* Set return value */
+ ret_value = (int)(app_ref ? info->app_count : info->count);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_inc_ref() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_get_ref
+ *
+ * Purpose: Retrieve the reference count for an object.
+ *
+ * Return: Success: The reference count
+ * Failure: -1
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5I_get_ref(hid_t id, hbool_t app_ref)
+{
+ H5I_id_info_t *info = NULL; /* Pointer to the ID */
+ int ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI((-1))
+
+ /* Sanity check */
+ HDassert(id >= 0);
+
+ /* General lookup of the ID */
+ if (NULL == (info = H5I__find_id(id)))
+ HGOTO_ERROR(H5E_ATOM, H5E_BADATOM, (-1), "can't locate ID")
+
+ /* Set return value */
+ ret_value = (int)(app_ref ? info->app_count : info->count);
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_get_ref() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5I__inc_type_ref
+ *
+ * Purpose: Increment the reference count for an ID type.
+ *
+ * Return: Success: The new reference count
+ * Failure: -1
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5I__inc_type_ref(H5I_type_t type)
+{
+ H5I_type_info_t *type_info = NULL; /* Pointer to the type */
+ int ret_value = -1; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(type > 0 && (int)type < H5I_next_type_g);
+
+ /* Check arguments */
+ type_info = H5I_type_info_array_g[type];
+ if (NULL == type_info)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, (-1), "invalid type")
+
+ /* Set return value */
+ ret_value = (int)(++(type_info->init_count));
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I__inc_type_ref() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_dec_type_ref
+ *
+ * Purpose: Decrements the reference count on an entire type of IDs.
+ * If the type reference count becomes zero then the type is
+ * destroyed along with all IDs in that type regardless of
+ * their reference counts. Destroying IDs involves calling
+ * the free-func for each ID's object and then adding the ID
+ * struct to the ID free list.
+ * Returns the number of references to the type on success; a
+ * return value of 0 means that the type will have to be
+ * re-initialized before it can be used again (and should probably
+ * be set to H5I_UNINIT).
+ *
+ * Return: Success: Number of references to type
+ * Failure: -1
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5I_dec_type_ref(H5I_type_t type)
+{
+ H5I_type_info_t *type_info = NULL; /* Pointer to the ID type */
+ herr_t ret_value = 0; /* Return value */
+
+ FUNC_ENTER_NOAPI((-1))
+
+ if (type <= H5I_BADID || (int)type >= H5I_next_type_g)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, (-1), "invalid type number")
+
+ type_info = H5I_type_info_array_g[type];
+ if (type_info == NULL || type_info->init_count <= 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, (-1), "invalid type")
+
+ /* Decrement the number of users of the ID type. If this is the
+ * last user of the type then release all IDs from the type and
+ * free all memory it used. The free function is invoked for each ID
+ * being freed.
+ */
+ if (1 == type_info->init_count) {
+ H5I__destroy_type(type);
+ ret_value = 0;
+ }
+ else {
+ --(type_info->init_count);
+ ret_value = (herr_t)type_info->init_count;
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_dec_type_ref() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5I__get_type_ref
+ *
+ * Purpose: Retrieve the reference count for an ID type.
+ *
+ * Return: Success: The reference count
+ *
+ * Failure: -1
+ *
+ *-------------------------------------------------------------------------
+ */
+int
+H5I__get_type_ref(H5I_type_t type)
+{
+ H5I_type_info_t *type_info = NULL; /* Pointer to the type */
+ int ret_value = -1; /* Return value */
+
+ FUNC_ENTER_STATIC
+
+ /* Sanity check */
+ HDassert(type >= 0);
+
+ /* Check arguments */
+ type_info = H5I_type_info_array_g[type];
+ if (!type_info)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, (-1), "invalid type")
+
+ /* Set return value */
+ ret_value = (int)type_info->init_count;
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I__get_type_ref() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5I__iterate_cb
+ *
+ * Purpose: Callback routine for H5I_iterate, invokes "user" callback
+ * function, and then sets return value, based on the result of
+ * that callback.
+ *
+ * Return: Success: H5_ITER_CONT (0) or H5_ITER_STOP (1)
+ * Failure: H5_ITER_ERROR (-1)
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5I__iterate_cb(void *_item, void H5_ATTR_UNUSED *_key, void *_udata)
+{
+ H5I_id_info_t * info = (H5I_id_info_t *)_item; /* Pointer to the ID info */
+ H5I_iterate_ud_t *udata = (H5I_iterate_ud_t *)_udata; /* User data for callback */
+ int ret_value = H5_ITER_CONT; /* Callback return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Only invoke the callback function if this ID is visible externally and
+ * its reference count is positive.
+ */
+ if ((!udata->app_ref) || (info->app_count > 0)) {
+ H5I_type_t type = udata->obj_type;
+ void * object;
+ herr_t cb_ret_val;
+
+ /* The stored object pointer might be an H5VL_object_t, in which
+ * case we'll need to get the wrapped object struct (H5F_t *, etc.).
+ */
+ H5_GCC_DIAG_OFF("cast-qual")
+ object = H5I__unwrap((void *)info->object, type); /* Casting away const OK */
+ H5_GCC_DIAG_ON("cast-qual")
+
+ /* Invoke callback function */
+ cb_ret_val =
+ (*udata->user_func)((void *)object, info->id, udata->user_udata);
+
+ /* Set the return value based on the callback's return value */
+ if (cb_ret_val > 0)
+ ret_value = H5_ITER_STOP; /* terminate iteration early */
+ else if (cb_ret_val < 0)
+ ret_value = H5_ITER_ERROR; /* indicate failure (which terminates iteration) */
+ }
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I__iterate_cb() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_iterate
+ *
+ * Purpose: Apply function FUNC to each member of type TYPE (with
+ * non-zero application reference count if app_ref is TRUE).
+ * Stop if FUNC returns a non zero value (i.e. anything
+ * other than H5_ITER_CONT).
+ *
+ * If FUNC returns a positive value (i.e. H5_ITER_STOP),
+ * return SUCCEED.
+ *
+ * If FUNC returns a negative value (i.e. H5_ITER_ERROR),
+ * return FAIL.
+ *
+ * The FUNC should take a pointer to the object and the
+ * udata as arguments and return non-zero to terminate
+ * siteration, and zero to continue.
+ *
+ * Limitation: Currently there is no way to start the iteration from
+ * where a previous iteration left off.
+ *
+ * Return: SUCCEED/FAIL
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5I_iterate(H5I_type_t type, H5I_search_func_t func, void *udata, hbool_t app_ref)
+{
+ H5I_type_info_t *type_info = NULL; /* Pointer to the type */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ /* Check arguments */
+ if (type <= H5I_BADID || (int)type >= H5I_next_type_g)
+ HGOTO_ERROR(H5E_ARGS, H5E_BADRANGE, FAIL, "invalid type number")
+ type_info = H5I_type_info_array_g[type];
+
+ /* Only iterate through ID list if it is initialized and there are IDs in type */
+ if (type_info && type_info->init_count > 0 && type_info->id_count > 0) {
+ H5I_iterate_ud_t iter_udata; /* User data for iteration callback */
+ herr_t iter_status; /* Iteration status */
+
+ /* Set up iterator user data */
+ iter_udata.user_func = func;
+ iter_udata.user_udata = udata;
+ iter_udata.app_ref = app_ref;
+ iter_udata.obj_type = type;
+
+ /* Iterate over IDs */
+ if ((iter_status = H5SL_iterate(type_info->ids, H5I__iterate_cb, &iter_udata)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADITER, FAIL, "iteration failed")
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_iterate() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5I__find_id
+ *
+ * Purpose: Given an object ID find the info struct that describes the
+ * object.
+ *
+ * Return: Success: A pointer to the object's info struct.
+ *
+ * Failure: NULL
+ *
+ *-------------------------------------------------------------------------
+ */
+H5I_id_info_t *
+H5I__find_id(hid_t id)
+{
+ H5I_type_t type; /* ID's type */
+ H5I_type_info_t *type_info = NULL; /* Pointer to the type */
+ H5I_id_info_t *ret_value = NULL; /* Return value */
+
+ FUNC_ENTER_PACKAGE_NOERR
+
+ /* Check arguments */
+ type = H5I_TYPE(id);
+ if (type <= H5I_BADID || (int)type >= H5I_next_type_g)
+ HGOTO_DONE(NULL)
+ type_info = H5I_type_info_array_g[type];
+ if (!type_info || type_info->init_count <= 0)
+ HGOTO_DONE(NULL)
+
+ /* Check for same ID as we have looked up last time */
+ if (type_info->last_id_info && type_info->last_id_info->id == id)
+ ret_value = type_info->last_id_info;
+ else {
+ /* Locate the ID node for the ID */
+ ret_value = (H5I_id_info_t *)H5SL_search(type_info->ids, &id);
+
+ /* Remember this ID */
+ type_info->last_id_info = ret_value;
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I__find_id() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5I__find_id_cb
+ *
+ * Purpose: Callback for searching for an ID with a specific pointer
+ *
+ * Return: Success: H5_ITER_CONT (0) or H5_ITER_STOP (1)
+ * Failure: H5_ITER_ERROR (-1)
+ *
+ *-------------------------------------------------------------------------
+ */
+static int
+H5I__find_id_cb(void *_item, void H5_ATTR_UNUSED *_key, void *_udata)
+{
+ H5I_id_info_t * info = (H5I_id_info_t *)_item; /* Pointer to the ID info */
+ H5I_get_id_ud_t *udata = (H5I_get_id_ud_t *)_udata; /* Pointer to user data */
+ H5I_type_t type = udata->obj_type;
+ const void * object = NULL;
+ int ret_value = H5_ITER_CONT; /* Return value */
+
+ FUNC_ENTER_STATIC_NOERR
+
+ /* Sanity check */
+ HDassert(info);
+ HDassert(udata);
+
+ /* Get a pointer to the VOL connector's data */
+ H5_GCC_DIAG_OFF("cast-qual")
+ object = H5I__unwrap((void *)info->object, type); /* Casting away const OK */
+ H5_GCC_DIAG_ON("cast-qual")
+
+ /* Check for a match */
+ if (object == udata->object) {
+ udata->ret_id = info->id;
+ ret_value = H5_ITER_STOP;
+ }
+
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I__find_id_cb() */
+
+/*-------------------------------------------------------------------------
+ * Function: H5I_find_id
+ *
+ * Purpose: Return the ID of an object by searching through the ID list
+ * for the type.
+ *
+ * Return: SUCCEED/FAIL
+ * (id will be set to H5I_INVALID_HID on errors or not found)
+ *
+ *-------------------------------------------------------------------------
+ */
+herr_t
+H5I_find_id(const void *object, H5I_type_t type, hid_t *id)
+{
+ H5I_type_info_t *type_info = NULL; /* Pointer to the type */
+ herr_t ret_value = SUCCEED; /* Return value */
+
+ FUNC_ENTER_NOAPI(FAIL)
+
+ HDassert(id);
+
+ *id = H5I_INVALID_HID;
+
+ type_info = H5I_type_info_array_g[type];
+ if (!type_info || type_info->init_count <= 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADGROUP, FAIL, "invalid type")
+
+ /* Only iterate through ID list if it is initialized and there are IDs in type */
+ if (type_info->init_count > 0 && type_info->id_count > 0) {
+ H5I_get_id_ud_t udata; /* User data */
+ herr_t iter_status; /* Iteration status */
+
+ /* Set up iterator user data */
+ udata.object = object;
+ udata.obj_type = type;
+ udata.ret_id = H5I_INVALID_HID;
+
+ /* Iterate over IDs for the ID type */
+ if ((iter_status = H5SL_iterate(type_info->ids, H5I__find_id_cb, &udata)) < 0)
+ HGOTO_ERROR(H5E_ATOM, H5E_BADITER, FAIL, "iteration failed")
+
+ *id = udata.ret_id;
+ }
+
+done:
+ FUNC_LEAVE_NOAPI(ret_value)
+} /* end H5I_find_id() */
+
+