/**
 * Get ::CCLDevice wrapper at given index.
 *
 * @protected @memberof ccl_dev_container
 *
 * @param[in] devcon The device container object.
 * @param[in] get_devices Function to get cl_device_id's from wrapped
 * object.
 * @param[in] index Index of device in device container.
 * @param[out] err Return location for a GError, or `NULL` if error
 * reporting is to be ignored.
 * @return The ::CCLDevice wrapper at given index or `NULL` if an error
 * occurs.
 * */
CCL_EXPORT
CCLDevice* ccl_dev_container_get_device(
	CCLDevContainer* devcon,
	ccl_dev_container_get_cldevices get_devices, cl_uint index,
	GError** err) {

	/* Make sure err is NULL or it is not set. */
	g_return_val_if_fail(err == NULL || *err == NULL, NULL);

	/* Make sure devcon is not NULL. */
	g_return_val_if_fail(devcon != NULL, NULL);

	/* The return value. */
	CCLDevice* device_ret;

	/* Internal error object. */
	GError* err_internal = NULL;

	/* Check if device list is already initialized. */
	if (devcon->devices == NULL) {

		/* Not initialized, initialize it. */
		ccl_dev_container_init_devices(
			devcon, get_devices, &err_internal);

		/* Check for errors. */
		ccl_if_err_propagate_goto(err, err_internal, error_handler);

	}

	/* Make sure device index is less than the number of devices. */
	ccl_if_err_create_goto(*err, CCL_ERROR, index >= devcon->num_devices,
		CCL_ERROR_DEVICE_NOT_FOUND, error_handler,
		"%s: device index (%d) out of bounds (%d devices in list).",
		 G_STRLOC, index, devcon->num_devices);

	/* If we got here, everything is OK. */
	g_assert(err == NULL || *err == NULL);
	device_ret = devcon->devices[index];
	goto finish;

error_handler:

	/* If we got here there was an error, verify that it is so. */
	g_assert(err == NULL || *err != NULL);
	device_ret = NULL;

finish:

	/* Return list of device wrappers. */
	return device_ret;

}
/**
 * @internal
 * Return number of devices in device container.
 *
 * @protected @memberof ccl_dev_container
 *
 * @param[in] devcon The device container object.
 * @param[in] get_devices Function to get cl_device_id's from wrapped
 * object.
 * @param[out] err Return location for a GError, or `NULL` if error
 * reporting is to be ignored.
 * @return The number of devices in device container or 0 if an error
 * occurs or is otherwise not possible to get any device.
 * */
cl_uint ccl_dev_container_get_num_devices(
	CCLDevContainer* devcon,
	ccl_dev_container_get_cldevices get_devices, GError** err) {

	/* Make sure devcon is not NULL. */
	g_return_val_if_fail(devcon != NULL, 0);

	/* Make sure err is NULL or it is not set. */
	g_return_val_if_fail(err == NULL || *err == NULL, 0);

	/* Check if device list is already initialized. */
	if (devcon->devices == NULL) {

		/* Not initialized, initialize it. */
		ccl_dev_container_init_devices(devcon, get_devices, err);

	}

	/* Return the number of devices in context. */
	return devcon->num_devices;

}