diff --git a/bob/io/__init__.py b/bob/io/__init__.py index 2ab1e28b150f0549def9963e9e87de3fdd6b2579..edbb4090fca046b19d22d3982711084621bff3be 100644 --- a/bob/io/__init__.py +++ b/bob/io/__init__.py @@ -1,3 +1,4 @@ # see https://docs.python.org/3/library/pkgutil.html from pkgutil import extend_path + __path__ = extend_path(__path__, __name__) diff --git a/bob/io/base/__init__.py b/bob/io/base/__init__.py index dbe34b9e2e60149ed198e8d6da2d299479eb897b..a32b34115daf0aacdafa2abb5832035de9695613 100644 --- a/bob/io/base/__init__.py +++ b/bob/io/base/__init__.py @@ -1,512 +1,431 @@ # import Libraries of other lib packages -import numpy -import bob.core +import numpy as np +import h5py +from pygments import format +import imageio +import cv2 +from PIL import Image +from .utils import to_bob -# import our own Library -import bob.extension -bob.extension.load_bob_library('bob.io.base', __file__) - -from ._library import File as _File_C, HDF5File as _HDF5File_C, extensions -from . import version -from .version import module as __version__ -from .version import api as __api_version__ import os -class File(_File_C): - __doc__ = _File_C.__doc__ - - def __enter__(self): - return self - - def __exit__(self, type, value, traceback): - self.close() - - -class HDF5File(_HDF5File_C): - __doc__ = _HDF5File_C.__doc__ - - def __enter__(self): - return self - - def __exit__(self, type, value, traceback): - return self.close() - - def __contains__(self, x): - __doc__ = self.has_key.__doc__ - return self.has_key(x) - - def __iter__(self): - __doc__ = self.keys.__doc__ - return iter(self.keys()) - - def __getitem__(self, name): - __doc__ = self.get.__doc__ - return self.get(name) - - def __setitem__(self, name, value): - __doc__ = self.set.__doc__ - return self.set(name, value) - - def values(self): - '''Yields the datasets contained in the current directory. - - Yields - ------- - object - The datasets that are being read. - ''' - return (self[key] for key in self) - - def items(self): - '''Yields the keys and the datasets contained in the current directory. - - Yields - ------- - tuple - The key and the datasets that are being read in a tuple. - ''' - return ((key, self[key]) for key in self) +hdf5_extensions = [".hdf5", ".h5", ".hdf", ".hdf5", ".h5", ".hdf", ".hdf5"] +image_extensions = [ + ".jpg", + ".jpeg", + ".png", + ".bmp", + ".gif", + ".tif", + ".tiff", + ".pgm", + ".pbm", + ".pnm", + ".ppm", +] def _is_string(s): - """Returns ``True`` if the given object is a string + """Returns ``True`` if the given object is a string - This method can be used with Python-2.x or 3.x and returns a string - respecting each environment's constraints. - """ + This method can be used with Python-2.x or 3.x and returns a string + respecting each environment's constraints. + """ - from sys import version_info + from sys import version_info - return (version_info[0] < 3 and isinstance(s, (str, unicode))) or \ - isinstance(s, (bytes, str)) + return (version_info[0] < 3 and isinstance(s, (str, unicode))) or isinstance( + s, (bytes, str) + ) -@numpy.deprecate(new_name="os.makedirs(directory, exist_ok=True)") +@np.deprecate(new_name="os.makedirs(directory, exist_ok=True)") def create_directories_safe(directory, dryrun=False): - """Creates a directory if it does not exists, with concurrent access support. - This function will also create any parent directories that might be required. - If the dryrun option is selected, it does not actually create the directory, - but just writes the (Linux) command that would have been executed. - - **Parameters:** - - ``directory`` : str - The directory that you want to create. - - ``dryrun`` : bool - Only ``print`` the command to console, but do not execute it. - """ - if dryrun: - print("[dry-run] mkdir -p '%s'" % directory) - else: - os.makedirs(directory, exist_ok=True) - - -def load(inputs): - """load(inputs) -> data - - Loads the contents of a file, an iterable of files, or an iterable of - :py:class:`bob.io.base.File`'s into a :py:class:`numpy.ndarray`. - - **Parameters:** - - ``inputs`` : various types - - This might represent several different entities: - - 1. The name of a file (full path) from where to load the data. In this - case, this assumes that the file contains an array and returns a loaded - numpy ndarray. - 2. An iterable of filenames to be loaded in memory. In this case, this - would assume that each file contains a single 1D sample or a set of 1D - samples, load them in memory and concatenate them into a single and - returned 2D :py:class:`numpy.ndarray`. - 3. An iterable of :py:class:`File`. In this case, this would assume - that each :py:class:`File` contains a single 1D sample or a set - of 1D samples, load them in memory if required and concatenate them into - a single and returned 2D :py:class:`numpy.ndarray`. - 4. An iterable with mixed filenames and :py:class:`File`. In this - case, this would returned a 2D :py:class:`numpy.ndarray`, as described - by points 2 and 3 above. - - **Returns:** - - ``data`` : :py:class:`numpy.ndarray` - The data loaded from the given ``inputs``. - """ - - from collections.abc import Iterable - import numpy - if _is_string(inputs): - if not os.path.exists(inputs): - raise RuntimeError(f"`{inputs}' does not exist!") - return File(inputs, 'r').read() - elif isinstance(inputs, Iterable): - retval = [] - for obj in inputs: - if _is_string(obj): - retval.append(load(obj)) - elif isinstance(obj, File): - retval.append(obj.read()) - else: - raise TypeError( - "Iterable contains an object which is not a filename nor a " - "bob.io.base.File.") - return numpy.vstack(retval) - else: - raise TypeError( - "Unexpected input object. This function is expecting a filename, " - "or an iterable of filenames and/or bob.io.base.File's") - - -def merge(filenames): - """merge(filenames) -> files + """Creates a directory if it does not exists, with concurrent access support. + This function will also create any parent directories that might be required. + If the dryrun option is selected, it does not actually create the directory, + but just writes the (Linux) command that would have been executed. - Converts an iterable of filenames into an iterable over read-only - :py:class:`bob.io.base.File`'s. + **Parameters:** - **Parameters:** + ``directory`` : str + The directory that you want to create. - ``filenames`` : str or [str] - - A list of file names. - This might represent: - - 1. A single filename. In this case, an iterable with a single - :py:class:`File` is returned. - 2. An iterable of filenames to be converted into an iterable of - :py:class:`File`'s. - - **Returns:** + ``dryrun`` : bool + Only ``print`` the command to console, but do not execute it. + """ + if dryrun: + print("[dry-run] mkdir -p '%s'" % directory) + else: + os.makedirs(directory, exist_ok=True) - ``files`` : [:py:class:`File`] - The list of files. - """ - from collections import Iterable - from .utils import is_string - if is_string(filenames): - return [File(filenames, 'r')] - elif isinstance(filenames, Iterable): - return [File(k, 'r') for k in filenames] - else: - raise TypeError( - "Unexpected input object. This function is expecting an " - "iterable of filenames.") +def open_file(filename): + """open_file(filename) -> file + Opens a file for reading. -def save(array, filename, create_directories=False): - """Saves the contents of an array-like object to file. + Parameters + ---------- - Effectively, this is the same as creating a :py:class:`File` object - with the mode flag set to ``'w'`` (write with truncation) and calling - :py:meth:`File.write` passing ``array`` as parameter. + ``filename`` : str + The name of the file to open. - Parameters: - ``array`` : array_like - The array-like object to be saved on the file + """ - ``filename`` : str - The name of the file where you need the contents saved to + def check_gray(img): + # Checking for gray scaled images + if ( + img.ndim > 2 + and np.allclose(img[:, :, 0], img[:, :, 1]) + and np.allclose(img[:, :, 0], img[:, :, 2]) + ): + img = img[:, :, 0] + return img - ``create_directories`` : bool - Automatically generate the directories if required (defaults to ``False`` - because of compatibility reasons; might change in future to default to - ``True``) - """ - # create directory if not existent yet - if create_directories: - create_directories_safe(os.path.dirname(filename)) + extension = os.path.splitext(filename)[1] # get the extension - # requires data is c-contiguous and aligned, will create a copy otherwise - array = numpy.require(array, requirements=('C_CONTIGUOUS', 'ALIGNED')) + if extension in hdf5_extensions: + with h5py.File(filename, "r") as f: + if "array" not in f.keys(): + raise RuntimeError( + "The file '%s' does not contain the key 'array'" % filename + ) - return File(filename, 'w').write(array) + return np.array(f["array"]) + elif extension in image_extensions: -# Just to make it homogenous with the C++ API -write = save -read = load + img = imageio.imread(filename) + # PNGs have a 4th channel, which we don't want + # Alpha channels for instance have to be ignored + if extension.lower() == ".png": + img = img[:, :, 0:3] -def append(array, filename): - """append(array, filename) -> position - - Appends the contents of an array-like object to file. + img = check_gray(img) + return img if img.ndim == 2 else to_bob(img) + else: + raise RuntimeError(f"Unknown file extension: {extension}") - Effectively, this is the same as creating a :py:class:`File` object - with the mode flag set to ``'a'`` (append) and calling - :py:meth:`File.append` passing ``array`` as parameter. - **Parameters:** +def write_file(filename, data, format="pillow"): + """ + write_file(filename, data) -> None - ``array`` : array_like - The array-like object to be saved on the file + Writes the contents of a :py:class:`numpy.ndarray` to a file. - ``filename`` : str - The name of the file where you need the contents saved to + Parameters + ---------- - **Returns:** + ``filename`` : str + The name of the file to write to. - ``position`` : int - See :py:meth:`File.append` - """ + ``data`` : :py:class:`numpy.ndarray` + The data to write to the file. - # requires data is c-contiguous and aligned, will create a copy otherwise - array = numpy.require(array, requirements=('C_CONTIGUOUS', 'ALIGNED')) + ``format`` : str + The format to use to read the file. By default imageio selects the appropriate for you based on the filename and its contents - return File(filename, 'a').append(array) + """ -def peek(filename): - """peek(filename) -> dtype, shape, stride + extension = os.path.splitext(filename)[1] # get the extension - Returns the type of array (frame or sample) saved in the given file. + if extension in hdf5_extensions: + with h5py.File(filename, "w") as f: + f["array"] = data + elif extension in image_extensions: + # Pillow is the format with the best support for all image formats + imageio.imwrite(filename, data, format=format) + else: + raise RuntimeError(f"Unknown file extension: {extension}") - Effectively, this is the same as creating a :py:class:`File` object - with the mode flag set to `r` (read-only) and calling - :py:meth:`File.describe`. - **Parameters**: +def load(inputs): + """load(inputs) -> data + + Loads the contents of a file, an iterable of files, or an iterable of + :py:class:`bob.io.base.File`'s into a :py:class:`numpy.ndarray`. + + **Parameters:** + + ``inputs`` : various types + + This might represent several different entities: + + 1. The name of a file (full path) from where to load the data. In this + case, this assumes that the file contains an array and returns a loaded + numpy ndarray. + 2. An iterable of filenames to be loaded in memory. In this case, this + would assume that each file contains a single 1D sample or a set of 1D + samples, load them in memory and concatenate them into a single and + returned 2D :py:class:`numpy.ndarray`. + 3. An iterable of :py:class:`File`. In this case, this would assume + that each :py:class:`File` contains a single 1D sample or a set + of 1D samples, load them in memory if required and concatenate them into + a single and returned 2D :py:class:`numpy.ndarray`. + 4. An iterable with mixed filenames and :py:class:`File`. In this + case, this would returned a 2D :py:class:`numpy.ndarray`, as described + by points 2 and 3 above. + + **Returns:** + + ``data`` : :py:class:`numpy.ndarray` + The data loaded from the given ``inputs``. + """ + + from collections.abc import Iterable + import numpy + + if _is_string(inputs): + if not os.path.exists(inputs): + raise RuntimeError(f"`{inputs}' does not exist!") + return open_file(inputs) + + elif isinstance(inputs, Iterable): + retval = [] + for obj in inputs: + if _is_string(obj): + retval.append(load(obj)) + # elif isinstance(obj, File): + # retval.append(obj.read()) + else: + raise TypeError( + "Iterable contains an object which is not a filename nor a " + "bob.io.base.File." + ) + return numpy.vstack(retval) + else: + raise TypeError( + "Unexpected input object. This function is expecting a filename, " + "or an iterable of filenames and/or bob.io.base.File's" + ) - ``filename`` : str - The name of the file to peek information from - **Returns:** +def save(array, filename, create_directories=False): + """Saves the contents of an array-like object to file. - ``dtype, shape, stride`` : see :py:meth:`File.describe` - """ - return File(filename, 'r').describe() + Effectively, this is the same as creating a :py:class:`File` object + with the mode flag set to ``'w'`` (write with truncation) and calling + :py:meth:`File.write` passing ``array`` as parameter. + Parameters: -def peek_all(filename): - """peek_all(filename) -> dtype, shape, stride + ``array`` : array_like + The array-like object to be saved on the file - Returns the type of array (for full readouts) saved in the given file. + ``filename`` : str + The name of the file where you need the contents saved to - Effectively, this is the same as creating a :py:class:`File` object - with the mode flag set to ``'r'`` (read-only) and returning - ``File.describe`` with its parameter ``all`` set to ``True``. + ``create_directories`` : bool + Automatically generate the directories if required (defaults to ``False`` + because of compatibility reasons; might change in future to default to + ``True``) + """ + # create directory if not existent yet + if create_directories: + create_directories_safe(os.path.dirname(filename)) - **Parameters:** + # requires data is c-contiguous and aligned, will create a copy otherwise + array = np.require(array, requirements=("C_CONTIGUOUS", "ALIGNED")) - ``filename`` : str - The name of the file to peek information from + write_file(filename, array) - **Returns:** - ``dtype, shape, stride`` : see :py:meth:`File.describe` - """ - return File(filename, 'r').describe(all=True) +# Just to make it homogenous with the C++ API +write = save +read = load # Keeps compatibility with the previously existing API -open = File - - -def get_config(): - """Returns a string containing the configuration information. - """ - return bob.extension.get_config(__name__, version.externals, version.api) +# open = File def get_include_directories(): - """get_include_directories() -> includes - - Returns a list of include directories for dependent libraries, such as HDF5. - This function is automatically used by - :py:func:`bob.extension.get_bob_libraries` to retrieve the non-standard - include directories that are required to use the C bindings of this library - in dependent classes. You shouldn't normally need to call this function by - hand. - - **Returns:** - - ``includes`` : [str] - The list of non-standard include directories required to use the C bindings - of this class. For now, only the directory for the HDF5 headers are - returned. - """ - # try to use pkg_config first - try: - from bob.extension.utils import find_header - # locate pkg-config on our own - header = 'hdf5.h' - candidates = find_header(header) - if not candidates: - raise RuntimeError( - "could not find %s's `%s' - have you installed %s on this " - "machine?" % ('hdf5', header, 'hdf5')) - - return [os.path.dirname(candidates[0])] - except RuntimeError: - from bob.extension import pkgconfig - pkg = pkgconfig('hdf5') - return pkg.include_directories() - - -def get_macros(): - """get_macros() -> macros - - Returns a list of preprocessor macros, such as ``(HAVE_HDF5, 1)``. This - function is automatically used by :py:func:`bob.extension.get_bob_libraries` - to retrieve the prerpocessor definitions that are required to use the C - bindings of this library in dependent classes. You shouldn't normally need to - call this function by hand. - - **Returns:** - - ``macros`` : [(str,str)] - The list of preprocessor macros required to use the C bindings of this - class. For now, only ``('HAVE_HDF5', '1')`` is returned, when applicable. - """ - # get include directories - if get_include_directories(): - return [('HAVE_HDF5', '1')] + """get_include_directories() -> includes + + Returns a list of include directories for dependent libraries, such as HDF5. + This function is automatically used by + :py:func:`bob.extension.get_bob_libraries` to retrieve the non-standard + include directories that are required to use the C bindings of this library + in dependent classes. You shouldn't normally need to call this function by + hand. + + **Returns:** + + ``includes`` : [str] + The list of non-standard include directories required to use the C bindings + of this class. For now, only the directory for the HDF5 headers are + returned. + """ + # try to use pkg_config first + try: + from bob.extension.utils import find_header + + # locate pkg-config on our own + header = "hdf5.h" + candidates = find_header(header) + if not candidates: + raise RuntimeError( + "could not find %s's `%s' - have you installed %s on this " + "machine?" % ("hdf5", header, "hdf5") + ) + + return [os.path.dirname(candidates[0])] + except RuntimeError: + from bob.extension import pkgconfig + + pkg = pkgconfig("hdf5") + return pkg.include_directories() def _generate_features(reader, paths, same_size=False): - """Load and stack features in a memory efficient way. This function is - meant to be used inside :py:func:`vstack_features`. - - Parameters - ---------- - reader : ``collections.Callable`` - See the documentation of :py:func:`vstack_features`. - paths : ``collections.Iterable`` - See the documentation of :py:func:`vstack_features`. - same_size : :obj:`bool`, optional - See the documentation of :py:func:`vstack_features`. - - Yields - ------ - object - The first object returned is a tuple of :py:class:`numpy.dtype` of - features and the shape of the first feature. The rest of objects are - the actual values in features. The features are returned in C order. - """ - - shape_determined = False - for i, path in enumerate(paths): - - feature = numpy.atleast_2d(reader(path)) - feature = numpy.ascontiguousarray(feature) - if not shape_determined: - shape_determined = True - dtype = feature.dtype - shape = list(feature.shape) - yield (dtype, shape) - else: - # make sure all features have the same shape and dtype - if same_size: - assert shape == list(feature.shape), f"Expected feature shape of {shape}, got {feature.shape}" - else: - assert shape[1:] == list(feature.shape[1:]), f"Ignoring first dimension, expected feature shape of {shape}, got {feature.shape}" - assert dtype == feature.dtype + """Load and stack features in a memory efficient way. This function is + meant to be used inside :py:func:`vstack_features`. + + Parameters + ---------- + reader : ``collections.Callable`` + See the documentation of :py:func:`vstack_features`. + paths : ``collections.Iterable`` + See the documentation of :py:func:`vstack_features`. + same_size : :obj:`bool`, optional + See the documentation of :py:func:`vstack_features`. - if same_size: - yield (feature.ravel(),) - else: - for feat in feature: - yield (feat.ravel(),) + Yields + ------ + object + The first object returned is a tuple of :py:class:`numpy.dtype` of + features and the shape of the first feature. The rest of objects are + the actual values in features. The features are returned in C order. + """ + + shape_determined = False + for i, path in enumerate(paths): + + feature = np.atleast_2d(reader(path)) + feature = np.ascontiguousarray(feature) + if not shape_determined: + shape_determined = True + dtype = feature.dtype + shape = list(feature.shape) + yield (dtype, shape) + else: + # make sure all features have the same shape and dtype + if same_size: + assert shape == list( + feature.shape + ), f"Expected feature shape of {shape}, got {feature.shape}" + else: + assert shape[1:] == list( + feature.shape[1:] + ), f"Ignoring first dimension, expected feature shape of {shape}, got {feature.shape}" + assert dtype == feature.dtype + + if same_size: + yield (feature.ravel(),) + else: + for feat in feature: + yield (feat.ravel(),) def vstack_features(reader, paths, same_size=False, dtype=None): - """Stacks all features in a memory efficient way. - - Parameters - ---------- - reader : ``collections.Callable`` - The function to load the features. The function should only take one - argument ``path`` and return loaded features. Use :any:`functools.partial` - to accommodate your reader to this format. - The features returned by ``reader`` are expected to have the same - :py:class:`numpy.dtype` and the same shape except for their first - dimension. First dimension should correspond to the number of samples. - paths : ``collections.Iterable`` - An iterable of paths to iterate on. Whatever is inside path is given to - ``reader`` so they do not need to be necessarily paths to actual files. - If ``same_size`` is ``True``, ``len(paths)`` must be valid. - same_size : :obj:`bool`, optional - If ``True``, it assumes that arrays inside all the paths are the same - shape. If you know the features are the same size in all paths, set this - to ``True`` to improve the performance. - dtype : :py:class:`numpy.dtype`, optional - If provided, the data will be casted to this format. - - Returns - ------- - numpy.ndarray - The read features with the shape ``(n_samples, *features_shape[1:])``. - - Examples - -------- - This function in a simple way is equivalent to calling - ``numpy.vstack([reader(p) for p in paths])``. - - >>> import numpy - >>> from bob.io.base import vstack_features - >>> def reader(path): - ... # in each file, there are 5 samples and features are 2 dimensional. - ... return numpy.arange(10).reshape(5,2) - >>> paths = ['path1', 'path2'] - >>> all_features = vstack_features(reader, paths) - >>> numpy.allclose(all_features, numpy.array( - ... [[0, 1], - ... [2, 3], - ... [4, 5], - ... [6, 7], - ... [8, 9], - ... [0, 1], - ... [2, 3], - ... [4, 5], - ... [6, 7], - ... [8, 9]])) - True - >>> all_features_with_more_memory = numpy.vstack([reader(p) for p in paths]) - >>> numpy.allclose(all_features, all_features_with_more_memory) - True - - You can allocate the array at once to improve the performance if you know - that all features in paths have the same shape and you know the total number - of the paths: - - >>> all_features = vstack_features(reader, paths, same_size=True) - >>> numpy.allclose(all_features, numpy.array( - ... [[0, 1], - ... [2, 3], - ... [4, 5], - ... [6, 7], - ... [8, 9], - ... [0, 1], - ... [2, 3], - ... [4, 5], - ... [6, 7], - ... [8, 9]])) - True - """ - iterable = _generate_features(reader, paths, same_size) - data_dtype, shape = next(iterable) - if dtype is None: - dtype = data_dtype - if same_size: - # numpy black magic: https://stackoverflow.com/a/12473478/1286165 - field_dtype = [("", (dtype, (numpy.prod(shape),)))] - total_size = len(paths) - all_features = numpy.fromiter(iterable, field_dtype, total_size) - else: - field_dtype = [("", (dtype, (numpy.prod(shape[1:]),)))] - all_features = numpy.fromiter(iterable, field_dtype) - - # go from a field array to a normal array - all_features = all_features.view(dtype) - # the shape is assumed to be (n_samples, ...) it can be (5, 2) or (5, 3, 4). - shape = list(shape) - shape[0] = -1 - return numpy.reshape(all_features, shape, order="C") + """Stacks all features in a memory efficient way. + + Parameters + ---------- + reader : ``collections.Callable`` + The function to load the features. The function should only take one + argument ``path`` and return loaded features. Use :any:`functools.partial` + to accommodate your reader to this format. + The features returned by ``reader`` are expected to have the same + :py:class:`numpy.dtype` and the same shape except for their first + dimension. First dimension should correspond to the number of samples. + paths : ``collections.Iterable`` + An iterable of paths to iterate on. Whatever is inside path is given to + ``reader`` so they do not need to be necessarily paths to actual files. + If ``same_size`` is ``True``, ``len(paths)`` must be valid. + same_size : :obj:`bool`, optional + If ``True``, it assumes that arrays inside all the paths are the same + shape. If you know the features are the same size in all paths, set this + to ``True`` to improve the performance. + dtype : :py:class:`numpy.dtype`, optional + If provided, the data will be casted to this format. + + Returns + ------- + numpy.ndarray + The read features with the shape ``(n_samples, *features_shape[1:])``. + + Examples + -------- + This function in a simple way is equivalent to calling + ``numpy.vstack([reader(p) for p in paths])``. + + >>> import numpy + >>> from bob.io.base import vstack_features + >>> def reader(path): + ... # in each file, there are 5 samples and features are 2 dimensional. + ... return numpy.arange(10).reshape(5,2) + >>> paths = ['path1', 'path2'] + >>> all_features = vstack_features(reader, paths) + >>> numpy.allclose(all_features, numpy.array( + ... [[0, 1], + ... [2, 3], + ... [4, 5], + ... [6, 7], + ... [8, 9], + ... [0, 1], + ... [2, 3], + ... [4, 5], + ... [6, 7], + ... [8, 9]])) + True + >>> all_features_with_more_memory = numpy.vstack([reader(p) for p in paths]) + >>> numpy.allclose(all_features, all_features_with_more_memory) + True + + You can allocate the array at once to improve the performance if you know + that all features in paths have the same shape and you know the total number + of the paths: + + >>> all_features = vstack_features(reader, paths, same_size=True) + >>> numpy.allclose(all_features, numpy.array( + ... [[0, 1], + ... [2, 3], + ... [4, 5], + ... [6, 7], + ... [8, 9], + ... [0, 1], + ... [2, 3], + ... [4, 5], + ... [6, 7], + ... [8, 9]])) + True + """ + iterable = _generate_features(reader, paths, same_size) + data_dtype, shape = next(iterable) + if dtype is None: + dtype = data_dtype + if same_size: + # numpy black magic: https://stackoverflow.com/a/12473478/1286165 + field_dtype = [("", (dtype, (np.prod(shape),)))] + total_size = len(paths) + all_features = np.fromiter(iterable, field_dtype, total_size) + else: + field_dtype = [("", (dtype, (np.prod(shape[1:]),)))] + all_features = np.fromiter(iterable, field_dtype) + + # go from a field array to a normal array + all_features = all_features.view(dtype) + # the shape is assumed to be (n_samples, ...) it can be (5, 2) or (5, 3, 4). + shape = list(shape) + shape[0] = -1 + return np.reshape(all_features, shape, order="C") # gets sphinx autodoc done right - don't remove it -__all__ = [_ for _ in dir() if not _.startswith('_')] +__all__ = [_ for _ in dir() if not _.startswith("_")] diff --git a/bob/io/base/bobskin.cpp b/bob/io/base/bobskin.cpp deleted file mode 100644 index 494bdafc26fe3520f67b7a5f826d8a9982ba3557..0000000000000000000000000000000000000000 --- a/bob/io/base/bobskin.cpp +++ /dev/null @@ -1,159 +0,0 @@ -/** - * @author Andre Anjos <andre.anjos@idiap.ch> - * @date Wed 6 Nov 07:57:57 2013 - * - * @brief Implementation of our bobskin class - */ - -#include "bobskin.h" -#include <stdexcept> - -bobskin::bobskin(PyObject* array, bob::io::base::array::ElementType eltype) { - - if (!PyArray_CheckExact(array)) { - PyErr_SetString(PyExc_TypeError, "input object to bobskin constructor is not (exactly) a numpy.ndarray"); - throw std::runtime_error("error is already set"); - } - - m_type.set<npy_intp>(eltype, PyArray_NDIM((PyArrayObject*)array), - PyArray_DIMS((PyArrayObject*)array), - PyArray_STRIDES((PyArrayObject*)array)); - - m_ptr = PyArray_DATA((PyArrayObject*)array); - -} - -bobskin::bobskin(PyArrayObject* array, bob::io::base::array::ElementType eltype) { - - m_type.set<npy_intp>(eltype, PyArray_NDIM((PyArrayObject*)array), - PyArray_DIMS((PyArrayObject*)array), - PyArray_STRIDES((PyArrayObject*)array)); - - m_ptr = PyArray_DATA((PyArrayObject*)array); - -} - -static bob::io::base::array::ElementType signed_integer_type(int bits) { - switch(bits) { - case 8: - return bob::io::base::array::t_int8; - case 16: - return bob::io::base::array::t_int16; - case 32: - return bob::io::base::array::t_int32; - case 64: - return bob::io::base::array::t_int64; - default: - PyErr_Format(PyExc_TypeError, "unsupported signed integer element type with %d bits", bits); - } - return bob::io::base::array::t_unknown; -} - -static bob::io::base::array::ElementType unsigned_integer_type(int bits) { - switch(bits) { - case 8: - return bob::io::base::array::t_uint8; - case 16: - return bob::io::base::array::t_uint16; - case 32: - return bob::io::base::array::t_uint32; - case 64: - return bob::io::base::array::t_uint64; - default: - PyErr_Format(PyExc_TypeError, "unsupported unsigned signed integer element type with %d bits", bits); - } - return bob::io::base::array::t_unknown; -} - -static bob::io::base::array::ElementType num_to_type (int num) { - switch(num) { - case NPY_BOOL: - return bob::io::base::array::t_bool; - - //signed integers - case NPY_BYTE: - return signed_integer_type(NPY_BITSOF_CHAR); - case NPY_SHORT: - return signed_integer_type(NPY_BITSOF_SHORT); - case NPY_INT: - return signed_integer_type(NPY_BITSOF_INT); - case NPY_LONG: - return signed_integer_type(NPY_BITSOF_LONG); - case NPY_LONGLONG: - return signed_integer_type(NPY_BITSOF_LONGLONG); - - //unsigned integers - case NPY_UBYTE: - return unsigned_integer_type(NPY_BITSOF_CHAR); - case NPY_USHORT: - return unsigned_integer_type(NPY_BITSOF_SHORT); - case NPY_UINT: - return unsigned_integer_type(NPY_BITSOF_INT); - case NPY_ULONG: - return unsigned_integer_type(NPY_BITSOF_LONG); - case NPY_ULONGLONG: - return unsigned_integer_type(NPY_BITSOF_LONGLONG); - - //floats - case NPY_FLOAT32: - return bob::io::base::array::t_float32; - case NPY_FLOAT64: - return bob::io::base::array::t_float64; -#ifdef NPY_FLOAT128 - case NPY_FLOAT128: - return bob::io::base::array::t_float128; -#endif - - //complex - case NPY_COMPLEX64: - return bob::io::base::array::t_complex64; - case NPY_COMPLEX128: - return bob::io::base::array::t_complex128; -#ifdef NPY_COMPLEX256 - case NPY_COMPLEX256: - return bob::io::base::array::t_complex256; -#endif - - default: - PyErr_Format(PyExc_TypeError, "unsupported NumPy element type (%d)", num); - } - - return bob::io::base::array::t_unknown; -} - -bobskin::bobskin(PyBlitzArrayObject* array) { - bob::io::base::array::ElementType eltype = num_to_type(array->type_num); - if (eltype == bob::io::base::array::t_unknown) { - throw std::runtime_error("error is already set"); - } - m_type.set<Py_ssize_t>(num_to_type(array->type_num), array->ndim, - array->shape, array->stride); - m_ptr = array->data; -} - -bobskin::~bobskin() { } - -void bobskin::set(const interface&) { - PyErr_SetString(PyExc_NotImplementedError, "setting C++ bobskin with (const interface&) is not implemented - DEBUG ME!"); - throw std::runtime_error("error is already set"); -} - -void bobskin::set(boost::shared_ptr<interface>) { - PyErr_SetString(PyExc_NotImplementedError, "setting C++ bobskin with (boost::shared_ptr<interface>) is not implemented - DEBUG ME!"); - throw std::runtime_error("error is already set"); -} - -void bobskin::set (const bob::io::base::array::typeinfo&) { - PyErr_SetString(PyExc_NotImplementedError, "setting C++ bobskin with (const typeinfo&) implemented - DEBUG ME!"); - throw std::runtime_error("error is already set"); -} - -boost::shared_ptr<void> bobskin::owner() { - PyErr_SetString(PyExc_NotImplementedError, "acquiring non-const owner from C++ bobskin is not implemented - DEBUG ME!"); - throw std::runtime_error("error is already set"); -} - -boost::shared_ptr<const void> bobskin::owner() const { - PyErr_SetString(PyExc_NotImplementedError, "acquiring const owner from C++ bobskin is not implemented - DEBUG ME!"); - throw std::runtime_error("error is already set"); -} diff --git a/bob/io/base/bobskin.h b/bob/io/base/bobskin.h deleted file mode 100644 index d18cf6e40e1d70cc5daa15e6c1f71ff0f50c6225..0000000000000000000000000000000000000000 --- a/bob/io/base/bobskin.h +++ /dev/null @@ -1,91 +0,0 @@ -/** - * @author Andre Anjos <andre.anjos@idiap.ch> - * @date Tue 5 Nov 22:09:07 2013 - * - * @brief A pythonic version of bob::io::base::array::interface, with minimal - * functionality. - */ - -#ifndef PYTHON_BOB_IO_BOBSKIN_H -#define PYTHON_BOB_IO_BOBSKIN_H - -#include <Python.h> - -#include <bob.io.base/array.h> - -#include <bob.blitz/capi.h> - - -/** - * Wraps a PyArrayObject such that we can access it from bob::io - */ -class bobskin: public bob::io::base::array::interface { - - public: //api - - /** - * @brief Builds a new skin from an array like object - */ - bobskin(PyObject* array, bob::io::base::array::ElementType eltype); - - /** - * @brief Builds a new skin from a numpy array object - */ - bobskin(PyArrayObject* array, bob::io::base::array::ElementType eltype); - - /** - * @brief Builds a new skin around a blitz array object - */ - bobskin(PyBlitzArrayObject* array); - - /** - * @brief By default, the interface is never freed. You must override - * this method to do something special for your class type. - */ - virtual ~bobskin(); - - /** - * @brief Copies the data from another interface. - */ - virtual void set(const interface& other); - - /** - * @brief Refers to the data of another interface. - */ - virtual void set(boost::shared_ptr<interface> other); - - /** - * @brief Re-allocates this interface taking into consideration new - * requirements. The internal memory should be considered uninitialized. - */ - virtual void set (const bob::io::base::array::typeinfo& req); - - /** - * @brief Type information for this interface. - */ - virtual const bob::io::base::array::typeinfo& type() const { return m_type; } - - /** - * @brief Borrows a reference from the underlying memory. This means - * this object continues to be responsible for deleting the memory and - * you should make sure that it outlives the usage of the returned - * pointer. - */ - virtual void* ptr() { return m_ptr; } - virtual const void* ptr() const { return m_ptr; } - - /** - * @brief Returns a representation of the internal cache using shared - * pointers. - */ - virtual boost::shared_ptr<void> owner(); - virtual boost::shared_ptr<const void> owner() const; - - private: //representation - - bob::io::base::array::typeinfo m_type; ///< type information - void* m_ptr; ///< pointer to the data - -}; - -#endif /* PYTHON_BOB_IO_BOBSKIN_H */ diff --git a/bob/io/base/codec.cpp b/bob/io/base/codec.cpp deleted file mode 100644 index bfc3eb94de0f9b29371f3d4b9c6a85f45837b441..0000000000000000000000000000000000000000 --- a/bob/io/base/codec.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/** - * @author Andre Anjos <andre.anjos@idiap.ch> - * @date Wed 14 May 11:53:36 2014 CEST - * - * @brief Bindings to bob::io::base::CodecRegistry - */ - -#define BOB_IO_BASE_MODULE -#include <bob.io.base/api.h> - -int PyBobIoCodec_Register (const char* extension, const char* description, bob::io::base::file_factory_t factory) { - boost::shared_ptr<bob::io::base::CodecRegistry> instance = - bob::io::base::CodecRegistry::instance(); - - if (instance->isRegistered(extension)) { - PyErr_Format(PyExc_RuntimeError, "codec for extension `%s' is already registered with description `%s' - in order to register a new codec for such an extension, first unregister the existing codec", extension, PyBobIoCodec_GetDescription(extension)); - return 0; - } - - instance->registerExtension(extension, description, factory); - return 1; -} - -int PyBobIoCodec_Deregister (const char* extension) { - boost::shared_ptr<bob::io::base::CodecRegistry> instance = - bob::io::base::CodecRegistry::instance(); - - if (!instance->isRegistered(extension)) { - PyErr_Format(PyExc_RuntimeError, "there is no codec registered for extension `%s'", extension); - return 0; - } - - instance->deregisterExtension(extension); - return 1; -} - -int PyBobIoCodec_IsRegistered (const char* extension) { - boost::shared_ptr<bob::io::base::CodecRegistry> instance = - bob::io::base::CodecRegistry::instance(); - if (instance->isRegistered(extension)) return 1; - return 0; -} - -const char* PyBobIoCodec_GetDescription (const char* extension) { - boost::shared_ptr<bob::io::base::CodecRegistry> instance = - bob::io::base::CodecRegistry::instance(); - return instance->getDescription(extension); -} diff --git a/bob/io/base/cpp/CodecRegistry.cpp b/bob/io/base/cpp/CodecRegistry.cpp deleted file mode 100644 index 1f6c6d05c19187cda37d8bfc1255d24b54a0a9cf..0000000000000000000000000000000000000000 --- a/bob/io/base/cpp/CodecRegistry.cpp +++ /dev/null @@ -1,98 +0,0 @@ -/** - * @date Tue Oct 25 23:25:46 2011 +0200 - * @author Andre Anjos <andre.anjos@idiap.ch> - * - * @brief Implements the CodecRegistry class. - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#include <vector> - -#include <boost/filesystem.hpp> -#include <boost/format.hpp> - -#include <bob.io.base/CodecRegistry.h> - -#include <bob.core/logging.h> - -boost::shared_ptr<bob::io::base::CodecRegistry> bob::io::base::CodecRegistry::instance() { - static boost::shared_ptr<bob::io::base::CodecRegistry> s_instance(new CodecRegistry()); - return s_instance; -} - -void bob::io::base::CodecRegistry::deregisterExtension(const char* ext) { - s_extension2codec.erase(ext); - s_extension2description.erase(ext); -} - -const char* bob::io::base::CodecRegistry::getDescription(const char* ext) { - auto it = s_extension2description.find(ext); - if (it == s_extension2description.end()) return 0; - return it->second.c_str(); -} - -void bob::io::base::CodecRegistry::deregisterFactory(bob::io::base::file_factory_t factory) { - - std::vector<std::string> to_remove; - for (auto it = s_extension2codec.begin(); it != s_extension2codec.end(); ++it) { - if (it->second == factory) to_remove.push_back(it->first); - } - - for (auto it = to_remove.begin(); it != to_remove.end(); ++it) { - s_extension2codec.erase(*it); - s_extension2description.erase(*it); - } - -} - -void bob::io::base::CodecRegistry::registerExtension(const char* extension, - const char* description, bob::io::base::file_factory_t codec) { - - auto it = s_extension2codec.find(extension); - - if (it == s_extension2codec.end()) { - s_extension2codec[extension] = codec; - s_extension2description[extension] = description; - } - else if (!s_ignore) { - boost::format m("extension already registered: %s - ignoring second registration with description `%s'"); - m % extension % description; - bob::core::error << m.str() << std::endl; - throw std::runtime_error(m.str()); - } - -} - -bool bob::io::base::CodecRegistry::isRegistered(const char* ext) { - std::string extension(ext); - std::string lower_extension = extension; - std::transform(extension.begin(), extension.end(), lower_extension.begin(), ::tolower); - return (s_extension2codec.find(lower_extension) != s_extension2codec.end()); -} - -bob::io::base::file_factory_t bob::io::base::CodecRegistry::findByExtension (const char* ext) { - - std::string extension(ext); - std::string lower_extension = extension; - std::transform(extension.begin(), extension.end(), lower_extension.begin(), ::tolower); - - std::map<std::string, bob::io::base::file_factory_t >::iterator it = - s_extension2codec.find(lower_extension); - - if (it == s_extension2codec.end()) { - boost::format m("unregistered extension: %s"); - m % lower_extension; - throw std::runtime_error(m.str()); - } - - return it->second; - -} - -bob::io::base::file_factory_t bob::io::base::CodecRegistry::findByFilenameExtension -(const char* filename) { - - return findByExtension(boost::filesystem::path(filename).extension().c_str()); - -} diff --git a/bob/io/base/cpp/File.cpp b/bob/io/base/cpp/File.cpp deleted file mode 100644 index bbdfedfe7e2a5d3dc733e2c6360e933475c0ad4d..0000000000000000000000000000000000000000 --- a/bob/io/base/cpp/File.cpp +++ /dev/null @@ -1,10 +0,0 @@ -/** - * @date Tue Oct 25 23:25:46 2011 +0200 - * @author Andre Anjos <andre.anjos@idiap.ch> - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#include <bob.io.base/File.h> - -bob::io::base::File::~File() { } diff --git a/bob/io/base/cpp/HDF5ArrayFile.cpp b/bob/io/base/cpp/HDF5ArrayFile.cpp deleted file mode 100644 index 8a9aa97f888fa38ea24ea37e85d74c883ed646b3..0000000000000000000000000000000000000000 --- a/bob/io/base/cpp/HDF5ArrayFile.cpp +++ /dev/null @@ -1,222 +0,0 @@ -/** - * @date Tue Oct 25 23:25:46 2011 +0200 - * @author Andre Anjos <andre.anjos@idiap.ch> - * - * @brief Implements the HDF5 (.hdf5) array codec - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#include <boost/make_shared.hpp> -#include <boost/filesystem.hpp> -#include <boost/format.hpp> - -#include <bob.io.base/CodecRegistry.h> -#include <bob.io.base/HDF5File.h> - -/** - * Read and write arrays in HDF5 format - */ -class HDF5ArrayFile: public bob::io::base::File { - - public: - - HDF5ArrayFile (const char* filename, bob::io::base::HDF5File::mode_t mode): - m_file(filename, mode), - m_filename(filename), - m_size_arrayset(0), - m_newfile(true) { - - //tries to update the current descriptors - std::vector<std::string> paths; - m_file.paths(paths); - - if (paths.size()) { //file contains data, read it and establish defaults - m_path = paths[0]; ///< locks on a path name from now on... - m_newfile = false; ///< blocks re-initialization - - //arrayset reading - const bob::io::base::HDF5Descriptor& desc_arrayset = m_file.describe(m_path)[0]; - desc_arrayset.type.copy_to(m_type_arrayset); - m_size_arrayset = desc_arrayset.size; - - //array reading - const bob::io::base::HDF5Descriptor& desc_array = m_file.describe(m_path)[1]; - desc_array.type.copy_to(m_type_array); - - //if m_type_all has extent == 1 on the first dimension and dimension - //0 is expandable, collapse that - if (m_type_array.shape[0] == 1 && desc_arrayset.expandable) - { - m_type_array = m_type_arrayset; - } - } - - else { - //default path in case the file is new or has been truncated - m_path = "/array"; - } - - } - - virtual ~HDF5ArrayFile() { } - - virtual const char* filename() const { - return m_filename.c_str(); - } - - virtual const bob::io::base::array::typeinfo& type_all () const { - return m_type_array; - } - - virtual const bob::io::base::array::typeinfo& type () const { - return m_type_arrayset; - } - - virtual size_t size() const { - return m_size_arrayset; - } - - virtual const char* name() const { - return s_codecname.c_str(); - } - - virtual void read_all(bob::io::base::array::interface& buffer) { - - if(m_newfile) { - boost::format f("uninitialized HDF5 file at '%s' cannot be read"); - f % m_filename; - throw std::runtime_error(f.str()); - } - - if(!buffer.type().is_compatible(m_type_array)) buffer.set(m_type_array); - - m_file.read_buffer(m_path, 0, buffer.type(), buffer.ptr()); - } - - virtual void read(bob::io::base::array::interface& buffer, size_t index) { - - if(m_newfile) { - boost::format f("uninitialized HDF5 file at '%s' cannot be read"); - f % m_filename; - throw std::runtime_error(f.str()); - } - - if(!buffer.type().is_compatible(m_type_arrayset)) buffer.set(m_type_arrayset); - - m_file.read_buffer(m_path, index, buffer.type(), buffer.ptr()); - } - - virtual size_t append (const bob::io::base::array::interface& buffer) { - - if (m_newfile) { - //creates non-compressible, extensible dataset on HDF5 file - m_newfile = false; - m_file.create(m_path, buffer.type(), true, 0); - m_file.describe(m_path)[0].type.copy_to(m_type_arrayset); - m_file.describe(m_path)[1].type.copy_to(m_type_array); - - //if m_type_all has extent == 1 on the first dimension, collapse that - if (m_type_array.shape[0] == 1) m_type_array = m_type_arrayset; - } - - m_file.extend_buffer(m_path, buffer.type(), buffer.ptr()); - ++m_size_arrayset; - //needs to flush the data to the file - return m_size_arrayset - 1; ///< index of this object in the file - - } - - virtual void write (const bob::io::base::array::interface& buffer) { - - if (!m_newfile) { - boost::format f("cannot perform single (array-style) write on file/dataset at '%s' that have already been initialized -- try to use a new file"); - f % m_filename; - throw std::runtime_error(f.str()); - } - - m_newfile = false; - m_file.create(m_path, buffer.type(), false, 0); - - m_file.describe(m_path)[0].type.copy_to(m_type_arrayset); - m_file.describe(m_path)[1].type.copy_to(m_type_array); - - //if m_type_all has extent == 1 on the first dimension, collapse that - if (m_type_array.shape[0] == 1) m_type_array = m_type_arrayset; - - //otherwise, all must be in place... - m_file.write_buffer(m_path, 0, buffer.type(), buffer.ptr()); - } - - private: //representation - - bob::io::base::HDF5File m_file; - std::string m_filename; - bob::io::base::array::typeinfo m_type_array; ///< type for reading all data at once - bob::io::base::array::typeinfo m_type_arrayset; ///< type for reading data by sub-arrays - size_t m_size_arrayset; ///< number of arrays in arrayset mode - std::string m_path; ///< default path to use - bool m_newfile; ///< path check optimization - - static std::string s_codecname; - -}; - -std::string HDF5ArrayFile::s_codecname = "bob.hdf5"; - -/** - * From this point onwards we have the registration procedure. If you are - * looking at this file for a coding example, just follow the procedure bellow, - * minus local modifications you may need to apply. - */ - -/** - * This defines the factory method F that can create codecs of this type. - * - * Here are the meanings of the mode flag that should be respected by your - * factory implementation: - * - * 'r': opens for reading only - no modifications can occur; it is an - * error to open a file that does not exist for read-only operations. - * 'w': opens for reading and writing, but truncates the file if it - * exists; it is not an error to open files that do not exist with - * this flag. - * 'a': opens for reading and writing - any type of modification can - * occur. If the file does not exist, this flag is effectively like - * 'w'. - * - * Returns a newly allocated File object that can read and write data to the - * file using a specific backend. - * - * @note: This method can be static. - */ -static boost::shared_ptr<bob::io::base::File> make_file (const char* path, char mode) { - - bob::io::base::HDF5File::mode_t h5mode; - if (mode == 'r') h5mode = bob::io::base::HDF5File::in; - else if (mode == 'w') h5mode = bob::io::base::HDF5File::trunc; - else if (mode == 'a') h5mode = bob::io::base::HDF5File::inout; - else throw std::runtime_error("unsupported file opening mode"); - - return boost::make_shared<HDF5ArrayFile>(path, h5mode); - -} - -/** - * Takes care of codec registration per se. - */ -static bool register_codec() { - static const char* description = "Hierarchical Data Format v5 (default)"; - - boost::shared_ptr<bob::io::base::CodecRegistry> instance = - bob::io::base::CodecRegistry::instance(); - - instance->registerExtension(".h5", description, &make_file); - instance->registerExtension(".hdf5", description, &make_file); - instance->registerExtension(".hdf", description, &make_file); - - return true; - -} - -static bool codec_registered = register_codec(); diff --git a/bob/io/base/cpp/HDF5Attribute.cpp b/bob/io/base/cpp/HDF5Attribute.cpp deleted file mode 100644 index 0a782042d4193fee0cd8c312709baf4103d7406e..0000000000000000000000000000000000000000 --- a/bob/io/base/cpp/HDF5Attribute.cpp +++ /dev/null @@ -1,243 +0,0 @@ -/** - * @author Andre Anjos <andre.anjos@idiap.ch> - * @date Fri 2 Mar 08:23:47 2012 - * - * @brief Implements attribute read/write for HDF5 files - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#include <boost/format.hpp> - -#include <bob.core/logging.h> - -#include <bob.io.base/HDF5Attribute.h> - -static std::runtime_error status_error(const char* f, herr_t s) { - boost::format m("call to HDF5 C-function %s() returned error %d. HDF5 error statck follows:\n%s"); - m % f % s % bob::io::base::format_hdf5_error(); - return std::runtime_error(m.str()); -} - -bool bob::io::base::detail::hdf5::has_attribute(const boost::shared_ptr<hid_t> location, - const std::string& name) { - return H5Aexists(*location, name.c_str()); -} - -/** - * Opens an "auto-destructible" HDF5 dataspace - */ -static void delete_h5dataspace (hid_t* p) { - if (*p >= 0) { - herr_t err = H5Sclose(*p); - if (err < 0) { - bob::core::error << "H5Sclose() exited with an error (" << err << "). The stack trace follows:" << std::endl; - bob::core::error << bob::io::base::format_hdf5_error() << std::endl; - } - } - delete p; -} - -static boost::shared_ptr<hid_t> open_memspace(const bob::io::base::HDF5Shape& s) { - boost::shared_ptr<hid_t> retval(new hid_t(-1), std::ptr_fun(delete_h5dataspace)); - *retval = H5Screate_simple(s.n(), s.get(), 0); - if (*retval < 0) throw status_error("H5Screate_simple", *retval); - return retval; -} - -/** - * Opens the memory space of attribute - */ -static boost::shared_ptr<hid_t> get_memspace(hid_t attr) { - boost::shared_ptr<hid_t> retval(new hid_t(-1), std::ptr_fun(delete_h5dataspace)); - *retval = H5Aget_space(attr); - if (*retval < 0) throw status_error("H5Aget_space", *retval); - return retval; -} - -/** - * Auto-destructing HDF5 type - */ -static void delete_h5type (hid_t* p) { - if (*p >= 0) { - herr_t err = H5Tclose(*p); - if (err < 0) { - bob::core::error << "H5Tclose() exited with an error (" << err << "). The stack trace follows:" << std::endl; - bob::core::error << bob::io::base::format_hdf5_error() << std::endl; - } - } - delete p; -} - -/** - * Gets datatype of attribute - */ -static boost::shared_ptr<hid_t> get_type(hid_t attr) { - boost::shared_ptr<hid_t> retval(new hid_t(-1), std::ptr_fun(delete_h5type)); - *retval = H5Aget_type(attr); - if (*retval < 0) throw status_error("H5Aget_type", *retval); - return retval; -} - -/** - * Figures out the extents of an attribute - */ -static bob::io::base::HDF5Shape get_extents(hid_t space) { - int rank = H5Sget_simple_extent_ndims(space); - if (rank < 0) throw status_error("H5Sget_simple_extent_ndims", rank); - //is at least a list of scalars, but could be a list of arrays - bob::io::base::HDF5Shape shape(rank); - herr_t status = H5Sget_simple_extent_dims(space, shape.get(), 0); - if (status < 0) throw status_error("H5Sget_simple_extent_dims",status); - return shape; -} - -/** - * Opens an "auto-destructible" HDF5 attribute - */ -static void delete_h5attribute (hid_t* p) { - if (*p >= 0) { - herr_t err = H5Aclose(*p); - if (err < 0) { - bob::core::error << "H5Aclose() exited with an error (" << err << "). The stack trace follows:" << std::endl; - bob::core::error << bob::io::base::format_hdf5_error() << std::endl; - } - } - delete p; -} - -static boost::shared_ptr<hid_t> open_attribute -(const boost::shared_ptr<hid_t> location, const std::string& name, - const bob::io::base::HDF5Type& t) { - - boost::shared_ptr<hid_t> retval(new hid_t(-1), - std::ptr_fun(delete_h5attribute)); - - *retval = H5Aopen(*location, name.c_str(), H5P_DEFAULT); - - if (*retval < 0) throw status_error("H5Aopen", *retval); - - //checks if the opened attribute is compatible w/ the expected type - bob::io::base::HDF5Type expected; - boost::shared_ptr<hid_t> atype = get_type(*retval); - if (H5Tget_class(*atype) == H5T_STRING) { - expected = bob::io::base::HDF5Type(atype); - } - else { - boost::shared_ptr<hid_t> aspace = get_memspace(*retval); - bob::io::base::HDF5Shape shape = get_extents(*aspace); - expected = bob::io::base::HDF5Type(atype, shape); - } - - if (expected != t) { - boost::format m("Trying to access attribute '%s' with incompatible buffer - expected `%s', but you gave me `%s'"); - m % name % expected.str() % t.str(); - throw std::runtime_error(m.str()); - } - - return retval; -} - -void bob::io::base::detail::hdf5::delete_attribute (boost::shared_ptr<hid_t> location, - const std::string& name) { - herr_t err = H5Adelete(*location, name.c_str()); - if (err < 0) throw status_error("H5Adelete", err); -} - -void bob::io::base::detail::hdf5::read_attribute (const boost::shared_ptr<hid_t> location, - const std::string& name, const bob::io::base::HDF5Type& dest, - void* buffer) { - boost::shared_ptr<hid_t> attribute = open_attribute(location, name, dest); - herr_t err = H5Aread(*attribute, *dest.htype(), buffer); - if (err < 0) throw status_error("H5Aread", err); -} - -void bob::io::base::detail::hdf5::gettype_attribute (const boost::shared_ptr<hid_t> location, - const std::string& name, bob::io::base::HDF5Type& type) { - - boost::shared_ptr<hid_t> attr(new hid_t(-1), - std::ptr_fun(delete_h5attribute)); - - *attr = H5Aopen(*location, name.c_str(), H5P_DEFAULT); - - if (*attr < 0) throw status_error("H5Aopen", *attr); - - boost::shared_ptr<hid_t> atype = get_type(*attr); - if (H5Tget_class(*atype) == H5T_STRING) { - type = bob::io::base::HDF5Type(atype); - } - else { - boost::shared_ptr<hid_t> aspace = get_memspace(*attr); - bob::io::base::HDF5Shape shape = get_extents(*aspace); - type = bob::io::base::HDF5Type(atype, shape); - } -} - -static boost::shared_ptr<hid_t> create_attribute(boost::shared_ptr<hid_t> loc, - const std::string& name, const bob::io::base::HDF5Type& t, - boost::shared_ptr<hid_t> space) { - - boost::shared_ptr<hid_t> retval(new hid_t(-1), - std::ptr_fun(delete_h5attribute)); - - *retval = H5Acreate2(*loc, name.c_str(), *t.htype(), *space, H5P_DEFAULT, - H5P_DEFAULT); - - if (*retval < 0) throw status_error("H5Acreate", *retval); - return retval; -} - -void bob::io::base::detail::hdf5::write_attribute (boost::shared_ptr<hid_t> location, - const std::string& name, const bob::io::base::HDF5Type& dest, const void* buffer) -{ - boost::shared_ptr<hid_t> dataspace; - //strings have to be treated slightly differently - if (dest.type() == bob::io::base::s) { - hsize_t strings = 1; - HDF5Shape shape(1, &strings); - dataspace = open_memspace(shape); - } - else { - dataspace = open_memspace(dest.shape()); - } - - if (bob::io::base::detail::hdf5::has_attribute(location, name)) bob::io::base::detail::hdf5::delete_attribute(location, name); - boost::shared_ptr<hid_t> attribute = - create_attribute(location, name, dest, dataspace); - - /* Write the attribute data. */ - herr_t err = H5Awrite(*attribute, *dest.htype(), buffer); - if (err < 0) throw status_error("H5Awrite", err); -} - -static herr_t attr_iterator (hid_t obj, const char* name, const H5A_info_t*, - void* cookie) { - std::map<std::string, bob::io::base::HDF5Type>& dict = - *static_cast<std::map<std::string, bob::io::base::HDF5Type>*>(cookie); - - boost::shared_ptr<hid_t> attr(new hid_t(-1), - std::ptr_fun(delete_h5attribute)); - - *attr = H5Aopen(obj, name, H5P_DEFAULT); - - if (*attr < 0) throw status_error("H5Aopen", *attr); - - boost::shared_ptr<hid_t> atype = get_type(*attr); - if (H5Tget_class(*atype) == H5T_STRING) { - dict[name] = bob::io::base::HDF5Type(atype); - } - else { - boost::shared_ptr<hid_t> aspace = get_memspace(*attr); - bob::io::base::HDF5Shape shape = get_extents(*aspace); - dict[name] = bob::io::base::HDF5Type(atype, shape); - } - - return 0; -} - -void bob::io::base::detail::hdf5::list_attributes(boost::shared_ptr<hid_t> location, - std::map<std::string, bob::io::base::HDF5Type>& attributes) { - hsize_t offset=0; - H5Aiterate2(*location, H5_INDEX_NAME, H5_ITER_NATIVE, &offset, attr_iterator, - static_cast<void*>(&attributes)); -} diff --git a/bob/io/base/cpp/HDF5Dataset.cpp b/bob/io/base/cpp/HDF5Dataset.cpp deleted file mode 100644 index 9fb6a0a232db5efbfa7f71e3e206cb22534419ab..0000000000000000000000000000000000000000 --- a/bob/io/base/cpp/HDF5Dataset.cpp +++ /dev/null @@ -1,612 +0,0 @@ -/** - * @author Andre Anjos <andre.anjos@idiap.ch> - * @date Wed 29 Feb 17:51:21 2012 - * - * @brief Implementation of the Dataset class - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#include <boost/format.hpp> -#include <boost/make_shared.hpp> -#include <boost/shared_array.hpp> - -#include <bob.core/logging.h> - -#include <bob.io.base/HDF5Utils.h> -#include <bob.io.base/HDF5Group.h> -#include <bob.io.base/HDF5Dataset.h> - -static std::runtime_error status_error(const char* f, herr_t s) { - boost::format m("call to HDF5 C-function %s() returned error %d. HDF5 error statck follows:\n%s"); - m % f % s % bob::io::base::format_hdf5_error(); - return std::runtime_error(m.str()); -} - -/** - * Opens an "auto-destructible" HDF5 dataset - */ -static void delete_h5dataset (hid_t* p) { - if (*p >= 0) { - herr_t err = H5Dclose(*p); - if (err < 0) { - bob::core::error << "H5Dclose() exited with an error (" << err << "). The stack trace follows:" << std::endl; - bob::core::error << bob::io::base::format_hdf5_error() << std::endl; - } - } - delete p; -} - -static boost::shared_ptr<hid_t> open_dataset -(boost::shared_ptr<bob::io::base::detail::hdf5::Group>& par, const std::string& name) { - if (!name.size() || name == "." || name == "..") { - boost::format m("Cannot open dataset with illegal name `%s' at `%s:%s'"); - m % name % par->file()->filename() % par->path(); - throw std::runtime_error(m.str()); - } - - boost::shared_ptr<hid_t> retval(new hid_t(-1), - std::ptr_fun(delete_h5dataset)); - *retval = H5Dopen2(*par->location(), name.c_str(), H5P_DEFAULT); - if (*retval < 0) { - throw status_error("H5Dopen2", *retval); - } - return retval; -} - -/** - * Opens an "auto-destructible" HDF5 datatype - */ -static void delete_h5datatype (hid_t* p) { - if (*p >= 0) { - herr_t err = H5Tclose(*p); - if (err < 0) { - bob::core::error << "H5Tclose() exited with an error (" << err << "). The stack trace follows:" << std::endl; - bob::core::error << bob::io::base::format_hdf5_error() << std::endl; - } - } - delete p; -} - -static boost::shared_ptr<hid_t> open_datatype -(const boost::shared_ptr<hid_t>& ds) { - boost::shared_ptr<hid_t> retval(new hid_t(-1), - std::ptr_fun(delete_h5datatype)); - *retval = H5Dget_type(*ds); - if (*retval < 0) { - throw status_error("H5Dget_type", *retval); - } - return retval; -} - -/** - * Opens an "auto-destructible" HDF5 property list - */ -static void delete_h5plist (hid_t* p) { - if (*p >= 0) { - herr_t err = H5Pclose(*p); - if (err < 0) { - bob::core::error << "H5Pclose() exited with an error (" << err << "). The stack trace follows:" << std::endl; - bob::core::error << bob::io::base::format_hdf5_error() << std::endl; - } - } - delete p; -} - -static boost::shared_ptr<hid_t> open_plist(hid_t classid) { - boost::shared_ptr<hid_t> retval(new hid_t(-1), std::ptr_fun(delete_h5plist)); - *retval = H5Pcreate(classid); - if (*retval < 0) { - throw status_error("H5Pcreate", *retval); - } - return retval; -} - -/** - * Opens an "auto-destructible" HDF5 dataspace - */ -static void delete_h5dataspace (hid_t* p) { - if (*p >= 0) { - herr_t err = H5Sclose(*p); - if (err < 0) { - bob::core::error << "H5Sclose() exited with an error (" << err << "). The stack trace follows:" << std::endl; - bob::core::error << bob::io::base::format_hdf5_error() << std::endl; - } - } - delete p; -} - -static boost::shared_ptr<hid_t> open_filespace -(const boost::shared_ptr<hid_t>& ds) { - boost::shared_ptr<hid_t> retval(new hid_t(-1), std::ptr_fun(delete_h5dataspace)); - *retval = H5Dget_space(*ds); - if (*retval < 0) throw status_error("H5Dget_space", *retval); - return retval; -} - -static boost::shared_ptr<hid_t> open_memspace(const bob::io::base::HDF5Shape& sh) { - boost::shared_ptr<hid_t> retval(new hid_t(-1), std::ptr_fun(delete_h5dataspace)); - *retval = H5Screate_simple(sh.n(), sh.get(), 0); - if (*retval < 0) throw status_error("H5Screate_simple", *retval); - return retval; -} - -static void set_memspace(boost::shared_ptr<hid_t> s, const bob::io::base::HDF5Shape& sh) { - herr_t status = H5Sset_extent_simple(*s, sh.n(), sh.get(), 0); - if (status < 0) throw status_error("H5Sset_extent_simple", status); -} - -/** - * Figures out if a dataset is expandible - */ -static bool is_extensible(boost::shared_ptr<hid_t>& space) { - - //has unlimited size on first dimension? - int rank = H5Sget_simple_extent_ndims(*space); - if (rank < 0) throw status_error("H5Sget_simple_extent_ndims", rank); - - bob::io::base::HDF5Shape maxshape(rank); - herr_t status = H5Sget_simple_extent_dims(*space, 0, maxshape.get()); - if (status < 0) throw status_error("H5Sget_simple_extent_dims",status); - - return (maxshape[0] == H5S_UNLIMITED); -} - -/** - * Figures out the extents of a dataset - */ -static bob::io::base::HDF5Shape get_extents(boost::shared_ptr<hid_t>& space) { - int rank = H5Sget_simple_extent_ndims(*space); - if (rank < 0) throw status_error("H5Sget_simple_extent_ndims", rank); - //is at least a list of scalars, but could be a list of arrays - bob::io::base::HDF5Shape shape(rank); - herr_t status = H5Sget_simple_extent_dims(*space, shape.get(), 0); - if (status < 0) throw status_error("H5Sget_simple_extent_dims",status); - return shape; -} - -/** - * Creates the extensive list of compatible types for each of possible ways to - * read/write this dataset. - */ -static void reset_compatibility_list(boost::shared_ptr<hid_t>& space, - const bob::io::base::HDF5Type& file_base, std::vector<bob::io::base::HDF5Descriptor>& descr) { - - if (!file_base.shape()) throw std::runtime_error("empty HDF5 dataset"); - - descr.clear(); - - switch (file_base.shape().n()) { - - case 1: ///< file type has 1 dimension - descr.push_back(bob::io::base::HDF5Descriptor(file_base.type(), - file_base.shape()[0], is_extensible(space))); - break; - - case 2: - case 3: - case 4: - case 5: - { - bob::io::base::HDF5Shape alt = file_base.shape(); - alt <<= 1; ///< contract shape - descr.push_back(bob::io::base::HDF5Descriptor(bob::io::base::HDF5Type(file_base.type(), alt), - file_base.shape()[0], is_extensible(space)).subselect()); - } - break; - - default: - { - boost::format m("%d exceeds the number of supported dimensions"); - m % file_base.shape().n(); - throw std::runtime_error(m.str()); - } - } - - //can always read the data as a single, non-expandible array - descr.push_back(bob::io::base::HDF5Descriptor(file_base, 1, false)); -} - -bob::io::base::detail::hdf5::Dataset::Dataset(boost::shared_ptr<Group> parent, - const std::string& name) : - m_parent(parent), - m_name(name), - m_id(open_dataset(parent, name)), - m_dt(open_datatype(m_id)), - m_filespace(open_filespace(m_id)), - m_descr(), - m_memspace() -{ - bob::io::base::HDF5Type type(m_dt, get_extents(m_filespace)); - reset_compatibility_list(m_filespace, type, m_descr); - - //strings have to be treated slightly differently - if (H5Tget_class(*m_dt) == H5T_STRING) { - hsize_t strings = 1; - HDF5Shape shape(1, &strings); - m_memspace = open_memspace(shape); - } - else { - m_memspace = open_memspace(m_descr[0].type.shape()); - } -} - -/** - * Creates and writes an "empty" Dataset in an existing file. - */ -static void create_dataset (boost::shared_ptr<bob::io::base::detail::hdf5::Group> par, - const std::string& name, const bob::io::base::HDF5Type& type, bool list, - size_t compression) { - - if (!name.size() || name == "." || name == "..") { - boost::format m("Cannot create dataset with illegal name `%s' at `%s:%s'"); - m % name % par->file()->filename() % par->path(); - throw std::runtime_error(m.str()); - } - - bob::io::base::HDF5Shape xshape(type.shape()); - - if (list) { ///< if it is a list, add and extra dimension as dimension 0 - xshape = type.shape(); - xshape >>= 1; - xshape[0] = 0; ///< no elements for the time being - } - - bob::io::base::HDF5Shape maxshape(xshape); - if (list) maxshape[0] = H5S_UNLIMITED; ///< can expand forever - - //creates the data space. - boost::shared_ptr<hid_t> space(new hid_t(-1), - std::ptr_fun(delete_h5dataspace)); - *space = H5Screate_simple(xshape.n(), xshape.get(), maxshape.get()); - if (*space < 0) throw status_error("H5Screate_simple", *space); - - //creates the property list saying we need the data to be chunked if this is - //supposed to be a list -- HDF5 only supports expandability like this. - boost::shared_ptr<hid_t> dcpl = open_plist(H5P_DATASET_CREATE); - - //according to the HDF5 manual, chunks have to have the same rank as the - //array shape. - bob::io::base::HDF5Shape chunking(xshape); - chunking[0] = 1; - if (list || compression) { ///< note: compression requires chunking - herr_t status = H5Pset_chunk(*dcpl, chunking.n(), chunking.get()); - if (status < 0) throw status_error("H5Pset_chunk", status); - } - - //if the user has decided to compress the dataset, do it with gzip. - if (compression) { - if (compression > 9) compression = 9; - herr_t status = H5Pset_deflate(*dcpl, compression); - if (status < 0) throw status_error("H5Pset_deflate", status); - } - - //our link creation property list for HDF5 - boost::shared_ptr<hid_t> lcpl = open_plist(H5P_LINK_CREATE); - herr_t status = H5Pset_create_intermediate_group(*lcpl, 1); //1 == true - if (status < 0) - throw status_error("H5Pset_create_intermediate_group", status); - - //please note that we don't define the fill value as in the example, but - //according to the HDF5 documentation, this value is set to zero by default. - - boost::shared_ptr<hid_t> cls = type.htype(); - - //finally create the dataset on the file. - boost::shared_ptr<hid_t> dataset(new hid_t(-1), - std::ptr_fun(delete_h5dataset)); - *dataset = H5Dcreate2(*par->location(), name.c_str(), - *cls, *space, *lcpl, *dcpl, H5P_DEFAULT); - - if (*dataset < 0) throw status_error("H5Dcreate2", *dataset); -} - -/** - * Creates and writes an "empty" std::string Dataset in an existing file. - */ -static void create_string_dataset (boost::shared_ptr<bob::io::base::detail::hdf5::Group> par, - const std::string& name, const bob::io::base::HDF5Type& type, size_t compression) { - - if (!name.size() || name == "." || name == "..") { - boost::format m("Cannot create dataset with illegal name `%s' at `%s:%s'"); - m % name % par->file()->filename() % par->path(); - throw std::runtime_error(m.str()); - } - - //there can be only 1 string in a string dataset (for the time being) - hsize_t strings = 1; - bob::io::base::HDF5Shape xshape(1, &strings); - - //creates the data space. - boost::shared_ptr<hid_t> space(new hid_t(-1), - std::ptr_fun(delete_h5dataspace)); - *space = H5Screate_simple(xshape.n(), xshape.get(), xshape.get()); - if (*space < 0) throw status_error("H5Screate_simple", *space); - - //creates the property list saying we need the data to be chunked if this is - //supposed to be a list -- HDF5 only supports expandability like this. - boost::shared_ptr<hid_t> dcpl = open_plist(H5P_DATASET_CREATE); - - //if the user has decided to compress the dataset, do it with gzip. - if (compression) { - if (compression > 9) compression = 9; - herr_t status = H5Pset_deflate(*dcpl, compression); - if (status < 0) throw status_error("H5Pset_deflate", status); - } - - //our link creation property list for HDF5 - boost::shared_ptr<hid_t> lcpl = open_plist(H5P_LINK_CREATE); - herr_t status = H5Pset_create_intermediate_group(*lcpl, 1); //1 == true - if (status < 0) - throw status_error("H5Pset_create_intermediate_group", status); - - //please note that we don't define the fill value as in the example, but - //according to the HDF5 documentation, this value is set to zero by default. - - boost::shared_ptr<hid_t> cls = type.htype(); - - //finally create the dataset on the file. - boost::shared_ptr<hid_t> dataset(new hid_t(-1), - std::ptr_fun(delete_h5dataset)); - *dataset = H5Dcreate2(*par->location(), name.c_str(), - *cls, *space, *lcpl, *dcpl, H5P_DEFAULT); - - if (*dataset < 0) throw status_error("H5Dcreate2", *dataset); -} - -bob::io::base::detail::hdf5::Dataset::Dataset(boost::shared_ptr<Group> parent, - const std::string& name, const bob::io::base::HDF5Type& type, - bool list, size_t compression): - m_parent(parent), - m_name(name), - m_id(), - m_dt(), - m_filespace(), - m_descr(), - m_memspace() -{ - //First, we test to see if we can find the named dataset. - bob::io::base::DefaultHDF5ErrorStack->mute(); - hid_t set_id = H5Dopen2(*parent->location(),m_name.c_str(),H5P_DEFAULT); - bob::io::base::DefaultHDF5ErrorStack->unmute(); - - if (set_id < 0) { - if (type.type() == bob::io::base::s) - create_string_dataset(parent, m_name, type, compression); - else - create_dataset(parent, m_name, type, list, compression); - } - else H5Dclose(set_id); //close it, will re-open it properly - - m_id = open_dataset(parent, m_name); - m_dt = open_datatype(m_id); - m_filespace = open_filespace(m_id); - bob::io::base::HDF5Type file_type(m_dt, get_extents(m_filespace)); - reset_compatibility_list(m_filespace, file_type, m_descr); - - //strings have to be treated slightly differently - if (H5Tget_class(*m_dt) == H5T_STRING) { - hsize_t strings = 1; - HDF5Shape shape(1, &strings); - m_memspace = open_memspace(shape); - } - else { - m_memspace = open_memspace(m_descr[0].type.shape()); - } -} - -bob::io::base::detail::hdf5::Dataset::~Dataset() { } - -size_t bob::io::base::detail::hdf5::Dataset::size () const { - return m_descr[0].size; -} - -size_t bob::io::base::detail::hdf5::Dataset::size (const bob::io::base::HDF5Type& type) const { - for (size_t k=0; k<m_descr.size(); ++k) { - if (m_descr[k].type == type) return m_descr[k].size; - } - boost::format m("trying to read or write `%s' at `%s' that only accepts `%s'"); - m % type.str() % url() % m_descr[0].type.str(); - throw std::runtime_error(m.str()); -} - -const boost::shared_ptr<bob::io::base::detail::hdf5::Group> bob::io::base::detail::hdf5::Dataset::parent() const { - return m_parent.lock(); -} - -boost::shared_ptr<bob::io::base::detail::hdf5::Group> bob::io::base::detail::hdf5::Dataset::parent() { - return m_parent.lock(); -} - -const std::string& bob::io::base::detail::hdf5::Dataset::filename() const { - return parent()->filename(); -} - -std::string bob::io::base::detail::hdf5::Dataset::url() const { - return filename() + ":" + path(); -} - -std::string bob::io::base::detail::hdf5::Dataset::path() const { - return parent()->path() + "/" + m_name; -} - -const boost::shared_ptr<bob::io::base::detail::hdf5::File> bob::io::base::detail::hdf5::Dataset::file() const { - return parent()->file(); -} - -boost::shared_ptr<bob::io::base::detail::hdf5::File> bob::io::base::detail::hdf5::Dataset::file() { - return parent()->file(); -} - -/** - * Locates a compatible type or returns end(). - */ -static std::vector<bob::io::base::HDF5Descriptor>::iterator - find_type_index(std::vector<bob::io::base::HDF5Descriptor>& descr, - const bob::io::base::HDF5Type& user_type) { - std::vector<bob::io::base::HDF5Descriptor>::iterator it = descr.begin(); - for (; it != descr.end(); ++it) { - if (it->type == user_type) break; - } - return it; -} - -std::vector<bob::io::base::HDF5Descriptor>::iterator -bob::io::base::detail::hdf5::Dataset::select (size_t index, const bob::io::base::HDF5Type& dest) { - - //finds compatibility type - std::vector<bob::io::base::HDF5Descriptor>::iterator it = find_type_index(m_descr, dest); - - //if we cannot find a compatible type, we throw - if (it == m_descr.end()) { - boost::format m("trying to read or write `%s' at `%s' that only accepts `%s'"); - m % dest.str() % url() % m_descr[0].type.str(); - throw std::runtime_error(m.str()); - } - - //checks indexing - if (index >= it->size) { - boost::format m("trying to access element %d in Dataset '%s' that only contains %d elements"); - m % index % url() % it->size; - throw std::runtime_error(m.str()); - } - - set_memspace(m_memspace, it->type.shape()); - - it->hyperslab_start[0] = index; - - herr_t status = H5Sselect_hyperslab(*m_filespace, H5S_SELECT_SET, - it->hyperslab_start.get(), 0, it->hyperslab_count.get(), 0); - if (status < 0) throw status_error("H5Sselect_hyperslab", status); - - return it; -} - -void bob::io::base::detail::hdf5::Dataset::read_buffer (size_t index, const bob::io::base::HDF5Type& dest, void* buffer) { - - std::vector<bob::io::base::HDF5Descriptor>::iterator it = select(index, dest); - - herr_t status = H5Dread(*m_id, *it->type.htype(), - *m_memspace, *m_filespace, H5P_DEFAULT, buffer); - - if (status < 0) throw status_error("H5Dread", status); -} - -void bob::io::base::detail::hdf5::Dataset::write_buffer (size_t index, const bob::io::base::HDF5Type& dest, - const void* buffer) { - - std::vector<bob::io::base::HDF5Descriptor>::iterator it = select(index, dest); - - herr_t status = H5Dwrite(*m_id, *it->type.htype(), - *m_memspace, *m_filespace, H5P_DEFAULT, buffer); - - if (status < 0) throw status_error("H5Dwrite", status); -} - -void bob::io::base::detail::hdf5::Dataset::extend_buffer (const bob::io::base::HDF5Type& dest, const void* buffer) { - - //finds compatibility type - std::vector<bob::io::base::HDF5Descriptor>::iterator it = find_type_index(m_descr, dest); - - //if we cannot find a compatible type, we throw - if (it == m_descr.end()) { - boost::format m("trying to read or write `%s' at `%s' that only accepts `%s'"); - m % dest.str() % url() % m_descr[0].type.str(); - throw std::runtime_error(m.str()); - } - - if (!it->expandable) { - boost::format m("trying to append to '%s' that is not expandible"); - m % url(); - throw std::runtime_error(m.str()); - } - - //if it is expandible, try expansion - bob::io::base::HDF5Shape tmp(it->type.shape()); - tmp >>= 1; - tmp[0] = it->size + 1; - herr_t status = H5Dset_extent(*m_id, tmp.get()); - if (status < 0) throw status_error("H5Dset_extent", status); - - //if expansion succeeded, update all compatible types - for (size_t k=0; k<m_descr.size(); ++k) { - if (m_descr[k].expandable) { //updated only the length - m_descr[k].size += 1; - } - else { //not expandable, update the shape/count for a straight read/write - m_descr[k].type.shape()[0] += 1; - m_descr[k].hyperslab_count[0] += 1; - } - } - - m_filespace = open_filespace(m_id); //update filespace - - write_buffer(tmp[0]-1, dest, buffer); -} - -void bob::io::base::detail::hdf5::Dataset::gettype_attribute(const std::string& name, - bob::io::base::HDF5Type& type) const { - bob::io::base::detail::hdf5::gettype_attribute(m_id, name, type); -} - -bool bob::io::base::detail::hdf5::Dataset::has_attribute(const std::string& name) const { - return bob::io::base::detail::hdf5::has_attribute(m_id, name); -} - -void bob::io::base::detail::hdf5::Dataset::delete_attribute (const std::string& name) { - bob::io::base::detail::hdf5::delete_attribute(m_id, name); -} - -void bob::io::base::detail::hdf5::Dataset::read_attribute (const std::string& name, - const bob::io::base::HDF5Type& dest_type, void* buffer) const { - bob::io::base::detail::hdf5::read_attribute(m_id, name, dest_type, buffer); -} - -void bob::io::base::detail::hdf5::Dataset::write_attribute (const std::string& name, - const bob::io::base::HDF5Type& dest_type, const void* buffer) { - bob::io::base::detail::hdf5::write_attribute(m_id, name, dest_type, buffer); -} - -void bob::io::base::detail::hdf5::Dataset::list_attributes(std::map<std::string, bob::io::base::HDF5Type>& attributes) const { - bob::io::base::detail::hdf5::list_attributes(m_id, attributes); -} - -template <> void bob::io::base::detail::hdf5::Dataset::read<std::string>(size_t index, std::string& value) { - if (index != 0) throw std::runtime_error("Bob's HDF5 bindings do not (yet) support string vectors - reading something on position > 0 is therefore not possible"); - - size_t str_size = H5Tget_size(*m_dt); ///< finds out string size - boost::shared_array<char> storage(new char[str_size+1]); - storage[str_size] = 0; ///< null termination - - herr_t status = H5Dread(*m_id, *m_dt, *m_memspace, *m_filespace, H5P_DEFAULT, storage.get()); - if (status < 0) throw status_error("H5Dread", status); - - value = storage.get(); -} - -template <> void bob::io::base::detail::hdf5::Dataset::replace<std::string>(size_t index, const std::string& value) { - if (index != 0) throw std::runtime_error("Bob's HDF5 bindings do not (yet) support string vectors - indexing something on position > 0 is therefore not possible"); - - herr_t status = H5Dwrite(*m_id, *m_dt, *m_memspace, *m_filespace, H5P_DEFAULT, value.c_str()); - if (status < 0) throw status_error("H5Dwrite", status); -} - -template <> void bob::io::base::detail::hdf5::Dataset::add<std::string>(const std::string& value) { - herr_t status = H5Dwrite(*m_id, *m_dt, *m_memspace, *m_filespace, H5P_DEFAULT, value.c_str()); - if (status < 0) throw status_error("H5Dwrite", status); -} - -template <> void bob::io::base::detail::hdf5::Dataset::set_attribute<std::string>(const std::string& name, const std::string& v) { - bob::io::base::HDF5Type dest_type(v); - write_attribute(name, dest_type, reinterpret_cast<const void*>(v.c_str())); -} - -template <> std::string bob::io::base::detail::hdf5::Dataset::get_attribute(const std::string& name) const { - HDF5Type type; - gettype_attribute(name, type); - boost::shared_array<char> v(new char[type.shape()[0]+1]); - v[type.shape()[0]] = 0; ///< null termination - read_attribute(name, type, reinterpret_cast<void*>(v.get())); - std::string retval(v.get()); - return retval; -} diff --git a/bob/io/base/cpp/HDF5File.cpp b/bob/io/base/cpp/HDF5File.cpp deleted file mode 100644 index 549069f8ab821df603ef35727d0da07a4a757137..0000000000000000000000000000000000000000 --- a/bob/io/base/cpp/HDF5File.cpp +++ /dev/null @@ -1,294 +0,0 @@ -/** - * @date Wed Jun 22 17:50:08 2011 +0200 - * @author Andre Anjos <andre.anjos@idiap.ch> - * - * @brief Implementation of the read/write functionality for HDF5 files - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#include <boost/format.hpp> - -#include <bob.io.base/HDF5File.h> - -static unsigned int getH5Access (bob::io::base::HDF5File::mode_t v) { - switch(v) { - case 0: return H5F_ACC_RDONLY; - case 1: return H5F_ACC_RDWR; - case 2: return H5F_ACC_TRUNC; - case 4: return H5F_ACC_EXCL; - default: - { - boost::format m("Trying to use an undefined access mode '%d'"); - m % v; - throw std::runtime_error(m.str()); - } - } -} - -bob::io::base::HDF5File::HDF5File(const std::string& filename, mode_t mode): - m_file(new bob::io::base::detail::hdf5::File(filename, getH5Access(mode))), - m_cwd(m_file->root()) ///< we start by looking at the root directory -{ -} - -bob::io::base::HDF5File::HDF5File(const std::string& filename, const char mode): -m_file(), -m_cwd() -{ - bob::io::base::HDF5File::mode_t new_mode = bob::io::base::HDF5File::inout; - switch (mode){ - case 'r': new_mode = bob::io::base::HDF5File::in; break; - case 'a': new_mode = bob::io::base::HDF5File::inout; break; - case 'w': new_mode = bob::io::base::HDF5File::trunc; break; - case 'x': new_mode = bob::io::base::HDF5File::excl; break; - default: - throw std::runtime_error("Supported flags are 'r' (read-only), 'a' (read/write/append), 'w' (read/write/truncate) or 'x' (read/write/exclusive)"); - } - m_file.reset(new bob::io::base::detail::hdf5::File(filename, getH5Access(new_mode))); - m_cwd = m_file->root(); ///< we start by looking at the root directory - -} - -bob::io::base::HDF5File::HDF5File(const bob::io::base::HDF5File& other_file): - m_file(other_file.m_file), - m_cwd(other_file.m_cwd) -{ -} - -bob::io::base::HDF5File::~HDF5File() { -} - -bob::io::base::HDF5File& bob::io::base::HDF5File::operator =(const bob::io::base::HDF5File& other_file){ - m_file = other_file.m_file; - m_cwd = other_file.m_cwd; - return *this; -} - -void bob::io::base::HDF5File::close() { - m_file.reset(); - m_cwd.reset(); -} - -void bob::io::base::HDF5File::cd(const std::string& path) { - check_open(); - m_cwd = m_cwd->cd(path); -} - -bool bob::io::base::HDF5File::hasGroup(const std::string& path) { - check_open(); - return m_cwd->has_group(path); -} - -void bob::io::base::HDF5File::createGroup(const std::string& path) { - check_open(); - if (!m_file->writable()) { - boost::format m("cannot create group '%s' at path '%s' of file '%s' because it is not writeable"); - m % path % m_cwd->path() % m_file->filename(); - throw std::runtime_error(m.str()); - } - m_cwd->create_group(path); -} - -std::string bob::io::base::HDF5File::cwd() const { - check_open(); - return m_cwd->path(); -} - -bool bob::io::base::HDF5File::contains (const std::string& path) const { - check_open(); - return m_cwd->has_dataset(path); -} - -const std::vector<bob::io::base::HDF5Descriptor>& bob::io::base::HDF5File::describe -(const std::string& path) const { - check_open(); - return (*m_cwd)[path]->m_descr; -} - -void bob::io::base::HDF5File::unlink (const std::string& path) { - check_open(); - if (!m_file->writable()) { - boost::format m("cannot remove dataset at path '%s' of file '%s' because it is not writeable"); - m % path % m_cwd->path() % m_file->filename(); - throw std::runtime_error(m.str()); - } - m_cwd->remove_dataset(path); -} - -void bob::io::base::HDF5File::rename (const std::string& from, const std::string& to) { - check_open(); - if (!m_file->writable()) { - boost::format m("cannot rename dataset '%s' -> '%s' at path '%s' of file '%s' because it is not writeable"); - m % from % to % m_cwd->path() % m_file->filename(); - throw std::runtime_error(m.str()); - } - m_cwd->rename_dataset(from, to); - std::string current_path = m_cwd->path(); - m_file->reset(); //re-read the whole structure - m_cwd = m_file->root(); - m_cwd = m_cwd->cd(current_path); //go back to the path we were before -} - -void bob::io::base::HDF5File::copy (HDF5File& other) { - check_open(); - if (!m_file->writable()) { - boost::format m("cannot copy data of file '%s' to path '%s' of file '%s' because it is not writeable"); - m % other.filename() % m_cwd->path() % m_file->filename(); - throw std::runtime_error(m.str()); - } - - //groups - typedef std::map<std::string, boost::shared_ptr<bob::io::base::detail::hdf5::Group> > group_map_type; - const group_map_type& group_map = other.m_file->root()->groups(); - for (group_map_type::const_iterator it=group_map.begin(); - it != group_map.end(); ++it) { - m_cwd->copy_group(it->second, it->first); - } - - //datasets - typedef std::map<std::string, boost::shared_ptr<bob::io::base::detail::hdf5::Dataset> > dataset_map_type; - const dataset_map_type& dataset_map = other.m_file->root()->datasets(); - for (dataset_map_type::const_iterator it=dataset_map.begin(); - it != dataset_map.end(); ++it) { - m_cwd->copy_dataset(it->second, it->first); - } -} - -void bob::io::base::HDF5File::create (const std::string& path, const bob::io::base::HDF5Type& type, - bool list, size_t compression) { - check_open(); - if (!m_file->writable()) { - boost::format m("cannot create dataset '%s' at path '%s' of file '%s' because it is not writeable"); - m % path % m_cwd->path() % m_file->filename(); - throw std::runtime_error(m.str()); - } - if (!contains(path)) m_cwd->create_dataset(path, type, list, compression); - else (*m_cwd)[path]->size(type); -} - -void bob::io::base::HDF5File::read_buffer (const std::string& path, size_t pos, - const bob::io::base::HDF5Type& type, void* buffer) const { - check_open(); - (*m_cwd)[path]->read_buffer(pos, type, buffer); -} - -void bob::io::base::HDF5File::write_buffer (const std::string& path, - size_t pos, const bob::io::base::HDF5Type& type, const void* buffer) { - check_open(); - if (!m_file->writable()) { - boost::format m("cannot write to object '%s' at path '%s' of file '%s' because it is not writeable"); - m % path % m_cwd->path() % m_file->filename(); - throw std::runtime_error(m.str()); - } - (*m_cwd)[path]->write_buffer(pos, type, buffer); -} - -void bob::io::base::HDF5File::extend_buffer(const std::string& path, - const bob::io::base::HDF5Type& type, const void* buffer) { - check_open(); - if (!m_file->writable()) { - boost::format m("cannot extend object '%s' at path '%s' of file '%s' because the file is not writeable"); - m % path % m_cwd->path() % m_file->filename(); - throw std::runtime_error(m.str()); - } - (*m_cwd)[path]->extend_buffer(type, buffer); -} - -bool bob::io::base::HDF5File::hasAttribute(const std::string& path, - const std::string& name) const { - check_open(); - if (m_cwd->has_dataset(path)) { - return (*m_cwd)[path]->has_attribute(name); - } - else if (m_cwd->has_group(path)) { - return m_cwd->cd(path)->has_attribute(name); - } - return false; -} - -void bob::io::base::HDF5File::getAttributeType(const std::string& path, - const std::string& name, HDF5Type& type) const { - check_open(); - if (m_cwd->has_dataset(path)) { - (*m_cwd)[path]->gettype_attribute(name, type); - } - else if (m_cwd->has_group(path)) { - m_cwd->cd(path)->gettype_attribute(name, type); - } - else { - boost::format m("cannot read attribute '%s' type at path/dataset '%s' of file '%s' (cwd: '%s') because this path/dataset does not currently exist"); - m % name % path % m_file->filename() % m_cwd->path(); - throw std::runtime_error(m.str()); - } -} - -void bob::io::base::HDF5File::deleteAttribute(const std::string& path, - const std::string& name) { - check_open(); - if (m_cwd->has_dataset(path)) { - (*m_cwd)[path]->delete_attribute(name); - } - else if (m_cwd->has_group(path)) { - m_cwd->cd(path)->delete_attribute(name); - } - else { - boost::format m("cannot delete attribute '%s' at path/dataset '%s' of file '%s' (cwd: '%s') because this path/dataset does not currently exist"); - m % name % path % m_file->filename() % m_cwd->path(); - throw std::runtime_error(m.str()); - } -} - -void bob::io::base::HDF5File::listAttributes(const std::string& path, - std::map<std::string, bob::io::base::HDF5Type>& attributes) const { - check_open(); - if (m_cwd->has_dataset(path)) { - (*m_cwd)[path]->list_attributes(attributes); - } - else if (m_cwd->has_group(path)) { - m_cwd->cd(path)->list_attributes(attributes); - } - else { - boost::format m("cannot list attributes at path/dataset '%s' of file '%s' (cwd: '%s') because this path/dataset does not currently exist"); - m % path % m_file->filename() % m_cwd->path(); - throw std::runtime_error(m.str()); - } -} - -void bob::io::base::HDF5File::read_attribute(const std::string& path, - const std::string& name, const bob::io::base::HDF5Type& type, void* buffer) const { - check_open(); - if (m_cwd->has_dataset(path)) { - (*m_cwd)[path]->read_attribute(name, type, buffer); - } - else if (m_cwd->has_group(path)) { - m_cwd->cd(path)->read_attribute(name, type, buffer); - } - else { - boost::format m("cannot get attribute '%s' at path/dataset '%s' of file '%s' (cwd: '%s') because this path/dataset does not currently exist"); - m % name % path % m_file->filename() % m_cwd->path(); - throw std::runtime_error(m.str()); - } -} - -void bob::io::base::HDF5File::write_attribute(const std::string& path, - const std::string& name, const bob::io::base::HDF5Type& type, const void* buffer) { - check_open(); - if (m_cwd->has_dataset(path)) { - (*m_cwd)[path]->write_attribute(name, type, buffer); - } - else if (m_cwd->has_group(path)) { - m_cwd->cd(path)->write_attribute(name, type, buffer); - } - else { - boost::format m("cannot set attribute '%s' at path/dataset '%s' of file '%s' (cwd: '%s') because this path/dataset does not currently exist"); - m % name % path % m_file->filename() % m_cwd->path(); - throw std::runtime_error(m.str()); - } -} - -void bob::io::base::HDF5File::check_open() const{ - if (!m_cwd || ! m_file){ - throw std::runtime_error("The file is not opened yet / any more"); - } -} diff --git a/bob/io/base/cpp/HDF5Group.cpp b/bob/io/base/cpp/HDF5Group.cpp deleted file mode 100644 index 6c39b18b559def62a5ba6245426bd267bdd379e5..0000000000000000000000000000000000000000 --- a/bob/io/base/cpp/HDF5Group.cpp +++ /dev/null @@ -1,560 +0,0 @@ -/** - * @author Andre Anjos <andre.anjos@idiap.ch> - * @date Wed 29 Feb 17:24:10 2012 - * - * @brief Implements HDF5 groups. - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#include <boost/make_shared.hpp> -#include <boost/shared_array.hpp> -#include <boost/filesystem.hpp> -#include <boost/format.hpp> -#include <boost/algorithm/string.hpp> - -#include <bob.core/logging.h> - -#include <bob.io.base/HDF5Group.h> -#include <bob.io.base/HDF5Utils.h> - -/** - * Creates an "auto-destructible" HDF5 Group - */ -static void delete_h5g (hid_t* p) { - if (*p >= 0) { - herr_t err = H5Gclose(*p); - if (err < 0) { - bob::core::error << "H5Gclose() exited with an error (" << err << "). The stack trace follows:" << std::endl; - bob::core::error << bob::io::base::format_hdf5_error() << std::endl; - } - } - delete p; -} - -static boost::shared_ptr<hid_t> create_new_group(boost::shared_ptr<hid_t> p, - const std::string& name) { - boost::shared_ptr<hid_t> retval(new hid_t(-1), std::ptr_fun(delete_h5g)); - *retval = H5Gcreate2(*p, name.c_str(), H5P_DEFAULT, H5P_DEFAULT, - H5P_DEFAULT); - if (*retval < 0) { - boost::format m("call to HDF5 C-function H5Gcreate2() returned error %d. HDF5 error statck follows:\n%s"); - m % *retval % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - return retval; -} - -static boost::shared_ptr<hid_t> open_group(boost::shared_ptr<hid_t> g, - const char* name) { - boost::shared_ptr<hid_t> retval(new hid_t(-1), std::ptr_fun(delete_h5g)); - *retval = H5Gopen2(*g, name, H5P_DEFAULT); - if (*retval < 0) { - boost::format m("call to HDF5 C-function H5Gopen2() returned error %d. HDF5 error statck follows:\n%s"); - m % *retval % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - return retval; -} - -bob::io::base::detail::hdf5::Group::Group(boost::shared_ptr<Group> parent, const std::string& name): - m_name(name), - m_id(create_new_group(parent->location(), name)), - m_parent(parent) -{ -} - -/** - * Simple wrapper to call internal bob::io::base::detail::hdf5::Group::iterate_callback, that can call - * Group and Dataset constructors. Note that those are private or protected for - * design reasons. - */ -static herr_t group_iterate_callback(hid_t self, const char *name, - const H5L_info_t *info, void *object) { - return static_cast<bob::io::base::detail::hdf5::Group*>(object)->iterate_callback(self, name, info); -} - -herr_t bob::io::base::detail::hdf5::Group::iterate_callback(hid_t self, const char *name, - const H5L_info_t *info) { - - // If we are not looking at a hard link to the data, just ignore - if (info->type != H5L_TYPE_HARD) { - TDEBUG1("Ignoring soft-link `" << name << "' in HDF5 file"); - return 0; - } - - // Get information about the HDF5 object - H5O_info_t obj_info; - herr_t status = H5Oget_info_by_name(self, name, &obj_info, H5P_DEFAULT); - if (status < 0) { - boost::format m("call to HDF5 C-function H5Oget_info_by_name() returned error %d. HDF5 error statck follows:\n%s"); - m % status % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - - switch(obj_info.type) { - case H5O_TYPE_GROUP: - //creates with recursion - m_groups[name] = boost::make_shared<bob::io::base::detail::hdf5::Group>(shared_from_this(), - name, true); - m_groups[name]->open_recursively(); - break; - case H5O_TYPE_DATASET: - m_datasets[name] = boost::make_shared<bob::io::base::detail::hdf5::Dataset>(shared_from_this(), - std::string(name)); - break; - default: - break; - } - - return 0; -} - -bob::io::base::detail::hdf5::Group::Group(boost::shared_ptr<Group> parent, - const std::string& name, bool): - m_name(name), - m_id(open_group(parent->location(), name.c_str())), - m_parent(parent) -{ - //checks name - if (!m_name.size() || m_name == "." || m_name == "..") { - boost::format m("Cannot create group with illegal name `%s' at `%s'"); - m % name % url(); - throw std::runtime_error(m.str()); - } -} - -void bob::io::base::detail::hdf5::Group::open_recursively() { - //iterates over this group only and instantiates what needs to be instantiated - herr_t status = H5Literate(*m_id, H5_INDEX_NAME, - H5_ITER_NATIVE, 0, group_iterate_callback, static_cast<void*>(this)); - if (status < 0) { - boost::format m("Call to HDF5 C-function H5Literate() returned error %d. HDF5 error statck follows:\n%s"); - m % status % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } -} - -bob::io::base::detail::hdf5::Group::Group(boost::shared_ptr<File> parent): - m_name(""), - m_id(open_group(parent->location(), "/")), - m_parent() -{ -} - -bob::io::base::detail::hdf5::Group::~Group() { } - -const boost::shared_ptr<bob::io::base::detail::hdf5::Group> bob::io::base::detail::hdf5::Group::parent() const { - return m_parent.lock(); -} - -boost::shared_ptr<bob::io::base::detail::hdf5::Group> bob::io::base::detail::hdf5::Group::parent() { - return m_parent.lock(); -} - -const std::string& bob::io::base::detail::hdf5::Group::filename() const { - return parent()->filename(); -} - -std::string bob::io::base::detail::hdf5::Group::path() const { - return (m_name.size()?parent()->path():"") + "/" + m_name; -} - -std::string bob::io::base::detail::hdf5::Group::url() const { - return filename() + ":" + path(); -} - -const boost::shared_ptr<bob::io::base::detail::hdf5::File> bob::io::base::detail::hdf5::Group::file() const { - return parent()->file(); -} - -boost::shared_ptr<bob::io::base::detail::hdf5::File> bob::io::base::detail::hdf5::Group::file() { - return parent()->file(); -} - -boost::shared_ptr<bob::io::base::detail::hdf5::Group> bob::io::base::detail::hdf5::Group::cd(const std::string& dir) { - //empty dir == void action, return self - if (!dir.size()) return shared_from_this(); - - if (dir[0] == '/') { //absolute path given, apply to root node - return file()->root()->cd(dir.substr(1)); - } - - //relative path given, start from self - std::string::size_type pos = dir.find_first_of('/'); - if (pos == std::string::npos) { //it should be one of my children - if (dir == ".") return shared_from_this(); - if (dir == "..") { - if (!m_name.size()) { //this is the root group already - boost::format m("Cannot go beyond root directory at file `%s'"); - m % file()->filename(); - throw std::runtime_error(m.str()); - } - //else, just return its parent - return parent(); - } - if (!has_group(dir)) { - boost::format m("Cannot find group `%s' at `%s'"); - m % dir % url(); - throw std::runtime_error(m.str()); - } - //else, just return the named group - return m_groups[dir]; - } - - //if you get to this point, we are just traversing - std::string mydir = dir.substr(0, pos); - if (mydir == ".") return cd(dir.substr(pos+1)); - if (mydir == "..") return parent()->cd(dir.substr(pos+1)); - if (!has_group(mydir)) { - boost::format m("Cannot find group `%s' at `%s'"); - m % dir % url(); - throw std::runtime_error(m.str()); - } - - //else, just recurse to the next group - return m_groups[mydir]->cd(dir.substr(pos+1)); -} - -const boost::shared_ptr<bob::io::base::detail::hdf5::Group> bob::io::base::detail::hdf5::Group::cd(const std::string& dir) const { - return const_cast<bob::io::base::detail::hdf5::Group*>(this)->cd(dir); -} - -boost::shared_ptr<bob::io::base::detail::hdf5::Dataset> bob::io::base::detail::hdf5::Group::operator[] (const std::string& dir) { - std::string::size_type pos = dir.find_last_of('/'); - if (pos == std::string::npos) { //search on the current group - if (!has_dataset(dir)) { - boost::format m("Cannot find dataset `%s' at `%s'"); - m % dir % url(); - throw std::runtime_error(m.str()); - } - return m_datasets[dir]; - } - - //if you get to this point, the search routine needs to be performed on - //another group, indicated by the path. So, we first cd() there and then do - //the same as we do here. This will recurse through the directory structure - //until we find the place defined by the user or raise an exception. - std::string dest = dir.substr(0, pos); - if (!dest.size()) dest = "/"; - boost::shared_ptr<bob::io::base::detail::hdf5::Group> g = cd(dest); - return g->operator[](dir.substr(pos+1)); -} - -const boost::shared_ptr<bob::io::base::detail::hdf5::Dataset> bob::io::base::detail::hdf5::Group::operator[] (const std::string& dir) const { - return const_cast<bob::io::base::detail::hdf5::Group*>(this)->operator[](dir); -} - -void bob::io::base::detail::hdf5::Group::reset() { - typedef std::map<std::string, boost::shared_ptr<bob::io::base::detail::hdf5::Group> > group_map_type; - for (group_map_type::const_iterator it = m_groups.begin(); - it != m_groups.end(); ++it) { - remove_group(it->first); - } - - typedef std::map<std::string, boost::shared_ptr<bob::io::base::detail::hdf5::Dataset> > - dataset_map_type; - for (dataset_map_type::const_iterator it = m_datasets.begin(); - it != m_datasets.end(); ++it) { - remove_dataset(it->first); - } -} - -boost::shared_ptr<bob::io::base::detail::hdf5::Group> bob::io::base::detail::hdf5::Group::create_group(const std::string& dir) { - std::string::size_type pos = dir.find_last_of('/'); - if (pos == std::string::npos) { //creates on the current group - boost::shared_ptr<bob::io::base::detail::hdf5::Group> g = - boost::make_shared<bob::io::base::detail::hdf5::Group>(shared_from_this(), dir); - m_groups[dir] = g; - return g; - } - - //if you get to this point, the search routine needs to be performed on - //another group, indicated by the path. So, we first cd() there and then do - //the same as we do here. This will recurse through the directory structure - //until we find the place defined by the user or raise an exception. - std::string dest = dir.substr(0, pos); - if (!dest.size()) dest = "/"; - boost::shared_ptr<bob::io::base::detail::hdf5::Group> g = cd(dest); - return g->create_group(dir.substr(pos+1)); -} - -void bob::io::base::detail::hdf5::Group::remove_group(const std::string& dir) { - std::string::size_type pos = dir.find_last_of('/'); - if (pos == std::string::npos) { //copy on the current group - herr_t status = H5Ldelete(*m_id, dir.c_str(), H5P_DEFAULT); - if (status < 0) { - boost::format m("Call to HDF5 C-function H5Ldelete() returned error %d. HDF5 error statck follows:\n%s"); - m % status % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - typedef std::map<std::string, boost::shared_ptr<bob::io::base::detail::hdf5::Group> > map_type; - map_type::iterator it = m_groups.find(dir); - m_groups.erase(it); - return; - } - - //if you get to this point, the removal routine needs to be performed on - //another group, indicated by the path. So, we first cd() there and then do - //the same as we do here. This will recurse through the directory structure - //until we find the place defined by the user or raise an exception. - std::string dest = dir.substr(0, pos); - if (!dest.size()) dest = "/"; - boost::shared_ptr<bob::io::base::detail::hdf5::Group> g = cd(dest); - return g->remove_group(dir.substr(pos+1)); -} - -/** - * Opens an "auto-destructible" HDF5 property list - */ -static void delete_h5plist (hid_t* p) { - if (*p >= 0) { - herr_t err = H5Pclose(*p); - if (err < 0) { - bob::core::error << "H5Pclose() exited with an error (" << err << "). The stack trace follows:" << std::endl; - bob::core::error << bob::io::base::format_hdf5_error() << std::endl; - } - } - delete p; -} - -static boost::shared_ptr<hid_t> open_plist(hid_t classid) { - boost::shared_ptr<hid_t> retval(new hid_t(-1), std::ptr_fun(delete_h5plist)); - *retval = H5Pcreate(classid); - if (*retval < 0) { - boost::format m("call to HDF5 C-function H5Pcreate() returned error %d. HDF5 error statck follows:\n%s"); - m % *retval % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - return retval; -} - -void bob::io::base::detail::hdf5::Group::rename_group(const std::string& from, const std::string& to) { - boost::shared_ptr<hid_t> create_props = open_plist(H5P_LINK_CREATE); - H5Pset_create_intermediate_group(*create_props, 1); - herr_t status = H5Lmove(*m_id, from.c_str(), H5L_SAME_LOC, to.c_str(), - *create_props, H5P_DEFAULT); - if (status < 0) { - boost::format m("Call to HDF5 C-function H5Lmove() returned error %d. HDF5 error statck follows:\n%s"); - m % status % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } -} - -void bob::io::base::detail::hdf5::Group::copy_group(const boost::shared_ptr<Group> other, - const std::string& dir) { - std::string::size_type pos = dir.find_last_of('/'); - if (pos == std::string::npos) { //copy on the current group - const char* use_name = dir.size()?dir.c_str():other->name().c_str(); - herr_t status = H5Ocopy(*other->parent()->location(), - other->name().c_str(), *m_id, use_name, H5P_DEFAULT, H5P_DEFAULT); - if (status < 0) { - boost::format m("call to HDF5 C-function H5Ocopy() returned error %d. HDF5 error statck follows:\n%s"); - m % status % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - - //read new group contents - boost::shared_ptr<bob::io::base::detail::hdf5::Group> copied = - boost::make_shared<bob::io::base::detail::hdf5::Group>(shared_from_this(), use_name); - copied->open_recursively(); - - //index it - m_groups[use_name] = copied; - - return; - } - - //if you get to this point, the copy routine needs to be performed on - //another group, indicated by the path. So, we first cd() there and then do - //the same as we do here. This will recurse through the directory structure - //until we find the place defined by the user or return false. - std::string dest = dir.substr(0, pos); - if (!dest.size()) dest = "/"; - boost::shared_ptr<bob::io::base::detail::hdf5::Group> g = cd(dest); - return g->copy_group(other, dir.substr(pos+1)); -} - -bool bob::io::base::detail::hdf5::Group::has_group(const std::string& dir) const { - std::string::size_type pos = dir.find_last_of('/'); - if (pos == std::string::npos) { //search on the current group - if (dir == "." || dir == "..") return true; //special case - typedef std::map<std::string, boost::shared_ptr<bob::io::base::detail::hdf5::Group> > map_type; - map_type::const_iterator it = m_groups.find(dir); - return (it != m_groups.end()); - } - - //if you get to this point, the search routine needs to be performed on - //another group, indicated by the path. So, we first cd() there and then do - //the same as we do here. This will recurse through the directory structure - //until we find the place defined by the user or return false. - std::string dest = dir.substr(0, pos); - if (!dest.size()) dest = "/"; - boost::shared_ptr<bob::io::base::detail::hdf5::Group> g = cd(dest); - return g->has_group(dir.substr(pos+1)); -} - -boost::shared_ptr<bob::io::base::detail::hdf5::Dataset> bob::io::base::detail::hdf5::Group::create_dataset -(const std::string& dir, const bob::io::base::HDF5Type& type, bool list, - size_t compression) { - std::string::size_type pos = dir.find_last_of('/'); - if (pos == std::string::npos) { //creates on the current group - boost::shared_ptr<bob::io::base::detail::hdf5::Dataset> d = - boost::make_shared<bob::io::base::detail::hdf5::Dataset>(shared_from_this(), dir, type, - list, compression); - m_datasets[dir] = d; - return d; - } - - //if you get to this point, the search routine needs to be performed on - //another group, indicated by the path. So, we first cd() there and then do - //the same as we do here. This will recurse through the directory structure - //until we find the place defined by the user or return false. - std::string dest = dir.substr(0, pos); - boost::shared_ptr<bob::io::base::detail::hdf5::Group> g; - if (!dest.size()) g = cd("/"); - else { - //let's make sure the directory exists, or let's create it recursively - if (!has_group(dest)) g = create_group(dest); - else g = cd(dest); - } - return g->create_dataset(dir.substr(pos+1), type, list, compression); -} - -void bob::io::base::detail::hdf5::Group::remove_dataset(const std::string& dir) { - std::string::size_type pos = dir.find_last_of('/'); - if (pos == std::string::npos) { //removes on the current group - herr_t status = H5Ldelete(*m_id, dir.c_str(), H5P_DEFAULT); - if (status < 0) { - boost::format m("Call to HDF5 C-function H5Ldelete() returned error %d. HDF5 error statck follows:\n%s"); - m % status % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - typedef std::map<std::string, boost::shared_ptr<bob::io::base::detail::hdf5::Dataset> > map_type; - map_type::iterator it = m_datasets.find(dir); - m_datasets.erase(it); - return; - } - - //if you get to this point, the removal routine needs to be performed on - //another group, indicated by the path. So, we first cd() there and then do - //the same as we do here. This will recurse through the directory structure - //until we find the place defined by the user or raise an exception. - std::string dest = dir.substr(0, pos); - if (!dest.size()) dest = "/"; - boost::shared_ptr<bob::io::base::detail::hdf5::Group> g = cd(dest); - return g->remove_dataset(dir.substr(pos+1)); -} - -void bob::io::base::detail::hdf5::Group::rename_dataset(const std::string& from, const std::string& to) { - boost::shared_ptr<hid_t> create_props = open_plist(H5P_LINK_CREATE); - H5Pset_create_intermediate_group(*create_props, 1); - herr_t status = H5Lmove(*m_id, from.c_str(), H5L_SAME_LOC, to.c_str(), - *create_props, H5P_DEFAULT); - if (status < 0) { - boost::format m("Call to HDF5 C-function H5Ldelete() returned error %d. HDF5 error statck follows:\n%s"); - m % status % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } -} - -void bob::io::base::detail::hdf5::Group::copy_dataset(const boost::shared_ptr<Dataset> other, - const std::string& dir) { - - std::string::size_type pos = dir.find_last_of('/'); - if (pos == std::string::npos) { //search on the current group - const char* use_name = dir.size()?dir.c_str():other->name().c_str(); - herr_t status = H5Ocopy(*other->parent()->location(), - other->name().c_str(), *m_id, use_name, H5P_DEFAULT, H5P_DEFAULT); - if (status < 0) { - boost::format m("Call to HDF5 C-function H5Ocopy() returned error %d. HDF5 error statck follows:\n%s"); - m % status % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - //read new group contents - m_datasets[use_name] = boost::make_shared<bob::io::base::detail::hdf5::Dataset>(shared_from_this(), use_name); - return; - } - - //if you get to this point, the copy routine needs to be performed on - //another group, indicated by the path. So, we first cd() there and then do - //the same as we do here. This will recurse through the directory structure - //until we find the place defined by the user. - std::string dest = dir.substr(0, pos); - if (!dest.size()) dest = "/"; - boost::shared_ptr<bob::io::base::detail::hdf5::Group> g = cd(dest); - return g->copy_dataset(other, dir.substr(pos+1)); -} - -bool bob::io::base::detail::hdf5::Group::has_dataset(const std::string& dir) const { - std::string::size_type pos = dir.find_last_of('/'); - if (pos == std::string::npos) { //search on the current group - typedef std::map<std::string, boost::shared_ptr<bob::io::base::detail::hdf5::Dataset> > map_type; - map_type::const_iterator it = m_datasets.find(dir); - return (it != m_datasets.end()); - } - - //if you get to this point, the search routine needs to be performed on - //another group, indicated by the path. So, we first cd() there and then do - //the same as we do here. This will recurse through the directory structure - //until we find the place defined by the user or return false. - std::string dest = dir.substr(0, pos); - if (!dest.size()) dest = "/"; - boost::shared_ptr<bob::io::base::detail::hdf5::Group> g = cd(dest); - return g->has_dataset(dir.substr(pos+1)); -} - -void bob::io::base::detail::hdf5::Group::gettype_attribute(const std::string& name, - bob::io::base::HDF5Type& type) const { - bob::io::base::detail::hdf5::gettype_attribute(m_id, name, type); -} - -bool bob::io::base::detail::hdf5::Group::has_attribute(const std::string& name) const { - return bob::io::base::detail::hdf5::has_attribute(m_id, name); -} - -void bob::io::base::detail::hdf5::Group::delete_attribute (const std::string& name) { - bob::io::base::detail::hdf5::delete_attribute(m_id, name); -} - -void bob::io::base::detail::hdf5::Group::read_attribute (const std::string& name, - const bob::io::base::HDF5Type& dest_type, void* buffer) const { - bob::io::base::detail::hdf5::read_attribute(m_id, name, dest_type, buffer); -} - -void bob::io::base::detail::hdf5::Group::write_attribute (const std::string& name, - const bob::io::base::HDF5Type& dest_type, const void* buffer) { - bob::io::base::detail::hdf5::write_attribute(m_id, name, dest_type, buffer); -} - -void bob::io::base::detail::hdf5::Group::list_attributes(std::map<std::string, bob::io::base::HDF5Type>& attributes) const { - bob::io::base::detail::hdf5::list_attributes(m_id, attributes); -} - -template <> void bob::io::base::detail::hdf5::Group::set_attribute<std::string>(const std::string& name, const std::string& v) { - bob::io::base::HDF5Type dest_type(v); - write_attribute(name, dest_type, reinterpret_cast<const void*>(v.c_str())); -} - -template <> std::string bob::io::base::detail::hdf5::Group::get_attribute(const std::string& name) const { - HDF5Type type; - gettype_attribute(name, type); - boost::shared_array<char> v(new char[type.shape()[0]+1]); - v[type.shape()[0]] = 0; ///< null termination - read_attribute(name, type, reinterpret_cast<void*>(v.get())); - std::string retval(v.get()); - return retval; -} - -bob::io::base::detail::hdf5::RootGroup::RootGroup(boost::shared_ptr<File> parent): - bob::io::base::detail::hdf5::Group(parent), - m_parent(parent) -{ -} - -bob::io::base::detail::hdf5::RootGroup::~RootGroup() { -} - -const std::string& bob::io::base::detail::hdf5::RootGroup::filename() const { - return m_parent.lock()->filename(); -} diff --git a/bob/io/base/cpp/HDF5Types.cpp b/bob/io/base/cpp/HDF5Types.cpp deleted file mode 100644 index 0f38566863e7b727b5c36d4b68232de0ca0f7b14..0000000000000000000000000000000000000000 --- a/bob/io/base/cpp/HDF5Types.cpp +++ /dev/null @@ -1,866 +0,0 @@ -/** - * @date Wed Jun 22 17:50:08 2011 +0200 - * @author Andre Anjos <andre.anjos@idiap.ch> - * - * @brief A few helpers to handle HDF5 datasets in a more abstract way. - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#include <boost/format.hpp> -#include <sstream> -#include <boost/make_shared.hpp> - -/** - * MT "lock" support was only introduced in Boost 1.35. Before copying this - * very ugly hack, make sure we are still using Boost 1.34. This will no longer - * be the case starting January 2011. - */ -#include <boost/version.hpp> -#include <boost/thread/mutex.hpp> -#if ((BOOST_VERSION / 100) % 1000) > 34 -#include <boost/thread/locks.hpp> -#else -#warning Disabling MT locks because Boost < 1.35! -#endif - -#include <bob.core/logging.h> - -#include <bob.io.base/HDF5Types.h> - -const char* bob::io::base::stringize (hdf5type t) { - switch (t) { - case bob::io::base::s: - return "string"; - case bob::io::base::b: - return "bool"; - case bob::io::base::i8: - return "int8"; - case bob::io::base::i16: - return "int16"; - case bob::io::base::i32: - return "int32"; - case bob::io::base::i64: - return "int64"; - case bob::io::base::u8: - return "uint8"; - case bob::io::base::u16: - return "uint16"; - case bob::io::base::u32: - return "uint32"; - case bob::io::base::u64: - return "uint64"; - case bob::io::base::f32: - return "float32"; - case bob::io::base::f64: - return "float64"; - case bob::io::base::f128: - return "float128"; - case bob::io::base::c64: - return "complex64"; - case bob::io::base::c128: - return "complex128"; - case bob::io::base::c256: - return "complex256"; - case bob::io::base::unsupported: - return "unsupported"; - } - return "unsupported"; ///< just to silence gcc -} - -static herr_t walker(unsigned n, const H5E_error2_t *desc, void *cookie) { - bob::io::base::HDF5ErrorStack& stack = *(bob::io::base::HDF5ErrorStack*)cookie; - std::vector<std::string>& sv = stack.get(); - boost::format fmt("%s() @ %s+%d: %s"); - fmt % desc->func_name % desc->file_name % desc->line % desc->desc; - sv.push_back(fmt.str()); - return 0; -} - -static herr_t err_callback(hid_t stack, void* cookie) { - bob::io::base::HDF5ErrorStack& err_stack = *(bob::io::base::HDF5ErrorStack*)cookie; - if (!err_stack.muted()) H5Ewalk2(stack, H5E_WALK_DOWNWARD, walker, cookie); - H5Eclear2(stack); - return 0; -} - -bob::io::base::HDF5ErrorStack::HDF5ErrorStack (): - m_stack(H5E_DEFAULT), - m_muted(false), - m_err(), - m_func(0), - m_client_data(0) -{ - H5Eget_auto2(m_stack, &m_func, &m_client_data); - H5Eset_auto2(m_stack, err_callback, this); -} - -bob::io::base::HDF5ErrorStack::HDF5ErrorStack (hid_t stack): - m_stack(stack), - m_muted(false), - m_err(), - m_func(0), - m_client_data(0) -{ - H5Eget_auto2(m_stack, &m_func, &m_client_data); - H5Eset_auto2(m_stack, err_callback, this); -} - -bob::io::base::HDF5ErrorStack::~HDF5ErrorStack () { - H5Eset_auto2(m_stack, m_func, m_client_data); -} - -//creates a pointer to the default HDF5 error stack that is global to the -//application level. -const boost::shared_ptr<bob::io::base::HDF5ErrorStack> - bob::io::base::DefaultHDF5ErrorStack(new HDF5ErrorStack()); - -bob::io::base::HDF5Shape::HDF5Shape (size_t n): - m_n(n), - m_shape() -{ - if (n > MAX_HDF5SHAPE_SIZE) { - boost::format m("cannot create shape with %u dimensions, exceeding the maximum number of dimensions supported by this API (%u)"); - m % n % MAX_HDF5SHAPE_SIZE; - throw std::runtime_error(m.str()); - } - for (size_t i=0; i<n; ++i) m_shape[i] = 0; -} - -bob::io::base::HDF5Shape::HDF5Shape (): - m_n(0), - m_shape() -{ -} - -bob::io::base::HDF5Shape::HDF5Shape (const bob::io::base::HDF5Shape& other): - m_n(other.m_n), - m_shape() -{ - for (size_t i=0; i<m_n; ++i) m_shape[i] = other.m_shape[i]; -} - -bob::io::base::HDF5Shape::~HDF5Shape() { -} - -bob::io::base::HDF5Shape& bob::io::base::HDF5Shape::operator= (const bob::io::base::HDF5Shape& other) { - m_n = other.m_n; - for (size_t i=0; i<m_n; ++i) m_shape[i] = other.m_shape[i]; - return *this; -} - -void bob::io::base::HDF5Shape::copy(const bob::io::base::HDF5Shape& other) { - if (m_n <= other.m_n) { //I'm smaller or equal - for (size_t i=0; i<m_n; ++i) m_shape[i] = other.m_shape[i]; - } - else { //The other is smaller - for (size_t i=0; i<other.m_n; ++i) m_shape[i] = other.m_shape[i]; - } -} - -void bob::io::base::HDF5Shape::reset() { - m_n = 0; -} - -bob::io::base::HDF5Shape& bob::io::base::HDF5Shape::operator <<= (size_t pos) { - if (!m_n || !pos) return *this; - for (size_t i=0; i<(m_n-pos); ++i) m_shape[i] = m_shape[i+pos]; - m_n -= pos; - return *this; -} - -bob::io::base::HDF5Shape& bob::io::base::HDF5Shape::operator >>= (size_t pos) { - if (!pos) return *this; - if ( (m_n + pos) > MAX_HDF5SHAPE_SIZE) { - boost::format m("if you shift right this shape by %u positions, you will exceed the maximum number of dimensions supported by this API (%u)"); - m % pos % MAX_HDF5SHAPE_SIZE; - throw std::runtime_error(m.str()); - } - for (size_t i=(m_n+pos-1); i>(pos-1); --i) m_shape[i] = m_shape[i-1]; - for (size_t i=0; i<pos; ++i) m_shape[i] = 1; - m_n += pos; - return *this; -} - -hsize_t bob::io::base::HDF5Shape::product() const { - hsize_t retval = 1; - for (size_t i=0; i<m_n; ++i) retval *= m_shape[i]; - return retval; -} - -bool bob::io::base::HDF5Shape::operator== (const HDF5Shape& other) const { - if (m_n != other.m_n) return false; - for (size_t i=0; i<m_n; ++i) if (m_shape[i] != other[i]) return false; - return true; -} - -bool bob::io::base::HDF5Shape::operator!= (const HDF5Shape& other) const { - return !(*this == other); -} - -std::string bob::io::base::HDF5Shape::str () const { - if (m_n == 0) return ""; - std::ostringstream retval(""); - retval << m_shape[0]; - for (size_t i=1; i<m_n; ++i) retval << ", " << m_shape[i]; - return retval.str(); -} - -/** - * Deleter method for auto-destroyable HDF5 datatypes. - */ -static void delete_h5datatype (hid_t* p) { - if (*p >= 0) { - herr_t err = H5Tclose(*p); - if (err < 0) { - bob::core::error << "H5Tclose() exited with an error (" << err << "). The stack trace follows:" << std::endl; - bob::core::error << bob::io::base::format_hdf5_error() << std::endl; - } - } - delete p; -} - -/** - * Given a datatype which is a compound type, returns the std::complex<T> - * hdf5type equivalent or raises. - */ -static bob::io::base::hdf5type equivctype(const boost::shared_ptr<hid_t>& dt) { - if (H5Tget_nmembers(*dt) != 2) throw std::runtime_error("the internal HDF5 type is not supported by our HDF5 interface"); - - //members have to: - // 1. have names "real" and "imag" - // 2. have class type H5T_FLOAT - // 3. have equal size - // 4. have a size of 4, 8 or 16 bytes - - // 1. - int real = H5Tget_member_index(*dt, "real"); - if (real < 0) { - throw std::runtime_error("the complex member index for `real' is not present on this HDF5 type"); - } - int imag = H5Tget_member_index(*dt, "imag"); - if (imag < 0) { - throw std::runtime_error("the complex member index for `imag' is not present on this HDF5 type"); - } - - // 2. - if (H5Tget_member_class(*dt, real) != H5T_FLOAT) - throw std::runtime_error("the raw type for member `real' on complex structure in HDF5 is not H5T_FLOAT as expected"); - if (H5Tget_member_class(*dt, imag) != H5T_FLOAT) - throw std::runtime_error("the raw type for member `imag' on complex structure in HDF5 is not H5T_FLOAT as expected"); - - // 3. - boost::shared_ptr<hid_t> realid(new hid_t(-1), std::ptr_fun(delete_h5datatype)); - *realid = H5Tget_member_type(*dt, real); - boost::shared_ptr<hid_t> imagid(new hid_t(-1), std::ptr_fun(delete_h5datatype)); - *imagid = H5Tget_member_type(*dt, imag); - size_t realsize = H5Tget_size(*realid); - size_t imagsize = H5Tget_size(*imagid); - if (realsize != imagsize) { - throw std::runtime_error("the sizes of the real and imaginary parts on HDF5 complex struct are not the same"); - } - - // 4. - switch (realsize) { - case 4: //std::complex<float> - return bob::io::base::c64; - case 8: //std::complex<double> - return bob::io::base::c128; - case 16: //std::complex<double> - return bob::io::base::c256; - default: - break; - } - - throw std::runtime_error("could not find the equivalent internal type for (supposedly) complex HDF5 structure"); -} - -/** - * Checks if a given type can be read as boolean - */ -static void checkbool(const boost::shared_ptr<hid_t>& dt) { - - if (H5Tget_nmembers(*dt) != 2) { - throw std::runtime_error("the number of enumeration members for the locally installed boolean type is not 2"); - } - - int8_t value; - herr_t status = H5Tget_member_value(*dt, 0, &value); - if (status < 0) { - boost::format m("call to HDF5 C-function H5Tget_member_value() returned error %d. HDF5 error statck follows:\n%s"); - m % status % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - bool next_is_false = false; - if (value != 0) next_is_false = true; - status = H5Tget_member_value(*dt, 1, &value); - if (status < 0) { - boost::format m("call to HDF5 C-function H5Tget_member_value() returned error %d. HDF5 error statck follows:\n%s"); - m % status % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - if (next_is_false) { - if (value != 0) { - throw std::runtime_error("the attribution of false(0) or true(1) is messed up on the current data type, which is supposed to be a boolean"); - } - } - else { - if (value == 0) { - throw std::runtime_error("the attribution of false(0) or true(1) is messed up on the current data type, which is supposed to be a boolean"); - } - } -} - -/** - * Given a datatype, returns the supported type equivalent or raises - */ -static bob::io::base::hdf5type get_datatype -(const boost::shared_ptr<hid_t>& dt) { - H5T_class_t classtype = H5Tget_class(*dt); - - if (classtype == H5T_STRING) return bob::io::base::s; //no need to check further - - size_t typesize = H5Tget_size(*dt); ///< element size - H5T_sign_t signtype = H5Tget_sign(*dt); - - //we only support little-endian byte-ordering - H5T_order_t ordertype = H5Tget_order(*dt); - - //please note that checking compound types for hdf5 < 1.8.6 does not work. -# if H5_VERSION_GE(1,8,6) - if (ordertype < 0) { - boost::format m("call to HDF5 C-function H5Tget_order returned error %d. HDF5 error statck follows:\n%s"); - m % ordertype % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - - if (ordertype != H5T_ORDER_LE) { - throw std::runtime_error("The endianness of datatype is not little-endian"); - } -# else - if ((ordertype >= 0) && (ordertype != H5T_ORDER_LE)) { - throw std::runtime_error("The endianness of datatype is not little-endian"); - } -# endif - - switch (classtype) { - case H5T_ENUM: - checkbool(dt); - return bob::io::base::b; - case H5T_INTEGER: - switch (typesize) { - case 1: //int8 or uint8 - switch (signtype) { - case H5T_SGN_NONE: - return bob::io::base::u8; - case H5T_SGN_2: //two's complement == "is signed" ;-) - return bob::io::base::i8; - default: - throw std::runtime_error("HDF5 1-byte integer datatype (read from file) cannot be mapped into a C++ type supported by this API"); - } - break; - case 2: //int16 or uint16 - switch (signtype) { - case H5T_SGN_NONE: - return bob::io::base::u16; - case H5T_SGN_2: //two's complement == "is signed" ;-) - return bob::io::base::i16; - default: - throw std::runtime_error("HDF5 2-byte integer datatype (read from file) cannot be mapped into a C++ type supported by this API"); - } - break; - case 4: //int32 or uint32 - switch (signtype) { - case H5T_SGN_NONE: - return bob::io::base::u32; - case H5T_SGN_2: //two's complement == "is signed" ;-) - return bob::io::base::i32; - default: - throw std::runtime_error("HDF5 4-byte integer datatype (read from file) cannot be mapped into a C++ type supported by this API"); - } - break; - case 8: //int64 or uint64 - switch (signtype) { - case H5T_SGN_NONE: - return bob::io::base::u64; - case H5T_SGN_2: //two's complement == "is signed" ;-) - return bob::io::base::i64; - default: - throw std::runtime_error("HDF5 8-byte integer datatype (read from file) cannot be mapped into a C++ type supported by this API"); - } - break; - default: - break; - } - break; - case H5T_FLOAT: - switch (typesize) { - case 4: //float - return bob::io::base::f32; - case 8: //double - return bob::io::base::f64; - case 16: //long double - return bob::io::base::f128; - default: - break; - } - break; - case H5T_COMPOUND: //complex - return equivctype(dt); - default: - break; - } - - throw std::runtime_error("cannot handle HDF5 datatype on file using one of the native types supported by this API"); -} - -bool bob::io::base::HDF5Type::compatible (const bob::io::base::array::typeinfo& value) const -{ - return *this == HDF5Type(value); -} - -/** - * Given a datatype, returns the supported HDF5 datatype equivalent or -1 - */ -boost::shared_ptr<hid_t> bob::io::base::HDF5Type::htype() const { - switch (m_type) { - case bob::io::base::s: - { - boost::shared_ptr<hid_t> retval(new hid_t(-1), - std::ptr_fun(delete_h5datatype)); - *retval = H5Tcopy(H5T_C_S1); - if (*retval < 0) { - boost::format m("call to HDF5 C-function H5Tcopy() returned error %d. HDF5 error statck follows:\n%s"); - m % *retval % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - - //set string size - herr_t status = H5Tset_size(*retval, m_shape[0]); - if (status < 0) { - boost::format m("Call to HDF5 C-function H5Tset_size() returned error %d. HDF5 error statck follows:\n%s"); - m % status % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - - return retval; - } - case bob::io::base::b: - { - //why? HDF5 is a C library and in C there is no boolean type - //bottom-line => we have to define our own... - - boost::shared_ptr<hid_t> retval(new hid_t(-1), - std::ptr_fun(delete_h5datatype)); - *retval = H5Tenum_create(H5T_NATIVE_INT8); - if (*retval < 0) { - boost::format m("call to HDF5 C-function H5Tenum_create() returned error %d. HDF5 error statck follows:\n%s"); - m % *retval % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - int8_t val; - herr_t status; - - //defines false - val = 0; - status = H5Tenum_insert(*retval, "false", &val); - if (status < 0) { - boost::format m("call to HDF5 C-function H5Tenum_insert() returned error %d. HDF5 error statck follows:\n%s"); - m % status % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - - //defines true - val = 1; - status = H5Tenum_insert(*retval, "true", &val); - if (*retval < 0) { - boost::format m("call to HDF5 C-function H5Tenum_insert() returned error %d. HDF5 error statck follows:\n%s"); - m % *retval % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - - return retval; - } - case bob::io::base::i8: - return boost::make_shared<hid_t>(H5T_NATIVE_INT8); - case bob::io::base::i16: - return boost::make_shared<hid_t>(H5T_NATIVE_INT16); - case bob::io::base::i32: - return boost::make_shared<hid_t>(H5T_NATIVE_INT32); - case bob::io::base::i64: - return boost::make_shared<hid_t>(H5T_NATIVE_INT64); - case bob::io::base::u8: - return boost::make_shared<hid_t>(H5T_NATIVE_UINT8); - case bob::io::base::u16: - return boost::make_shared<hid_t>(H5T_NATIVE_UINT16); - case bob::io::base::u32: - return boost::make_shared<hid_t>(H5T_NATIVE_UINT32); - case bob::io::base::u64: - return boost::make_shared<hid_t>(H5T_NATIVE_UINT64); - case bob::io::base::f32: - return boost::make_shared<hid_t>(H5T_NATIVE_FLOAT); - case bob::io::base::f64: - return boost::make_shared<hid_t>(H5T_NATIVE_DOUBLE); - case bob::io::base::f128: - return boost::make_shared<hid_t>(H5T_NATIVE_LDOUBLE); - case bob::io::base::c64: - { - boost::shared_ptr<hid_t> retval(new hid_t(-1), - std::ptr_fun(delete_h5datatype)); - *retval = H5Tcreate(H5T_COMPOUND, 2*sizeof(float)); - if (*retval < 0) { - boost::format m("call to HDF5 C-function H5Tcreate() returned error %d. HDF5 error statck follows:\n%s"); - m % *retval % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - herr_t status = H5Tinsert(*retval, "real", 0, H5T_NATIVE_FLOAT); - if (status < 0) { - boost::format m("call to HDF5 C-function H5Tinsert() returned error %d. HDF5 error statck follows:\n%s"); - m % status % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - status = H5Tinsert(*retval, "imag", sizeof(float), H5T_NATIVE_FLOAT); - if (status < 0) { - boost::format m("call to HDF5 C-function H5Tinsert() returned error %d. HDF5 error statck follows:\n%s"); - m % status % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - return retval; - } - case bob::io::base::c128: - { - boost::shared_ptr<hid_t> retval(new hid_t(-1), - std::ptr_fun(delete_h5datatype)); - *retval = H5Tcreate(H5T_COMPOUND, 2*sizeof(double)); - if (*retval < 0) { - boost::format m("call to HDF5 C-function H5Tcreate() returned error %d. HDF5 error statck follows:\n%s"); - m % *retval % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - herr_t status = H5Tinsert(*retval, "real", 0, H5T_NATIVE_DOUBLE); - if (status < 0) { - boost::format m("call to HDF5 C-function H5Tinsert() returned error %d. HDF5 error statck follows:\n%s"); - m % status % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - status = H5Tinsert(*retval, "imag", sizeof(double), H5T_NATIVE_DOUBLE); - if (status < 0) { - boost::format m("call to HDF5 C-function H5Tinsert() returned error %d. HDF5 error statck follows:\n%s"); - m % status % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - return retval; - } - case bob::io::base::c256: - { - boost::shared_ptr<hid_t> retval(new hid_t(-1), - std::ptr_fun(delete_h5datatype)); - *retval = H5Tcreate(H5T_COMPOUND, 2*sizeof(long double)); - if (*retval < 0) { - boost::format m("call to HDF5 C-function H5Tcreate() returned error %d. HDF5 error statck follows:\n%s"); - m % *retval % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - herr_t status = H5Tinsert(*retval, "real", 0, H5T_NATIVE_LDOUBLE); - if (status < 0) { - boost::format m("call to HDF5 C-function H5Tinsert() returned error %d. HDF5 error statck follows:\n%s"); - m % status % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - status = H5Tinsert(*retval, "imag", sizeof(long double), H5T_NATIVE_LDOUBLE); - if (status < 0) { - boost::format m("call to HDF5 C-function H5Tinsert() returned error %d. HDF5 error statck follows:\n%s"); - m % status % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - return retval; - } - default: - break; - } - throw std::runtime_error("the C++ type you are trying to convert into a native HDF5 type is not supported by this API"); -} - -#define DEFINE_SUPPORT(T,E) bob::io::base::HDF5Type::HDF5Type(const T& value): \ - m_type(E), m_shape(1) { m_shape[0] = 1; } -DEFINE_SUPPORT(bool,bob::io::base::b) -DEFINE_SUPPORT(int8_t,bob::io::base::i8) -DEFINE_SUPPORT(int16_t,bob::io::base::i16) -DEFINE_SUPPORT(int32_t,bob::io::base::i32) -DEFINE_SUPPORT(int64_t,bob::io::base::i64) -DEFINE_SUPPORT(uint8_t,bob::io::base::u8) -DEFINE_SUPPORT(uint16_t,bob::io::base::u16) -DEFINE_SUPPORT(uint32_t,bob::io::base::u32) -DEFINE_SUPPORT(uint64_t,bob::io::base::u64) -DEFINE_SUPPORT(float,bob::io::base::f32) -DEFINE_SUPPORT(double,bob::io::base::f64) -DEFINE_SUPPORT(long double,bob::io::base::f128) -DEFINE_SUPPORT(std::complex<float>,bob::io::base::c64) -DEFINE_SUPPORT(std::complex<double>,bob::io::base::c128) -DEFINE_SUPPORT(std::complex<long double>,bob::io::base::c256) -#undef DEFINE_SUPPORT - -bob::io::base::HDF5Type::HDF5Type(const char* value): - m_type(bob::io::base::s), - m_shape(1) -{ - m_shape[0] = std::strlen(value); -} - -bob::io::base::HDF5Type::HDF5Type(const std::string& value): - m_type(bob::io::base::s), - m_shape(1) -{ - m_shape[0] = value.size(); -} - -#define DEFINE_SUPPORT(T,E,N) bob::io::base::HDF5Type::HDF5Type \ - (const blitz::Array<T,N>& value): \ - m_type(E), \ - m_shape(value.shape()) { \ - if (N > bob::io::base::array::N_MAX_DIMENSIONS_ARRAY) {\ - boost::format m("you passed an array with %d dimensions, but this HDF5 API only supports arrays with up to %d dimensions"); \ - m % N % bob::io::base::array::N_MAX_DIMENSIONS_ARRAY; \ - throw std::runtime_error(m.str()); \ - } \ - } - -#define DEFINE_BZ_SUPPORT(T,E) \ - DEFINE_SUPPORT(T,E,1) \ - DEFINE_SUPPORT(T,E,2) \ - DEFINE_SUPPORT(T,E,3) \ - DEFINE_SUPPORT(T,E,4) - -DEFINE_BZ_SUPPORT(bool,bob::io::base::b) -DEFINE_BZ_SUPPORT(int8_t,bob::io::base::i8) -DEFINE_BZ_SUPPORT(int16_t,bob::io::base::i16) -DEFINE_BZ_SUPPORT(int32_t,bob::io::base::i32) -DEFINE_BZ_SUPPORT(int64_t,bob::io::base::i64) -DEFINE_BZ_SUPPORT(uint8_t,bob::io::base::u8) -DEFINE_BZ_SUPPORT(uint16_t,bob::io::base::u16) -DEFINE_BZ_SUPPORT(uint32_t,bob::io::base::u32) -DEFINE_BZ_SUPPORT(uint64_t,bob::io::base::u64) -DEFINE_BZ_SUPPORT(float,bob::io::base::f32) -DEFINE_BZ_SUPPORT(double,bob::io::base::f64) -DEFINE_BZ_SUPPORT(long double,bob::io::base::f128) -DEFINE_BZ_SUPPORT(std::complex<float>,bob::io::base::c64) -DEFINE_BZ_SUPPORT(std::complex<double>,bob::io::base::c128) -DEFINE_BZ_SUPPORT(std::complex<long double>,bob::io::base::c256) -#undef DEFINE_BZ_SUPPORT -#undef DEFINE_SUPPORT - -bob::io::base::HDF5Type::HDF5Type(): - m_type(bob::io::base::unsupported), - m_shape() -{ -} - -bob::io::base::HDF5Type::HDF5Type(bob::io::base::hdf5type type): - m_type(type), - m_shape(1) -{ - m_shape[0] = 1; -} - -bob::io::base::HDF5Type::HDF5Type(bob::io::base::hdf5type type, const bob::io::base::HDF5Shape& extents): - m_type(type), - m_shape(extents) -{ -} - -static bob::io::base::hdf5type array_to_hdf5 (bob::io::base::array::ElementType eltype) { - switch(eltype) { - case bob::io::base::array::t_unknown: - return bob::io::base::unsupported; - case bob::io::base::array::t_bool: - return bob::io::base::b; - case bob::io::base::array::t_int8: - return bob::io::base::i8; - case bob::io::base::array::t_int16: - return bob::io::base::i16; - case bob::io::base::array::t_int32: - return bob::io::base::i32; - case bob::io::base::array::t_int64: - return bob::io::base::i64; - case bob::io::base::array::t_uint8: - return bob::io::base::u8; - case bob::io::base::array::t_uint16: - return bob::io::base::u16; - case bob::io::base::array::t_uint32: - return bob::io::base::u32; - case bob::io::base::array::t_uint64: - return bob::io::base::u64; - case bob::io::base::array::t_float32: - return bob::io::base::f32; - case bob::io::base::array::t_float64: - return bob::io::base::f64; - case bob::io::base::array::t_float128: - return bob::io::base::f128; - case bob::io::base::array::t_complex64: - return bob::io::base::c64; - case bob::io::base::array::t_complex128: - return bob::io::base::c128; - case bob::io::base::array::t_complex256: - return bob::io::base::c256; - } - throw std::runtime_error("unsupported dtype <=> hdf5 type conversion -- FIXME"); -} - -bob::io::base::HDF5Type::HDF5Type(const bob::io::base::array::typeinfo& ti): - m_type(array_to_hdf5(ti.dtype)), - m_shape(ti.nd, ti.shape) -{ -} - -bob::io::base::HDF5Type::HDF5Type(bob::io::base::array::ElementType eltype, - const HDF5Shape& extents): - m_type(array_to_hdf5(eltype)), - m_shape(extents) -{ -} - -bob::io::base::HDF5Type::HDF5Type(const boost::shared_ptr<hid_t>& type, - const bob::io::base::HDF5Shape& extents): - m_type(get_datatype(type)), - m_shape(extents) -{ -} - -bob::io::base::HDF5Type::HDF5Type(const boost::shared_ptr<hid_t>& type): - m_type(get_datatype(type)), - m_shape(1) -{ - //strings have to be treated slightly differently - if (H5Tget_class(*type) == H5T_STRING) m_shape[0] = H5Tget_size(*type); - else m_shape[0] = 1; -} - -bob::io::base::HDF5Type::HDF5Type(const HDF5Type& other): - m_type(other.m_type), - m_shape(other.m_shape) -{ -} - -bob::io::base::HDF5Type::~HDF5Type() { } - -bob::io::base::HDF5Type& bob::io::base::HDF5Type::operator= (const bob::io::base::HDF5Type& other) -{ - m_type = other.m_type; - m_shape = other.m_shape; - return *this; -} - -bool bob::io::base::HDF5Type::operator== (const bob::io::base::HDF5Type& other) const { - return (m_type == other.m_type) && (m_shape == other.m_shape); -} - -bool bob::io::base::HDF5Type::operator!= (const bob::io::base::HDF5Type& other) const { - return !(*this == other); -} - -std::string bob::io::base::HDF5Type::str() const { - boost::format retval("%s (%s)"); - retval % bob::io::base::stringize(m_type) % m_shape.str(); - return retval.str(); -} - -bob::io::base::array::ElementType bob::io::base::HDF5Type::element_type() const { - switch (m_type) { - case b: - return bob::io::base::array::t_bool; - case i8: - return bob::io::base::array::t_int8; - case i16: - return bob::io::base::array::t_int16; - case i32: - return bob::io::base::array::t_int32; - case i64: - return bob::io::base::array::t_int64; - case u8: - return bob::io::base::array::t_uint8; - case u16: - return bob::io::base::array::t_uint16; - case u32: - return bob::io::base::array::t_uint32; - case u64: - return bob::io::base::array::t_uint64; - case f32: - return bob::io::base::array::t_float32; - case f64: - return bob::io::base::array::t_float64; - case f128: - return bob::io::base::array::t_float128; - case c64: - return bob::io::base::array::t_complex64; - case c128: - return bob::io::base::array::t_complex128; - case c256: - return bob::io::base::array::t_complex256; - case s: - throw std::runtime_error("Cannot convert HDF5 string type to an element type to be used in blitz::Array's - FIXME: something is wrong in the logic"); - default: - break; - } - return bob::io::base::array::t_unknown; -} - -void bob::io::base::HDF5Type::copy_to (bob::io::base::array::typeinfo& ti) const { - ti.dtype = element_type(); - ti.nd = shape().n(); - if (ti.nd > (BOB_MAX_DIM+1)) { - boost::format f("HDF5 type has more (%d) than the allowed maximum number of dimensions (%d)"); - f % ti.nd % (BOB_MAX_DIM+1); - throw std::runtime_error(f.str()); - } - for (size_t i=0; i<ti.nd; ++i) ti.shape[i] = shape()[i]; - ti.update_strides(); -} - -bob::io::base::HDF5Descriptor::HDF5Descriptor(const HDF5Type& type, size_t size, - bool expand): - type(type), - size(size), - expandable(expand), - hyperslab_start(type.shape().n()), - hyperslab_count(type.shape()) -{ -} - -bob::io::base::HDF5Descriptor::HDF5Descriptor(const HDF5Descriptor& other): - type(other.type), - size(other.size), - expandable(other.expandable), - hyperslab_start(other.hyperslab_start), - hyperslab_count(other.hyperslab_count) -{ -} - -bob::io::base::HDF5Descriptor::~HDF5Descriptor() { } - -bob::io::base::HDF5Descriptor& bob::io::base::HDF5Descriptor::operator= -(const bob::io::base::HDF5Descriptor& other) { - type = other.type; - size = other.size; - expandable = other.expandable; - hyperslab_start = other.hyperslab_start; - hyperslab_count = other.hyperslab_count; - return *this; -} - -bob::io::base::HDF5Descriptor& bob::io::base::HDF5Descriptor::subselect() { - hyperslab_start >>= 1; - hyperslab_count >>= 1; - hyperslab_count[0] = 1; - return *this; -} - -std::string bob::io::base::format_hdf5_error() { - const std::vector<std::string>& stack = bob::io::base::DefaultHDF5ErrorStack->get(); - std::ostringstream retval; - std::string prefix(" "); - if (stack.size()) retval << prefix << stack[0]; - for (size_t i=1; i<stack.size(); ++i) - retval << std::endl << prefix << stack[i]; - bob::io::base::DefaultHDF5ErrorStack->clear(); - return retval.str(); -} diff --git a/bob/io/base/cpp/HDF5Utils.cpp b/bob/io/base/cpp/HDF5Utils.cpp deleted file mode 100644 index 12c13ea807ea3c44c564fbbbddb1f0b3c1bbde50..0000000000000000000000000000000000000000 --- a/bob/io/base/cpp/HDF5Utils.cpp +++ /dev/null @@ -1,157 +0,0 @@ -/** - * @date Wed Jun 22 17:50:08 2011 +0200 - * @author Andre Anjos <andre.anjos@idiap.ch> - * - * @brief Implements a set of utilities to read HDF5 files. - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#include <boost/format.hpp> -#include <boost/make_shared.hpp> - -#include <bob.core/logging.h> - -#include <bob.io.base/HDF5Utils.h> - -/** - * Opens/Creates an "auto-destructible" HDF5 file - */ -static void delete_h5file (hid_t* p) { - if (*p >= 0) { - herr_t err = H5Fclose(*p); - if (err < 0) { - bob::core::error << "H5Fclose(hid=" << *p << ") exited with an error (" << err << "). The stack trace follows:" << std::endl; - bob::core::error << bob::io::base::format_hdf5_error() << std::endl; - } - } - delete p; -} - -/** - * Opens/Creates and "auto-destructible" HDF5 file creation property list - */ -static void delete_h5p (hid_t* p) { - if (*p >= 0) { - herr_t err = H5Pclose(*p); - if (err < 0) { - bob::core::error << "H5Pclose(hid=" << *p << ") exited with an error (" << err << "). The stack trace follows:" << std::endl; - bob::core::error << bob::io::base::format_hdf5_error() << std::endl; - return; - } - } - delete p; -} - -static boost::shared_ptr<hid_t> open_file(const boost::filesystem::path& path, - unsigned int flags, boost::shared_ptr<hid_t>& fcpl) { - - boost::shared_ptr<hid_t> retval(new hid_t(-1), std::ptr_fun(delete_h5file)); - - if (!boost::filesystem::exists(path) && flags == H5F_ACC_RDONLY) { - //file was opened for reading, but does not exist... Raise - boost::format m("cannot open file `%s'"); - m % path.string(); - throw std::runtime_error(m.str()); - } - - if (boost::filesystem::exists(path) && flags != H5F_ACC_TRUNC) { //open - *retval = H5Fopen(path.string().c_str(), flags, H5P_DEFAULT); - if (*retval < 0) { - boost::format m("call to HDF5 C-function H5Fopen() returned error %d on file '%s'. HDF5 error statck follows:\n%s"); - m % *retval % path.string().c_str() % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - //replaces the file create list properties with the one from the file - fcpl = boost::shared_ptr<hid_t>(new hid_t(-1), std::ptr_fun(delete_h5p)); - *fcpl = H5Fget_create_plist(*retval); - if (*fcpl < 0) { - boost::format m("call to HDF5 C-function H5Fget_create_list() returned error %d on file '%s'. HDF5 error statck follows:\n%s"); - m % *fcpl % path.string().c_str() % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - } - else { //file needs to be created or truncated (can set user block) - *retval = H5Fcreate(path.string().c_str(), H5F_ACC_TRUNC, - *fcpl, H5P_DEFAULT); - if (*retval < 0) { - boost::format m("call to HDF5 C-function H5Fcreate() returned error %d on file '%s'. HDF5 error statck follows:\n%s"); - m % *retval % path.string().c_str() % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - } - return retval; -} - -static boost::shared_ptr<hid_t> create_fcpl(hsize_t userblock_size) { - if (!userblock_size) return boost::make_shared<hid_t>(H5P_DEFAULT); - //otherwise we have to go through the settings - boost::shared_ptr<hid_t> retval(new hid_t(-1), std::ptr_fun(delete_h5p)); - *retval = H5Pcreate(H5P_FILE_CREATE); - if (*retval < 0) { - boost::format m("call to HDF5 C-function H5Pcreate() returned error %d. HDF5 error statck follows:\n%s"); - m % *retval % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - herr_t err = H5Pset_userblock(*retval, userblock_size); - if (err < 0) { - boost::format m("call to HDF5 C-function H5Pset_userblock() returned error %d. HDF5 error statck follows:\n%s"); - m % err % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - return retval; -} - -bob::io::base::detail::hdf5::File::File(const boost::filesystem::path& path, unsigned int flags, - size_t userblock_size): - m_path(path), - m_flags(flags), - m_fcpl(create_fcpl(userblock_size)), - m_id(open_file(m_path, m_flags, m_fcpl)) -{ -} - -bob::io::base::detail::hdf5::File::~File() { -} - -boost::shared_ptr<bob::io::base::detail::hdf5::RootGroup> bob::io::base::detail::hdf5::File::root() { - if (!m_root) { - m_root = boost::make_shared<bob::io::base::detail::hdf5::RootGroup>(shared_from_this()); - m_root->open_recursively(); - } - return m_root; -} - -void bob::io::base::detail::hdf5::File::reset() { - m_root.reset(); -} - -void bob::io::base::detail::hdf5::File::flush() { - herr_t err = H5Fflush(*m_id, H5F_SCOPE_GLOBAL); - if (err < 0){ - std::runtime_error("H5Fflush returned with an error code."); - } -} - -bool bob::io::base::detail::hdf5::File::writable() const { - return (m_flags != H5F_ACC_RDONLY); -} - -size_t bob::io::base::detail::hdf5::File::userblock_size() const { - hsize_t retval; - herr_t err = H5Pget_userblock(*m_fcpl, &retval); - if (err < 0) { - boost::format m("Call to HDF5 C-function H5Pget_create_plist() returned error %d. HDF5 error statck follows:\n%s"); - m % err % bob::io::base::format_hdf5_error(); - throw std::runtime_error(m.str()); - } - return retval; -} - -void bob::io::base::detail::hdf5::File::get_userblock(std::string& data) const { - //TODO -} - -void bob::io::base::detail::hdf5::File::set_userblock(const std::string& data) { - //TODO -} diff --git a/bob/io/base/cpp/array.cpp b/bob/io/base/cpp/array.cpp deleted file mode 100644 index 2ffc94d77a13adec893f99fa8b052a55c45554ff..0000000000000000000000000000000000000000 --- a/bob/io/base/cpp/array.cpp +++ /dev/null @@ -1,134 +0,0 @@ -/** - * @date Tue Nov 8 15:34:31 2011 +0100 - * @author Andre Anjos <andre.anjos@idiap.ch> - * - * @brief Some buffer stuff - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#include <boost/format.hpp> -#include <bob.io.base/array.h> - -bob::io::base::array::typeinfo::typeinfo(): - dtype(bob::io::base::array::t_unknown), - nd(0) -{ -} - -bob::io::base::array::typeinfo::typeinfo(const bob::io::base::array::typeinfo& other): - dtype(other.dtype) -{ - set_shape(other.nd, other.shape); -} - -bob::io::base::array::typeinfo& bob::io::base::array::typeinfo::operator= (const bob::io::base::array::typeinfo& other) { - dtype = other.dtype; - set_shape(other.nd, other.shape); - return *this; -} - -void bob::io::base::array::typeinfo::reset() { - dtype = bob::io::base::array::t_unknown; - nd = 0; -} - -bool bob::io::base::array::typeinfo::is_valid() const { - return (dtype != bob::io::base::array::t_unknown) && (nd > 0) && (nd <= (BOB_MAX_DIM+1)) && has_valid_shape(); -} - -void bob::io::base::array::typeinfo::update_strides() { - switch (nd) { - case 0: - return; - case 1: - stride[0] = 1; - return; - case 2: - stride[1] = 1; - stride[0] = shape[1]; - return; - case 3: - stride[2] = 1; - stride[1] = shape[2]; - stride[0] = shape[1]*shape[2]; - return; - case 4: - stride[3] = 1; - stride[2] = shape[3]; - stride[1] = shape[2]*shape[3]; - stride[0] = shape[1]*shape[2]*shape[3]; - return; - case 5: - stride[4] = 1; - stride[3] = shape[4]; - stride[2] = shape[3]*shape[4]; - stride[1] = shape[2]*shape[3]*shape[4]; - stride[0] = shape[1]*shape[2]*shape[3]*shape[4]; - return; - default: - break; - } - throw std::runtime_error("unsupported number of dimensions"); -} - -size_t bob::io::base::array::typeinfo::size() const { - size_t retval = 1; - for (size_t k=0; k<nd; ++k) retval *= shape[k]; - return retval; -} - -size_t bob::io::base::array::typeinfo::buffer_size() const { - return size()*bob::io::base::array::getElementSize(dtype); -} - -static bool same_shape(size_t nd, const size_t* s1, const size_t* s2) { - for (size_t k=0; k<nd; ++k) if (s1[k] != s2[k]) return false; - return true; -} - -bool bob::io::base::array::typeinfo::is_compatible(const bob::io::base::array::typeinfo& other) const { - return (dtype == other.dtype) && (nd == other.nd) && same_shape(nd, shape, other.shape); -} - -std::string bob::io::base::array::typeinfo::str() const { - boost::format s("dtype: %s (%d); shape: [%s]; size: %d bytes"); - size_t sz = 0; - size_t buf_sz = 0; - if (dtype != bob::io::base::array::t_unknown) { - //otherwise it throws - sz = item_size(); - buf_sz = buffer_size(); - } - s % item_str() % sz; - switch (nd) { - case 0: - s % ""; - break; - case 1: - s % (boost::format("%d") % shape[0]).str(); - break; - case 2: - s % (boost::format("%d,%d") % shape[0] % shape[1]).str(); - break; - case 3: - s % (boost::format("%d,%d,%d") % shape[0] % shape[1] % shape[2]).str(); - break; - case 4: - s % (boost::format("%d,%d,%d,%d") % shape[0] % shape[1] % shape[2] % shape[3]).str(); - break; - default: - s % ">4 dimensions?"; - break; - } - s % buf_sz; - return s.str(); -} - -void bob::io::base::array::typeinfo::reset_shape() { - shape[0] = 0; -} - -bool bob::io::base::array::typeinfo::has_valid_shape() const { - return shape[0] != 0; -} diff --git a/bob/io/base/cpp/array_type.cpp b/bob/io/base/cpp/array_type.cpp deleted file mode 100644 index d42368e9175199572724f337ba5623d6a8a76a71..0000000000000000000000000000000000000000 --- a/bob/io/base/cpp/array_type.cpp +++ /dev/null @@ -1,126 +0,0 @@ -/** - * @date Sat Apr 9 18:10:10 2011 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * @brief Some type-related array utilities - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#include <bob.io.base/array_type.h> -#include <boost/format.hpp> - -static const char* t_bool_string = "bool"; -static const char* t_int8_string = "int8"; -static const char* t_int16_string = "int16"; -static const char* t_int32_string = "int32"; -static const char* t_int64_string = "int64"; -static const char* t_uint8_string = "uint8"; -static const char* t_uint16_string = "uint16"; -static const char* t_uint32_string = "uint32"; -static const char* t_uint64_string = "uint64"; -static const char* t_float32_string = "float32"; -static const char* t_float64_string = "float64"; -static const char* t_float128_string = "float128"; -static const char* t_complex64_string = "complex64"; -static const char* t_complex128_string = "complex128"; -static const char* t_complex256_string = "complex256"; -static const char* t_unknown_string = "unknown"; - -size_t bob::io::base::array::getElementSize(ElementType t) { - switch(t) { - case bob::io::base::array::t_bool: - return sizeof(bool); - case bob::io::base::array::t_int8: - return sizeof(int8_t); - case bob::io::base::array::t_int16: - return sizeof(int16_t); - case bob::io::base::array::t_int32: - return sizeof(int32_t); - case bob::io::base::array::t_int64: - return sizeof(int64_t); - case bob::io::base::array::t_uint8: - return sizeof(uint8_t); - case bob::io::base::array::t_uint16: - return sizeof(uint16_t); - case bob::io::base::array::t_uint32: - return sizeof(uint32_t); - case bob::io::base::array::t_uint64: - return sizeof(uint64_t); - case bob::io::base::array::t_float32: - return sizeof(float); - case bob::io::base::array::t_float64: - return sizeof(double); - case bob::io::base::array::t_float128: - return sizeof(long double); - case bob::io::base::array::t_complex64: - return sizeof(std::complex<float>); - case bob::io::base::array::t_complex128: - return sizeof(std::complex<double>); - case bob::io::base::array::t_complex256: - return sizeof(std::complex<long double>); - default: - { - boost::format m("unsupported element type (%d)"); - m % (int)t; - throw std::runtime_error(m.str()); - } - } -} - -const char* bob::io::base::array::stringize(ElementType t) { - switch(t) { - case bob::io::base::array::t_bool: - return t_bool_string; - case bob::io::base::array::t_int8: - return t_int8_string; - case bob::io::base::array::t_int16: - return t_int16_string; - case bob::io::base::array::t_int32: - return t_int32_string; - case bob::io::base::array::t_int64: - return t_int64_string; - case bob::io::base::array::t_uint8: - return t_uint8_string; - case bob::io::base::array::t_uint16: - return t_uint16_string; - case bob::io::base::array::t_uint32: - return t_uint32_string; - case bob::io::base::array::t_uint64: - return t_uint64_string; - case bob::io::base::array::t_float32: - return t_float32_string; - case bob::io::base::array::t_float64: - return t_float64_string; - case bob::io::base::array::t_float128: - return t_float128_string; - case bob::io::base::array::t_complex64: - return t_complex64_string; - case bob::io::base::array::t_complex128: - return t_complex128_string; - case bob::io::base::array::t_complex256: - return t_complex256_string; - default: - return t_unknown_string; - } -} - -bob::io::base::array::ElementType bob::io::base::array::unstringize(const char* s) { - std::string sc(s); - if (sc == t_bool_string) return bob::io::base::array::t_bool; - if (sc == t_int8_string) return bob::io::base::array::t_int8; - if (sc == t_int16_string) return bob::io::base::array::t_int16; - if (sc == t_int32_string) return bob::io::base::array::t_int32; - if (sc == t_int64_string) return bob::io::base::array::t_int64; - if (sc == t_uint8_string) return bob::io::base::array::t_uint8; - if (sc == t_uint16_string) return bob::io::base::array::t_uint16; - if (sc == t_uint32_string) return bob::io::base::array::t_uint32; - if (sc == t_uint64_string) return bob::io::base::array::t_uint64; - if (sc == t_float32_string) return bob::io::base::array::t_float32; - if (sc == t_float64_string) return bob::io::base::array::t_float64; - if (sc == t_float128_string) return bob::io::base::array::t_float128; - if (sc == t_complex64_string) return bob::io::base::array::t_complex64; - if (sc == t_complex128_string) return bob::io::base::array::t_complex128; - if (sc == t_complex256_string) return bob::io::base::array::t_complex256; - return bob::io::base::array::t_unknown; -} diff --git a/bob/io/base/cpp/blitz_array.cpp b/bob/io/base/cpp/blitz_array.cpp deleted file mode 100644 index 2bc723a71d4b2770207fb24732641e1e67a1948f..0000000000000000000000000000000000000000 --- a/bob/io/base/cpp/blitz_array.cpp +++ /dev/null @@ -1,166 +0,0 @@ -/** - * @date Tue Nov 8 15:34:31 2011 +0100 - * @author Andre Anjos <andre.anjos@idiap.ch> - * - * @brief Implementation of non-templated methods of the blitz - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#include <stdexcept> - -#include <bob.io.base/blitz_array.h> - -bob::io::base::array::blitz_array::blitz_array(boost::shared_ptr<blitz_array> other) { - set(other); -} - -bob::io::base::array::blitz_array::blitz_array(const blitz_array& other) { - set(other); -} - -bob::io::base::array::blitz_array::blitz_array(boost::shared_ptr<interface> other) { - set(other); -} - -bob::io::base::array::blitz_array::blitz_array(const interface& other) { - set(other); -} - -bob::io::base::array::blitz_array::blitz_array(const typeinfo& info) { - set(info); -} - -bob::io::base::array::blitz_array::blitz_array(void* data, const typeinfo& info): - m_type(info), - m_ptr(data), - m_is_blitz(false) { -} - -bob::io::base::array::blitz_array::~blitz_array() { -} - -void bob::io::base::array::blitz_array::set(boost::shared_ptr<blitz_array> other) { - m_type = other->m_type; - m_ptr = other->m_ptr; - m_is_blitz = other->m_is_blitz; - m_data = other->m_data; -} - -void bob::io::base::array::blitz_array::set(const interface& other) { - set(other.type()); - memcpy(m_ptr, other.ptr(), m_type.buffer_size()); -} - -void bob::io::base::array::blitz_array::set(boost::shared_ptr<interface> other) { - m_type = other->type(); - m_ptr = other->ptr(); - m_is_blitz = false; - m_data = other; -} - -template <typename T> -static boost::shared_ptr<void> make_array(size_t nd, const size_t* shape, - void*& ptr) { - switch(nd) { - case 1: - { - blitz::TinyVector<int,1> tv_shape; - for (size_t k=0; k<nd; ++k) tv_shape[k] = shape[k]; - boost::shared_ptr<void> retval = - boost::make_shared<blitz::Array<T,1> >(tv_shape); - ptr = reinterpret_cast<void*>(boost::static_pointer_cast<blitz::Array<T,1> >(retval)->data()); - return retval; - } - case 2: - { - blitz::TinyVector<int,2> tv_shape; - for (size_t k=0; k<nd; ++k) tv_shape[k] = shape[k]; - boost::shared_ptr<void> retval = - boost::make_shared<blitz::Array<T,2> >(tv_shape); - ptr = reinterpret_cast<void*>(boost::static_pointer_cast<blitz::Array<T,2> >(retval)->data()); - return retval; - } - case 3: - { - blitz::TinyVector<int,3> tv_shape; - for (size_t k=0; k<nd; ++k) tv_shape[k] = shape[k]; - boost::shared_ptr<void> retval = - boost::make_shared<blitz::Array<T,3> >(tv_shape); - ptr = reinterpret_cast<void*>(boost::static_pointer_cast<blitz::Array<T,3> >(retval)->data()); - return retval; - } - case 4: - { - blitz::TinyVector<int,4> tv_shape; - for (size_t k=0; k<nd; ++k) tv_shape[k] = shape[k]; - boost::shared_ptr<void> retval = - boost::make_shared<blitz::Array<T,4> >(tv_shape); - ptr = reinterpret_cast<void*>(boost::static_pointer_cast<blitz::Array<T,4> >(retval)->data()); - return retval; - } - default: - break; - } - throw std::runtime_error("unsupported number of dimensions -- debug me"); -} - -void bob::io::base::array::blitz_array::set (const bob::io::base::array::typeinfo& req) { - if (m_type.is_compatible(req)) return; ///< double-check requirement first! - - //ok, have to go through reallocation - m_type = req; - m_is_blitz = true; - switch (m_type.dtype) { - case bob::io::base::array::t_bool: - m_data = make_array<bool>(req.nd, req.shape, m_ptr); - return; - case bob::io::base::array::t_int8: - m_data = make_array<int8_t>(req.nd, req.shape, m_ptr); - return; - case bob::io::base::array::t_int16: - m_data = make_array<int16_t>(req.nd, req.shape, m_ptr); - return; - case bob::io::base::array::t_int32: - m_data = make_array<int32_t>(req.nd, req.shape, m_ptr); - return; - case bob::io::base::array::t_int64: - m_data = make_array<int64_t>(req.nd, req.shape, m_ptr); - return; - case bob::io::base::array::t_uint8: - m_data = make_array<uint8_t>(req.nd, req.shape, m_ptr); - return; - case bob::io::base::array::t_uint16: - m_data = make_array<uint16_t>(req.nd, req.shape, m_ptr); - return; - case bob::io::base::array::t_uint32: - m_data = make_array<uint32_t>(req.nd, req.shape, m_ptr); - return; - case bob::io::base::array::t_uint64: - m_data = make_array<uint64_t>(req.nd, req.shape, m_ptr); - return; - case bob::io::base::array::t_float32: - m_data = make_array<float>(req.nd, req.shape, m_ptr); - return; - case bob::io::base::array::t_float64: - m_data = make_array<double>(req.nd, req.shape, m_ptr); - return; - case bob::io::base::array::t_float128: - m_data = make_array<long double>(req.nd, req.shape, m_ptr); - return; - case bob::io::base::array::t_complex64: - m_data = make_array<std::complex<float> >(req.nd, req.shape, m_ptr); - return; - case bob::io::base::array::t_complex128: - m_data = make_array<std::complex<double> >(req.nd, req.shape, m_ptr); - return; - case bob::io::base::array::t_complex256: - m_data = make_array<std::complex<long double> >(req.nd, req.shape, m_ptr); - return; - default: - break; - } - - //if we get to this point, there is nothing much we can do... - throw std::runtime_error("invalid data type on blitz array reset -- debug me"); -} diff --git a/bob/io/base/cpp/reorder.cpp b/bob/io/base/cpp/reorder.cpp deleted file mode 100644 index cda5ab335a47cb9a05dcf2e14357b91f6311cdfd..0000000000000000000000000000000000000000 --- a/bob/io/base/cpp/reorder.cpp +++ /dev/null @@ -1,288 +0,0 @@ -/** - * @date Tue Nov 22 11:24:44 2011 +0100 - * @author Andre Anjos <andre.anjos@idiap.ch> - * - * @brief Implementation of row-major/column-major reordering - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#include <boost/format.hpp> -#include <cstring> //for memcpy - -#include <bob.io.base/reorder.h> - -void bob::io::base::rc2d(size_t& row, size_t& col, const size_t i, const size_t j, - const size_t* shape) { - row = (i * shape[1]) + j; - col = (j * shape[0]) + i; -} - -void bob::io::base::rc3d(size_t& row, size_t& col, const size_t i, const size_t j, - const size_t k, const size_t* shape) { - row = ( (i * shape[1]) + j ) * shape[2] + k; - col = ( (k * shape[1]) + j ) * shape[0] + i; -} - -void bob::io::base::rc4d(size_t& row, size_t& col, const size_t i, const size_t j, - const size_t k, const size_t l, const size_t* shape) { - row = ( ( i * shape[1] + j ) * shape[2] + k ) * shape[3] + l; - col = ( ( l * shape[2] + k ) * shape[1] + j ) * shape[0] + i; -} - -void bob::io::base::row_to_col_order(const void* src_, void* dst_, - const bob::io::base::array::typeinfo& info) { - - size_t dsize = info.item_size(); - - //cast to byte type so we can manipulate the pointers... - const uint8_t* src = static_cast<const uint8_t*>(src_); - uint8_t* dst = static_cast<uint8_t*>(dst_); - - switch(info.nd) { - - case 1: - std::memcpy(dst, src, info.buffer_size()); - break; - - case 2: - for (size_t i=0; i<info.shape[0]; ++i) - for (size_t j=0; j<info.shape[1]; ++j) { - size_t row_major, col_major; - bob::io::base::rc2d(row_major, col_major, i, j, info.shape); - row_major *= dsize; - col_major *= dsize; - std::memcpy(&dst[col_major], &src[row_major], dsize); - } - break; - - case 3: - for (size_t i=0; i<info.shape[0]; ++i) - for (size_t j=0; j<info.shape[1]; ++j) - for (size_t k=0; k<info.shape[2]; ++k) { - size_t row_major, col_major; - bob::io::base::rc3d(row_major, col_major, i, j, k, info.shape); - row_major *= dsize; - col_major *= dsize; - std::memcpy(&dst[col_major], &src[row_major], dsize); - } - break; - - case 4: - for (size_t i=0; i<info.shape[0]; ++i) - for (size_t j=0; j<info.shape[1]; ++j) - for (size_t k=0; k<info.shape[2]; ++k) - for (size_t l=0; l<info.shape[3]; ++l) { - size_t row_major, col_major; - bob::io::base::rc4d(row_major, col_major, i, j, k, l, info.shape); - row_major *= dsize; - col_major *= dsize; - std::memcpy(&dst[col_major], &src[row_major], dsize); - } - break; - - default: - { - boost::format m("row_to_col_order() can only flip arrays with up to %u dimensions - you passed one with %u dimensions"); - m % BOB_MAX_DIM % info.nd; - throw std::runtime_error(m.str()); - } - } -} - -void bob::io::base::col_to_row_order(const void* src_, void* dst_, - const bob::io::base::array::typeinfo& info) { - - size_t dsize = info.item_size(); - - //cast to byte type so we can manipulate the pointers... - const uint8_t* src = static_cast<const uint8_t*>(src_); - uint8_t* dst = static_cast<uint8_t*>(dst_); - - switch(info.nd) { - - case 1: - std::memcpy(dst, src, info.buffer_size()); - break; - - case 2: - for (size_t i=0; i<info.shape[0]; ++i) - for (size_t j=0; j<info.shape[1]; ++j) { - size_t row_major, col_major; - bob::io::base::rc2d(row_major, col_major, i, j, info.shape); - row_major *= dsize; - col_major *= dsize; - std::memcpy(&dst[row_major], &src[col_major], dsize); - } - break; - - case 3: - for (size_t i=0; i<info.shape[0]; ++i) - for (size_t j=0; j<info.shape[1]; ++j) - for (size_t k=0; k<info.shape[2]; ++k) { - size_t row_major, col_major; - bob::io::base::rc3d(row_major, col_major, i, j, k, info.shape); - row_major *= dsize; - col_major *= dsize; - std::memcpy(&dst[row_major], &src[col_major], dsize); - } - break; - - case 4: - for (size_t i=0; i<info.shape[0]; ++i) - for (size_t j=0; j<info.shape[1]; ++j) - for (size_t k=0; k<info.shape[2]; ++k) - for (size_t l=0; l<info.shape[3]; ++l) { - size_t row_major, col_major; - bob::io::base::rc4d(row_major, col_major, i, j, k, l, info.shape); - row_major *= dsize; - col_major *= dsize; - std::memcpy(&dst[row_major], &src[col_major], dsize); - } - break; - - default: - { - boost::format m("col_to_row_order() can only flip arrays with up to %u dimensions - you passed one with %u dimensions"); - m % BOB_MAX_DIM % info.nd; - throw std::runtime_error(m.str()); - } - } -} - -void bob::io::base::row_to_col_order_complex(const void* src_, void* dst_re_, - void* dst_im_, const bob::io::base::array::typeinfo& info) { - - size_t dsize = info.item_size(); - size_t dsize2 = dsize/2; ///< size of each complex component (real, imaginary) - - //cast to byte type so we can manipulate the pointers... - const uint8_t* src = static_cast<const uint8_t*>(src_); - uint8_t* dst_re = static_cast<uint8_t*>(dst_re_); - uint8_t* dst_im = static_cast<uint8_t*>(dst_im_); - - switch(info.nd) { - - case 1: - for (size_t i=0; i<info.shape[0]; ++i) { - std::memcpy(&dst_re[dsize2*i], &src[dsize*i] , dsize2); - std::memcpy(&dst_im[dsize2*i], &src[dsize*i]+dsize2, dsize2); - } - break; - - case 2: - for (size_t i=0; i<info.shape[0]; ++i) - for (size_t j=0; j<info.shape[1]; ++j) { - size_t row_major, col_major; - bob::io::base::rc2d(row_major, col_major, i, j, info.shape); - row_major *= dsize; - col_major *= dsize2; - std::memcpy(&dst_re[col_major], &src[row_major] , dsize2); - std::memcpy(&dst_im[col_major], &src[row_major]+dsize2, dsize2); - } - break; - - case 3: - for (size_t i=0; i<info.shape[0]; ++i) - for (size_t j=0; j<info.shape[1]; ++j) - for (size_t k=0; k<info.shape[2]; ++k) { - size_t row_major, col_major; - bob::io::base::rc3d(row_major, col_major, i, j, k, info.shape); - row_major *= dsize; - col_major *= dsize2; - std::memcpy(&dst_re[col_major], &src[row_major] , dsize2); - std::memcpy(&dst_im[col_major], &src[row_major]+dsize2, dsize2); - } - break; - - case 4: - for (size_t i=0; i<info.shape[0]; ++i) - for (size_t j=0; j<info.shape[1]; ++j) - for (size_t k=0; k<info.shape[2]; ++k) - for (size_t l=0; l<info.shape[3]; ++l) { - size_t row_major, col_major; - bob::io::base::rc4d(row_major, col_major, i, j, k, l, info.shape); - row_major *= dsize; - col_major *= dsize2; - std::memcpy(&dst_re[col_major], &src[row_major] , dsize2); - std::memcpy(&dst_im[col_major], &src[row_major]+dsize2, dsize2); - } - break; - - default: - { - boost::format m("row_to_col_order_complex() can only flip arrays with up to %u dimensions - you passed one with %u dimensions"); - m % BOB_MAX_DIM % info.nd; - throw std::runtime_error(m.str()); - } - } -} - -void bob::io::base::col_to_row_order_complex(const void* src_re_, const void* src_im_, - void* dst_, const bob::io::base::array::typeinfo& info) { - - size_t dsize = info.item_size(); - size_t dsize2 = dsize/2; ///< size of each complex component (real, imaginary) - - //cast to byte type so we can manipulate the pointers... - const uint8_t* src_re = static_cast<const uint8_t*>(src_re_); - const uint8_t* src_im = static_cast<const uint8_t*>(src_im_); - uint8_t* dst = static_cast<uint8_t*>(dst_); - - switch(info.nd) { - - case 1: - for (size_t i=0; i<info.shape[0]; ++i) { - std::memcpy(&dst[dsize*i] , &src_re[dsize2*i], dsize2); - std::memcpy(&dst[dsize*i]+dsize2, &src_im[dsize2*i], dsize2); - } - break; - - case 2: - for (size_t i=0; i<info.shape[0]; ++i) - for (size_t j=0; j<info.shape[1]; ++j) { - size_t row_major, col_major; - bob::io::base::rc2d(row_major, col_major, i, j, info.shape); - row_major *= dsize; - col_major *= dsize2; - std::memcpy(&dst[row_major], &src_re[col_major], dsize2); - std::memcpy(&dst[row_major]+dsize2, &src_im[col_major], dsize2); - } - break; - - case 3: - for (size_t i=0; i<info.shape[0]; ++i) - for (size_t j=0; j<info.shape[1]; ++j) - for (size_t k=0; k<info.shape[2]; ++k) { - size_t row_major, col_major; - bob::io::base::rc3d(row_major, col_major, i, j, k, info.shape); - row_major *= dsize; - col_major *= dsize2; - std::memcpy(&dst[row_major] , &src_re[col_major], dsize2); - std::memcpy(&dst[row_major]+dsize2, &src_im[col_major], dsize2); - } - break; - - case 4: - for (size_t i=0; i<info.shape[0]; ++i) - for (size_t j=0; j<info.shape[1]; ++j) - for (size_t k=0; k<info.shape[2]; ++k) - for (size_t l=0; l<info.shape[3]; ++l) { - size_t row_major, col_major; - bob::io::base::rc4d(row_major, col_major, i, j, k, l, info.shape); - row_major *= dsize; - col_major *= dsize2; - std::memcpy(&dst[row_major] , &src_re[col_major], dsize2); - std::memcpy(&dst[row_major]+dsize2, &src_im[col_major], dsize2); - } - break; - - default: - { - boost::format m("col_to_row_order_complex() can only flip arrays with up to %u dimensions - you passed one with %u dimensions"); - m % BOB_MAX_DIM % info.nd; - throw std::runtime_error(m.str()); - } - } -} - diff --git a/bob/io/base/cpp/utils.cpp b/bob/io/base/cpp/utils.cpp deleted file mode 100644 index 3467b997726137f619d1fb4911d5df8b28caaadc..0000000000000000000000000000000000000000 --- a/bob/io/base/cpp/utils.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/** - * @author Andre Anjos <andre.anjos@idiap.ch> - * @date Wed 3 Oct 08:36:48 2012 - * - * @brief Implementation of some compile-time I/O utitlites - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#include <bob.io.base/CodecRegistry.h> -#include <bob.io.base/utils.h> - -boost::shared_ptr<bob::io::base::File> bob::io::base::open (const char* filename, - char mode, const char* pretend_extension) { - boost::shared_ptr<bob::io::base::CodecRegistry> instance = bob::io::base::CodecRegistry::instance(); - return instance->findByExtension(pretend_extension)(filename, mode); -} - -boost::shared_ptr<bob::io::base::File> bob::io::base::open (const char* filename, char mode) { - boost::shared_ptr<bob::io::base::CodecRegistry> instance = bob::io::base::CodecRegistry::instance(); - return instance->findByFilenameExtension(filename)(filename, mode); -} - -bob::io::base::array::typeinfo bob::io::base::peek (const char* filename) { - return open(filename, 'r')->type(); -} - -bob::io::base::array::typeinfo bob::io::base::peek_all (const char* filename) { - return open(filename, 'r')->type_all(); -} diff --git a/bob/io/base/file.cpp b/bob/io/base/file.cpp deleted file mode 100644 index fc2622a7efb5f595b8f0fdf33094b4e4b285fe36..0000000000000000000000000000000000000000 --- a/bob/io/base/file.cpp +++ /dev/null @@ -1,603 +0,0 @@ -/** - * @author Andre Anjos <andre.anjos@idiap.ch> - * @date Tue 5 Nov 11:16:09 2013 - * - * @brief Bindings to bob::io::base::File - */ - -#define BOB_IO_BASE_MODULE -#include "bobskin.h" -#include <bob.io.base/api.h> -#include <numpy/arrayobject.h> -#include <bob.blitz/capi.h> -#include <bob.blitz/cleanup.h> -#include <bob.extension/documentation.h> -#include <stdexcept> - -#include <bob.io.base/CodecRegistry.h> -#include <bob.io.base/utils.h> - -/* Creates an exception message including the name of the given file, if possible */ -inline const std::string exception_message(PyBobIoFileObject* self, const std::string& name){ - std::ostringstream str; - str << name << " ("; - try{ - str << "'" << self->f->filename() << "'"; - } catch (...){ - str << "<unkown>"; - } - str << ")"; - return str.str(); -} - -static auto s_file = bob::extension::ClassDoc( - "File", - "Use this object to read and write data into files" -) -.add_constructor( - bob::extension::FunctionDoc( - "File", - "Opens a file for reading or writing", - "Normally, we read the file matching the extension to one of the available codecs installed with the present release of Bob. " - "If you set the ``pretend_extension`` parameter though, we will read the file as it had a given extension. " - "The value should start with a ``'.'``. " - "For example ``'.hdf5'``, to make the file be treated like an HDF5 file.", - true - ) - .add_prototype("filename, [mode], [pretend_extension]", "") - .add_parameter("filename", "str", "The file path to the file you want to open") - .add_parameter("mode", "one of ('r', 'w', 'a')", "[Default: ``'r'``] A single character indicating if you'd like to ``'r'``\\ ead, ``'w'``\\ rite or ``'a'``\\ ppend into the file; if you choose ``'w'`` and the file already exists, it will be truncated") - .add_parameter("pretend_extension", "str", "[optional] An extension to use; see :py:func:`bob.io.base.extensions` for a list of (currently) supported extensions") -); -/* How to create a new PyBobIoFileObject */ -static PyObject* PyBobIoFile_New(PyTypeObject* type, PyObject*, PyObject*) { - - /* Allocates the python object itself */ - PyBobIoFileObject* self = (PyBobIoFileObject*)type->tp_alloc(type, 0); - - self->f.reset(); - - return reinterpret_cast<PyObject*>(self); -} - -static void PyBobIoFile_Delete (PyBobIoFileObject* o) { - - o->f.reset(); - Py_TYPE(o)->tp_free((PyObject*)o); - -} - -int PyBobIo_FilenameConverter (PyObject* o, const char** b) { -#if PY_VERSION_HEX >= 0x03000000 - if (PyUnicode_Check(o)) { - *b = PyUnicode_AsUTF8(o); - } else { - PyObject* temp = PyObject_Bytes(o); - if (!temp) return 0; - auto temp_ = make_safe(temp); - *b = PyBytes_AsString(temp); - } -#else - if (PyUnicode_Check(o)) { - PyObject* temp = PyUnicode_AsEncodedString(o, Py_FileSystemDefaultEncoding, "strict"); - if (!temp) return 0; - auto temp_ = make_safe(temp); - *b = PyString_AsString(temp); - } else { - *b = PyString_AsString(o); - } -#endif - return b != 0; -} - -/* The __init__(self) method */ -static int PyBobIoFile_init(PyBobIoFileObject* self, PyObject *args, PyObject* kwds) { -BOB_TRY - /* Parses input arguments in a single shot */ - static char** kwlist = s_file.kwlist(); - - const char* filename; - const char* pretend_extension = 0; - -#if PY_VERSION_HEX >= 0x03000000 -# define MODE_CHAR "C" - int mode = 'r'; -#else -# define MODE_CHAR "c" - char mode = 'r'; -#endif - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|" MODE_CHAR "s", kwlist, - &PyBobIo_FilenameConverter, &filename, &mode, &pretend_extension)) return -1; - -#undef MODE_CHAR - - if (mode != 'r' && mode != 'w' && mode != 'a') { - PyErr_Format(PyExc_ValueError, "file open mode string should have 1 element and be either 'r' (read), 'w' (write) or 'a' (append)"); - return -1; - } - - if (pretend_extension) { - self->f = bob::io::base::open(filename, mode, pretend_extension); - } - else { - self->f = bob::io::base::open(filename, mode); - } - - return 0; ///< SUCCESS -BOB_CATCH_MEMBER("constructor", -1); -} - -static PyObject* PyBobIoFile_repr(PyBobIoFileObject* self) { - return PyString_FromFormat("%s(filename='%s', codec='%s')", Py_TYPE(self)->tp_name, self->f->filename(), self->f->name()); -} - -static auto s_filename = bob::extension::VariableDoc( - "filename", - "str", - "The path to the file being read/written" -); -static PyObject* PyBobIoFile_Filename(PyBobIoFileObject* self) { - return Py_BuildValue("s", self->f->filename()); -} - -static auto s_codec_name = bob::extension::VariableDoc( - "codec_name", - "str", - "Name of the File class implementation", - "This variable is available for compatibility reasons with the previous versions of this library." -); -static PyObject* PyBobIoFile_CodecName(PyBobIoFileObject* self) { - return Py_BuildValue("s", self->f->name()); -} - - -static PyGetSetDef PyBobIoFile_getseters[] = { - { - s_filename.name(), - (getter)PyBobIoFile_Filename, - 0, - s_filename.doc(), - 0, - }, - { - s_codec_name.name(), - (getter)PyBobIoFile_CodecName, - 0, - s_codec_name.doc(), - 0, - }, - {0} /* Sentinel */ -}; - -static Py_ssize_t PyBobIoFile_len (PyBobIoFileObject* self) { - Py_ssize_t retval = self->f->size(); - return retval; -} - -int PyBobIo_AsTypenum (bob::io::base::array::ElementType type) { - - switch(type) { - case bob::io::base::array::t_bool: - return NPY_BOOL; - case bob::io::base::array::t_int8: - return NPY_INT8; - case bob::io::base::array::t_int16: - return NPY_INT16; - case bob::io::base::array::t_int32: - return NPY_INT32; - case bob::io::base::array::t_int64: - return NPY_INT64; - case bob::io::base::array::t_uint8: - return NPY_UINT8; - case bob::io::base::array::t_uint16: - return NPY_UINT16; - case bob::io::base::array::t_uint32: - return NPY_UINT32; - case bob::io::base::array::t_uint64: - return NPY_UINT64; - case bob::io::base::array::t_float32: - return NPY_FLOAT32; - case bob::io::base::array::t_float64: - return NPY_FLOAT64; -#ifdef NPY_FLOAT128 - case bob::io::base::array::t_float128: - return NPY_FLOAT128; -#endif - case bob::io::base::array::t_complex64: - return NPY_COMPLEX64; - case bob::io::base::array::t_complex128: - return NPY_COMPLEX128; -#ifdef NPY_COMPLEX256 - case bob::io::base::array::t_complex256: - return NPY_COMPLEX256; -#endif - default: - PyErr_Format(PyExc_TypeError, "unsupported Bob/C++ element type (%s)", bob::io::base::array::stringize(type)); - } - - return NPY_NOTYPE; - -} - -static PyObject* PyBobIoFile_getIndex (PyBobIoFileObject* self, Py_ssize_t i) { - if (i < 0) i += self->f->size(); ///< adjust for negative indexing - - if (i < 0 || (size_t)i >= self->f->size()) { - PyErr_Format(PyExc_IndexError, "file index out of range - `%s' only contains %" PY_FORMAT_SIZE_T "d object(s)", self->f->filename(), self->f->size()); - return 0; - } - - const bob::io::base::array::typeinfo& info = self->f->type(); - - npy_intp shape[NPY_MAXDIMS]; - for (size_t k=0; k<info.nd; ++k) shape[k] = info.shape[k]; - - int type_num = PyBobIo_AsTypenum(info.dtype); - if (type_num == NPY_NOTYPE) return 0; ///< failure - - PyObject* retval = PyArray_SimpleNew(info.nd, shape, type_num); - if (!retval) return 0; - auto retval_ = make_safe(retval); - - bobskin skin((PyArrayObject*)retval, info.dtype); - self->f->read(skin, i); - return Py_BuildValue("O", retval); -} - -static PyObject* PyBobIoFile_getSlice (PyBobIoFileObject* self, PySliceObject* slice) { - - Py_ssize_t start, stop, step, slicelength; -#if PY_VERSION_HEX < 0x03000000 - if (PySlice_GetIndicesEx(slice, -#else - if (PySlice_GetIndicesEx(reinterpret_cast<PyObject*>(slice), -#endif - self->f->size(), &start, &stop, &step, &slicelength) < 0) return 0; - - //creates the return array - const bob::io::base::array::typeinfo& info = self->f->type(); - - int type_num = PyBobIo_AsTypenum(info.dtype); - if (type_num == NPY_NOTYPE) return 0; ///< failure - - if (slicelength <= 0) return PyArray_SimpleNew(0, 0, type_num); - - npy_intp shape[NPY_MAXDIMS]; - shape[0] = slicelength; - for (size_t k=0; k<info.nd; ++k) shape[k+1] = info.shape[k]; - - PyObject* retval = PyArray_SimpleNew(info.nd+1, shape, type_num); - if (!retval) return 0; - auto retval_ = make_safe(retval); - - Py_ssize_t counter = 0; - for (auto i = start; (start<=stop)?i<stop:i>stop; i+=step) { - - //get slice to fill - PyObject* islice = Py_BuildValue("n", counter++); - if (!islice) return 0; - auto islice_ = make_safe(islice); - - PyObject* item = PyObject_GetItem(retval, islice); - if (!item) return 0; - auto item_ = make_safe(item); - - bobskin skin((PyArrayObject*)item, info.dtype); - self->f->read(skin, i); - } - - return Py_BuildValue("O", retval); -} - -static PyObject* PyBobIoFile_getItem (PyBobIoFileObject* self, PyObject* item) { - if (PyIndex_Check(item)) { - Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); - if (i == -1 && PyErr_Occurred()) return 0; - return PyBobIoFile_getIndex(self, i); - } - if (PySlice_Check(item)) { - return PyBobIoFile_getSlice(self, (PySliceObject*)item); - } - else { - PyErr_Format(PyExc_TypeError, "File indices must be integers, not %s", Py_TYPE(item)->tp_name); - return 0; - } -} - -static PyMappingMethods PyBobIoFile_Mapping = { - (lenfunc)PyBobIoFile_len, //mp_length - (binaryfunc)PyBobIoFile_getItem, //mp_subscript - 0 /* (objobjargproc)PyBobIoFile_SetItem //mp_ass_subscript */ -}; - - -static auto s_read = bob::extension::FunctionDoc( - "read", - "Reads a specific object in the file, or the whole file", - "This method reads data from the file. " - "If you specified an ``index``, it reads just the object indicated by the index, as you would do using the ``[]`` operator. " - "If the ``index`` is not specified, reads the whole contents of the file into a :py:class:`numpy.ndarray`.", - true -) -.add_prototype("[index]", "data") -.add_parameter("index", "int", "[optional] The index to the object one wishes to retrieve from the file; negative indexing is supported; if not given, implies retrieval of the whole file contents.") -.add_return("data", ":py:class:`numpy.ndarray`", "The contents of the file, as array") -; -static PyObject* PyBobIoFile_read(PyBobIoFileObject* self, PyObject *args, PyObject* kwds) { -BOB_TRY - /* Parses input arguments in a single shot */ - static char** kwlist = s_read.kwlist(); - - Py_ssize_t i = PY_SSIZE_T_MIN; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|n", kwlist, &i)) return 0; - - if (i != PY_SSIZE_T_MIN) { - - // reads a specific object inside the file - - if (i < 0) i += self->f->size(); - - if (i < 0 || (size_t)i >= self->f->size()) { - PyErr_Format(PyExc_IndexError, "file index out of range - `%s' only contains %" PY_FORMAT_SIZE_T "d object(s)", self->f->filename(), self->f->size()); - return 0; - } - - return PyBobIoFile_getIndex(self, i); - - } - - // reads the whole file in a single shot - - const bob::io::base::array::typeinfo& info = self->f->type_all(); - - npy_intp shape[NPY_MAXDIMS]; - for (size_t k=0; k<info.nd; ++k) shape[k] = info.shape[k]; - - int type_num = PyBobIo_AsTypenum(info.dtype); - if (type_num == NPY_NOTYPE) return 0; ///< failure - - PyObject* retval = PyArray_SimpleNew(info.nd, shape, type_num); - if (!retval) return 0; - auto retval_ = make_safe(retval); - - bobskin skin((PyArrayObject*)retval, info.dtype); - self->f->read_all(skin); - - return Py_BuildValue("O", retval); -BOB_CATCH_MEMBER(exception_message(self, s_read.name()).c_str(), 0) -} - - -static auto s_write = bob::extension::FunctionDoc( - "write", - "Writes the contents of an object to the file", - "This method writes data to the file. " - "It acts like the given array is the only piece of data that will ever be written to such a file. " - "No more data appending may happen after a call to this method.", - true -) -.add_prototype("data") -.add_parameter("data", "array_like", "The array to be written into the file; it can be a :py:class:`numpy.ndarray`, a :py:class:`bob.blitz.array` or any other object which can be converted to either of them") -; -static PyObject* PyBobIoFile_write(PyBobIoFileObject* self, PyObject *args, PyObject* kwds) { -BOB_TRY - /* Parses input arguments in a single shot */ - static char** kwlist = s_write.kwlist(); - - PyBlitzArrayObject* bz = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&", kwlist, &PyBlitzArray_Converter, &bz)) return 0; - - auto bz_ = make_safe(bz); - - bobskin skin(bz); - self->f->write(skin); - - Py_RETURN_NONE; -BOB_CATCH_MEMBER(exception_message(self, s_write.name()).c_str(), 0) -} - - -static auto s_append = bob::extension::FunctionDoc( - "append", - "Adds the contents of an object to the file", - "This method appends data to the file. " - "If the file does not exist, creates a new file, else, makes sure that the inserted array respects the previously set file structure.", - true -) -.add_prototype("data", "position") -.add_parameter("data", "array_like", "The array to be written into the file; it can be a :py:class:`numpy.ndarray`, a :py:class:`bob.blitz.array` or any other object which can be converted to either of them") -.add_return("position", "int", "The current position of the newly written data") -; -static PyObject* PyBobIoFile_append(PyBobIoFileObject* self, PyObject *args, PyObject* kwds) { -BOB_TRY - /* Parses input arguments in a single shot */ - static char** kwlist = s_append.kwlist(); - - PyBlitzArrayObject* bz = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&", kwlist, &PyBlitzArray_Converter, &bz)) return 0; - auto bz_ = make_safe(bz); - Py_ssize_t pos = -1; - - bobskin skin(bz); - pos = self->f->append(skin); - - return Py_BuildValue("n", pos); -BOB_CATCH_MEMBER(exception_message(self, s_append.name()).c_str(), 0) -} - - -PyObject* PyBobIo_TypeInfoAsTuple (const bob::io::base::array::typeinfo& ti) { - - int type_num = PyBobIo_AsTypenum(ti.dtype); - if (type_num == NPY_NOTYPE) return 0; - - PyObject* retval = Py_BuildValue("NNN", - reinterpret_cast<PyObject*>(PyArray_DescrFromType(type_num)), - PyTuple_New(ti.nd), //shape - PyTuple_New(ti.nd) //strides - ); - if (!retval) return 0; - - PyObject* shape = PyTuple_GET_ITEM(retval, 1); - PyObject* stride = PyTuple_GET_ITEM(retval, 2); - for (Py_ssize_t i=0; (size_t)i<ti.nd; ++i) { - PyTuple_SET_ITEM(shape, i, Py_BuildValue("n", ti.shape[i])); - PyTuple_SET_ITEM(stride, i, Py_BuildValue("n", ti.stride[i])); - } - - return retval; -} - -static auto s_describe = bob::extension::FunctionDoc( - "describe", - "Returns a description (dtype, shape, stride) of data at the file", - 0, - true -) -.add_prototype("[all]", "dtype, shape, stride") -.add_parameter("all", "bool", "[Default: ``False``] If set to ``True``, returns the shape and strides for reading the whole file contents in one shot.") -.add_return("dtype", ":py:class:`numpy.dtype`", "The data type of the object") -.add_return("shape", "tuple", "The shape of the object") -.add_return("stride", "tuple", "The stride of the object") -; -static PyObject* PyBobIoFile_describe(PyBobIoFileObject* self, PyObject *args, PyObject* kwds) { -BOB_TRY - /* Parses input arguments in a single shot */ - static const char* const_kwlist[] = {"all", 0}; - static char** kwlist = const_cast<char**>(const_kwlist); - - PyObject* all = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &all)) return 0; - - const bob::io::base::array::typeinfo* info = 0; - if (all && PyObject_IsTrue(all)) info = &self->f->type_all(); - else info = &self->f->type(); - - /* Now return type description and tuples with shape and strides */ - return PyBobIo_TypeInfoAsTuple(*info); -BOB_CATCH_MEMBER(exception_message(self, s_describe.name()).c_str(), 0) -} - - -static PyMethodDef PyBobIoFile_methods[] = { - { - s_read.name(), - (PyCFunction)PyBobIoFile_read, - METH_VARARGS|METH_KEYWORDS, - s_read.doc(), - }, - { - s_write.name(), - (PyCFunction)PyBobIoFile_write, - METH_VARARGS|METH_KEYWORDS, - s_write.doc(), - }, - { - s_append.name(), - (PyCFunction)PyBobIoFile_append, - METH_VARARGS|METH_KEYWORDS, - s_append.doc(), - }, - { - s_describe.name(), - (PyCFunction)PyBobIoFile_describe, - METH_VARARGS|METH_KEYWORDS, - s_describe.doc(), - }, - {0} /* Sentinel */ -}; - -/********************************** - * Definition of Iterator to File * - **********************************/ - -PyDoc_STRVAR(s_fileiterator_str, BOB_EXT_MODULE_PREFIX ".File.iter"); - -/* How to create a new PyBobIoFileIteratorObject */ -static PyObject* PyBobIoFileIterator_New(PyTypeObject* type, PyObject*, PyObject*) { - - /* Allocates the python object itself */ - PyBobIoFileIteratorObject* self = (PyBobIoFileIteratorObject*)type->tp_alloc(type, 0); - - return reinterpret_cast<PyObject*>(self); -} - -static PyObject* PyBobIoFileIterator_iter (PyBobIoFileIteratorObject* self) { - return reinterpret_cast<PyObject*>(self); -} - -static PyObject* PyBobIoFileIterator_next (PyBobIoFileIteratorObject* self) { - if ((size_t)self->curpos >= self->pyfile->f->size()) { - Py_XDECREF((PyObject*)self->pyfile); - self->pyfile = 0; - return 0; - } - return PyBobIoFile_getIndex(self->pyfile, self->curpos++); -} - -static PyObject* PyBobIoFile_iter (PyBobIoFileObject* self) { - PyBobIoFileIteratorObject* retval = (PyBobIoFileIteratorObject*)PyBobIoFileIterator_New(&PyBobIoFileIterator_Type, 0, 0); - if (!retval) return 0; - retval->pyfile = self; - retval->curpos = 0; - return Py_BuildValue("N", retval); -} - -#if PY_VERSION_HEX >= 0x03000000 -# define Py_TPFLAGS_HAVE_ITER 0 -#endif - -PyTypeObject PyBobIoFileIterator_Type = { - PyVarObject_HEAD_INIT(0, 0) - 0 -}; - - -PyTypeObject PyBobIoFile_Type = { - PyVarObject_HEAD_INIT(0, 0) - 0 -}; - -bool init_File(PyObject* module){ - - // initialize the iterator - PyBobIoFileIterator_Type.tp_name = s_fileiterator_str; - PyBobIoFileIterator_Type.tp_basicsize = sizeof(PyBobIoFileIteratorObject); - PyBobIoFileIterator_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER; - PyBobIoFileIterator_Type.tp_iter = (getiterfunc)PyBobIoFileIterator_iter; - PyBobIoFileIterator_Type.tp_iternext = (iternextfunc)PyBobIoFileIterator_next; - - // initialize the File - PyBobIoFile_Type.tp_name = s_file.name(); - PyBobIoFile_Type.tp_basicsize = sizeof(PyBobIoFileObject); - PyBobIoFile_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; - PyBobIoFile_Type.tp_doc = s_file.doc(); - - // set the functions - PyBobIoFile_Type.tp_new = PyBobIoFile_New; - PyBobIoFile_Type.tp_init = reinterpret_cast<initproc>(PyBobIoFile_init); - PyBobIoFile_Type.tp_dealloc = reinterpret_cast<destructor>(PyBobIoFile_Delete); - PyBobIoFile_Type.tp_methods = PyBobIoFile_methods; - PyBobIoFile_Type.tp_getset = PyBobIoFile_getseters; - PyBobIoFile_Type.tp_iter = (getiterfunc)PyBobIoFile_iter; - - PyBobIoFile_Type.tp_str = reinterpret_cast<reprfunc>(PyBobIoFile_repr); - PyBobIoFile_Type.tp_repr = reinterpret_cast<reprfunc>(PyBobIoFile_repr); - PyBobIoFile_Type.tp_as_mapping = &PyBobIoFile_Mapping; - - - // check that everything is fine - if (PyType_Ready(&PyBobIoFile_Type) < 0) - return false; - if (PyType_Ready(&PyBobIoFileIterator_Type) < 0) - return false; - - // add the type to the module - Py_INCREF(&PyBobIoFile_Type); - bool success = PyModule_AddObject(module, s_file.name(), (PyObject*)&PyBobIoFile_Type) >= 0; - if (!success) return false; - Py_INCREF(&PyBobIoFileIterator_Type); - success = PyModule_AddObject(module, s_fileiterator_str, (PyObject*)&PyBobIoFileIterator_Type) >= 0; - return success; -} diff --git a/bob/io/base/hdf5.cpp b/bob/io/base/hdf5.cpp deleted file mode 100644 index 42347bda96f5b47a0fb80c89cfba70e63627d30e..0000000000000000000000000000000000000000 --- a/bob/io/base/hdf5.cpp +++ /dev/null @@ -1,2137 +0,0 @@ -/** - * @author Andre Anjos <andre.anjos@idiap.ch> - * @date Tue 12 Nov 18:19:22 2013 - * - * @brief Bindings to bob::io::base::HDF5File - */ - -#define BOB_IO_BASE_MODULE -#include <bob.io.base/api.h> - -#include <boost/make_shared.hpp> -#include <numpy/arrayobject.h> -#include <bob.blitz/cppapi.h> -#include <bob.blitz/cleanup.h> -#include <bob.extension/documentation.h> -#include <stdexcept> -#include <cstring> - -/* Creates an exception message including the name of the given file, if possible */ -inline const std::string exception_message(PyBobIoHDF5FileObject* self, const std::string& name){ - std::ostringstream str; - str << name << " ("; - try{ - str << "'" << self->f->filename() << "'"; - } catch (...){ - str << "<unkown>"; - } - str << ")"; - return str.str(); -} - -static auto s_hdf5file = bob::extension::ClassDoc( - "HDF5File", - "Reads and writes data to HDF5 files.", - "HDF5 stands for Hierarchical Data Format version 5. " - "It is a flexible, binary file format that allows one to store and read data efficiently into or from files. " - "It is a cross-platform, cross-architecture format.\n\n" - "Objects of this class allows users to read and write data from and to files in HDF5 format. " - "For an introduction to HDF5, visit the `HDF5 Website <http://www.hdfgroup.org/HDF5>`_." -) -.add_constructor( - bob::extension::FunctionDoc( - "HDF5File", - "Opens an HFF5 file for reading, writing or appending.", - "For the ``open`` mode, use ``'r'`` for read-only ``'a'`` for read/write/append, ``'w'`` for read/write/truncate or ``'x'`` for (read/write/exclusive). " - "When another :py:class:`HDF5File` object is given, a shallow copy is created, pointing to the same file." - ) - .add_prototype("filename, [mode]","") - .add_prototype("hdf5", "") - .add_parameter("filename", "str", "The file path to the file you want to open for reading or writing") - .add_parameter("mode", "one of ('r', 'w', 'a', 'x')", "[Default: ``'r'``] The opening mode") - .add_parameter("hdf5", ":py:class:`HDF5File`", "An HDF5 file to copy-construct") -); - - -int PyBobIoHDF5File_Check(PyObject* o) { - if (!o) return 0; - return PyObject_IsInstance(o, reinterpret_cast<PyObject*>(&PyBobIoHDF5File_Type)); -} - -int PyBobIoHDF5File_Converter(PyObject* o, PyBobIoHDF5FileObject** a) { - if (!PyBobIoHDF5File_Check(o)) return 0; - Py_INCREF(o); - (*a) = reinterpret_cast<PyBobIoHDF5FileObject*>(o); - return 1; -} - -/* How to create a new PyBobIoHDF5FileObject */ -static PyObject* PyBobIoHDF5File_New(PyTypeObject* type, PyObject*, PyObject*) { - - /* Allocates the python object itself */ - PyBobIoHDF5FileObject* self = (PyBobIoHDF5FileObject*)type->tp_alloc(type, 0); - - self->f.reset(); - - return reinterpret_cast<PyObject*>(self); -} - -static void PyBobIoHDF5File_Delete (PyBobIoHDF5FileObject* o) { - - o->f.reset(); - Py_TYPE(o)->tp_free((PyObject*)o); -} - -static bob::io::base::HDF5File::mode_t mode_from_char (char mode) { - - bob::io::base::HDF5File::mode_t new_mode = bob::io::base::HDF5File::inout; - - switch (mode) { - case 'r': new_mode = bob::io::base::HDF5File::in; break; - case 'a': new_mode = bob::io::base::HDF5File::inout; break; - case 'w': new_mode = bob::io::base::HDF5File::trunc; break; - case 'x': new_mode = bob::io::base::HDF5File::excl; break; - default: - PyErr_SetString(PyExc_RuntimeError, "Supported flags are 'r' (read-only), 'a' (read/write/append), 'w' (read/write/truncate) or 'x' (read/write/exclusive)"); - } - - return new_mode; - -} - -/* The __init__(self) method */ -static int PyBobIoHDF5File_init(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) { -BOB_TRY - /* Parses input arguments in a single shot */ - static char** kwlist1 = s_hdf5file.kwlist(0); - static char** kwlist2 = s_hdf5file.kwlist(1); - - // get the number of command line arguments - Py_ssize_t nargs = (args?PyTuple_Size(args):0) + (kwds?PyDict_Size(kwds):0); - - if (!nargs){ - // at least one argument is required - PyErr_Format(PyExc_TypeError, "`%s' constructor requires at least one parameter", Py_TYPE(self)->tp_name); - return -1; - } // nargs == 0 - - PyObject* k = Py_BuildValue("s", kwlist2[0]); - auto k_ = make_safe(k); - if ( - (kwds && PyDict_Contains(kwds, k)) || - (args && PyBobIoHDF5File_Check(PyTuple_GET_ITEM(args, 0))) - ){ - PyBobIoHDF5FileObject* other; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&", kwlist2, &PyBobIoHDF5File_Converter, &other)) - return -1; - auto other_ = make_safe(other); - self->f = other->f; - return 0; - } - -#if PY_VERSION_HEX >= 0x03000000 -# define MODE_CHAR "C" - int mode = 'r'; -#else -# define MODE_CHAR "c" - char mode = 'r'; -#endif - - const char* filename; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&|" MODE_CHAR, kwlist1, - &PyBobIo_FilenameConverter, &filename, &mode)) - return -1; - -#undef MODE_CHAR - - if (mode != 'r' && mode != 'w' && mode != 'a' && mode != 'x') { - PyErr_Format(PyExc_ValueError, "file open mode string should have 1 element and be either 'r' (read), 'w' (write), 'a' (append), 'x' (exclusive)"); - return -1; - } - bob::io::base::HDF5File::mode_t mode_mode = mode_from_char(mode); - if (PyErr_Occurred()) return -1; - - self->f.reset(new bob::io::base::HDF5File(filename, mode_mode)); - return 0; ///< SUCCESS -BOB_CATCH_MEMBER("hdf5 constructor", -1) -} - - -static PyObject* PyBobIoHDF5File_repr(PyBobIoHDF5FileObject* self) { -BOB_TRY - return PyString_FromFormat("%s(filename='%s')", Py_TYPE(self)->tp_name, self->f->filename().c_str()); -BOB_CATCH_MEMBER("__repr__", 0) -} - - -static auto s_flush = bob::extension::FunctionDoc( - "flush", - "Flushes the content of the HDF5 file to disk", - "When the HDF5File is open for writing, this function synchronizes the contents on the disk with the one from the file. " - "When the file is open for reading, nothing happens.", - true -) - .add_prototype("") -; -static PyObject* PyBobIoHDF5File_flush(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) { -BOB_TRY - /* Parses input arguments in a single shot */ - static char** kwlist = s_flush.kwlist(); - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) return 0; - - self->f->flush(); - Py_RETURN_NONE; -BOB_CATCH_MEMBER(exception_message(self, s_flush.name()).c_str(), 0) -} - - -static auto s_close = bob::extension::FunctionDoc( - "close", - "Closes this file", - "This function closes the HDF5File after flushing all its contents to disk. " - "After the HDF5File is closed, any operation on it will result in an exception.", - true -) -.add_prototype("") -; -static PyObject* PyBobIoHDF5File_close(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) { -BOB_TRY - /* Parses input arguments in a single shot */ - static char** kwlist = s_close.kwlist(); - - if (!PyArg_ParseTupleAndKeywords(args, kwds, "", kwlist)) return 0; - - self->f->close(); - - Py_RETURN_NONE; -BOB_CATCH_MEMBER(exception_message(self, s_close.name()).c_str(), 0); -} - - -static auto s_cd = bob::extension::FunctionDoc( - "cd", - "Changes the current prefix path", - "When this object is created the prefix path is empty, which means all following paths to data objects should be given using the full path. " - "If you set the ``path`` to a different value, it will be used as a prefix to any subsequent operation until you reset it. " - "If ``path`` starts with ``'/'``, it is treated as an absolute path. " - "If the value is relative, it is added to the current path; ``'..'`` and ``'.'`` are supported. " - "If it is absolute, it causes the prefix to be reset.\n\n" - "..note:: All operations taking a relative path, following a :py:func:`cd`, will be considered relative to the value defined by the :py:attr:`cwd` property of this object.", - true -) -.add_prototype("path") -.add_parameter("path", "str", "The path to change directories to") -; - -static PyObject* PyBobIoHDF5File_changeDirectory(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) { -BOB_TRY - /* Parses input arguments in a single shot */ - static char** kwlist = s_cd.kwlist(); - - const char* path = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &path)) return 0; - - self->f->cd(path); - - Py_RETURN_NONE; -BOB_CATCH_MEMBER(exception_message(self, s_cd.name()).c_str(), 0) -} - - -static auto s_has_group = bob::extension::FunctionDoc( - "has_group", - "Checks if a path (group) exists inside a file", - "This method does not work for datasets, only for directories. " - "If the given path is relative, it is take w.r.t. to the current working directory.", - true -) -.add_prototype("path") -.add_parameter("path", "str", "The path to check") -; -static PyObject* PyBobIoHDF5File_hasGroup(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) { -BOB_TRY - /* Parses input arguments in a single shot */ - static char** kwlist = s_has_group.kwlist(); - - const char* path = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &path)) return 0; - - if (self->f->hasGroup(path)) Py_RETURN_TRUE; - Py_RETURN_FALSE; -BOB_CATCH_MEMBER(exception_message(self, s_has_group.name()).c_str(), 0) -} - - -static auto s_create_group = bob::extension::FunctionDoc( - "create_group", - "Creates a new path (group) inside the file", - "A relative path is taken w.r.t. to the current directory. " - "If the directory already exists (check it with :py:meth:`has_group`), an exception will be raised.", - true -) -.add_prototype("path") -.add_parameter("path", "str", "The path to create.") -; -static PyObject* PyBobIoHDF5File_createGroup(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) { -BOB_TRY - /* Parses input arguments in a single shot */ - static char** kwlist = s_create_group.kwlist(); - - const char* path = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &path)) return 0; - - self->f->createGroup(path); - - Py_RETURN_NONE; -BOB_CATCH_MEMBER(exception_message(self, s_create_group.name()).c_str(), 0) -} - - -static auto s_has_dataset = bob::extension::FunctionDoc( - "has_dataset", - "Checks if a dataset exists inside a file", - "Checks if a dataset exists inside a file, on the specified path. " - "If the given path is relative, it is take w.r.t. to the current working directory.\n\n" - ".. note:: The functions :py:meth:`has_dataset` and :py:meth:`has_key` are synonyms. " - "You can also use the Python's ``in`` operator instead of :py:meth:`has_key`: ``key in hdf5file``.", - true -) -.add_prototype("key") -.add_parameter("key", "str", "The dataset path to check") -; -auto s_has_key = s_has_dataset.clone("has_key"); -static PyObject* PyBobIoHDF5File_hasDataset(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) { -BOB_TRY - /* Parses input arguments in a single shot */ - static char** kwlist = s_has_dataset.kwlist(); - - const char* key = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &key)) return 0; - - if (self->f->contains(key)) Py_RETURN_TRUE; - - Py_RETURN_FALSE; -BOB_CATCH_MEMBER(exception_message(self, s_has_dataset.name()).c_str(), 0) -} - -static bob::io::base::hdf5type PyBobIo_H5FromTypenum (int type_num) { - - switch(type_num) { - case NPY_STRING: return bob::io::base::s; - case NPY_BOOL: return bob::io::base::b; - case NPY_INT8: return bob::io::base::i8; - case NPY_INT16: return bob::io::base::i16; - case NPY_INT32: return bob::io::base::i32; - case NPY_INT64: return bob::io::base::i64; - case NPY_UINT8: return bob::io::base::u8; - case NPY_UINT16: return bob::io::base::u16; - case NPY_UINT32: return bob::io::base::u32; - case NPY_UINT64: return bob::io::base::u64; - case NPY_FLOAT32: return bob::io::base::f32; - case NPY_FLOAT64: return bob::io::base::f64; -#ifdef NPY_FLOAT128 - case NPY_FLOAT128: return bob::io::base::f128; -#endif - case NPY_COMPLEX64: return bob::io::base::c64; - case NPY_COMPLEX128: return bob::io::base::c128; -#ifdef NPY_COMPLEX256 - case NPY_COMPLEX256: return bob::io::base::c256; -#endif -#if defined(__LP64__) || defined(__APPLE__) - case NPY_LONGLONG: - switch (NPY_BITSOF_LONGLONG) { - case 8: return bob::io::base::i8; - case 16: return bob::io::base::i16; - case 32: return bob::io::base::i32; - case 64: return bob::io::base::i64; - default: return bob::io::base::unsupported; - } - break; - case NPY_ULONGLONG: - switch (NPY_BITSOF_LONGLONG) { - case 8: return bob::io::base::u8; - case 16: return bob::io::base::u16; - case 32: return bob::io::base::u32; - case 64: return bob::io::base::u64; - default: return bob::io::base::unsupported; - } - break; -#endif - default: return bob::io::base::unsupported; - } - -} - -static int PyBobIo_H5AsTypenum (bob::io::base::hdf5type type) { - - switch(type) { - case bob::io::base::s: return NPY_STRING; - case bob::io::base::b: return NPY_BOOL; - case bob::io::base::i8: return NPY_INT8; - case bob::io::base::i16: return NPY_INT16; - case bob::io::base::i32: return NPY_INT32; - case bob::io::base::i64: return NPY_INT64; - case bob::io::base::u8: return NPY_UINT8; - case bob::io::base::u16: return NPY_UINT16; - case bob::io::base::u32: return NPY_UINT32; - case bob::io::base::u64: return NPY_UINT64; - case bob::io::base::f32: return NPY_FLOAT32; - case bob::io::base::f64: return NPY_FLOAT64; -#ifdef NPY_FLOAT128 - case bob::io::base::f128: return NPY_FLOAT128; -#endif - case bob::io::base::c64: return NPY_COMPLEX64; - case bob::io::base::c128: return NPY_COMPLEX128; -#ifdef NPY_COMPLEX256 - case bob::io::base::c256: return NPY_COMPLEX256; -#endif - default: return NPY_NOTYPE; - } - -} - -static PyObject* PyBobIo_HDF5TypeAsTuple (const bob::io::base::HDF5Type& t) { - - const bob::io::base::HDF5Shape& sh = t.shape(); - size_t ndim = sh.n(); - const hsize_t* shptr = sh.get(); - - int type_num = PyBobIo_H5AsTypenum(t.type()); - if (type_num == NPY_NOTYPE) { - PyErr_Format(PyExc_TypeError, "unsupported HDF5 element type (%d) found during conversion to numpy type number", (int)t.type()); - return 0; - } - - PyObject* dtype = reinterpret_cast<PyObject*>(PyArray_DescrFromType(type_num)); - if (!dtype) return 0; - auto dtype_ = make_safe(dtype); - - PyObject* shape = PyTuple_New(ndim); - if (!shape) return 0; - auto shape_ = make_safe(shape); - - PyObject* retval = Py_BuildValue("OO", dtype, shape); - if (!retval) return 0; - auto retval_ = make_safe(retval); - - for (Py_ssize_t i=0; i<(Py_ssize_t)ndim; ++i) { - PyObject* value = Py_BuildValue("n", shptr[i]); - if (!value) return 0; - PyTuple_SET_ITEM(shape, i, value); - } - - return Py_BuildValue("O", retval); - -} - -static PyObject* PyBobIo_HDF5DescriptorAsTuple (const bob::io::base::HDF5Descriptor& d) { - return Py_BuildValue("NnO", - PyBobIo_HDF5TypeAsTuple(d.type), - d.size, - d.expandable? Py_True : Py_False - ); //steals references, except for True/False -} - - -static auto s_describe = bob::extension::FunctionDoc( - "describe", - "Describes a dataset type/shape, if it exists inside a file", - "If a given ``key`` to an HDF5 dataset exists inside the file, returns a type description of objects recorded in such a dataset, otherwise, raises an exception. " - "The returned value type is a list of tuples (HDF5Type, number-of-objects, expandable) describing the capabilities if the file is read using these formats. \n\n", - true -) -.add_prototype("key", "[(hdf5type, size, expandable)]") -.add_parameter("key", "str", "The dataset path to describe") -.add_return("hdf5type", "tuple", "The HDF5Type of the returned array") -.add_return("size", "int", "The number of objects in the dataset") -.add_return("expandable", "bool", "Defines if this object can be resized.") -; -static PyObject* PyBobIoHDF5File_describe(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) { -BOB_TRY - /* Parses input arguments in a single shot */ - static char** kwlist = s_describe.kwlist(); - - const char* key = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &key)) return 0; - - const std::vector<bob::io::base::HDF5Descriptor>& dv = self->f->describe(key); - PyObject* retval = PyList_New(dv.size()); - if (!retval) return 0; - auto retval_ = make_safe(retval); - - for (size_t k=0; k<dv.size(); ++k) { - PyObject* entry = PyBobIo_HDF5DescriptorAsTuple(dv[k]); - if (!entry) return 0; - PyList_SET_ITEM(retval, k, entry); - } - - return Py_BuildValue("O", retval); -BOB_CATCH_MEMBER(exception_message(self, s_describe.name()).c_str(), 0) -} - - -static auto s_unlink = bob::extension::FunctionDoc( - "unlink", - "Unlinks datasets inside the file making them invisible", - "If a given path to an HDF5 dataset exists inside the file, unlinks it." - "Please note this will note remove the data from the file, just make it inaccessible. " - "If you wish to cleanup, save the reacheable objects from this file to another :py:class:`HDF5File` object using :py:meth:`copy`, for example.", - true -) -.add_prototype("key") -.add_parameter("key", "str", "The dataset path to unlink") -; -static PyObject* PyBobIoHDF5File_unlink(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) { -BOB_TRY - /* Parses input arguments in a single shot */ - static char** kwlist = s_unlink.kwlist(); - - const char* key = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &key)) return 0; - - self->f->unlink(key); - - Py_RETURN_NONE; -BOB_CATCH_MEMBER(exception_message(self, s_unlink.name()).c_str(), 0) -} - - -static auto s_rename = bob::extension::FunctionDoc( - "rename", - "Renames datasets in a file", - 0, - true -) -.add_prototype("from, to") -.add_parameter("from", "str", "The path to the data to be renamed") -.add_parameter("to", "str", "The new name of the dataset") -; -static PyObject* PyBobIoHDF5File_rename(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) { -BOB_TRY - /* Parses input arguments in a single shot */ - static char** kwlist = s_rename.kwlist(); - - const char* from = 0; - const char* to = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "ss", kwlist, &from, &to)) return 0; - - self->f->rename(from, to); - - Py_RETURN_NONE; -BOB_CATCH_MEMBER(exception_message(self, s_rename.name()).c_str(), 0) -} - - -static auto s_paths = bob::extension::FunctionDoc( - "paths", - "Lists datasets available inside this file", - "Returns all paths to datasets available inside this file, stored under the current working directory. " - "If ``relative`` is set to ``True``, the returned paths are relative to the current working directory, otherwise they are absolute.\n\n" - ".. note:: The functions :py:meth:`keys` and :py:meth:`paths` are synonyms.", - true -) -.add_prototype("[relative]", "paths") -.add_parameter("relative", "bool", "[Default: ``False``] If set to ``True``, the returned paths are relative to the current working directory, otherwise they are absolute") -.add_return("paths", "[str]", "A list of paths inside this file") -; -auto s_keys = s_paths.clone("keys"); -static PyObject* PyBobIoHDF5File_paths(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) { -BOB_TRY - /* Parses input arguments in a single shot */ - static char** kwlist = s_paths.kwlist(); - - PyObject* pyrel = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O", kwlist, &pyrel)) return 0; - - bool relative = false; - if (pyrel && PyObject_IsTrue(pyrel)) relative = true; - - std::vector<std::string> values; - self->f->paths(values, relative); - PyObject* retval = PyList_New(values.size()); - if (!retval) return 0; - auto retval_ = make_safe(retval); - for (size_t i=0; i<values.size(); ++i) { - PyList_SET_ITEM(retval, i, Py_BuildValue("s", values[i].c_str())); - } - - return Py_BuildValue("O", retval); -BOB_CATCH_MEMBER(exception_message(self, s_paths.name()).c_str(), 0) -} - - -static auto s_sub_groups = bob::extension::FunctionDoc( - "sub_groups", - "Lists groups (directories) in the current file", - 0, - true -) -.add_prototype("[relative], [recursive]", "groups") -.add_parameter("relative", "bool", "[Default: ``False``] If set to ``True``, the returned sub-groups are relative to the current working directory, otherwise they are absolute") -.add_parameter("recursive", "bool", "[Default: ``True``] If set to ``False``, the returned sub-groups are only the ones in the current directory, otherwise recurses down the directory structure") -.add_return("groups", "[str]", "The list of directories (groups) inside this file") -; -static PyObject* PyBobIoHDF5File_subGroups(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) { -BOB_TRY - /* Parses input arguments in a single shot */ - static char** kwlist = s_sub_groups.kwlist(); - - PyObject* pyrel = 0; - PyObject* pyrec = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|OO", kwlist, &pyrel, &pyrec)) return 0; - - bool relative = (pyrel && PyObject_IsTrue(pyrel)); - bool recursive = (!pyrec || PyObject_IsTrue(pyrec)); - - std::vector<std::string> values; - self->f->sub_groups(values, relative, recursive); - PyObject* retval = PyList_New(values.size()); - if (!retval) return 0; - auto retval_ = make_safe(retval); - for (size_t i=0; i<values.size(); ++i) { - PyList_SET_ITEM(retval, i, Py_BuildValue("s", values[i].c_str())); - } - - return Py_BuildValue("O", retval); -BOB_CATCH_MEMBER(exception_message(self, s_sub_groups.name()).c_str(), 0) -} - - -static PyObject* PyBobIoHDF5File_Xread(PyBobIoHDF5FileObject* self, const char* p, int descriptor, int pos) { - - const std::vector<bob::io::base::HDF5Descriptor> D = self->f->describe(p); - - //last descriptor always contains the full readout. - const bob::io::base::HDF5Type& type = D[descriptor].type; - const bob::io::base::HDF5Shape& shape = type.shape(); - - if (shape.n() == 1 && shape[0] == 1) { //read as scalar - switch(type.type()) { - case bob::io::base::s: - return Py_BuildValue("s", self->f->read<std::string>(p, pos).c_str()); - case bob::io::base::b: - return PyBlitzArrayCxx_FromCScalar(self->f->read<bool>(p, pos)); - case bob::io::base::i8: - return PyBlitzArrayCxx_FromCScalar(self->f->read<int8_t>(p, pos)); - case bob::io::base::i16: - return PyBlitzArrayCxx_FromCScalar(self->f->read<int16_t>(p, pos)); - case bob::io::base::i32: - return PyBlitzArrayCxx_FromCScalar(self->f->read<int32_t>(p, pos)); - case bob::io::base::i64: - return PyBlitzArrayCxx_FromCScalar(self->f->read<int64_t>(p, pos)); - case bob::io::base::u8: - return PyBlitzArrayCxx_FromCScalar(self->f->read<uint8_t>(p, pos)); - case bob::io::base::u16: - return PyBlitzArrayCxx_FromCScalar(self->f->read<uint16_t>(p, pos)); - case bob::io::base::u32: - return PyBlitzArrayCxx_FromCScalar(self->f->read<uint32_t>(p, pos)); - case bob::io::base::u64: - return PyBlitzArrayCxx_FromCScalar(self->f->read<uint64_t>(p, pos)); - case bob::io::base::f32: - return PyBlitzArrayCxx_FromCScalar(self->f->read<float>(p, pos)); - case bob::io::base::f64: - return PyBlitzArrayCxx_FromCScalar(self->f->read<double>(p, pos)); - case bob::io::base::f128: - return PyBlitzArrayCxx_FromCScalar(self->f->read<long double>(p, pos)); - case bob::io::base::c64: - return PyBlitzArrayCxx_FromCScalar(self->f->read<std::complex<float> >(p, pos)); - case bob::io::base::c128: - return PyBlitzArrayCxx_FromCScalar(self->f->read<std::complex<double> >(p, pos)); - case bob::io::base::c256: - return PyBlitzArrayCxx_FromCScalar(self->f->read<std::complex<long double> >(p, pos)); - default: - PyErr_Format(PyExc_TypeError, "unsupported HDF5 type: %s", type.str().c_str()); - return 0; - } - } - - //read as an numpy array - int type_num = PyBobIo_H5AsTypenum(type.type()); - if (type_num == NPY_NOTYPE) return 0; ///< failure - - npy_intp pyshape[NPY_MAXDIMS]; - for (size_t k=0; k<shape.n(); ++k) pyshape[k] = shape.get()[k]; - - PyObject* retval = PyArray_SimpleNew(shape.n(), pyshape, type_num); - if (!retval) return 0; - auto retval_ = make_safe(retval); - - self->f->read_buffer(p, pos, type, PyArray_DATA((PyArrayObject*)retval)); - - return Py_BuildValue("O", retval); -} - - -static auto s_read = bob::extension::FunctionDoc( - "read", - "Reads whole datasets from the file", - "This function reads full data sets from this file. " - "The data type is dependent on the stored data, but is generally a :py:class:`numpy.ndarray`.\n\n" - ".. note:: The functions :py:func:`read` and :py:func:`get` are synonyms." -) -.add_prototype("key", "data") -.add_parameter("key", "str", "The path to the dataset to read data from; can be an absolute value (starting with a leading ``'/'``) or relative to the current working directory :py:attr:`cwd`") -.add_return("data", ":py:class:`numpy.ndarray` or other", "The data read from this file at the given key") -; -auto s_get = s_read.clone("get"); -static PyObject* PyBobIoHDF5File_read(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) { -BOB_TRY - - /* Parses input arguments in a single shot */ - static char** kwlist = s_read.kwlist(); - - const char* key = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &key)) return 0; - - return PyBobIoHDF5File_Xread(self, key, 1, 0); -BOB_CATCH_MEMBER(exception_message(self, s_read.name()).c_str(), 0) -} - - -static auto s_lread = bob::extension::FunctionDoc( - "lread", - "Reads some contents of the dataset", - "This method reads contents from a dataset, treating the N-dimensional dataset like a container for multiple objects with N-1 dimensions. " - "It returns a single :py:class:`numpy.ndarray` in case ``pos`` is set to a value >= 0, or a list of arrays otherwise." -) -.add_prototype("key, [pos]", "data") -.add_parameter("key", "str", "The path to the dataset to read data from, can be an absolute value (starting with a leading ``'/'``) or relative to the current working directory :py:attr:`cwd`") -.add_parameter("pos", "int", "If given and >= 0 returns the data object with the given index, otherwise returns a list by reading all objects in sequence") -.add_return("data", ":py:class:`numpy.ndarray` or [:py:class:`numpy.ndarray`]", "The data read from this file") -; -static PyObject* PyBobIoHDF5File_listRead(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) { -BOB_TRY - /* Parses input arguments in a single shot */ - static char** kwlist = s_lread.kwlist(); - - const char* key = 0; - Py_ssize_t pos = -1; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|n", kwlist, &key, &pos)) return 0; - - if (pos >= 0) return PyBobIoHDF5File_Xread(self, key, 0, pos); - - //otherwise returns as a list - const std::vector<bob::io::base::HDF5Descriptor>& D = self->f->describe(key); - - PyObject* retval = PyList_New(D[0].size); - if (!retval) return 0; - auto retval_ = make_safe(retval); - - for (uint64_t k=0; k<D[0].size; ++k) { - PyObject* item = PyBobIoHDF5File_Xread(self, key, 0, k); - if (!item) return 0; - PyList_SET_ITEM(retval, k, item); - } - - return Py_BuildValue("O", retval); -BOB_CATCH_MEMBER(exception_message(self, s_lread.name()).c_str(), 0) -} - - -/** - * Sets at 't', the type of the object 'o' according to our support types. - * Raise in case of problems. Furthermore, returns 'true' if the object is as - * simple scalar. - */ - -static void null_char_array_deleter(char*) {} - -#if PY_VERSION_HEX >= 0x03000000 -static void char_array_deleter(char* o) { delete[] o; } -#endif - -static boost::shared_ptr<char> PyBobIo_GetString(PyObject* o) { - -#if PY_VERSION_HEX < 0x03000000 - - return boost::shared_ptr<char>(PyString_AsString(o), null_char_array_deleter); - -#else - - if (PyBytes_Check(o)) { - //fast way out - return boost::shared_ptr<char>(PyBytes_AsString(o), null_char_array_deleter); - } - - PyObject* bytes = 0; - - if (PyUnicode_Check(o)) { - //re-encode using utf-8 - bytes = PyUnicode_AsEncodedString(o, "utf-8", "strict"); - } - else { - //tries coercion - bytes = PyObject_Bytes(o); - } - auto bytes_ = make_safe(bytes); ///< protects acquired resource - - Py_ssize_t length = PyBytes_GET_SIZE(bytes)+1; - char* copy = new char[length]; - std::strncpy(copy, PyBytes_AsString(bytes), length); - - return boost::shared_ptr<char>(copy, char_array_deleter); - -#endif - -} - -static int PyBobIoHDF5File_setStringType(bob::io::base::HDF5Type& t, PyObject* o) { - auto value = PyBobIo_GetString(o); - if (!value) return -1; - t = bob::io::base::HDF5Type(value.get()); - return 0; -} - -template <typename T> int PyBobIoHDF5File_setType(bob::io::base::HDF5Type& t) { - T v; - t = bob::io::base::HDF5Type(v); - return 0; -} - -/** - * A function to check for python scalars that works with numpy-1.6.x - */ -static bool PyBobIoHDF5File_isPythonScalar(PyObject* obj) { - return ( - PyBool_Check(obj) || -#if PY_VERSION_HEX < 0x03000000 - PyString_Check(obj) || -#else - PyBytes_Check(obj) || -#endif - PyUnicode_Check(obj) || -#if PY_VERSION_HEX < 0x03000000 - PyInt_Check(obj) || -#endif - PyLong_Check(obj) || - PyFloat_Check(obj) || - PyComplex_Check(obj) - ); -} - -/** - * Returns the type of object `op' is - a scalar (return value = 0), a - * bob.blitz.array (return value = 1), a numpy.ndarray (return value = 2), an - * object which is convertible to a numpy.ndarray (return value = 3) or returns - * -1 if the object cannot be converted. No error is set on the python stack. - * - * If the object is convertible into a numpy.ndarray, then it is converted into - * a numpy ndarray and the resulting object is placed in `converted'. If - * `*converted' is set to 0 (NULL), then we don't try a conversion, returning - * -1. - */ -static int PyBobIoHDF5File_getObjectType(PyObject* o, bob::io::base::HDF5Type& t, - PyObject** converted=0) { - - if (PyArray_IsScalar(o, Generic) || PyBobIoHDF5File_isPythonScalar(o)) { - - if (PyArray_IsScalar(o, String)) - return PyBobIoHDF5File_setStringType(t, o); - - else if (PyBool_Check(o)) - return PyBobIoHDF5File_setType<bool>(t); - -#if PY_VERSION_HEX < 0x03000000 - else if (PyString_Check(o)) - return PyBobIoHDF5File_setStringType(t, o); - -#else - else if (PyBytes_Check(o)) - return PyBobIoHDF5File_setStringType(t, o); - -#endif - else if (PyUnicode_Check(o)) - return PyBobIoHDF5File_setStringType(t, o); - -#if PY_VERSION_HEX < 0x03000000 - else if (PyInt_Check(o)) - return PyBobIoHDF5File_setType<int32_t>(t); - -#endif - else if (PyLong_Check(o)) - return PyBobIoHDF5File_setType<int64_t>(t); - - else if (PyFloat_Check(o)) - return PyBobIoHDF5File_setType<double>(t); - - else if (PyComplex_Check(o)) - return PyBobIoHDF5File_setType<std::complex<double> >(t); - - else if (PyArray_IsScalar(o, Bool)) - return PyBobIoHDF5File_setType<bool>(t); - - else if (PyArray_IsScalar(o, Int8)) - return PyBobIoHDF5File_setType<int8_t>(t); - - else if (PyArray_IsScalar(o, UInt8)) - return PyBobIoHDF5File_setType<uint8_t>(t); - - else if (PyArray_IsScalar(o, Int16)) - return PyBobIoHDF5File_setType<int16_t>(t); - - else if (PyArray_IsScalar(o, UInt16)) - return PyBobIoHDF5File_setType<uint16_t>(t); - - else if (PyArray_IsScalar(o, Int32)) - return PyBobIoHDF5File_setType<int32_t>(t); - - else if (PyArray_IsScalar(o, UInt32)) - return PyBobIoHDF5File_setType<uint32_t>(t); - - else if (PyArray_IsScalar(o, Int64)) - return PyBobIoHDF5File_setType<int64_t>(t); - - else if (PyArray_IsScalar(o, UInt64)) - return PyBobIoHDF5File_setType<uint64_t>(t); - - else if (PyArray_IsScalar(o, Float)) - return PyBobIoHDF5File_setType<float>(t); - - else if (PyArray_IsScalar(o, Double)) - return PyBobIoHDF5File_setType<double>(t); - - else if (PyArray_IsScalar(o, LongDouble)) - return PyBobIoHDF5File_setType<long double>(t); - - else if (PyArray_IsScalar(o, CFloat)) - return PyBobIoHDF5File_setType<std::complex<float> >(t); - - else if (PyArray_IsScalar(o, CDouble)) - return PyBobIoHDF5File_setType<std::complex<double> >(t); - - else if (PyArray_IsScalar(o, CLongDouble)) - return PyBobIoHDF5File_setType<std::complex<long double> >(t); - - //if you get to this, point, it is an unsupported scalar - return -1; - - } - - else if (PyBlitzArray_Check(o)) { - - PyBlitzArrayObject* bz = reinterpret_cast<PyBlitzArrayObject*>(o); - bob::io::base::hdf5type h5type = PyBobIo_H5FromTypenum(bz->type_num); - if (h5type == bob::io::base::unsupported) return -1; - bob::io::base::HDF5Shape h5shape(bz->ndim, bz->shape); - t = bob::io::base::HDF5Type(h5type, h5shape); - return 1; - - } - - else if (PyArray_CheckExact(o) && PyArray_ISCARRAY_RO((PyArrayObject*)o)) { - - PyArrayObject* np = reinterpret_cast<PyArrayObject*>(o); - bob::io::base::hdf5type h5type = PyBobIo_H5FromTypenum(PyArray_DESCR(np)->type_num); - if (h5type == bob::io::base::unsupported) return -1; - bob::io::base::HDF5Shape h5shape(PyArray_NDIM(np), PyArray_DIMS(np)); - t = bob::io::base::HDF5Type(h5type, h5shape); - return 2; - - } - - else if (converted) { - - *converted = PyArray_FromAny(o, 0, 1, 0, -#if NPY_FEATURE_VERSION >= NUMPY17_API /* NumPy C-API version >= 1.7 */ - NPY_ARRAY_CARRAY_RO, -# else - NPY_CARRAY_RO, -# endif - 0); - if (!*converted) return -1; ///< error condition - - PyArrayObject* np = reinterpret_cast<PyArrayObject*>(*converted); - bob::io::base::hdf5type h5type = PyBobIo_H5FromTypenum(PyArray_DESCR(np)->type_num); - if (h5type == bob::io::base::unsupported) { - Py_CLEAR(*converted); - return -1; - } - bob::io::base::HDF5Shape h5shape(PyArray_NDIM(np), PyArray_DIMS(np)); - t = bob::io::base::HDF5Type(h5type, h5shape); - return 3; - - } - - //if you get to this, point, it is an unsupported type - return -1; - -} - -template <typename T> -static PyObject* PyBobIoHDF5File_replaceScalar(PyBobIoHDF5FileObject* self, - const char* path, Py_ssize_t pos, PyObject* o) { - - T value = PyBlitzArrayCxx_AsCScalar<T>(o); - if (PyErr_Occurred()) return 0; - self->f->replace(path, pos, value); - - Py_RETURN_NONE; - -} - - -static auto s_replace = bob::extension::FunctionDoc( - "replace", - "Modifies the value of a scalar/array in a dataset.", - 0, - true -) -.add_prototype("path, pos, data") -.add_parameter("path", "str", "The path to the dataset to read data from; can be an absolute value (starting with a leading ``'/'``) or relative to the current working directory :py:attr:`cwd`") -.add_parameter("pos", "int", "Position, within the dataset, of the object to be replaced; the object position on the dataset must exist, or an exception is raised") -.add_parameter("data", ":py:class:`numpy.ndarray` or scalar", "Object to replace the value with; this value must be compatible with the typing information on the dataset, or an exception will be raised") -; -static PyObject* PyBobIoHDF5File_replace(PyBobIoHDF5FileObject* self, PyObject* args, PyObject* kwds) { -BOB_TRY - /* Parses input arguments in a single shot */ - static char** kwlist = s_replace.kwlist(); - - const char* path = 0; - Py_ssize_t pos = -1; - PyObject* data = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "snO", kwlist, &path, &pos, &data)) return 0; - - bob::io::base::HDF5Type type; - PyObject* converted = 0; - int is_array = PyBobIoHDF5File_getObjectType(data, type, &converted); - auto converted_ = make_xsafe(converted); - - if (is_array < 0) { ///< error condition, signal - const char* filename = "<unknown>"; - try{ filename = self->f->filename().c_str(); } catch(...){} - PyErr_Format(PyExc_TypeError, "error replacing position %" PY_FORMAT_SIZE_T "d of dataset `%s' at HDF5 file `%s': no support for storing objects of type `%s' on HDF5 files", pos, path, filename, Py_TYPE(data)->tp_name); - return 0; - } - - if (!is_array) { //write as a scalar - - switch(type.type()) { - case bob::io::base::s: - { - auto value = PyBobIo_GetString(data); - if (!value) return 0; - self->f->replace<std::string>(path, pos, value.get()); - Py_RETURN_NONE; - } - case bob::io::base::b: - return PyBobIoHDF5File_replaceScalar<bool>(self, path, pos, data); - case bob::io::base::i8: - return PyBobIoHDF5File_replaceScalar<int8_t>(self, path, pos, data); - case bob::io::base::i16: - return PyBobIoHDF5File_replaceScalar<int16_t>(self, path, pos, data); - case bob::io::base::i32: - return PyBobIoHDF5File_replaceScalar<int32_t>(self, path, pos, data); - case bob::io::base::i64: - return PyBobIoHDF5File_replaceScalar<int64_t>(self, path, pos, data); - case bob::io::base::u8: - return PyBobIoHDF5File_replaceScalar<uint8_t>(self, path, pos, data); - case bob::io::base::u16: - return PyBobIoHDF5File_replaceScalar<uint16_t>(self, path, pos, data); - case bob::io::base::u32: - return PyBobIoHDF5File_replaceScalar<uint32_t>(self, path, pos, data); - case bob::io::base::u64: - return PyBobIoHDF5File_replaceScalar<uint64_t>(self, path, pos, data); - case bob::io::base::f32: - return PyBobIoHDF5File_replaceScalar<float>(self, path, pos, data); - case bob::io::base::f64: - return PyBobIoHDF5File_replaceScalar<double>(self, path, pos, data); - case bob::io::base::f128: - return PyBobIoHDF5File_replaceScalar<long double>(self, path, pos, data); - case bob::io::base::c64: - return PyBobIoHDF5File_replaceScalar<std::complex<float> >(self, path, pos, data); - case bob::io::base::c128: - return PyBobIoHDF5File_replaceScalar<std::complex<double> >(self, path, pos, data); - case bob::io::base::c256: - return PyBobIoHDF5File_replaceScalar<std::complex<long double> >(self, path, pos, data); - default: - break; - } - - } - - else { //write as array - - switch (is_array) { - case 1: //bob.blitz.array - self->f->write_buffer(path, pos, type, ((PyBlitzArrayObject*)data)->data); - break; - - case 2: //numpy.ndarray - self->f->write_buffer(path, pos, type, PyArray_DATA((PyArrayObject*)data)); - break; - - case 3: //converted numpy.ndarray - self->f->write_buffer(path, pos, type, PyArray_DATA((PyArrayObject*)converted)); - break; - - default: - const char* filename = "<unknown>"; - try{ filename = self->f->filename().c_str(); } catch(...){} - PyErr_Format(PyExc_NotImplementedError, "error replacing position %" PY_FORMAT_SIZE_T "d of dataset `%s' at HDF5 file `%s': HDF5 replace function is uncovered for array type %d (DEBUG ME)", pos, path, filename, is_array); - return 0; - } - - } - - Py_RETURN_NONE; -BOB_CATCH_MEMBER(exception_message(self, s_replace.name()).c_str(), 0) -} - - -template <typename T> -static int PyBobIoHDF5File_appendScalar(PyBobIoHDF5FileObject* self, - const char* path, PyObject* o) { - - T value = PyBlitzArrayCxx_AsCScalar<T>(o); - if (PyErr_Occurred()) return 0; - self->f->append(path, value); - - return 1; - -} - -static int PyBobIoHDF5File_innerAppend(PyBobIoHDF5FileObject* self, const char* path, PyObject* data, Py_ssize_t compression) { - - bob::io::base::HDF5Type type; - PyObject* converted = 0; - int is_array = PyBobIoHDF5File_getObjectType(data, type, &converted); - auto converted_ = make_xsafe(converted); - - if (is_array < 0) { ///< error condition, signal - const char* filename = "<unknown>"; - try{ filename = self->f->filename().c_str(); } catch(...){} - PyErr_Format(PyExc_TypeError, "error appending to object `%s' of HDF5 file `%s': no support for storing objects of type `%s' on HDF5 files", path, filename, Py_TYPE(data)->tp_name); - return 0; - } - - try { - - if (!is_array) { //write as a scalar - - switch(type.type()) { - case bob::io::base::s: - { - auto value = PyBobIo_GetString(data); - if (!value) return 0; - self->f->append<std::string>(path, value.get()); - return 1; - } - case bob::io::base::b: - return PyBobIoHDF5File_appendScalar<bool>(self, path, data); - case bob::io::base::i8: - return PyBobIoHDF5File_appendScalar<int8_t>(self, path, data); - case bob::io::base::i16: - return PyBobIoHDF5File_appendScalar<int16_t>(self, path, data); - case bob::io::base::i32: - return PyBobIoHDF5File_appendScalar<int32_t>(self, path, data); - case bob::io::base::i64: - return PyBobIoHDF5File_appendScalar<int64_t>(self, path, data); - case bob::io::base::u8: - return PyBobIoHDF5File_appendScalar<uint8_t>(self, path, data); - case bob::io::base::u16: - return PyBobIoHDF5File_appendScalar<uint16_t>(self, path, data); - case bob::io::base::u32: - return PyBobIoHDF5File_appendScalar<uint32_t>(self, path, data); - case bob::io::base::u64: - return PyBobIoHDF5File_appendScalar<uint64_t>(self, path, data); - case bob::io::base::f32: - return PyBobIoHDF5File_appendScalar<float>(self, path, data); - case bob::io::base::f64: - return PyBobIoHDF5File_appendScalar<double>(self, path, data); - case bob::io::base::f128: - return PyBobIoHDF5File_appendScalar<long double>(self, path, data); - case bob::io::base::c64: - return PyBobIoHDF5File_appendScalar<std::complex<float> >(self, path, data); - case bob::io::base::c128: - return PyBobIoHDF5File_appendScalar<std::complex<double> >(self, path, data); - case bob::io::base::c256: - return PyBobIoHDF5File_appendScalar<std::complex<long double> >(self, path, data); - default: - break; - } - - } - - else { //write as array - - switch (is_array) { - case 1: //bob.blitz.array - if (!self->f->contains(path)) self->f->create(path, type, true, compression); - self->f->extend_buffer(path, type, ((PyBlitzArrayObject*)data)->data); - break; - - case 2: //numpy.ndarray - if (!self->f->contains(path)) self->f->create(path, type, true, compression); - self->f->extend_buffer(path, type, PyArray_DATA((PyArrayObject*)data)); - break; - - case 3: //converted numpy.ndarray - if (!self->f->contains(path)) self->f->create(path, type, true, compression); - self->f->extend_buffer(path, type, PyArray_DATA((PyArrayObject*)converted)); - break; - - default:{ - const char* filename = "<unknown>"; - try{ filename = self->f->filename().c_str(); } catch(...){} - PyErr_Format(PyExc_NotImplementedError, "error appending to object `%s' at HDF5 file `%s': HDF5 replace function is uncovered for array type %d (DEBUG ME)", path, filename, is_array); - return 0; - } - } - - } - - } - catch (std::exception& e) { - PyErr_SetString(PyExc_RuntimeError, e.what()); - return 0; - } - catch (...) { - const char* filename = "<unknown>"; - try{ filename = self->f->filename().c_str(); } catch(...){} - PyErr_Format(PyExc_RuntimeError, "cannot append to object `%s' at HDF5 file `%s': unknown exception caught", path, filename); - return 0; - } - - return 1; - -} - - -static auto s_append = bob::extension::FunctionDoc( - "append", - "Appends a scalar or an array to a dataset", - "The object must be compatible with the typing information on the dataset, or an exception will be raised. " - "You can also, optionally, set this to an iterable of scalars or arrays. " - "This will cause this method to iterate over the elements and add each individually.\n\n" - "The ``compression`` parameter is effective when appending arrays. " - "Set this to a number betwen 0 (default) and 9 (maximum) to compress the contents of this dataset. " - "This setting is only effective if the dataset does not yet exist, otherwise, the previous setting is respected.", - true -) -.add_prototype("path, data, [compression]") -.add_parameter("path", "str", "The path to the dataset to append data at; can be an absolute value (starting with a leading ``'/'``) or relative to the current working directory :py:attr:`cwd`") -.add_parameter("data", ":py:class:`numpy.ndarray` or scalar", "Object to append to the dataset") -.add_parameter("compression", "int", "A compression value between 0 and 9") -; -static PyObject* PyBobIoHDF5File_append(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) { -BOB_TRY - /* Parses input arguments in a single shot */ - static char** kwlist = s_append.kwlist(); - - char* path = 0; - PyObject* data = 0; - Py_ssize_t compression = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "sO|n", kwlist, &path, &data, &compression)) return 0; - - if (compression < 0 || compression > 9) { - PyErr_SetString(PyExc_ValueError, "compression should be set to an integer value between and including 0 and 9"); - return 0; - } - - // special case: user passes a tuple or list of arrays or scalars to append - if (PyTuple_Check(data) || PyList_Check(data)) { - PyObject* iter = PyObject_GetIter(data); - if (!iter) return 0; - auto iter_ = make_safe(iter); - while (PyObject* item = PyIter_Next(iter)) { - auto item_ = make_safe(item); - int ok = PyBobIoHDF5File_innerAppend(self, path, item, compression); - if (!ok) return 0; - } - Py_RETURN_NONE; - } - - int ok = PyBobIoHDF5File_innerAppend(self, path, data, compression); - if (!ok) return 0; - Py_RETURN_NONE; -BOB_CATCH_MEMBER(exception_message(self, s_append.name()).c_str(), 0) -} - - -template <typename T> -static PyObject* PyBobIoHDF5File_setScalar(PyBobIoHDF5FileObject* self, - const char* path, PyObject* o) { - - T value = PyBlitzArrayCxx_AsCScalar<T>(o); - if (PyErr_Occurred()) return 0; - self->f->set(path, value); - - Py_RETURN_NONE; - -} - - -static auto s_set = bob::extension::FunctionDoc( - "set", - "Sets the scalar or array at position 0 to the given value", - "This method is equivalent to checking if the scalar or array at position 0 exists and then replacing it. " - "If the path does not exist, we append the new scalar or array.\n\n" - "The ``data`` must be compatible with the typing information on the dataset, or an exception will be raised. " - "You can also, optionally, set this to an iterable of scalars or arrays. " - "This will cause this method to iterate over the elements and add each individually.\n\n" - "The ``compression`` parameter is effective when writing arrays. " - "Set this to a number betwen 0 (default) and 9 (maximum) to compress the contents of this dataset. " - "This setting is only effective if the dataset does not yet exist, otherwise, the previous setting is respected.\n\n" - ".. note:: The functions :py:meth:`set` and :py:meth:`write` are synonyms.", - true -) -.add_prototype("path, data, [compression]") -.add_parameter("path", "str", "The path to the dataset to write data to; can be an absolute value (starting with a leading ``'/'``) or relative to the current working directory :py:attr:`cwd`") -.add_parameter("data", ":py:class:`numpy.ndarray` or scalar", "Object to write to the dataset") -.add_parameter("compression", "int", "A compression value between 0 and 9") -; -auto s_write = s_set.clone("write"); -static PyObject* PyBobIoHDF5File_set(PyBobIoHDF5FileObject* self, PyObject* args, PyObject* kwds) { -BOB_TRY - /* Parses input arguments in a single shot */ - static const char* const_kwlist[] = {"path", "data", "compression", 0}; - static char** kwlist = const_cast<char**>(const_kwlist); - - char* path = 0; - PyObject* data = 0; - Py_ssize_t compression = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "sO|n", kwlist, &path, &data, &compression)) return 0; - - if (compression < 0 || compression > 9) { - PyErr_SetString(PyExc_ValueError, "compression should be set to an integer value between and including 0 and 9"); - return 0; - } - - bob::io::base::HDF5Type type; - PyObject* converted = 0; - int is_array = PyBobIoHDF5File_getObjectType(data, type, &converted); - auto converted_ = make_xsafe(converted); - - if (is_array < 0) { ///< error condition, signal - const char* filename = "<unknown>"; - try{ filename = self->f->filename().c_str(); } catch(...){} - PyErr_Format(PyExc_TypeError, "error setting object `%s' of HDF5 file `%s': no support for storing objects of type `%s' on HDF5 files", path, filename, Py_TYPE(data)->tp_name); - return 0; - } - - if (!is_array) { //write as a scalar - - switch(type.type()) { - case bob::io::base::s: - { - auto value = PyBobIo_GetString(data); - if (!value) return 0; - self->f->set<std::string>(path, value.get()); - Py_RETURN_NONE; - } - break; - case bob::io::base::b: - return PyBobIoHDF5File_setScalar<bool>(self, path, data); - case bob::io::base::i8: - return PyBobIoHDF5File_setScalar<int8_t>(self, path, data); - case bob::io::base::i16: - return PyBobIoHDF5File_setScalar<int16_t>(self, path, data); - case bob::io::base::i32: - return PyBobIoHDF5File_setScalar<int32_t>(self, path, data); - case bob::io::base::i64: - return PyBobIoHDF5File_setScalar<int64_t>(self, path, data); - case bob::io::base::u8: - return PyBobIoHDF5File_setScalar<uint8_t>(self, path, data); - case bob::io::base::u16: - return PyBobIoHDF5File_setScalar<uint16_t>(self, path, data); - case bob::io::base::u32: - return PyBobIoHDF5File_setScalar<uint32_t>(self, path, data); - case bob::io::base::u64: - return PyBobIoHDF5File_setScalar<uint64_t>(self, path, data); - case bob::io::base::f32: - return PyBobIoHDF5File_setScalar<float>(self, path, data); - case bob::io::base::f64: - return PyBobIoHDF5File_setScalar<double>(self, path, data); - case bob::io::base::f128: - return PyBobIoHDF5File_setScalar<long double>(self, path, data); - case bob::io::base::c64: - return PyBobIoHDF5File_setScalar<std::complex<float> >(self, path, data); - case bob::io::base::c128: - return PyBobIoHDF5File_setScalar<std::complex<double> >(self, path, data); - case bob::io::base::c256: - return PyBobIoHDF5File_setScalar<std::complex<long double> >(self, path, data); - default: - break; - } - - } - - else { //write as array - - switch (is_array) { - case 1: //bob.blitz.array - if (!self->f->contains(path)) self->f->create(path, type, false, compression); - self->f->write_buffer(path, 0, type, ((PyBlitzArrayObject*)data)->data); - break; - - case 2: //numpy.ndarray - if (!self->f->contains(path)) self->f->create(path, type, false, compression); - self->f->write_buffer(path, 0, type, PyArray_DATA((PyArrayObject*)data)); - break; - - case 3: //converted numpy.ndarray - if (!self->f->contains(path)) self->f->create(path, type, false, compression); - self->f->write_buffer(path, 0, type, PyArray_DATA((PyArrayObject*)converted)); - break; - - default: - const char* filename = "<unknown>"; - try{ filename = self->f->filename().c_str(); } catch(...){} - PyErr_Format(PyExc_NotImplementedError, "error setting object `%s' at HDF5 file `%s': HDF5 replace function is uncovered for array type %d (DEBUG ME)", path, filename, is_array); - return 0; - } - - } - - Py_RETURN_NONE; -BOB_CATCH_MEMBER(exception_message(self, s_set.name()).c_str(), 0) -} - - -static auto s_copy = bob::extension::FunctionDoc( - "copy", - "Copies all accessible content to another HDF5 file", - "Unlinked contents of this file will not be copied. " - "This can be used as a method to trim unwanted content in a file.", - true -) -.add_prototype("hdf5") -.add_parameter("hdf5", ":py:class:`HDF5File`", "The HDF5 file (already opened for writing), to copy the contents to") -; -static PyObject* PyBobIoHDF5File_copy(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) { -BOB_TRY - /* Parses input arguments in a single shot */ - static char** kwlist = s_copy.kwlist(); - - PyBobIoHDF5FileObject* other = 0; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O&", kwlist, &PyBobIoHDF5File_Converter, &other)) return 0; - - self->f->copy(*other->f); - - Py_RETURN_NONE; -BOB_CATCH_MEMBER(exception_message(self, s_copy.name()).c_str(), 0) -} - - -template <typename T> static PyObject* PyBobIoHDF5File_readScalarAttribute -(PyBobIoHDF5FileObject* self, const char* path, const char* name, - const bob::io::base::HDF5Type& type) { - T value; - self->f->read_attribute(path, name, type, static_cast<void*>(&value)); - return PyBlitzArrayCxx_FromCScalar(value); -} - -template <> PyObject* PyBobIoHDF5File_readScalarAttribute<const char*> -(PyBobIoHDF5FileObject* self, const char* path, const char* name, - const bob::io::base::HDF5Type& type) { - std::string retval; - self->f->getAttribute(path, name, retval); - return Py_BuildValue("s", retval.c_str()); -} - -static PyObject* PyBobIoHDF5File_readAttribute(PyBobIoHDF5FileObject* self, - const char* path, const char* name, const bob::io::base::HDF5Type& type) { - - //no error detection: this should be done before reaching this method - - const bob::io::base::HDF5Shape& shape = type.shape(); - - if (type.type() == bob::io::base::s || (shape.n() == 1 && shape[0] == 1)) { - //read as scalar - switch(type.type()) { - case bob::io::base::s: - return PyBobIoHDF5File_readScalarAttribute<const char*>(self, path, name, type); - case bob::io::base::b: - return PyBobIoHDF5File_readScalarAttribute<bool>(self, path, name, type); - case bob::io::base::i8: - return PyBobIoHDF5File_readScalarAttribute<int8_t>(self, path, name, type); - case bob::io::base::i16: - return PyBobIoHDF5File_readScalarAttribute<int16_t>(self, path, name, type); - case bob::io::base::i32: - return PyBobIoHDF5File_readScalarAttribute<int32_t>(self, path, name, type); - case bob::io::base::i64: - return PyBobIoHDF5File_readScalarAttribute<int64_t>(self, path, name, type); - case bob::io::base::u8: - return PyBobIoHDF5File_readScalarAttribute<uint8_t>(self, path, name, type); - case bob::io::base::u16: - return PyBobIoHDF5File_readScalarAttribute<uint16_t>(self, path, name, type); - case bob::io::base::u32: - return PyBobIoHDF5File_readScalarAttribute<uint32_t>(self, path, name, type); - case bob::io::base::u64: - return PyBobIoHDF5File_readScalarAttribute<uint64_t>(self, path, name, type); - case bob::io::base::f32: - return PyBobIoHDF5File_readScalarAttribute<float>(self, path, name, type); - case bob::io::base::f64: - return PyBobIoHDF5File_readScalarAttribute<double>(self, path, name, type); - case bob::io::base::f128: - return PyBobIoHDF5File_readScalarAttribute<long double>(self, path, name, type); - case bob::io::base::c64: - return PyBobIoHDF5File_readScalarAttribute<std::complex<float> >(self, path, name, type); - case bob::io::base::c128: - return PyBobIoHDF5File_readScalarAttribute<std::complex<double> >(self, path, name, type); - case bob::io::base::c256: - return PyBobIoHDF5File_readScalarAttribute<std::complex<long double> >(self, path, name, type); - default: - break; - } - } - - //read as an numpy array - int type_num = PyBobIo_H5AsTypenum(type.type()); - if (type_num == NPY_NOTYPE) return 0; ///< failure - - npy_intp pyshape[NPY_MAXDIMS]; - for (size_t k=0; k<shape.n(); ++k) pyshape[k] = shape.get()[k]; - - PyObject* retval = PyArray_SimpleNew(shape.n(), pyshape, type_num); - if (!retval) return 0; - auto retval_ = make_safe(retval); - - self->f->read_attribute(path, name, type, PyArray_DATA((PyArrayObject*)retval)); - - return Py_BuildValue("O", retval); -} - - -static auto s_get_attribute = bob::extension::FunctionDoc( - "get_attribute", - "Retrieve a given attribute from the named resource", - "This method returns a single value corresponding to what is stored inside the attribute container for the given resource. " - "If you would like to retrieve all attributes at once, use :py:meth:`get_attributes` instead.", - true -) -.add_prototype("name, [path]", "attribute") -.add_parameter("name", "str", "The name of the attribute to retrieve; if the attribute is not available, a ``RuntimeError`` is raised") -.add_parameter("path", "str", "[Default: ``'.'``] The path leading to the resource (dataset or group|directory) you would like to get an attribute from; if the path does not exist, a ``RuntimeError`` is raised") -.add_return("attribute", ":py:class:`numpy.ndarray` or scalar", "The read attribute") -; -static PyObject* PyBobIoHDF5File_getAttribute(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) { -BOB_TRY - /* Parses input arguments in a single shot */ - static char** kwlist = s_get_attribute.kwlist(); - - const char* name = 0; - const char* path = "."; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|s", kwlist, &name, &path)) return 0; - - bob::io::base::HDF5Type type; - - self->f->getAttributeType(path, name, type); - - if (type.type() == bob::io::base::unsupported) { - const char* filename = "<unknown>"; - try{ filename = self->f->filename().c_str(); } catch(...){} - boost::format m("unsupported HDF5 data type detected for attribute `%s' at path `%s' of file `%s' - returning None"); - m % name % path % filename; - PyErr_Warn(PyExc_UserWarning, m.str().c_str()); - Py_RETURN_NONE; - } - - return PyBobIoHDF5File_readAttribute(self, path, name, type); -BOB_CATCH_MEMBER(exception_message(self, s_get_attribute.name()).c_str(), 0) -} - - -static auto s_get_attributes = bob::extension::FunctionDoc( - "get_attributes", - "Reads all attributes of the given path", - "Attributes are returned in a dictionary in which each key corresponds to the attribute name and each value corresponds to the value stored inside the HDF5 file. " - "To retrieve only a specific attribute, use :py:meth:`get_attribute`.", - true -) -.add_prototype("[path]", "attributes") -.add_parameter("path", "str", "[Default: ``'.'``] The path leading to the resource (dataset or group|directory) you would like to get all attributes from; if the path does not exist, a ``RuntimeError`` is raised.") -.add_return("attributes", "{str:value}", "The attributes organized in dictionary, where ``value`` might be a :py:class:`numpy.ndarray` or a scalar") -; -static PyObject* PyBobIoHDF5File_getAttributes(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) { -BOB_TRY - /* Parses input arguments in a single shot */ - static char** kwlist = s_get_attributes.kwlist(); - - const char* path = "."; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s", kwlist, &path)) return 0; - - std::map<std::string, bob::io::base::HDF5Type> attributes; - self->f->listAttributes(path, attributes); - PyObject* retval = PyDict_New(); - if (!retval) return 0; - auto retval_ = make_safe(retval); - - for (auto k=attributes.begin(); k!=attributes.end(); ++k) { - PyObject* item = 0; - if (k->second.type() == bob::io::base::unsupported) { - const char* filename = "<unknown>"; - try{ filename = self->f->filename().c_str(); } catch(...){} - boost::format m("unsupported HDF5 data type detected for attribute `%s' at path `%s' of file `%s' - returning None"); - m % k->first % k->second.str() % filename; - PyErr_Warn(PyExc_UserWarning, m.str().c_str()); - item = Py_BuildValue(""); - } - else item = PyBobIoHDF5File_readAttribute(self, path, k->first.c_str(), k->second); - - if (!item) return 0; - auto item_ = make_safe(item); - - if (PyDict_SetItemString(retval, k->first.c_str(), item) != 0) return 0; - } - - return Py_BuildValue("O", retval); -BOB_CATCH_MEMBER(exception_message(self, s_get_attributes.name()).c_str(), 0) -} - - -template <typename T> PyObject* PyBobIoHDF5File_writeScalarAttribute(PyBobIoHDF5FileObject* self, const char* path, const char* name, const bob::io::base::HDF5Type& type, PyObject* o) { - T value = PyBlitzArrayCxx_AsCScalar<T>(o); - if (PyErr_Occurred()) return 0; - - self->f->write_attribute(path, name, type, static_cast<void*>(&value)); - - Py_RETURN_NONE; -} - -template <> PyObject* PyBobIoHDF5File_writeScalarAttribute<const char*>(PyBobIoHDF5FileObject* self, const char* path, const char* name, const bob::io::base::HDF5Type& type, PyObject* o) { - auto value = PyBobIo_GetString(o); - if (!value) return 0; - self->f->write_attribute(path, name, type, static_cast<const void*>(value.get())); - Py_RETURN_NONE; -} - -static PyObject* PyBobIoHDF5File_writeAttribute(PyBobIoHDF5FileObject* self, - const char* path, const char* name, const bob::io::base::HDF5Type& type, - PyObject* o, int is_array, PyObject* converted) { - - //no error detection: this should be done before reaching this method - - if (!is_array) { //write as a scalar - switch(type.type()) { - case bob::io::base::s: - return PyBobIoHDF5File_writeScalarAttribute<const char*>(self, path, name, type, o); - case bob::io::base::b: - return PyBobIoHDF5File_writeScalarAttribute<bool>(self, path, name, type, o); - case bob::io::base::i8: - return PyBobIoHDF5File_writeScalarAttribute<int8_t>(self, path, name, type, o); - case bob::io::base::i16: - return PyBobIoHDF5File_writeScalarAttribute<int16_t>(self, path, name, type, o); - case bob::io::base::i32: - return PyBobIoHDF5File_writeScalarAttribute<int32_t>(self, path, name, type, o); - case bob::io::base::i64: - return PyBobIoHDF5File_writeScalarAttribute<int64_t>(self, path, name, type, o); - case bob::io::base::u8: - return PyBobIoHDF5File_writeScalarAttribute<uint8_t>(self, path, name, type, o); - case bob::io::base::u16: - return PyBobIoHDF5File_writeScalarAttribute<uint16_t>(self, path, name, type, o); - case bob::io::base::u32: - return PyBobIoHDF5File_writeScalarAttribute<uint32_t>(self, path, name, type, o); - case bob::io::base::u64: - return PyBobIoHDF5File_writeScalarAttribute<uint64_t>(self, path, name, type, o); - case bob::io::base::f32: - return PyBobIoHDF5File_writeScalarAttribute<float>(self, path, name, type, o); - case bob::io::base::f64: - return PyBobIoHDF5File_writeScalarAttribute<double>(self, path, name, type, o); - case bob::io::base::f128: - return PyBobIoHDF5File_writeScalarAttribute<long double>(self, path, name, type, o); - case bob::io::base::c64: - return PyBobIoHDF5File_writeScalarAttribute<std::complex<float> >(self, path, name, type, o); - case bob::io::base::c128: - return PyBobIoHDF5File_writeScalarAttribute<std::complex<double> >(self, path, name, type, o); - case bob::io::base::c256: - return PyBobIoHDF5File_writeScalarAttribute<std::complex<long double> >(self, path, name, type, o); - default: - break; - } - } - - else { //write as an numpy array - - switch (is_array) { - - case 1: //bob.blitz.array - self->f->write_attribute(path, name, type, ((PyBlitzArrayObject*)o)->data); - break; - - case 2: //numpy.ndarray - self->f->write_attribute(path, name, type, PyArray_DATA((PyArrayObject*)o)); - break; - - case 3: //converted numpy.ndarray - self->f->write_attribute(path, name, type, PyArray_DATA((PyArrayObject*)converted)); - break; - - default:{ - const char* filename = "<unknown>"; - try{ filename = self->f->filename().c_str(); } catch(...){} - PyErr_Format(PyExc_NotImplementedError, "error setting attribute `%s' at resource `%s' of HDF5 file `%s': HDF5 attribute setting function is uncovered for array type %d (DEBUG ME)", name, path, filename, is_array); - return 0; - } - } - } - Py_RETURN_NONE; -} - -static auto s_set_attribute = bob::extension::FunctionDoc( - "set_attribute", - "Sets a given attribute at the named resource", - "Only simple scalars (booleans, integers, floats and complex numbers) and arrays of those are supported at the time being. " - "You can use :py:mod:`numpy` scalars to set values with arbitrary precision (e.g. :py:class:`numpy.uint8`).\n\n" - ".. warning:: Attributes in HDF5 files are supposed to be small containers or simple scalars that provide extra information about the data stored on the main resource (dataset or group|directory). " - "Attributes cannot be retrieved in chunks, contrary to data in datasets. " - "Currently, **no limitations** for the size of values stored on attributes is imposed.", - true -) -.add_prototype("name, value, [path]") -.add_parameter("name", "str", "The name of the attribute to set") -.add_parameter("value", ":py:class:`numpy.ndarray` or scalar", "A simple scalar to set for the given attribute on the named resources ``path``") -.add_parameter("path", "str", "[Default: ``'.'``] The path leading to the resource (dataset or group|directory) you would like to set an attribute at") -; -static PyObject* PyBobIoHDF5File_setAttribute(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) { -BOB_TRY - /* Parses input arguments in a single shot */ - static char** kwlist = s_set_attribute.kwlist(); - - const char* name = 0; - PyObject* value = 0; - const char* path = "."; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "sO|s", kwlist, &name, &value, &path)) return 0; - - bob::io::base::HDF5Type type; - PyObject* converted = 0; - int is_array = PyBobIoHDF5File_getObjectType(value, type, &converted); - auto converted_ = make_xsafe(converted); - - if (is_array < 0) { ///< error condition, signal - const char* filename = "<unknown>"; - try{ filename = self->f->filename().c_str(); } catch(...){} - PyErr_Format(PyExc_TypeError, "error setting attribute `%s' of resource `%s' at HDF5 file `%s': no support for storing objects of type `%s' on HDF5 files", name, path, filename, Py_TYPE(value)->tp_name); - return 0; - } - - return PyBobIoHDF5File_writeAttribute(self, path, name, type, value, is_array, converted); -BOB_CATCH_MEMBER(exception_message(self, s_set_attribute.name()).c_str(), 0) -} - - -static auto s_set_attributes = bob::extension::FunctionDoc( - "set_attributes", - "Sets several attribute at the named resource using a dictionary", - "Each value in the dictionary should be simple scalars (booleans, integers, floats and complex numbers) or arrays of those are supported at the time being. " - "You can use :py:mod:`numpy` scalars to set values with arbitrary precision (e.g. :py:class:`numpy.uint8`).\n\n" - ".. warning:: Attributes in HDF5 files are supposed to be small containers or simple scalars that provide extra information about the data stored on the main resource (dataset or group|directory). " - "Attributes cannot be retrieved in chunks, contrary to data in datasets. " - "Currently, **no limitations** for the size of values stored on attributes is imposed.", - true -) -.add_prototype("attributes, [path]") -.add_parameter("attributes", "{str: value}", "A python dictionary containing pairs of strings and values, which can be a py:class:`numpy.ndarray` or a scalar") -.add_parameter("path", "str", "[Default: ``'.'``] The path leading to the resource (dataset or group|directory) you would like to set attributes at") -; -static PyObject* PyBobIoHDF5File_setAttributes(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) { -BOB_TRY - /* Parses input arguments in a single shot */ - static char** kwlist = s_set_attributes.kwlist(); - - PyObject* attrs = 0; - const char* path = "."; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|s", kwlist, &attrs, &path)) return 0; - - if (!PyDict_Check(attrs)) { - PyErr_Format(PyExc_TypeError, "parameter `%s' should be a dictionary where keys are strings and values are the attribute values", kwlist[0]); - return 0; - } - - PyObject *key, *value; - Py_ssize_t pos = 0; - while (PyDict_Next(attrs, &pos, &key, &value)) { - bob::io::base::HDF5Type type; - PyObject* converted = 0; - - auto name = PyBobIo_GetString(key); - if (!name) return 0; - - int is_array = PyBobIoHDF5File_getObjectType(value, type, &converted); - auto converted_ = make_xsafe(converted); - - if (is_array < 0) { ///< error condition, signal - const char* filename = "<unknown>"; - try{ filename = self->f->filename().c_str(); } catch(...){} - PyErr_Format(PyExc_TypeError, "error setting attribute `%s' of resource `%s' at HDF5 file `%s': no support for storing objects of type `%s' on HDF5 files", name.get(), path, filename, Py_TYPE(value)->tp_name); - return 0; - } - - PyObject* retval = PyBobIoHDF5File_writeAttribute(self, path, name.get(), type, value, is_array, converted); - if (!retval) return 0; - Py_DECREF(retval); - - } - - Py_RETURN_NONE; -BOB_CATCH_MEMBER(exception_message(self, s_set_attributes.name()).c_str(), 0) -} - - -static auto s_del_attribute = bob::extension::FunctionDoc( - "del_attribute", - "Removes a given attribute at the named resource", - 0, - true -) -.add_prototype("name, [path]") -.add_parameter("name", "str", "The name of the attribute to delete; if the attribute is not available, a ``RuntimeError`` is raised") -.add_parameter("path", "str", "[Default: ``'.'``] The path leading to the resource (dataset or group|directory) you would like to delete an attribute from; if the path does not exist, a ``RuntimeError`` is raised") -; -static PyObject* PyBobIoHDF5File_delAttribute(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) { -BOB_TRY - /* Parses input arguments in a single shot */ - static char** kwlist = s_del_attribute.kwlist(); - - const char* name = 0; - const char* path = "."; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|s", kwlist, &name, &path)) return 0; - - self->f->deleteAttribute(path, name); - - Py_RETURN_NONE; -BOB_CATCH_MEMBER(exception_message(self, s_del_attribute.name()).c_str(), 0) -} - - -static auto s_del_attributes = bob::extension::FunctionDoc( - "del_attributes", - "Removes attributes in a given (existing) path", - "If the ``attributes`` are not given or set to ``None``, then remove all attributes at the named resource.", - true -) -.add_prototype("[attributes], [path]") -.add_parameter("attributes", "[str] or None", "[Default: ``None``] An iterable containing the names of the attributes to be removed, or ``None``") -.add_parameter("path", "str", "[Default: ``'.'``] The path leading to the resource (dataset or group|directory) you would like to delete attributes from; if the path does not exist, a ``RuntimeError`` is raised") -; -static PyObject* PyBobIoHDF5File_delAttributes(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) { -BOB_TRY - /* Parses input arguments in a single shot */ - static char** kwlist = s_del_attributes.kwlist(); - - PyObject* attrs = 0; - const char* path = "."; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "|Os", kwlist, &attrs, &path)) return 0; - - if (attrs && !PyIter_Check(attrs)) { - PyErr_Format(PyExc_TypeError, "parameter `%s', if set, must be an iterable of strings", kwlist[0]); - return 0; - } - - if (attrs) { - PyObject* iter = PyObject_GetIter(attrs); - if (!iter) return 0; - auto iter_ = make_safe(iter); - while (PyObject* item = PyIter_Next(iter)) { - auto item_ = make_safe(item); - auto name = PyBobIo_GetString(item); - if (!name) return 0; - self->f->deleteAttribute(path, name.get()); - } - Py_RETURN_NONE; - } - - //else, find the attributes and remove all of them - std::map<std::string, bob::io::base::HDF5Type> attributes; - self->f->listAttributes(path, attributes); - for (auto k=attributes.begin(); k!=attributes.end(); ++k) { - self->f->deleteAttribute(path, k->first); - } - - Py_RETURN_NONE; -BOB_CATCH_MEMBER(exception_message(self, s_del_attributes.name()).c_str(), 0) -} - - -static auto s_has_attribute = bob::extension::FunctionDoc( - "has_attribute", - "Checks existence of a given attribute at the named resource", - 0, - true -) -.add_prototype("name, [path]", "existence") -.add_parameter("name", "str", "The name of the attribute to check") -.add_parameter("path", "str", "[Default: ``'.'``] The path leading to the resource (dataset or group|directory) you would like to delete attributes from; if the path does not exist, a ``RuntimeError`` is raised") -.add_return("existence", "bool", "``True``, if the attribute ``name`` exists, otherwise ``False``") -; -static PyObject* PyBobIoHDF5File_hasAttribute(PyBobIoHDF5FileObject* self, PyObject *args, PyObject* kwds) { -BOB_TRY - /* Parses input arguments in a single shot */ - static char** kwlist = s_has_attribute.kwlist(); - - const char* name = 0; - const char* path = "."; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|s", kwlist, &name, &path)) return 0; - - if (self->f->hasAttribute(path, name)) - Py_RETURN_TRUE; - Py_RETURN_FALSE; - -BOB_CATCH_MEMBER(exception_message(self, s_has_attribute.name()).c_str(), 0) -} - - -static PyMethodDef PyBobIoHDF5File_methods[] = { - { - s_close.name(), - (PyCFunction)PyBobIoHDF5File_close, - METH_VARARGS|METH_KEYWORDS, - s_close.doc() - }, - { - s_flush.name(), - (PyCFunction)PyBobIoHDF5File_flush, - METH_VARARGS|METH_KEYWORDS, - s_flush.doc() - }, - { - s_cd.name(), - (PyCFunction)PyBobIoHDF5File_changeDirectory, - METH_VARARGS|METH_KEYWORDS, - s_cd.doc(), - }, - { - s_has_group.name(), - (PyCFunction)PyBobIoHDF5File_hasGroup, - METH_VARARGS|METH_KEYWORDS, - s_has_group.doc(), - }, - { - s_create_group.name(), - (PyCFunction)PyBobIoHDF5File_createGroup, - METH_VARARGS|METH_KEYWORDS, - s_create_group.doc(), - }, - { - s_has_dataset.name(), - (PyCFunction)PyBobIoHDF5File_hasDataset, - METH_VARARGS|METH_KEYWORDS, - s_has_dataset.doc(), - }, - { - s_has_key.name(), - (PyCFunction)PyBobIoHDF5File_hasDataset, - METH_VARARGS|METH_KEYWORDS, - s_has_key.doc(), - }, - { - s_describe.name(), - (PyCFunction)PyBobIoHDF5File_describe, - METH_VARARGS|METH_KEYWORDS, - s_describe.doc(), - }, - { - s_unlink.name(), - (PyCFunction)PyBobIoHDF5File_unlink, - METH_VARARGS|METH_KEYWORDS, - s_unlink.doc(), - }, - { - s_rename.name(), - (PyCFunction)PyBobIoHDF5File_rename, - METH_VARARGS|METH_KEYWORDS, - s_rename.doc(), - }, - { - s_paths.name(), - (PyCFunction)PyBobIoHDF5File_paths, - METH_VARARGS|METH_KEYWORDS, - s_paths.doc(), - }, - { - s_keys.name(), - (PyCFunction)PyBobIoHDF5File_paths, - METH_VARARGS|METH_KEYWORDS, - s_keys.doc(), - }, - { - s_sub_groups.name(), - (PyCFunction)PyBobIoHDF5File_subGroups, - METH_VARARGS|METH_KEYWORDS, - s_sub_groups.doc(), - }, - { - s_read.name(), - (PyCFunction)PyBobIoHDF5File_read, - METH_VARARGS|METH_KEYWORDS, - s_read.doc(), - }, - { - s_get.name(), - (PyCFunction)PyBobIoHDF5File_read, - METH_VARARGS|METH_KEYWORDS, - s_get.doc(), - }, - { - s_lread.name(), - (PyCFunction)PyBobIoHDF5File_listRead, - METH_VARARGS|METH_KEYWORDS, - s_lread.doc(), - }, - { - s_replace.name(), - (PyCFunction)PyBobIoHDF5File_replace, - METH_VARARGS|METH_KEYWORDS, - s_replace.doc(), - }, - { - s_append.name(), - (PyCFunction)PyBobIoHDF5File_append, - METH_VARARGS|METH_KEYWORDS, - s_append.doc(), - }, - { - s_set.name(), - (PyCFunction)PyBobIoHDF5File_set, - METH_VARARGS|METH_KEYWORDS, - s_set.doc(), - }, - { - s_write.name(), - (PyCFunction)PyBobIoHDF5File_set, - METH_VARARGS|METH_KEYWORDS, - s_write.doc(), - }, - { - s_copy.name(), - (PyCFunction)PyBobIoHDF5File_copy, - METH_VARARGS|METH_KEYWORDS, - s_copy.doc(), - }, - { - s_get_attribute.name(), - (PyCFunction)PyBobIoHDF5File_getAttribute, - METH_VARARGS|METH_KEYWORDS, - s_get_attribute.doc(), - }, - { - s_get_attributes.name(), - (PyCFunction)PyBobIoHDF5File_getAttributes, - METH_VARARGS|METH_KEYWORDS, - s_get_attributes.doc(), - }, - { - s_set_attribute.name(), - (PyCFunction)PyBobIoHDF5File_setAttribute, - METH_VARARGS|METH_KEYWORDS, - s_set_attribute.doc(), - }, - { - s_set_attributes.name(), - (PyCFunction)PyBobIoHDF5File_setAttributes, - METH_VARARGS|METH_KEYWORDS, - s_set_attributes.doc(), - }, - { - s_del_attribute.name(), - (PyCFunction)PyBobIoHDF5File_delAttribute, - METH_VARARGS|METH_KEYWORDS, - s_del_attribute.doc(), - }, - { - s_del_attributes.name(), - (PyCFunction)PyBobIoHDF5File_delAttributes, - METH_VARARGS|METH_KEYWORDS, - s_del_attributes.doc(), - }, - { - s_has_attribute.name(), - (PyCFunction)PyBobIoHDF5File_hasAttribute, - METH_VARARGS|METH_KEYWORDS, - s_has_attribute.doc(), - }, - {0} /* Sentinel */ -}; - -static auto s_cwd = bob::extension::VariableDoc( - "cwd", - "str", - "The current working directory set on the file" -); -static PyObject* PyBobIoHDF5File_cwd(PyBobIoHDF5FileObject* self) { -BOB_TRY - return Py_BuildValue("s", self->f->cwd().c_str()); -BOB_CATCH_MEMBER(exception_message(self, s_cwd.name()).c_str(), 0) -} - -static auto s_filename = bob::extension::VariableDoc( - "filename", - "str", - "The name (and path) of the underlying file on hard disk" -); -static PyObject* PyBobIoHDF5File_filename(PyBobIoHDF5FileObject* self) { -BOB_TRY - return Py_BuildValue("s", self->f->filename().c_str()); -BOB_CATCH_MEMBER(exception_message(self, s_filename.name()).c_str(), 0) -} - - -static auto s_writable = bob::extension::VariableDoc( - "writable", - "bool", - "Has this file been opened in writable mode?" -); -static PyObject* PyBobIoHDF5File_writable(PyBobIoHDF5FileObject* self) { -BOB_TRY - return Py_BuildValue("b", self->f->writable()); -BOB_CATCH_MEMBER(exception_message(self, s_writable.name()).c_str(), 0) -} - -static PyGetSetDef PyBobIoHDF5File_getseters[] = { - { - s_cwd.name(), - (getter)PyBobIoHDF5File_cwd, - 0, - s_cwd.doc(), - 0, - }, - { - s_filename.name(), - (getter)PyBobIoHDF5File_filename, - 0, - s_filename.doc(), - 0, - }, - { - s_writable.name(), - (getter)PyBobIoHDF5File_writable, - 0, - s_writable.doc(), - 0, - }, - {0} /* Sentinel */ -}; - -PyTypeObject PyBobIoHDF5File_Type = { - PyVarObject_HEAD_INIT(0, 0) - 0 -}; - -bool init_HDF5File(PyObject* module){ - - // initialize the HDF5 file - PyBobIoHDF5File_Type.tp_name = s_hdf5file.name(); - PyBobIoHDF5File_Type.tp_basicsize = sizeof(PyBobIoHDF5FileObject); - PyBobIoHDF5File_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; - PyBobIoHDF5File_Type.tp_doc = s_hdf5file.doc(); - - // set the functions - PyBobIoHDF5File_Type.tp_new = PyBobIoHDF5File_New; - PyBobIoHDF5File_Type.tp_init = reinterpret_cast<initproc>(PyBobIoHDF5File_init); - PyBobIoHDF5File_Type.tp_dealloc = reinterpret_cast<destructor>(PyBobIoHDF5File_Delete); - PyBobIoHDF5File_Type.tp_methods = PyBobIoHDF5File_methods; - PyBobIoHDF5File_Type.tp_getset = PyBobIoHDF5File_getseters; - - PyBobIoHDF5File_Type.tp_str = reinterpret_cast<reprfunc>(PyBobIoHDF5File_repr); - PyBobIoHDF5File_Type.tp_repr = reinterpret_cast<reprfunc>(PyBobIoHDF5File_repr); - - - // check that everyting is fine - if (PyType_Ready(&PyBobIoHDF5File_Type) < 0) - return false; - - // add the type to the module - Py_INCREF(&PyBobIoHDF5File_Type); - return PyModule_AddObject(module, s_hdf5file.name(), (PyObject*)&PyBobIoHDF5File_Type) >= 0; -} diff --git a/bob/io/base/include/bob.io.base/CodecRegistry.h b/bob/io/base/include/bob.io.base/CodecRegistry.h deleted file mode 100644 index 019bb5770959199f2a27c6df1594770c65dcf1f6..0000000000000000000000000000000000000000 --- a/bob/io/base/include/bob.io.base/CodecRegistry.h +++ /dev/null @@ -1,81 +0,0 @@ -/** - * @date Tue Oct 25 23:25:46 2011 +0200 - * @author Andre Anjos <andre.anjos@idiap.ch> - * - * @brief - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_IO_BASE_CODECREGISTRY_H -#define BOB_IO_BASE_CODECREGISTRY_H - -#include <map> -#include <string> -#include <boost/shared_ptr.hpp> - -#include <bob.io.base/File.h> - -namespace bob { namespace io { namespace base { - - /** - * The CodecRegistry holds registered converters for different types of - * input files. It manages registration and helps the user in picking the - * best codecs for their data. This class is a singleton (single global - * variable). - */ - class CodecRegistry { - - public: //static access - - /** - * Returns the singleton - */ - static boost::shared_ptr<CodecRegistry> instance(); - - static const std::map<std::string, std::string>& getExtensions () { - boost::shared_ptr<CodecRegistry> ptr = instance(); - return ptr->s_extension2description; - } - - /** - * Sets and unsets double-registration ignore flag - */ - static bool ignoreDoubleRegistration() { return instance()->s_ignore; } - static void ignoreDoubleRegistration(bool v) { instance()->s_ignore = v; } - - public: //object access - - void registerExtension(const char* extension, const char* description, - file_factory_t factory); - - void deregisterFactory(file_factory_t factory); - void deregisterExtension(const char* ext); - - /** - * Returns the codec description, if an extension was registered with the - * matching input string. Otherwise, returns 0. - */ - const char* getDescription(const char* ext); - - file_factory_t findByExtension(const char* ext); - file_factory_t findByFilenameExtension(const char* fn); - - bool isRegistered(const char* ext); - - private: - - CodecRegistry(): s_extension2codec(), s_ignore(false) {} - - // Not implemented - CodecRegistry( const CodecRegistry&); - - std::map<std::string, file_factory_t> s_extension2codec; - std::map<std::string, std::string> s_extension2description; - bool s_ignore; ///< shall I ignore double-registrations? - - }; - -}}} - -#endif /* BOB_IO_BASE_CODECREGISTRY_H */ diff --git a/bob/io/base/include/bob.io.base/File.h b/bob/io/base/include/bob.io.base/File.h deleted file mode 100644 index e41bccdd9c4983f2be3526b3d1a24cacab150b87..0000000000000000000000000000000000000000 --- a/bob/io/base/include/bob.io.base/File.h +++ /dev/null @@ -1,184 +0,0 @@ -/** - * @date Tue Oct 25 23:25:46 2011 +0200 - * @author Andre Anjos <andre.anjos@idiap.ch> - * - * @brief Describes a generic API for reading and writing data to external - * files. - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_IO_BASE_FILE_H -#define BOB_IO_BASE_FILE_H - -#include <boost/shared_ptr.hpp> -#include <bob.io.base/array.h> -#include <bob.io.base/blitz_array.h> - -namespace bob { namespace io { namespace base { - - /** - * @brief Files deal with reading and writing multiple (homogeneous) array - * data to and from files. - */ - class File { - - public: //abstract API - - virtual ~File(); - - /** - * The filename this array codec current points to - */ - virtual const char* filename() const =0; - - /** - * The typeinfo of data within this file, if it is supposed to be read as - * as a sequence of arrays - */ - virtual const bob::io::base::array::typeinfo& type() const =0; - - /** - * The typeinfo of data within this file, if it is supposed to be read as - * a single array. - */ - virtual const bob::io::base::array::typeinfo& type_all() const =0; - - /** - * The number of arrays available in this file, if it is supposed to be - * read as a sequence of arrays. - */ - virtual size_t size() const =0; - - /** - * Returns the name of the codec, for compatibility reasons. - */ - virtual const char* name() const =0; - - /** - * Loads the data of the array into memory. If an index is specified - * loads the specific array data from the file, otherwise, loads the data - * at position 0. - * - * This method will check to see if the given array has enough space. If - * that is not the case, it will allocate enough space internally by - * reseting the input array and putting the data read from the file - * inside. - */ - virtual void read(bob::io::base::array::interface& buffer, size_t index) =0; - - /** - * Loads all the data available at the file into a single in-memory - * array. - * - * This method will check to see if the given array has enough space. If - * that is not the case, it will allocate enough space internally by - * reseting the input array and putting the data read from the file - * inside. - */ - virtual void read_all(bob::io::base::array::interface& buffer) =0; - - /** - * Appends the given buffer into a file. If the file does not exist, - * create a new file, else, makes sure that the inserted array respects - * the previously set file structure. - * - * Returns the current position of the newly written array. - */ - virtual size_t append (const bob::io::base::array::interface& buffer) =0; - - /** - * Writes the data from the given buffer into the file and act like it is - * the only piece of data that will ever be written to such a file. Not - * more data appending may happen after a call to this method. - */ - virtual void write (const bob::io::base::array::interface& buffer) =0; - - public: //blitz::Array specific API - - /** - * This method returns a copy of the array in the file with the element - * type you wish (just have to get the number of dimensions right!). - */ - template <typename T, int N> blitz::Array<T,N> cast(size_t index) { - bob::io::base::array::blitz_array tmp(type()); - read(tmp, index); - return tmp.cast<T,N>(); - } - - /** - * This method returns a copy of the array in the file with the element - * type you wish (just have to get the number of dimensions right!). - * - * This variant loads all data available into the file in a single array. - */ - template <typename T, int N> blitz::Array<T,N> cast_all() { - bob::io::base::array::blitz_array tmp(type_all()); - read_all(tmp); - return tmp.cast<T,N>(); - } - - template <typename T, int N> void read(blitz::Array<T,N>& io, - size_t index) { - bob::io::base::array::blitz_array use_this(io); - use_this.set(type()); - read(use_this, index); - io.reference(use_this.get<T,N>()); - } - - template <typename T, int N> blitz::Array<T,N> read(size_t index) { - bob::io::base::array::blitz_array tmp(type()); - read(tmp, index); - return tmp.get<T,N>(); - } - - template <typename T, int N> void read_all(blitz::Array<T,N>& io) { - bob::io::base::array::blitz_array use_this(io); - use_this.set(type_all()); - read_all(use_this); - io.reference(use_this.get<T,N>()); - } - - template <typename T, int N> blitz::Array<T,N> read_all() { - bob::io::base::array::blitz_array tmp(type_all()); - read_all(tmp); - return tmp.get<T,N>(); - } - - template <typename T, int N> size_t append(const blitz::Array<T,N>& in) { - bob::io::base::array::blitz_array use_this(in); - return append(use_this); - } - - template <typename T, int N> void write (const blitz::Array<T,N>& in) { - bob::io::base::array::blitz_array use_this(in); - write(use_this); - } - - }; - - /** - * @brief This defines the factory method F that can create codecs. Your - * task, as a codec developer is to create one of such methods for each of - * your codecs and statically register them to the codec registry. - * - * Here are the meanings of the mode flag that should be respected by your - * factory implementation: - * - * 'r': opens for reading only - no modifications can occur; it is an - * error to open a file that does not exist for read-only operations. - * 'w': opens for reading and writing, but truncates the file if it - * exists; it is not an error to open files that do not exist with - * this flag. - * 'a': opens for reading and writing - any type of modification can - * occur. If the file does not exist, this flag is effectively like - * 'w'. - * - * Returns a newly allocated File object that can read and write data to the - * file using a specific backend. - */ - typedef boost::shared_ptr<File> (*file_factory_t) (const char* filename, char mode); - -}}} - -#endif /* BOB_IO_BASE_FILE_H */ diff --git a/bob/io/base/include/bob.io.base/HDF5Attribute.h b/bob/io/base/include/bob.io.base/HDF5Attribute.h deleted file mode 100644 index 3af8a7a697f225e9d01ba1ffed856445774a736b..0000000000000000000000000000000000000000 --- a/bob/io/base/include/bob.io.base/HDF5Attribute.h +++ /dev/null @@ -1,87 +0,0 @@ -/** - * @author Andre Anjos <andre.anjos@idiap.ch> - * @date Fri 2 Mar 08:19:03 2012 - * - * @brief Simple attribute support for HDF5 files - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_IO_BASE_HDF5ATTRIBUTE_H -#define BOB_IO_BASE_HDF5ATTRIBUTE_H - -#include <string> -#include <map> -#include <boost/shared_ptr.hpp> -#include <hdf5.h> - -#include <bob.io.base/HDF5Types.h> - -namespace bob { namespace io { namespace base { namespace detail { namespace hdf5 { - - /** - * Finds out the type of the attribute, if it exists, raises otherwise. - */ - void gettype_attribute (const boost::shared_ptr<hid_t> location, - const std::string& name, HDF5Type& type); - - /** - * Reads the attribute value, place it in "buffer" - */ - void read_attribute (const boost::shared_ptr<hid_t> location, - const std::string& name, const bob::io::base::HDF5Type& dest, void* buffer); - - /** - * Writes an attribute value from "buffer" - */ - void write_attribute (boost::shared_ptr<hid_t> location, - const std::string& name, const bob::io::base::HDF5Type& dest, - const void* buffer); - - /** - * Sets a scalar attribute on the given location. Setting an existing - * attribute overwrites its value. - * - * @note Only simple scalars are supported for the time being - */ - template <typename T> void set_attribute(boost::shared_ptr<hid_t> location, - const std::string& name, const T& v) { - bob::io::base::HDF5Type dest_type(v); - write_attribute(location, name, dest_type, - reinterpret_cast<const void*>(&v)); - } - - /** - * Reads an attribute from the current group. Raises an error if such - * attribute does not exist on the group. To check for existence, use - * has_attribute(). - */ - template <typename T> T get_attribute(const boost::shared_ptr<hid_t> location, - const std::string& name) { - T v; - bob::io::base::HDF5Type dest_type(v); - read_attribute(location, name, dest_type, reinterpret_cast<void*>(&v)); - return v; - } - - /** - * Checks if a certain attribute exists in this location. - */ - bool has_attribute(const boost::shared_ptr<hid_t> location, - const std::string& name); - - /** - * Deletes an attribute from a location. - */ - void delete_attribute(boost::shared_ptr<hid_t> location, - const std::string& name); - - /** - * Lists all attributes and associated types currently available somewhere - */ - void list_attributes(boost::shared_ptr<hid_t> location, - std::map<std::string, bob::io::base::HDF5Type>& attributes); - -}}}}} - -#endif /* BOB_IO_BASE_HDF5ATTRIBUTE_H */ diff --git a/bob/io/base/include/bob.io.base/HDF5Dataset.h b/bob/io/base/include/bob.io.base/HDF5Dataset.h deleted file mode 100644 index 557241079ca1a289f8ea5d778cb082837ea648a9..0000000000000000000000000000000000000000 --- a/bob/io/base/include/bob.io.base/HDF5Dataset.h +++ /dev/null @@ -1,536 +0,0 @@ -/** - * @author Andre Anjos <andre.anjos@idiap.ch> - * @date Wed 29 Feb 17:27:45 2012 - * - * @brief Describes HDF5 datasets - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_IO_BASE_HDF5DATASET_H -#define BOB_IO_BASE_HDF5DATASET_H - -#include <vector> - -#include <boost/shared_ptr.hpp> -#include <blitz/array.h> -#include <hdf5.h> - -#include <bob.core/assert.h> -#include <bob.core/array_copy.h> - -#include <bob.io.base/HDF5Attribute.h> -#include <bob.io.base/HDF5Types.h> - -namespace bob { namespace io { namespace base { namespace detail { namespace hdf5 { - - class File; - class Group; - - /** - * An HDF5 C-style dataset that knows how to close itself. - */ - class Dataset { - - public: //better to protect? - - /** - * Creates a new HDF5 dataset by reading its contents from a certain - * file. - */ - Dataset(boost::shared_ptr<Group> parent, const std::string& name); - - /** - * Creates a new HDF5 dataset from scratch and inserts it in the given - * group. If the Dataset already exists on file and the types are - * compatible, we attach to that type, otherwise, we raise an exception. - * - * If a new Dataset is to be created, you can also set if you would like - * to have as a list and the compression level. Note these settings have - * no effect if the Dataset already exists on file, in which case the - * current settings for that dataset are respected. The maximum value for - * the gzip compression is 9. The value of zero turns compression off - * (the default). - * - * The effect of setting "list" to false is that the created dataset: - * - * a) Will not be expandable (chunked) - * b) Will contain the exact number of dimensions of the input type. - * - * When you set "list" to true (the default), datasets are created with - * chunking automatically enabled (the chunk size is set to the size of - * the given variable) and an extra dimension is inserted to accommodate - * list operations. - */ - Dataset(boost::shared_ptr<Group> parent, const std::string& name, - const bob::io::base::HDF5Type& type, bool list=true, - size_t compression=0); - - public: //api - - /** - * Destructor virtualization - */ - virtual ~Dataset(); - - /** - * Returns the number of objects installed at this dataset from the - * perspective of the default compatible type. - */ - size_t size() const; - - /** - * Returns the number of objects installed at this dataset from the - * perspective of the default compatible type. If the given type is not - * compatible, raises a type error. - */ - size_t size(const bob::io::base::HDF5Type& type) const; - - /** - * Get parent group - */ - virtual const boost::shared_ptr<Group> parent() const; - virtual boost::shared_ptr<Group> parent(); - - /** - * Filename where I'm sitting - */ - virtual const std::string& filename() const; - - /** - * Full path to myself. Constructed each time it is called. - */ - virtual std::string path() const; - - /** - * Path with filename. Constructed each time it is called. - */ - virtual std::string url() const; - - /** - * Access file - */ - virtual const boost::shared_ptr<File> file() const; - virtual boost::shared_ptr<File> file(); - - /** - * My name - */ - virtual const std::string& name() const { - return m_name; - } - - /** - * Accesses the current location id of this dataset - */ - const boost::shared_ptr<hid_t> location() const { - return m_id; - } - boost::shared_ptr<hid_t> location() { - return m_id; - } - - /** - * DATA READING FUNCTIONALITY - */ - - /** - * Reads data from the file into a scalar. The conditions bellow have to - * be respected: - * - * a. My internal shape is 1D **OR** my internal shape is 2D, but the - * extent of the second dimension is 1. - * b. The indexed position exists - * - * If the internal shape is not like defined above, raises a type error. - * If the indexed position does not exist, raises an index error. - */ - template <typename T> void read(size_t index, T& value) { - bob::io::base::HDF5Type dest_type(value); - read_buffer(index, dest_type, reinterpret_cast<void*>(&value)); - } - - /** - * Reads data from the file into a scalar (allocated internally). The - * same conditions as for read(index, value) apply. - */ - template <typename T> T read(size_t index) { - T retval; - read(index, retval); - return retval; - } - - /** - * Reads data from the file into a scalar. This is equivalent to using - * read(0). The same conditions as for read(index=0, value) apply. - */ - template <typename T> T read() { - T retval; - read(0, retval); - return retval; - } - - /** - * Reads data from the file into a array. The following conditions have - * to be respected: - * - * a. My internal shape is the same as the shape of the given value - * **OR** my internal shape has one more dimension as the given value. - * In this case, the first dimension of the internal shape is - * considered to be an index and the remaining shape values the - * dimension of the value to be read. The given array has to be - * compatible with this re-defined N-1 shape. - * b. The indexed position exists - * - * If the internal shape is not like defined above, raises a type error. - * If the index does not exist, raises an index error. - * - * @param index Which of the arrays to read in the current dataset, by - * order - * @param value The output array data will be stored inside this - * variable. This variable has to be a zero-based C-style contiguous - * storage array. If that is not the case, we will raise an exception. - */ - template <typename T, int N> - void readArray(size_t index, blitz::Array<T,N>& value) { - bob::core::array::assertCZeroBaseContiguous(value); - bob::io::base::HDF5Type dest_type(value); - read_buffer(index, dest_type, reinterpret_cast<void*>(value.data())); - } - - /** - * Reads data from the file into an array allocated dynamically. The same - * conditions as for readArray(index, value) apply. - * - * @param index Which of the arrays to read in the current dataset, by - * order - */ - template <typename T, int N> - blitz::Array<T,N> readArray(size_t index) { - for (size_t k=m_descr.size(); k>0; --k) { - const bob::io::base::HDF5Shape& S = m_descr[k-1].type.shape(); - if(S.n() == N) { - blitz::TinyVector<int,N> shape; - S.set(shape); - blitz::Array<T,N> retval(shape); - readArray(index, retval); - return retval; - } - } - boost::format m("trying to read or write `%s' at `%s' that only accepts `%s'"); - m % "unknown dynamic shape" % url() % m_descr[0].type.str(); - throw std::runtime_error(m.str()); - } - - /** - * Reads data from the file into a array. This is equivalent to using - * readArray(0, value). The same conditions as for readArray(index=0, - * value) apply. - * - * @param value The output array data will be stored inside this - * variable. This variable has to be a zero-based C-style contiguous - * storage array. If that is not the case, we will raise an exception. - */ - template <typename T, int N> - void readArray(blitz::Array<T,N>& value) { - readArray(0, value); - } - - /** - * Reads data from the file into a array. This is equivalent to using - * readArray(0). The same conditions as for readArray(index=0, value) - * apply. - */ - template <typename T, int N> - blitz::Array<T,N> readArray() { - return readArray<T,N>(0); - } - - /** - * DATA WRITING FUNCTIONALITY - */ - - /** - * Modifies the value of a scalar inside the file. Modifying a value - * requires that the expected internal shape for this dataset and the - * shape of the given scalar are consistent. To replace a scalar the - * conditions bellow have to be respected: - * - * a. The internal shape is 1D **OR** the internal shape is 2D, but the - * second dimension of the internal shape has is extent == 1. - * b. The given indexing position exists - * - * If the above conditions are not met, an exception is raised. - */ - template <typename T> void replace(size_t index, const T& value) { - bob::io::base::HDF5Type dest_type(value); - write_buffer(index, dest_type, reinterpret_cast<const void*>(&value)); - } - - /** - * Modifies the value of a scalar inside the file. This is equivalent to - * using replace(0, value). The same conditions as for replace(index=0, - * value) apply. - */ - template <typename T> void replace(const T& value) { - replace(0, value); - } - - /** - * Inserts a scalar in the current (existing ;-) dataset. This will - * trigger writing data to the file. Adding a scalar value requires that - * the expected internal shape for this dataset and the shape of the - * given scalar are consistent. To add a scalar the conditions - * bellow have to be respected: - * - * a. The internal shape is 1D **OR** the internal shape is 2D, but the - * second dimension of the internal shape has is extent == 1. - * b. This dataset is expandible (chunked) - * - * If the above conditions are not met, an exception is raised. - */ - template <typename T> void add(const T& value) { - bob::io::base::HDF5Type dest_type(value); - extend_buffer(dest_type, reinterpret_cast<const void*>(&value)); - } - - /** - * Replaces data at the file using a new array. Replacing an existing - * array requires shape consistence. The following conditions should be - * met: - * - * a. My internal shape is the same as the shape of the given value - * **OR** my internal shape has one more dimension as the given value. - * In this case, the first dimension of the internal shape is - * considered to be an index and the remaining shape values the - * dimension of the value to be read. The given array has to be - * compatible with this re-defined N-1 shape. - * b. The given indexing position exists. - * - * If the internal shape is not like defined above, raises a type error. - * If the indexed position does not exist, raises an index error. - * - * @param index Which of the arrays to read in the current dataset, by - * order - * @param value The output array data will be stored inside this - * variable. This variable has to be a zero-based C-style contiguous - * storage array. If that is not the case, we will raise an exception. - */ - template <typename T, int N> - void replaceArray(size_t index, const blitz::Array<T,N>& value) { - bob::io::base::HDF5Type dest_type(value); - if(!bob::core::array::isCZeroBaseContiguous(value)) { - blitz::Array<T,N> tmp = bob::core::array::ccopy(value); - write_buffer(index, dest_type, reinterpret_cast<const void*>(tmp.data())); - } - else { - write_buffer(index, dest_type, - reinterpret_cast<const void*>(value.data())); - } - } - - /** - * Replaces data at the file using a new array. This is equivalent to - * calling replaceArray(0, value). The conditions for - * replaceArray(index=0, value) apply. - * - * @param value The output array data will be stored inside this - * variable. This variable has to be a zero-based C-style contiguous - * storage array. If that is not the case, we will raise an exception. - */ - template <typename T, int N> - void replaceArray(const blitz::Array<T,N>& value) { - replaceArray(0, value); - } - - /** - * Appends a array in a certain subdirectory of the file. If that - * subdirectory (or a "group" in HDF5 parlance) does not exist, it is - * created. If the dataset does not exist, it is created, otherwise, we - * append to it. In this case, the dimensionality of the scalar has to be - * compatible with the existing dataset shape (or "dataspace" in HDF5 - * parlance). If you want to do this, first unlink and than use one of - * the add() methods. - */ - template <typename T, int N> - void addArray(const blitz::Array<T,N>& value) { - bob::io::base::HDF5Type dest_type(value); - if(!bob::core::array::isCZeroBaseContiguous(value)) { - blitz::Array<T,N> tmp = bob::core::array::ccopy(value); - extend_buffer(dest_type, reinterpret_cast<const void*>(tmp.data())); - } - else { - extend_buffer(dest_type, reinterpret_cast<const void*>(value.data())); - } - } - - private: //apis - - /** - * Selects a bit of the file to be affected at the next read or write - * operation. This method encapsulate calls to H5Sselect_hyperslab(). - * - * The index is checked for existence as well as the consistence of the - * destination type. - */ - std::vector<bob::io::base::HDF5Descriptor>::iterator select (size_t index, - const bob::io::base::HDF5Type& dest); - - public: //direct access for other bindings -- don't use these! - - /** - * Reads a previously selected area into the given (user) buffer. - */ - void read_buffer (size_t index, const bob::io::base::HDF5Type& dest, void* buffer); - - /** - * Writes the contents of a given buffer into the file. The area that the - * data will occupy should have been selected beforehand. - */ - void write_buffer (size_t index, const bob::io::base::HDF5Type& dest, - const void* buffer); - - /** - * Extend the dataset with one extra variable. - */ - void extend_buffer (const bob::io::base::HDF5Type& dest, const void* buffer); - - public: //attribute support - - /** - * Gets the current type set for an attribute - */ - void gettype_attribute(const std::string& name, - HDF5Type& type) const; - - /** - * Sets a scalar attribute on the current group. Setting an existing - * attribute overwrites its value. - */ - template <typename T> void set_attribute(const std::string& name, - const T& v) { - bob::io::base::HDF5Type dest_type(v); - write_attribute(name, dest_type, reinterpret_cast<const void*>(&v)); - } - - /** - * Reads an attribute from the current dataset. Raises an error if such - * attribute does not exist on the group. To check for existence, use - * has_attribute(). - */ - template <typename T> T get_attribute(const std::string& name) const { - T v; - bob::io::base::HDF5Type dest_type(v); - read_attribute(name, dest_type, reinterpret_cast<void*>(&v)); - return v; - } - - /** - * Checks if a certain attribute exists in this group. - */ - bool has_attribute(const std::string& name) const; - - /** - * Deletes an attribute - */ - void delete_attribute(const std::string& name); - - /** - * List attributes available on this dataset. - */ - void list_attributes(std::map<std::string, bob::io::base::HDF5Type>& attributes) const; - - public: //array attribute support - - /** - * Sets a array attribute on the current group. Setting an existing - * attribute overwrites its value. If the attribute exists it is erased - * and re-written. - */ - template <typename T, int N> void set_array_attribute(const std::string& name, - const blitz::Array<T,N>& v) { - bob::io::base::HDF5Type dest_type(v); - if(!bob::core::array::isCZeroBaseContiguous(v)) { - blitz::Array<T,N> tmp = bob::core::array::ccopy(v); - write_attribute(name, dest_type, reinterpret_cast<const void*>(tmp.data())); - } - else { - write_attribute(name, dest_type, reinterpret_cast<const void*>(v.data())); - } - } - - /** - * Reads an attribute from the current dataset. Raises an error if such - * attribute does not exist on the group. To check for existence, use - * has_attribute(). - */ - template <typename T, int N> blitz::Array<T,N> get_array_attribute(const std::string& name) const { - blitz::Array<T,N> v; - bob::io::base::HDF5Type dest_type(v); - read_attribute(name, dest_type, reinterpret_cast<void*>(v.data())); - return v; - } - - /** - * Reads an attribute from the current dataset. Places the data in an - * already allocated array. - */ - template <typename T, int N> void get_array_attribute(const std::string& name, - blitz::Array<T,N>& v) const { - bob::io::base::HDF5Type dest_type(v); - read_attribute(name, dest_type, reinterpret_cast<void*>(v.data())); - } - - public: //buffer attribute support - - /** - * Reads an attribute into a user buffer. It is the user's responsibility - * to have a buffer that represents the given type. - */ - void read_attribute (const std::string& name, - const bob::io::base::HDF5Type& dest, void* buffer) const; - - /** - * Writes the contents of a given buffer into the attribute. - */ - void write_attribute (const std::string& name, - const bob::io::base::HDF5Type& dest, const void* buffer); - - private: //not implemented - - /** - * Copies the contents of an existing dataset -- not implemented - */ - Dataset(const Dataset& other); - - /** - * Assigns the contents of an existing dataset to myself -- not - * implemented - */ - Dataset& operator= (const Dataset& other); - - public: //representation - - boost::weak_ptr<Group> m_parent; ///< my parent group - std::string m_name; ///< name of this object - boost::shared_ptr<hid_t> m_id; ///< the HDF5 Dataset this type points to - boost::shared_ptr<hid_t> m_dt; ///< the datatype of this Dataset - boost::shared_ptr<hid_t> m_filespace; ///< the "file" space for this set - std::vector<bob::io::base::HDF5Descriptor> m_descr; ///< read/write descr.'s - boost::shared_ptr<hid_t> m_memspace; ///< read/write space - - }; - - /** - * std::string specialization - */ - template <> void Dataset::read<std::string>(size_t index, std::string& value); - template <> void Dataset::replace<std::string>(size_t index, const std::string& value); - template <> void Dataset::add<std::string>(const std::string& value); - template <> void Dataset::set_attribute<std::string>(const std::string& name, const std::string& v); - template <> std::string Dataset::get_attribute(const std::string& name) const; - -}}}}} - - -#endif /* BOB_IO_BASE_HDF5DATASET_H */ diff --git a/bob/io/base/include/bob.io.base/HDF5File.h b/bob/io/base/include/bob.io.base/HDF5File.h deleted file mode 100644 index 31c65944e5088b51af3fe1307e270e466b71052a..0000000000000000000000000000000000000000 --- a/bob/io/base/include/bob.io.base/HDF5File.h +++ /dev/null @@ -1,558 +0,0 @@ -/** - * @date Wed Jun 22 17:50:08 2011 +0200 - * @author Andre Anjos <andre.anjos@idiap.ch> - * - * @brief bob support for HDF5 files. HDF5 is a open standard for - * self-describing data files. You can get more information in this webpage: - * http://www.hdfgroup.org/HDF5 - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_IO_BASE_HDF5FILE_H -#define BOB_IO_BASE_HDF5FILE_H - -#include <boost/format.hpp> - -#include <bob.io.base/HDF5Utils.h> - -namespace bob { namespace io { namespace base { - - /** - * This is the main type for interfacing bob with HDF5. It allows the user - * to create, delete and modify data objects using a very-level API. The - * total functionality provided by this API is, of course, much smaller than - * what is provided if you use the HDF5 C-APIs directly, but is much simpler - * as well. - */ - class HDF5File { - - public: - - /** - * This enumeration defines the different values with which you can open - * the files with - */ - typedef enum mode_t { - in = 0, //H5F_ACC_RDONLY < can only read file - inout = 1, //H5F_ACC_RDWR < open file for reading and writing - trunc = 2, //H5F_ACC_TRUNC < if file exists, truncate it and open - excl = 4 //H5F_ACC_EXCL < if file exists, raise, otherwise == inout - } mode_t; - - public: //api - - /** - * Constructor, starts a new HDF5File object giving it a file name and an - * action: excl/trunc/in/inout - */ - HDF5File (const std::string& filename, mode_t mode); - - /** - * Constructor, starts a new HDF5File object giving it a file name and an - * action: 'r' (read-only), 'a' (read/write/append), 'w' (read/write/truncate) or 'x' (read/write/exclusive) - */ - HDF5File (const std::string& filename, const char mode='r'); - - /** - * Destructor virtualization - */ - virtual ~HDF5File(); - - /** - * Flushes the current content of the file to disk. - */ - void flush() {m_file->flush();} - - /** - * Closes the file after writing its content to disk - */ - void close(); - - /** - * Changes the current prefix path. When this object is started, it - * points to the root of the file. If you set this to a different - * value, it will be used as a prefix to any subsequent operation on - * relative paths until you reset it. - * - * @param path If path starts with '/', it is treated as an absolute - * path. '..' and '.' are supported. This object should be a std::string. - * If the value is relative, it is added to the current path. - * - * @note All operations taking a relative path, following a cd(), will be - * considered relative to the value returned by cwd(). - */ - void cd(const std::string& path); - - /** - * Tells if a certain directory exists in a file. - */ - bool hasGroup(const std::string& path); - - /** - * Creates a directory within the file. It is an error to recreate a path - * that already exists. You can check this with hasGroup() - */ - void createGroup(const std::string& path); - - /** - * Returns the name of the file currently opened - */ - const std::string filename() const {check_open(); return m_file->filename(); } - - /** - * Checks if the file is open for writing - */ - bool writable() const {check_open(); return m_file->writable();} - - /** - * Returns the current working path, fully resolved. This is - * re-calculated every time you call this method. - */ - std::string cwd() const; - - /** - * Tells if we have a variable with the given name inside the HDF5 file. - * If the file path given is a relative file path, it is taken w.r.t. the - * current working directory, as returned by cwd(). - */ - bool contains(const std::string& path) const; - - /** - * Describe a certain dataset path. If the file path is a relative one, - * it is taken w.r.t. the current working directory, as returned by - * cwd(). - */ - const std::vector<HDF5Descriptor>& describe (const std::string& path) const; - - /** - * Unlinks a particular dataset from the file. Note that this will - * not erase the data on the current file as that functionality is not - * provided by HDF5. To actually reclaim the space occupied by the - * unlinked structure, you must re-save this file to another file. The - * new file will not contain the data of any dangling datasets (datasets - * w/o names or links). Relative paths are allowed. - */ - void unlink (const std::string& path); - - /** - * Renames an existing dataset - */ - void rename (const std::string& from, const std::string& to); - - /** - * Accesses all existing paths in one shot. Input has to be a std - * container with T = std::string and accepting push_back() - */ - template <typename T> void paths (T& container, const bool relative = false) const { - m_cwd->dataset_paths(container); - check_open(); - if (relative){ - const std::string d = cwd(); - const int len = d.length()+1; - for (typename T::iterator it = container.begin(); it != container.end(); ++it){ - // assert that the string contains the current path - assert(it->find(d) == 0); - // subtract current path - *it = it->substr(len); - } - } - } - - /** - * Accesses all existing paths in one shot. Input has to be a std - * container with T = std::string and accepting push_back() - */ - template <typename T> void sub_groups (T& container, bool relative = false, bool recursive = true) const { - check_open(); - m_cwd->subgroup_paths(container, recursive); - if (!relative){ - const std::string d = cwd() + "/"; - for (typename T::iterator it = container.begin(); it != container.end(); ++it){ - // add current path - *it = d + *it; - } - } - } - - /** - * Copies the contents of the other file to this file. This is a blind - * operation, so we try to copy everything from the given file to the - * current one. It is the user responsibility to make sure the "path" - * slots in the other file are not already taken. If that is detected, an - * exception will be raised. - * - * This operation will be conducted w.r.t. the currently set prefix path - * (verifiable using cwd()). - */ - void copy (HDF5File& other); - - /** - * Reads data from the file into a scalar. Raises an exception if the - * type is incompatible. Relative paths are accepted. - */ - template <typename T> - void read(const std::string& path, size_t pos, T& value) { - check_open(); - (*m_cwd)[path]->read(pos, value); - } - - /** - * Reads data from the file into a scalar. Returns by copy. Raises if the - * type T is incompatible. Relative paths are accepted. - */ - template <typename T> T read(const std::string& path, size_t pos) { - check_open(); - return (*m_cwd)[path]->read<T>(pos); - } - - /** - * Reads data from the file into a scalar. Raises an exception if the - * type is incompatible. Relative paths are accepted. Calling this method - * is equivalent to calling read(path, 0). Returns by copy. - */ - template <typename T> T read(const std::string& path) { - return read<T>(path, 0); - } - - /** - * Reads data from the file into a array. Raises an exception if the type - * is incompatible. Relative paths are accepted. - */ - template <typename T, int N> void readArray(const std::string& path, - size_t pos, blitz::Array<T,N>& value) { - check_open(); - (*m_cwd)[path]->readArray(pos, value); - } - - /** - * Reads data from the file into a array. Raises an exception if the type - * is incompatible. Relative paths are accepted. Destination array is - * allocated internally and returned by value. - */ - template <typename T, int N> blitz::Array<T,N> readArray - (const std::string& path, size_t pos) { - check_open(); - return (*m_cwd)[path]->readArray<T,N>(pos); - } - - /** - * Reads data from the file into a array. Raises an exception if the type - * is incompatible. Relative paths are accepted. Calling this method is - * equivalent to calling readArray(path, 0, value). - */ - template <typename T, int N> void readArray(const std::string& path, - blitz::Array<T,N>& value) { - readArray(path, 0, value); - } - - /** - * Reads data from the file into a array. Raises an exception if the type - * is incompatible. Relative paths are accepted. Calling this method is - * equivalent to calling readArray(path, 0). Destination array is - * allocated internally. - */ - template <typename T, int N> blitz::Array<T,N> readArray - (const std::string& path) { - return readArray<T,N>(path, 0); - } - - /** - * Modifies the value of a scalar inside the file. Relative paths are - * accepted. - */ - template <typename T> void replace(const std::string& path, size_t pos, - const T& value) { - check_open(); - if (!m_file->writable()) { - boost::format m("cannot replace value at dataset '%s' at path '%s' of file '%s' because it is not writeable"); - m % path % m_cwd->path() % m_file->filename(); - throw std::runtime_error(m.str()); - } - (*m_cwd)[path]->replace(pos, value); - } - - /** - * Modifies the value of a scalar inside the file. Relative paths are - * accepted. Calling this method is equivalent to calling replace(path, - * 0, value). - */ - template <typename T> void replace(const std::string& path, - const T& value) { - replace(path, 0, value); - } - - /** - * Modifies the value of a array inside the file. Relative paths are - * accepted. - */ - template <typename T> void replaceArray(const std::string& path, - size_t pos, const T& value) { - check_open(); - if (!m_file->writable()) { - boost::format m("cannot replace array at dataset '%s' at path '%s' of file '%s' because it is not writeable"); - m % path % m_cwd->path() % m_file->filename(); - throw std::runtime_error(m.str()); - } - (*m_cwd)[path]->replaceArray(pos, value); - } - - /** - * Modifies the value of a array inside the file. Relative paths are - * accepted. Calling this method is equivalent to calling - * replaceArray(path, 0, value). - */ - template <typename T> void replaceArray(const std::string& path, - const T& value) { - replaceArray(path, 0, value); - } - - /** - * Appends a scalar in a dataset. If the dataset does not yet exist, one - * is created with the type characteristics. Relative paths are accepted. - */ - template <typename T> void append(const std::string& path, - const T& value) { - check_open(); - if (!m_file->writable()) { - boost::format m("cannot append value to dataset '%s' at path '%s' of file '%s' because it is not writeable"); - m % path % m_cwd->path() % m_file->filename(); - throw std::runtime_error(m.str()); - } - if (!contains(path)) m_cwd->create_dataset(path, bob::io::base::HDF5Type(value), true, 0); - (*m_cwd)[path]->add(value); - } - - /** - * Appends a array in a dataset. If the dataset does not yet exist, one - * is created with the type characteristics. Relative paths are accepted. - * - * If a new Dataset is to be created, you can also set the compression - * level. Note this setting has no effect if the Dataset already exists - * on file, in which case the current setting for that dataset is - * respected. The maximum value for the gzip compression is 9. The value - * of zero turns compression off (the default). - */ - template <typename T> void appendArray(const std::string& path, - const T& value, size_t compression=0) { - check_open(); - if (!m_file->writable()) { - boost::format m("cannot append array to dataset '%s' at path '%s' of file '%s' because it is not writeable"); - m % path % m_cwd->path() % m_file->filename(); - throw std::runtime_error(m.str()); - } - if (!contains(path)) m_cwd->create_dataset(path, bob::io::base::HDF5Type(value), true, compression); - (*m_cwd)[path]->addArray(value); - } - - /** - * Sets the scalar at position 0 to the given value. This method is - * equivalent to checking if the scalar at position 0 exists and then - * replacing it. If the path does not exist, we append the new scalar. - */ - template <typename T> void set(const std::string& path, const T& value) { - check_open(); - if (!m_file->writable()) { - boost::format m("cannot set value at dataset '%s' at path '%s' of file '%s' because it is not writeable"); - m % path % m_cwd->path() % m_file->filename(); - throw std::runtime_error(m.str()); - } - if (!contains(path)) m_cwd->create_dataset(path, bob::io::base::HDF5Type(value), false, 0); - (*m_cwd)[path]->replace(0, value); - } - - /** - * Sets the array at position 0 to the given value. This method is - * equivalent to checking if the array at position 0 exists and then - * replacing it. If the path does not exist, we append the new array. - * - * If a new Dataset is to be created, you can also set the compression - * level. Note this setting has no effect if the Dataset already exists - * on file, in which case the current setting for that dataset is - * respected. The maximum value for the gzip compression is 9. The value - * of zero turns compression off (the default). - */ - template <typename T> void setArray(const std::string& path, - const T& value, size_t compression=0) { - check_open(); - if (!m_file->writable()) { - boost::format m("cannot set array at dataset '%s' at path '%s' of file '%s' because it is not writeable"); - m % path % m_cwd->path() % m_file->filename(); - throw std::runtime_error(m.str()); - } - if (!contains(path)) m_cwd->create_dataset(path, bob::io::base::HDF5Type(value), false, compression); - (*m_cwd)[path]->replaceArray(0, value); - } - - public: //api shortcuts to deal with buffers -- avoid these at all costs! - - /** - * creates a new dataset. If the dataset already exists, checks if the - * existing data is compatible with the required type. - */ - void create (const std::string& path, const HDF5Type& dest, bool list, - size_t compression); - - /** - * Reads data from the file into a buffer. The given buffer contains - * sufficient space to hold the type described in "dest". Raises an - * exception if the type is incompatible with the expected data in the - * file. Relative paths are accepted. - */ - void read_buffer (const std::string& path, size_t pos, - const HDF5Type& type, void* buffer) const; - - /** - * writes the contents of a given buffer into the file. the area that the - * data will occupy should have been selected beforehand. - */ - void write_buffer (const std::string& path, size_t pos, - const HDF5Type& type, const void* buffer); - - /** - * extend the dataset with one extra variable. - */ - void extend_buffer (const std::string& path, - const HDF5Type& type, const void* buffer); - - /** - * Copy construct an already opened HDF5File; just creates a shallow copy - * of the file - */ - HDF5File (const HDF5File& other); - - /** - * Drop the current settings and load new ones from the other file. - */ - HDF5File& operator= (const HDF5File& other); - - public: // attribute handling - - /** - * Tells if there is an attribute with a given name on the given path, - * relative to the current location, possibly. - */ - bool hasAttribute(const std::string& path, const std::string& name) const; - - /** - * Reads data from an attribute into a scalar. If the attribute does not - * exist, raise an exception. Raises a TypeError if the types are not - * compatible. - */ - template <typename T> - void getAttribute(const std::string& path, const std::string& name, - T& value) const { - check_open(); - if (m_cwd->has_dataset(path)) { - value = (*m_cwd)[path]->get_attribute<T>(name); - } - else if (m_cwd->has_group(path)) { - value = m_cwd->cd(path)->get_attribute<T>(name); - } - else { - boost::format m("cannot read attribute '%s' at path/dataset '%s' of file '%s' (cwd: '%s') because this path/dataset does not currently exist"); - m % name % path % m_file->filename() % m_cwd->path(); - throw std::runtime_error(m.str()); - } - } - - /** - * Reads data from an attribute into an array. If the attribute does not - * exist, raise an exception. Raises a type error if the types are not - * compatible. - */ - template <typename T, int N> - void getArrayAttribute(const std::string& path, - const std::string& name, blitz::Array<T,N>& value) const { - check_open(); - if (m_cwd->has_dataset(path)) { - value = (*m_cwd)[path]->get_array_attribute<T,N>(name); - } - else if (m_cwd->has_group(path)) { - value = m_cwd->cd(path)->get_array_attribute<T,N>(name); - } - else { - boost::format m("cannot read (array) attribute '%s' at path/dataset '%s' of file '%s' (cwd: '%s') because this path/dataset does not currently exist"); - m % name % path % m_file->filename() % m_cwd->path(); - throw std::runtime_error(m.str()); - } - } - - /** - * Writes a scalar as an attribute to a path in this file. - */ - template <typename T> - void setAttribute(const std::string& path, const std::string& name, - const T value) { - check_open(); - if (m_cwd->has_dataset(path)) { - (*m_cwd)[path]->set_attribute(name, value); - } - else if (m_cwd->has_group(path)) { - m_cwd->cd(path)->set_attribute(name, value); - } - else { - boost::format m("cannot write attribute '%s' at path/dataset '%s' of file '%s' (cwd: '%s') because this path/dataset does not currently exist"); - m % name % path % m_file->filename() % m_cwd->path(); - throw std::runtime_error(m.str()); - } - } - - /** - * Writes an array as an attribute to a path in this file. - */ - template <typename T, int N> - void setArrayAttribute(const std::string& path, - const std::string& name, const blitz::Array<T,N>& value) { - check_open(); - if (m_cwd->has_dataset(path)) { - (*m_cwd)[path]->set_array_attribute(name, value); - } - else if (m_cwd->has_group(path)) { - m_cwd->cd(path)->set_array_attribute(name, value); - } - else { - boost::format m("cannot write (array) attribute '%s' at path/dataset '%s' of file '%s' (cwd: '%s') because this path/dataset does not currently exist"); - m % name % path % m_file->filename() % m_cwd->path(); - throw std::runtime_error(m.str()); - } - } - - /** - * Gets the type information of an attribute - */ - void getAttributeType(const std::string& path, - const std::string& name, bob::io::base::HDF5Type& type) const; - - /** - * Deletes a given attribute - */ - void deleteAttribute(const std::string& path, - const std::string& name); - - /** - * List attributes available on a certain object. - */ - void listAttributes(const std::string& path, - std::map<std::string, bob::io::base::HDF5Type>& attributes) const; - - public: //raw accessors to attributes - - void read_attribute(const std::string& path, const std::string& name, - const bob::io::base::HDF5Type& type, void* buffer) const; - - void write_attribute(const std::string& path, const std::string& name, - const bob::io::base::HDF5Type& type, const void* buffer); - - private: //representation - - void check_open() const; - - boost::shared_ptr<detail::hdf5::File> m_file; ///< the file itself - boost::shared_ptr<detail::hdf5::Group> m_cwd; ///< current working dir - - }; - -}}} - -#endif /* BOB_IO_BASE_HDF5FILE_H */ diff --git a/bob/io/base/include/bob.io.base/HDF5Group.h b/bob/io/base/include/bob.io.base/HDF5Group.h deleted file mode 100644 index 9dcd7a6e76cccdb40c1e4b98b4efdec63bcc52ef..0000000000000000000000000000000000000000 --- a/bob/io/base/include/bob.io.base/HDF5Group.h +++ /dev/null @@ -1,468 +0,0 @@ -/** - * @author Andre Anjos <andre.anjos@idiap.ch> - * @date Wed 29 Feb 17:24:10 2012 - * - * @brief Describes HDF5 groups. - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_IO_BASE_HDF5GROUP_H -#define BOB_IO_BASE_HDF5GROUP_H - -#include <boost/shared_ptr.hpp> -#include <boost/enable_shared_from_this.hpp> -#include <hdf5.h> - -#include <bob.io.base/HDF5Types.h> -#include <bob.io.base/HDF5Dataset.h> -#include <bob.io.base/HDF5Attribute.h> - -namespace bob { namespace io { namespace base { namespace detail { namespace hdf5 { - - class File; - - /** - * A group represents a path inside the HDF5 file. It can contain Datasets or - * other Groups. - */ - class Group: public boost::enable_shared_from_this<Group> { - - public: //better to protect? - - /** - * Creates a new group in a given parent. - */ - Group(boost::shared_ptr<Group> parent, const std::string& name); - - /** - * Binds to an existing group in a parent, reads all the group contents - * recursively. Note that the last parameter is there only to - * differentiate from the above constructor. It is ignored. - */ - Group(boost::shared_ptr<Group> parent, const std::string& name, - bool open); - - /** - * Constructor used by the root group, just open the root group - */ - Group(boost::shared_ptr<File> parent); - - /** - * Recursively open sub-groups and datasets. This cannot be done at the - * constructor because of a enable_shared_from_this<> restriction that - * results in a bad weak pointer exception being raised. - */ - void open_recursively(); - - public: //api - - /** - * D'tor - presently, does nothing - */ - virtual ~Group(); - - /** - * Get parent group - */ - virtual const boost::shared_ptr<Group> parent() const; - virtual boost::shared_ptr<Group> parent(); - - /** - * Filename where I'm sitting - */ - virtual const std::string& filename() const; - - /** - * Full path to myself. Constructed each time it is called. - */ - virtual std::string path() const; - - /** - * Access file - */ - virtual const boost::shared_ptr<File> file() const; - virtual boost::shared_ptr<File> file(); - - /** - * My name - */ - virtual const std::string& name() const { - return m_name; - } - - /** - * Deletes all children nodes and properties in this group. - * - * Note that removing data already written in a file will only be - * effective in terms of space saving when you actually re-write that - * file. This instruction just unlinks all data from this group and makes - * them inaccessible to any further read operation. - */ - virtual void reset(); - - /** - * Accesses the current location id of this group - */ - const boost::shared_ptr<hid_t> location() const { - return m_id; - } - - boost::shared_ptr<hid_t> location() { - return m_id; - } - - /** - * Path with filename. Constructed each time it is called. - */ - virtual std::string url() const; - - /** - * move up-down on the group hierarchy - */ - virtual boost::shared_ptr<Group> cd(const std::string& path); - virtual const boost::shared_ptr<Group> cd(const std::string& path) const; - - /** - * Get a mapping of all child groups - */ - virtual const std::map<std::string, boost::shared_ptr<Group> >& groups() - const { - return m_groups; - } - - /** - * Create a new subgroup with a given name. - */ - virtual boost::shared_ptr<Group> create_group(const std::string& name); - - /** - * Deletes an existing subgroup with a given name. If a relative name is - * given, it is interpreted w.r.t. to this group. - * - * Note that removing data already written in a file will only be - * effective in terms of space saving when you actually re-write that - * file. This instruction just unlinks all data from this group and makes - * them inaccessible to any further read operation. - */ - virtual void remove_group(const std::string& path); - - /** - * Rename an existing group under me. - */ - virtual void rename_group(const std::string& from, const std::string& to); - - /** - * Copies all data from an existing group into myself, creating a new - * subgroup, by default, with the same name as the other group. If a - * relative name is given, it is interpreted w.r.t. to this group. - * - * If an empty string is given as "dir", copies the other group name. - */ - virtual void copy_group(const boost::shared_ptr<Group> other, const - std::string& path=""); - - /** - * Says if a group with a certain path exists in this group. - */ - virtual bool has_group(const std::string& path) const; - - /** - * Get all datasets attached to this group - */ - virtual const std::map<std::string, boost::shared_ptr<Dataset> >& - datasets() const { - return m_datasets; - } - - /** - * Creates a new HDF5 dataset from scratch and inserts it in this group. - * If the Dataset already exists on file and the types are compatible, we - * attach to that type, otherwise, we raise an exception. - * - * You can set if you would like to have the dataset created as a list - * and the compression level. - * - * The effect of setting "list" to false is that the created dataset: - * - * a) Will not be expandible (chunked) b) Will contain the exact number - * of dimensions of the input type. - * - * When you set "list" to true (the default), datasets are created with - * chunking automatically enabled (the chunk size is set to the size of - * the given variable) and an extra dimension is inserted to accomodate - * list operations. - */ - virtual boost::shared_ptr<Dataset> create_dataset - (const std::string& path, const bob::io::base::HDF5Type& type, bool list=true, - size_t compression=0); - - /** - * Deletes a dataset in this group - * - * Note that removing data already written in a file will only be - * effective in terms of space saving when you actually re-write that - * file. This instruction just unlinks all data from this group and makes - * them inaccessible to any further read operation. - */ - virtual void remove_dataset(const std::string& path); - - /** - * Rename an existing dataset under me. - */ - virtual void rename_dataset(const std::string& from, - const std::string& to); - - /** - * Copies the contents of the given dataset into this. By default, use - * the same name. - */ - virtual void copy_dataset(const boost::shared_ptr<Dataset> other, - const std::string& path=""); - - /** - * Says if a dataset with a certain name exists in the current file. - */ - virtual bool has_dataset(const std::string& path) const; - - /** - * Accesses a certain dataset from this group - */ - boost::shared_ptr<Dataset> operator[] (const std::string& path); - const boost::shared_ptr<Dataset> operator[] (const std::string& path) const; - - /** - * Accesses all existing paths in one shot. Input has to be a std - * container with T = std::string and accepting push_back() - */ - template <typename T> void dataset_paths (T& container) const { - for (std::map<std::string, boost::shared_ptr<io::base::detail::hdf5::Dataset> >::const_iterator it=m_datasets.begin(); it != m_datasets.end(); ++it) container.push_back(it->second->path()); - for (std::map<std::string, boost::shared_ptr<io::base::detail::hdf5::Group> >::const_iterator it=m_groups.begin(); it != m_groups.end(); ++it) it->second->dataset_paths(container); - } - - /** - * Accesses all existing sub-groups in one shot. Input has to be a std - * container with T = std::string and accepting push_back() - */ - template <typename T> void subgroup_paths (T& container, bool recursive = true) const { - for (std::map<std::string, boost::shared_ptr<io::base::detail::hdf5::Group> >::const_iterator it=m_groups.begin(); it != m_groups.end(); ++it){ - container.push_back(it->first); - if (recursive){ - unsigned pos = container.size(); - it->second->subgroup_paths(container); - for (unsigned p = pos; p < container.size(); ++p){ - container[p] = it->first + "/" + container[p]; - } - } - } - } - - /** - * Callback function for group iteration. Two cases are blessed here: - * - * 1. Object is another group. In this case just instantiate the group and - * recursively iterate from there - * 2. Object is a dataset. Instantiate it. - * - * Only hard-links are considered. At the time being, no soft links. - */ - herr_t iterate_callback(hid_t group, const char *name, - const H5L_info_t *info); - - public: //attribute support - - /** - * Gets the current type set for an attribute - */ - void gettype_attribute(const std::string& name, HDF5Type& type) const; - - /** - * Sets a scalar attribute on the current group. Setting an existing - * attribute overwrites its value. - * - * @note Only simple scalars are supported for the time being - */ - template <typename T> void set_attribute(const std::string& name, - const T& v) { - bob::io::base::HDF5Type dest_type(v); - write_attribute(name, dest_type, reinterpret_cast<const void*>(&v)); - } - - /** - * Reads an attribute from the current group. Raises an error if such - * attribute does not exist on the group. To check for existence, use - * has_attribute(). - */ - template <typename T> T get_attribute(const std::string& name) const { - T v; - bob::io::base::HDF5Type dest_type(v); - read_attribute(name, dest_type, reinterpret_cast<void*>(&v)); - return v; - } - - /** - * Checks if a certain attribute exists in this group. - */ - bool has_attribute(const std::string& name) const; - - /** - * Deletes an attribute - */ - void delete_attribute(const std::string& name); - - /** - * List attributes available on this dataset. - */ - void list_attributes(std::map<std::string, bob::io::base::HDF5Type>& attributes) const; - - public: //array attribute support - - /** - * Sets a array attribute on the current group. Setting an existing - * attribute overwrites its value. If the attribute exists it is erased - * and re-written. - */ - template <typename T, int N> void set_array_attribute(const std::string& name, - const blitz::Array<T,N>& v) { - bob::io::base::HDF5Type dest_type(v); - if(!bob::core::array::isCZeroBaseContiguous(v)) { - blitz::Array<T,N> tmp = bob::core::array::ccopy(v); - write_attribute(name, dest_type, reinterpret_cast<const void*>(tmp.data())); - } - else { - write_attribute(name, dest_type, reinterpret_cast<const void*>(v.data())); - } - } - - /** - * Reads an attribute from the current dataset. Raises an error if such - * attribute does not exist on the group. To check for existence, use - * has_attribute(). - */ - template <typename T, int N> blitz::Array<T,N> get_array_attribute - (const std::string& name) const { - blitz::Array<T,N> v; - bob::io::base::HDF5Type dest_type(v); - read_attribute(name, dest_type, reinterpret_cast<void*>(v.data())); - return v; - } - - /** - * Reads an attribute from the current dataset. Places the data in an - * already allocated array. - */ - template <typename T, int N> void get_array_attribute - (const std::string& name, blitz::Array<T,N>& v) const { - bob::io::base::HDF5Type dest_type(v); - read_attribute(name, dest_type, reinterpret_cast<void*>(v.data())); - } - - public: //buffer attribute support - - /** - * Reads an attribute into a user buffer. It is the user's responsibility - * to have a buffer that represents the given type. - */ - void read_attribute (const std::string& name, - const bob::io::base::HDF5Type& dest, void* buffer) const; - - /** - * Writes the contents of a given buffer into the attribute. - */ - void write_attribute (const std::string& name, - const bob::io::base::HDF5Type& dest, const void* buffer); - - private: //not implemented - - /** - * Copies the contents of an existing group -- not implemented - */ - Group(const Group& other); - - /** - * Assigns the contents of an existing group to myself -- not - * implemented - */ - Group& operator= (const Group& other); - - private: //representation - - std::string m_name; ///< my name - boost::shared_ptr<hid_t> m_id; ///< the HDF5 Group this object points to - boost::weak_ptr<Group> m_parent; - std::map<std::string, boost::shared_ptr<Group> > m_groups; - std::map<std::string, boost::shared_ptr<Dataset> > m_datasets; - //std::map<std::string, boost::shared_ptr<Attribute> > m_attributes; - - }; - - /** - * The RootGroup is a special case of the Group object that is directly - * attached to the File (no parents). - */ - class RootGroup: public Group { - - public: //api - - /** - * Binds to the root group of a file. - */ - RootGroup(boost::shared_ptr<File> parent); - - /** - * D'tor - presently, does nothing - */ - virtual ~RootGroup(); - - /** - * Get parent group - */ - virtual const boost::shared_ptr<Group> parent() const { - return boost::shared_ptr<Group>(); - } - - /** - * Get parent group - */ - virtual boost::shared_ptr<Group> parent() { - return boost::shared_ptr<Group>(); - } - - /** - * Filename where I'm sitting - */ - virtual const std::string& filename() const; - - /** - * Full path to myself. Constructed each time it is called. - */ - virtual std::string path() const { - return ""; - } - - /** - * Access file - */ - virtual const boost::shared_ptr<File> file() const { - return m_parent.lock(); - } - - virtual boost::shared_ptr<File> file() { - return m_parent.lock(); - } - - private: //representation - - boost::weak_ptr<File> m_parent; ///< the file I belong to - - }; - - /** - * std::string specialization - */ - template <> void Group::set_attribute<std::string>(const std::string& name, const std::string& v); - template <> std::string Group::get_attribute(const std::string& name) const; - -}}}}} - -#endif /* BOB_IO_BASE_HDF5GROUP_H */ diff --git a/bob/io/base/include/bob.io.base/HDF5Types.h b/bob/io/base/include/bob.io.base/HDF5Types.h deleted file mode 100644 index d19eab341873aafd33d2d4342fede82f5d7d3c79..0000000000000000000000000000000000000000 --- a/bob/io/base/include/bob.io.base/HDF5Types.h +++ /dev/null @@ -1,508 +0,0 @@ -/** - * @date Wed Jun 22 17:50:08 2011 +0200 - * @author Andre Anjos <andre.anjos@idiap.ch> - * - * @brief A few helpers to handle HDF5 datasets in a more abstract way. - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_IO_BASE_HDF5TYPES_H -#define BOB_IO_BASE_HDF5TYPES_H - -#include <vector> -#include <string> -#include <boost/shared_ptr.hpp> -#include <blitz/array.h> -#include <hdf5.h> - -/** - * Checks if the version of HDF5 installed is greater or equal to some set of - * values. (extracted from hdf5-1.8.7) - */ -#ifndef H5_VERSION_GE -#define H5_VERSION_GE(Maj,Min,Rel) \ - (((H5_VERS_MAJOR==Maj) && (H5_VERS_MINOR==Min) && (H5_VERS_RELEASE>=Rel)) || \ - ((H5_VERS_MAJOR==Maj) && (H5_VERS_MINOR>Min)) || \ - (H5_VERS_MAJOR>Maj)) -#endif - -#include <bob.io.base/array.h> - -namespace bob { namespace io { namespace base { - - /** - * Supported types - */ - typedef enum hdf5type { - s=0, //std::string - b, //bool - i8, //int8_t - i16, //int16_t - i32, //int32_t - i64, //int64_t - u8, //uint8_t - u16, //uint16_t - u32, //uint32_t - u64, //uint64_t - f32, //float - f64, //double - f128, //long double - c64, //std::complex<float> - c128, //std::complex<double> - c256, //std::complex<long double> - unsupported //this must be last - } hdf5type; - - /** - * Converts a hdf5type enumeration into its string representation - */ - const char* stringize (hdf5type t); - - /** - * A wrapper to handle the HDF5 C-API error printing in a nicer way... - */ - class HDF5ErrorStack { - - public: //api - - /** - * Binds the HDF5Error to the current default error stack. - */ - HDF5ErrorStack (); - - /** - * Binds to a specific HDF5 error stack - */ - HDF5ErrorStack (hid_t stack); - - /** - * Destructor virtualization. - */ - virtual ~HDF5ErrorStack(); - - /** - * Returns the currently captured error stack - */ - inline std::vector<std::string>& get() { return m_err; } - - /** - * Clears the current error stack - */ - inline void clear() { m_err.clear(); } - - /** - * Sets muting - */ - inline void mute () { m_muted = true; } - inline void unmute () { m_muted = false; } - inline bool muted () const { return m_muted; } - - private: //not implemented - - HDF5ErrorStack(const HDF5ErrorStack& other); - - HDF5ErrorStack& operator= (const HDF5ErrorStack& other); - - private: //representation - hid_t m_stack; ///< the stack I'm observing - bool m_muted; ///< if I'm currently muted - std::vector<std::string> m_err; ///< the current captured stack - herr_t (*m_func)(hid_t, void*); ///< temporary cache - void* m_client_data; ///< temporary cache - - }; - - // Global default HDF5 error stack - extern const boost::shared_ptr<HDF5ErrorStack> DefaultHDF5ErrorStack; - - /** - * This class defines the shape type: a counter and a variable-size hsize_t - * array that contains the dimensionality of a certain array. Internally, we - * always allocate a fixed size vector with 12 positions (after the maximum - * number of dimensions of a blitz::Array<T,N> + 1). - */ - class HDF5Shape { - -# define MAX_HDF5SHAPE_SIZE 12 - - public: //api - - /** - * Builds a new shape with a certain size and values. The size has to be - * smaller than the maximum number of supported dimensions (12). - */ - template <typename T> HDF5Shape(const size_t n, const T* values): - m_n(n), m_shape() { - if (n > MAX_HDF5SHAPE_SIZE) - throw std::length_error("maximum number of dimensions exceeded"); - for (size_t i=0; i<n; ++i) m_shape[i] = values[i]; - } - - /** - * Builds a new shape with data from a blitz::TinyVector - */ - template <int N> HDF5Shape(const blitz::TinyVector<int,N>& vec): - m_n(N), m_shape() { - if (N > MAX_HDF5SHAPE_SIZE) - throw std::length_error("maximum number of dimensions exceeded"); - for (size_t i=0; i<N; ++i) m_shape[i] = vec[i]; - } - - /** - * Allocates the shape space, but fills all with zeros - */ - HDF5Shape (size_t n); - - /** - * Default constructor (m_n = 0, no shape) - */ - HDF5Shape (); - - /** - * Copy construct the shape - */ - HDF5Shape (const HDF5Shape& other); - - /** - * Virtual destructor - */ - virtual ~HDF5Shape(); - - /** - * Resets this new shape - */ - HDF5Shape& operator= (const HDF5Shape& other); - - /** - * Returns the current size of shape. If values are less than zero, the - * shape is not valid. - */ - inline size_t n () const { return m_n; } - - /** - * Returs a pointer to the first element of the shape - */ - inline const hsize_t* get() const { return m_shape; } - inline hsize_t* get() { return m_shape; } - - /** - * Copies the data from the other HDF5Shape. If the other shape is - * smaller, will copy up to the number of positions in the other shape, - * if it is bigger, will copy up to my number of positions. - */ - void copy(const HDF5Shape& other); - - /** - * Sets a TinyVector with the contents of this shape. If the tinyvector - * shape is smaller, will copy up to the number of positions in the - * current shape. If that is bigger, will copy up to my number of - * positions - */ - template <int N> void set (blitz::TinyVector<int,N>& v) const { - if (N >= m_n) for (size_t i=0; i<m_n; ++i) v[i] = m_shape[i]; - else for (size_t i=0; i<N; ++i) v[i] = m_shape[i]; - } - - /** - * Resets the current shape so it becomes invalid. - */ - void reset(); - - /** - * Accesses a certain position of this shape (unchecked!) - */ - inline const hsize_t& operator[] (size_t pos) const { return m_shape[pos]; } - inline hsize_t& operator[] (size_t pos) { return m_shape[pos]; } - - /** - * Left-shift a number of positions, decreases the total size. - */ - HDF5Shape& operator <<= (size_t pos); - - /** - * Right-shift a number of positions, increases the total size. New - * positions are filled with 1's (ones). - */ - HDF5Shape& operator >>= (size_t pos); - - /** - * Returns the product of all dimensions - */ - hsize_t product() const; - - /** - * Compares two shapes for equality - */ - bool operator== (const HDF5Shape& other) const; - bool operator!= (const HDF5Shape& other) const; - - /** - * Compares a shape with a TinyVector for equality - */ - template <int N> - bool operator== (const blitz::TinyVector<int,N>& other) const { - if (N != m_n) return false; - for (size_t i=0; i<m_n; ++i) if (m_shape[i] != other[i]) return false; - return true; - } - - template <int N> - bool operator!= (const blitz::TinyVector<int,N>& other) const { - return !(*this == other); - } - - /** - * Tells if this shape is invalid - */ - inline bool operator! () const { return m_n == 0; } - - /** - * Returns a tuple-like string representation for this shape - */ - std::string str() const; - - private: //representation - size_t m_n; ///< The number of valid hsize_t's in this shape - hsize_t m_shape[MAX_HDF5SHAPE_SIZE]; ///< The actual shape values - - }; - - /** - * Support to compare data types, convert types into runtime equivalents and - * make our life easier when deciding what to input and output. - */ - class HDF5Type { - - public: - - /** - * Specific implementations bind the type T to the support_t enum - */ -# define DECLARE_SUPPORT(T) HDF5Type(const T& value); - DECLARE_SUPPORT(bool) - DECLARE_SUPPORT(int8_t) - DECLARE_SUPPORT(int16_t) - DECLARE_SUPPORT(int32_t) - DECLARE_SUPPORT(int64_t) - DECLARE_SUPPORT(uint8_t) - DECLARE_SUPPORT(uint16_t) - DECLARE_SUPPORT(uint32_t) - DECLARE_SUPPORT(uint64_t) - DECLARE_SUPPORT(float) - DECLARE_SUPPORT(double) - DECLARE_SUPPORT(long double) - DECLARE_SUPPORT(std::complex<float>) - DECLARE_SUPPORT(std::complex<double>) - DECLARE_SUPPORT(std::complex<long double>) -# undef DECLARE_SUPPORT - - /** - * Builds the type from a string (special HDF5 handling) - */ - HDF5Type(const char* value); - HDF5Type(const std::string& value); - -# define DECLARE_SUPPORT(T,N) HDF5Type(const blitz::Array<T,N>& value); - -# define DECLARE_BZ_SUPPORT(T) \ - DECLARE_SUPPORT(T,1) \ - DECLARE_SUPPORT(T,2) \ - DECLARE_SUPPORT(T,3) \ - DECLARE_SUPPORT(T,4) - - DECLARE_BZ_SUPPORT(bool) - DECLARE_BZ_SUPPORT(int8_t) - DECLARE_BZ_SUPPORT(int16_t) - DECLARE_BZ_SUPPORT(int32_t) - DECLARE_BZ_SUPPORT(int64_t) - DECLARE_BZ_SUPPORT(uint8_t) - DECLARE_BZ_SUPPORT(uint16_t) - DECLARE_BZ_SUPPORT(uint32_t) - DECLARE_BZ_SUPPORT(uint64_t) - DECLARE_BZ_SUPPORT(float) - DECLARE_BZ_SUPPORT(double) - DECLARE_BZ_SUPPORT(long double) - DECLARE_BZ_SUPPORT(std::complex<float>) - DECLARE_BZ_SUPPORT(std::complex<double>) - DECLARE_BZ_SUPPORT(std::complex<long double>) -# undef DECLARE_BZ_SUPPORT -# undef DECLARE_SUPPORT - - /** - * Default constructor, results in an unsupported type with invalid shape - */ - HDF5Type(); - - /** - * Creates a HDF5Type from a type enumeration, assumes it is a scalar - */ - HDF5Type(hdf5type type); - - /** - * Creates a HDF5Type from an bob::io::base::array::typeinfo - */ - HDF5Type(const bob::io::base::array::typeinfo& ti); - - /** - * Creates a HDF5Type from a type enumeration and an explicit shape - */ - HDF5Type(bob::io::base::array::ElementType eltype, const HDF5Shape& extents); - - /** - * Creates a HDF5Type from a type enumeration and an explicit shape - */ - HDF5Type(hdf5type type, const HDF5Shape& extents); - - /** - * Creates a HDF5Type from a HDF5 Dataset, Datatype and Dataspace - */ - HDF5Type(const boost::shared_ptr<hid_t>& type, - const HDF5Shape& extents); - - /** - * Scalar of a certain type - */ - HDF5Type(const boost::shared_ptr<hid_t>& type); - - /** - * Copy construction - */ - HDF5Type(const HDF5Type& other); - - /** - * Virtual destructor - */ - virtual ~HDF5Type(); - - /** - * Assignment - */ - HDF5Type& operator= (const HDF5Type& other); - - /** - * Checks if two types are the same - */ - bool operator== (const HDF5Type& other) const; - - /** - * Checks if two types are *not* the same - */ - bool operator!= (const HDF5Type& other) const; - - /** - * Checks if an existing object is compatible with my type - */ - template <typename T> bool compatible (const T& value) const { - return *this == HDF5Type(value); - } - - /** - * Checks if an existing object is compatible with my type - */ - bool compatible (const bob::io::base::array::typeinfo& value) const; - - /** - * Returns the HDF5Shape of this type - */ - const HDF5Shape& shape() const { return m_shape; } - - /** - * Returns the HDF5Shape of this type - */ - HDF5Shape& shape() { return m_shape; } - - /** - * Returns the equivalent HDF5 type info object for this type. - */ - boost::shared_ptr<hid_t> htype() const; - - /** - * Returns a string representation of this supported type. - */ - std::string str() const; - - /** - * Returns a string representation of the element type. - */ - std::string type_str() const { return stringize(m_type); } - - /** - * Returns the current enumeration for the type - */ - inline hdf5type type() const { return m_type; } - - /** - * Returns a mapping between the current type and the supported element - * types in bob::io::base::array - */ - bob::io::base::array::ElementType element_type() const; - - /** - * Copies this type information to a stock bob::io::base::array::typeinfo - */ - void copy_to (bob::io::base::array::typeinfo& ti) const; - - private: //representation - - hdf5type m_type; ///< the precise supported type - HDF5Shape m_shape; ///< what is the shape of the type (scalar) - - }; - - /** - * Describes ways to read a Dataset. - */ - struct HDF5Descriptor { - - public: //api - - /** - * Constructor - */ - HDF5Descriptor(const HDF5Type& type, size_t size = 0, bool expand = true); - - /** - * Copy constructor - */ - HDF5Descriptor(const HDF5Descriptor& other); - - /** - * Virtual destructor - */ - virtual ~HDF5Descriptor(); - - /** - * Assignment - */ - HDF5Descriptor& operator= (const HDF5Descriptor& other); - - /** - * Setup myself as I was supposed to be read from a space with N+1 - * dimensions. - */ - HDF5Descriptor& subselect(); - - public: //representation - - HDF5Type type; ///< base type for read/write operations - size_t size; ///< number of objects of this type stored at dataset - bool expandable; ///< is this dataset expandable using this type? - - /** - * Variables required for fast read/write operations. - */ - HDF5Shape hyperslab_start; ///< offset to read/write operations - HDF5Shape hyperslab_count; ///< count for read/write operations - - }; - - /** - * Format and returns the current HDF5 error stack. It also clears the stack - * before returning. - */ - std::string format_hdf5_error(); - -}}} - -#endif /* BOB_IO_BASE_HDF5TYPES_H */ diff --git a/bob/io/base/include/bob.io.base/HDF5Utils.h b/bob/io/base/include/bob.io.base/HDF5Utils.h deleted file mode 100644 index 670430e2b4ffdf47d16c4953b593b89ba5352058..0000000000000000000000000000000000000000 --- a/bob/io/base/include/bob.io.base/HDF5Utils.h +++ /dev/null @@ -1,135 +0,0 @@ -/** - * @date Wed Jun 22 17:50:08 2011 +0200 - * @author Andre Anjos <andre.anjos@idiap.ch> - * - * @brief A bunch of private utilities to make programming against the HDF5 - * library a little bit more confortable. - * - * Classes and non-member methods in this file handle the low-level HDF5 C-API - * and try to make it a little bit safer and higher-level for use by the - * publicly visible HDF5File class. The functionality here is heavily based on - * boost::shared_ptr's for handling automatic deletion and releasing of HDF5 - * objects. Two top-level classes do the whole work: File and Dataset. The File - * class represents a raw HDF5 file. You can iterate with it in a very limited - * way: create one, rename an object or delete one. The Dataset object - * encapsulates reading and writing of data from a specific HDF5 dataset. - * Everything is handled automatically and the user should not have to worry - * about it too much. - * - * @todo Missing support for list<std::string> - * @todo Inprint file creation time, author, comments? - * @todo Missing support for automatic endianness conversion - * @todo Missing true support for scalars - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_IO_BASE_HDF5UTILS_H -#define BOB_IO_BASE_HDF5UTILS_H - -#include <boost/filesystem.hpp> -#include <boost/shared_ptr.hpp> -#include <boost/enable_shared_from_this.hpp> -#include <hdf5.h> - -#include <bob.io.base/HDF5Group.h> - -namespace bob { namespace io { namespace base { namespace detail { namespace hdf5 { - - /** - * An HDF5 C-style file that knows how to close itself. - */ - class File: public boost::enable_shared_from_this<File> { - - public: - - /** - * Creates a new HDF5 file. Optionally set the userblock size (multiple - * of 2 number of bytes). - */ - File(const boost::filesystem::path& path, unsigned int flags, - size_t userblock_size=0); - - /** - * Copies a file by creating a copy of each of its groups - */ - File(const File& other); - - /** - * Destructor virtualization - */ - virtual ~File(); - - /** - * Assignment - */ - File& operator= (const File& other); - - /** - * Accesses the current location id of this file - */ - const boost::shared_ptr<hid_t> location() const { - return m_id; - } - boost::shared_ptr<hid_t> location() { - return m_id; - } - - /** - * Returns the userblock size - */ - size_t userblock_size() const; - - /** - * Copies the userblock into a string -- not yet implemented. If you want - * to do it, read the code for the command-line utilitlies h5jam and - * h5unjam. - */ - void get_userblock(std::string& data) const; - - /** - * Writes new data to the user block. Data is truncated up to the size - * set during file creation -- not yet implemented. If you want to do it, - * read the code for the command-line utilitlies h5jam and h5unjam. - */ - void set_userblock(const std::string& data); - - /** - * Gets the current path - */ - const std::string& filename() const { - return m_path.string(); - } - - /** - * Returns the root group - */ - boost::shared_ptr<RootGroup> root(); - - /** - * Resets this file, sets to read again all groups and datasets - */ - void reset(); - - /** - * Flushes the current content of the file to disk - */ - void flush(); - - /** - * Tells if this file is writable - */ - bool writable() const; - - private: //representation - - const boost::filesystem::path m_path; ///< path to the file - unsigned int m_flags; ///< flags used to open it - boost::shared_ptr<hid_t> m_fcpl; ///< file creation property lists - boost::shared_ptr<hid_t> m_id; ///< the HDF5 id attributed to this file. - boost::shared_ptr<RootGroup> m_root; - }; - -}}}}} - -#endif /* BOB_IO_BASE_HDF5UTILS_H */ diff --git a/bob/io/base/include/bob.io.base/api.h b/bob/io/base/include/bob.io.base/api.h deleted file mode 100644 index fe714e4b8ed873031c4ba672f4d43345ef1858e0..0000000000000000000000000000000000000000 --- a/bob/io/base/include/bob.io.base/api.h +++ /dev/null @@ -1,304 +0,0 @@ -/** - * @author Andre Anjos <andre.anjos@idiap.ch> - * @date Tue 5 Nov 12:22:48 2013 - * - * @brief Python API for bob::io::base - */ - -#ifndef BOB_IO_BASE_H -#define BOB_IO_BASE_H - -/* Define Module Name and Prefix for other Modules - Note: We cannot use BOB_EXT_* macros here, unfortunately */ -#define BOB_IO_BASE_PREFIX "bob.io.base" -#define BOB_IO_BASE_FULL_NAME "bob.io.base._library" - -#include <Python.h> - -#include <bob.io.base/config.h> -#include <bob.io.base/File.h> -#include <bob.io.base/CodecRegistry.h> -#include <bob.io.base/HDF5File.h> - -#include <boost/shared_ptr.hpp> - -/******************* - * C API functions * - *******************/ - -/* Enum defining entries in the function table */ -enum _PyBobIo_ENUM{ - PyBobIo_APIVersion_NUM = 0, - // Bindings for bob.io.base.File - PyBobIoFile_Type_NUM, - PyBobIoFileIterator_Type_NUM, - // I/O generic bindings - PyBobIo_AsTypenum_NUM, - PyBobIo_TypeInfoAsTuple_NUM, - PyBobIo_FilenameConverter_NUM, - // HDF5 bindings - PyBobIoHDF5File_Type_NUM, - PyBobIoHDF5File_Check_NUM, - PyBobIoHDF5File_Converter_NUM, - // Codec registration and de-registration - PyBobIoCodec_Register_NUM, - PyBobIoCodec_Deregister_NUM, - PyBobIoCodec_IsRegistered_NUM, - PyBobIoCodec_GetDescription_NUM, - // Total number of C API pointers - PyBobIo_API_pointers -}; - -/************** - * Versioning * - **************/ - -#define PyBobIo_APIVersion_TYPE int - -/********************************** - * Bindings for bob.io.base.File * - **********************************/ - -/* Type definition for PyBobIoFileObject */ -typedef struct { - PyObject_HEAD - - /* Type-specific fields go here. */ - boost::shared_ptr<bob::io::base::File> f; - -} PyBobIoFileObject; - -#define PyBobIoFile_Type_TYPE PyTypeObject - -typedef struct { - PyObject_HEAD - - /* Type-specific fields go here. */ - PyBobIoFileObject* pyfile; - Py_ssize_t curpos; - -} PyBobIoFileIteratorObject; - -#define PyBobIoFileIterator_Type_TYPE PyTypeObject - -/************************ - * I/O generic bindings * - ************************/ - -#define PyBobIo_AsTypenum_RET int -#define PyBobIo_AsTypenum_PROTO (bob::io::base::array::ElementType et) - -#define PyBobIo_TypeInfoAsTuple_RET PyObject* -#define PyBobIo_TypeInfoAsTuple_PROTO (const bob::io::base::array::typeinfo& ti) - -#define PyBobIo_FilenameConverter_RET int -#define PyBobIo_FilenameConverter_PROTO (PyObject* o, const char** b) - -/***************** - * HDF5 bindings * - *****************/ - -typedef struct { - PyObject_HEAD - - /* Type-specific fields go here. */ - boost::shared_ptr<bob::io::base::HDF5File> f; - -} PyBobIoHDF5FileObject; - -#define PyBobIoHDF5File_Type_TYPE PyTypeObject - -#define PyBobIoHDF5File_Check_RET int -#define PyBobIoHDF5File_Check_PROTO (PyObject* o) - -#define PyBobIoHDF5File_Converter_RET int -#define PyBobIoHDF5File_Converter_PROTO (PyObject* o, PyBobIoHDF5FileObject** a) - -/***************************************** - * Code Registration and De-registration * - *****************************************/ - -#define PyBobIoCodec_Register_RET int -#define PyBobIoCodec_Register_PROTO (const char* extension, const char* description, bob::io::base::file_factory_t factory) - -#define PyBobIoCodec_Deregister_RET int -#define PyBobIoCodec_Deregister_PROTO (const char* extension) - -#define PyBobIoCodec_IsRegistered_RET int -#define PyBobIoCodec_IsRegistered_PROTO (const char* extension) - -#define PyBobIoCodec_GetDescription_RET const char* -#define PyBobIoCodec_GetDescription_PROTO (const char* extension) - -#ifdef BOB_IO_BASE_MODULE - - /* This section is used when compiling `bob.io.base' itself */ - - /************** - * Versioning * - **************/ - - extern int PyBobIo_APIVersion; - - /********************************** - * Bindings for bob.io.base.File * - **********************************/ - - extern PyBobIoFile_Type_TYPE PyBobIoFile_Type; - extern PyBobIoFileIterator_Type_TYPE PyBobIoFileIterator_Type; - - /************************ - * I/O generic bindings * - ************************/ - - PyBobIo_AsTypenum_RET PyBobIo_AsTypenum PyBobIo_AsTypenum_PROTO; - - PyBobIo_TypeInfoAsTuple_RET PyBobIo_TypeInfoAsTuple PyBobIo_TypeInfoAsTuple_PROTO; - - PyBobIo_FilenameConverter_RET PyBobIo_FilenameConverter PyBobIo_FilenameConverter_PROTO; - -/***************** - * HDF5 bindings * - *****************/ - - extern PyBobIoHDF5File_Type_TYPE PyBobIoHDF5File_Type; - - PyBobIoHDF5File_Check_RET PyBobIoHDF5File_Check PyBobIoHDF5File_Check_PROTO; - - PyBobIoHDF5File_Converter_RET PyBobIoHDF5File_Converter PyBobIoHDF5File_Converter_PROTO; - -/***************************************** - * Code Registration and De-registration * - *****************************************/ - - PyBobIoCodec_Register_RET PyBobIoCodec_Register PyBobIoCodec_Register_PROTO; - - PyBobIoCodec_Deregister_RET PyBobIoCodec_Deregister PyBobIoCodec_Deregister_PROTO; - - PyBobIoCodec_IsRegistered_RET PyBobIoCodec_IsRegistered PyBobIoCodec_IsRegistered_PROTO; - - PyBobIoCodec_GetDescription_RET PyBobIoCodec_GetDescription PyBobIoCodec_GetDescription_PROTO; - -#else // BOB_IO_BASE_MODULE - - /* This section is used in modules that use `bob.io.base's' C-API */ - -# if defined(NO_IMPORT_ARRAY) - extern void **PyBobIo_API; -# else -# if defined(PY_ARRAY_UNIQUE_SYMBOL) - void **PyBobIo_API; -# else - static void **PyBobIo_API=NULL; -# endif -# endif - - /************** - * Versioning * - **************/ - -# define PyBobIo_APIVersion (*(PyBobIo_APIVersion_TYPE *)PyBobIo_API[PyBobIo_APIVersion_NUM]) - - /***************************** - * Bindings for bob.io.File * - *****************************/ - -# define PyBobIoFile_Type (*(PyBobIoFile_Type_TYPE *)PyBobIo_API[PyBobIoFile_Type_NUM]) -# define PyBobIoFileIterator_Type (*(PyBobIoFileIterator_Type_TYPE *)PyBobIo_API[PyBobIoFileIterator_Type_NUM]) - - /************************ - * I/O generic bindings * - ************************/ - -# define PyBobIo_AsTypenum (*(PyBobIo_AsTypenum_RET (*)PyBobIo_AsTypenum_PROTO) PyBobIo_API[PyBobIo_AsTypenum_NUM]) - -# define PyBobIo_TypeInfoAsTuple (*(PyBobIo_TypeInfoAsTuple_RET (*)PyBobIo_TypeInfoAsTuple_PROTO) PyBobIo_API[PyBobIo_TypeInfoAsTuple_NUM]) - -# define PyBobIo_FilenameConverter (*(PyBobIo_FilenameConverter_RET (*)PyBobIo_FilenameConverter_PROTO) PyBobIo_API[PyBobIo_FilenameConverter_NUM]) - - /***************** - * HDF5 bindings * - *****************/ - -# define PyBobIoHDF5File_Type (*(PyBobIoHDF5File_Type_TYPE *)PyBobIo_API[PyBobIoHDF5File_Type_NUM]) - -# define PyBobIoHDF5File_Check (*(PyBobIoHDF5File_Check_RET (*)PyBobIoHDF5File_Check_PROTO) PyBobIo_API[PyBobIoHDF5File_Check_NUM]) - -# define PyBobIoHDF5File_Converter (*(PyBobIoHDF5File_Converter_RET (*)PyBobIoHDF5File_Converter_PROTO) PyBobIo_API[PyBobIoHDF5File_Converter_NUM]) - -/***************************************** - * Code Registration and De-registration * - *****************************************/ - -# define PyBobIoCodec_Register (*(PyBobIoCodec_Register_RET (*)PyBobIoCodec_Register_PROTO) PyBobIo_API[PyBobIoCodec_Register_NUM]) - -# define PyBobIoCodec_Deregister (*(PyBobIoCodec_Deregister_RET (*)PyBobIoCodec_Deregister_PROTO) PyBobIo_API[PyBobIoCodec_Deregister_NUM]) - -# define PyBobIoCodec_IsRegistered (*(PyBobIoCodec_IsRegistered_RET (*)PyBobIoCodec_IsRegistered_PROTO) PyBobIo_API[PyBobIoCodec_IsRegistered_NUM]) - -# define PyBobIoCodec_GetDescription (*(PyBobIoCodec_GetDescription_RET (*)PyBobIoCodec_GetDescription_PROTO) PyBobIo_API[PyBobIoCodec_GetDescription_NUM]) - -# if !defined(NO_IMPORT_ARRAY) - - /** - * Returns -1 on error, 0 on success. - */ - static int import_bob_io_base(void) { - - PyObject *c_api_object; - PyObject *module; - - module = PyImport_ImportModule(BOB_IO_BASE_FULL_NAME); - - if (module == NULL) return -1; - - c_api_object = PyObject_GetAttrString(module, "_C_API"); - - if (c_api_object == NULL) { - Py_DECREF(module); - return -1; - } - -# if PY_VERSION_HEX >= 0x02070000 - if (PyCapsule_CheckExact(c_api_object)) { - PyBobIo_API = (void **)PyCapsule_GetPointer(c_api_object, - PyCapsule_GetName(c_api_object)); - } -# else - if (PyCObject_Check(c_api_object)) { - PyBobIo_API = (void **)PyCObject_AsVoidPtr(c_api_object); - } -# endif - - Py_DECREF(c_api_object); - Py_DECREF(module); - - if (!PyBobIo_API) { - PyErr_SetString(PyExc_ImportError, "cannot find C/C++ API " -# if PY_VERSION_HEX >= 0x02070000 - "capsule" -# else - "cobject" -# endif - " at `" BOB_IO_BASE_FULL_NAME "._C_API'"); - return -1; - } - - /* Checks that the imported version matches the compiled version */ - int imported_version = *(int*)PyBobIo_API[PyBobIo_APIVersion_NUM]; - - if (BOB_IO_BASE_API_VERSION != imported_version) { - PyErr_Format(PyExc_ImportError, BOB_IO_BASE_FULL_NAME " import error: you compiled against API version 0x%04x, but are now importing an API with version 0x%04x which is not compatible - check your Python runtime environment for errors", BOB_IO_BASE_API_VERSION, imported_version); - return -1; - } - - /* If you get to this point, all is good */ - return 0; - - } - -# endif //!defined(NO_IMPORT_ARRAY) - -#endif /* BOB_IO_BASE_MODULE */ - -#endif /* BOB_IO_BASE_H */ diff --git a/bob/io/base/include/bob.io.base/array.h b/bob/io/base/include/bob.io.base/array.h deleted file mode 100644 index 570c09f05f52fc115cc659f207c1137e080acce0..0000000000000000000000000000000000000000 --- a/bob/io/base/include/bob.io.base/array.h +++ /dev/null @@ -1,255 +0,0 @@ -/** - * @date Tue Nov 8 15:34:31 2011 +0100 - * @author Andre Anjos <andre.anjos@idiap.ch> - * - * @brief The array API describes a non-specific way to handle N dimensional - * array data. - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_IO_BASE_ARRAY_INTERFACE_H -#define BOB_IO_BASE_ARRAY_INTERFACE_H - -#include <stdexcept> -#include <string> - -#include <boost/shared_ptr.hpp> -#include <blitz/array.h> - -#include <bob.io.base/array_type.h> - -/* MinGW flags */ -#ifdef _WIN32 -#undef interface -#endif - -/** - * @brief Array submodule API of the I/O module - */ -namespace bob { namespace io { namespace base { namespace array { - - /** - * @brief Encapsulation of special type information of interfaces. - */ - struct typeinfo { - - ElementType dtype; ///< data type - size_t nd; ///< number of dimensions - size_t shape[BOB_MAX_DIM+1]; ///< length along each dimension - size_t stride[BOB_MAX_DIM+1]; ///< strides along each dimension - - /** - * @brief Default constructor - */ - typeinfo(); - - /** - * @brief Simplification to build a typeinfo from a size - */ - template <typename T> typeinfo(ElementType dtype_, T nd_) { - set(dtype_, nd_); - } - - /** - * @brief Simplification to build a typeinfo from a shape pointer. - */ - template <typename T> typeinfo(ElementType dtype_, T nd_, const T* shape_) { - set(dtype_, nd_, shape_); - } - - /** - * @brief Copies information from another typeinfo - */ - typeinfo(const typeinfo& other); - - /** - * @brief Assignment - */ - typeinfo& operator= (const typeinfo& other); - - /** - * @brief Builds with type and number of dimensions, but set the shape and - * strides to all zeros. - */ - template <typename T> - void set(ElementType dtype_, T nd_) { - dtype = dtype_; - nd = nd_; - reset_shape(); - } - - /** - * @brief Set to specific values - */ - template <typename T> - void set(ElementType dtype_, T nd_, const T* shape_) { - dtype = dtype_; - set_shape(nd_, shape_); - } - - /** - * @brief Set to specific values, including strides - */ - template <typename T> - void set(ElementType dtype_, T nd_, const T* shape_, - const T* stride_) { - dtype = dtype_; - nd = nd_; - for (size_t k=0; k<nd; ++k) { - shape[k] = shape_[k]; - stride[k] = stride_[k]; - } - } - - /** - * @brief Reset to defaults -- as if uninitialized. - */ - void reset(); - - /** - * @brief Is this a valid type information? - */ - bool is_valid() const; - - /** - * @brief Does this has a valid shape information? - */ - bool has_valid_shape() const; - - /** - * @brief sets the shape - */ - template <typename T> void set_shape(T nd_, const T* shape_) { - if (nd_ > (BOB_MAX_DIM+1)) - throw std::runtime_error("unsupported number of dimensions"); - nd = nd_; - for (size_t k=0; k<nd; ++k) shape[k] = shape_[k]; - update_strides(); - } - - /** - * @brief resets the shape to all zeros - */ - void reset_shape(); - - /** - * @brief Update my own stride vector. Called automatically after any use - * of set_shape(). - */ - void update_strides(); - - /** - * @brief Returns the total number of elements available - */ - size_t size() const; - - /** - * @brief Returns the size of each element - */ - inline size_t item_size() const { return getElementSize(dtype); } - - /** - * @brief Returns the total size (in bytes) of the buffer that I'm - * associated with. - */ - size_t buffer_size() const; - - /** - * @brief Returns the item type description - */ - const char* item_str() const { return stringize(dtype); } - - /** - * @brief Checks compatibility with other typeinfo - */ - bool is_compatible(const typeinfo& other) const; - - /** - * @brief Formats and returns a string containing the full typeinfo - * description. - */ - std::string str() const; - - /** - * @brief Make it easy to set for blitz::Array<T,N> - */ - template <typename T, int N> void set(const blitz::Array<T,N>& array) { - dtype = getElementType<T>(); - set_shape(array.shape()); - } - - template <typename T, int N> - void set(boost::shared_ptr<blitz::Array<T,N> >& array) { - dtype = getElementType<T>(); - set_shape(array->shape()); - } - - template <int N> void set_shape(const blitz::TinyVector<int,N>& tv_shape) { - nd = N; - for (size_t k=0; k<nd; ++k) shape[k] = tv_shape(k); - update_strides(); - } - - }; - - /** - * @brief The interface manager introduces a concept for managing the - * interfaces that can be handled as C-style arrays. It encapsulates methods - * to store and delete the buffer contents in a safe way. - * - * The interface is an entity that either stores a copy of its own data or - * refers to data belonging to another interface. - */ - class interface { - - public: //api - - /** - * @brief By default, the interface is never freed. You must override - * this method to do something special for your class type. - */ - virtual ~interface() { } - - /** - * @brief Copies the data from another interface. - */ - virtual void set(const interface& other) =0; - - /** - * @brief Refers to the data of another interface. - */ - virtual void set(boost::shared_ptr<interface> other) =0; - - /** - * @brief Re-allocates this interface taking into consideration new - * requirements. The internal memory should be considered uninitialized. - */ - virtual void set (const typeinfo& req) =0; - - /** - * @brief Type information for this interface. - */ - virtual const typeinfo& type() const =0; - - /** - * @brief Borrows a reference from the underlying memory. This means - * this object continues to be responsible for deleting the memory and - * you should make sure that it outlives the usage of the returned - * pointer. - */ - virtual void* ptr() =0; - virtual const void* ptr() const =0; - - /** - * @brief Returns a representation of the internal cache using shared - * pointers. - */ - virtual boost::shared_ptr<void> owner() =0; - virtual boost::shared_ptr<const void> owner() const =0; - - }; - -}}}} - -#endif /* BOB_IO_BASE_ARRAY_INTERFACE_H */ diff --git a/bob/io/base/include/bob.io.base/array_type.h b/bob/io/base/include/bob.io.base/array_type.h deleted file mode 100644 index 89eb1e26df2000beb040f2dc47aced0429029f6e..0000000000000000000000000000000000000000 --- a/bob/io/base/include/bob.io.base/array_type.h +++ /dev/null @@ -1,162 +0,0 @@ -/** - * @date Sat Apr 9 18:10:10 2011 +0200 - * @author Laurent El Shafey <Laurent.El-Shafey@idiap.ch> - * - * @brief This file contains information about the supported arrays - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_IO_BASE_ARRAY_TYPE_H -#define BOB_IO_BASE_ARRAY_TYPE_H - -#include <stdint.h> -#include <cstdlib> -#include <complex> - -/** - * @ingroup IO_ARRAY - * @brief This macro defines the maximum number of dimensions supported by bob. - * A variable in the bob.io.array namespace is created from this macro - * receiving the same value. Use that variable on your programs, or this macro - * on your preprocessor code. - */ -#define BOB_MAX_DIM 4 - -namespace bob { namespace io { namespace base { namespace array { - - /** - * @brief Enumeration of the supported type for multidimensional arrays - * @warning float128 and complex256 are defined but currently not - * supported - */ - typedef enum ElementType { - t_unknown=0, - t_bool=1, - t_int8=2, - t_int16=3, - t_int32=4, - t_int64=5, - t_uint8=6, - t_uint16=7, - t_uint32=8, - t_uint64=9, - t_float32=10, - t_float64=11, - t_float128=12, - t_complex64=13, - t_complex128=14, - t_complex256=15 - } ElementType; - - /** - * @brief Maximum number of supported dimensions for multidimensional - * arrays. - */ - const size_t N_MAX_DIMENSIONS_ARRAY = BOB_MAX_DIM; - - /** - * @brief These are some type to element type conversions - */ - template<typename T> ElementType getElementType() { - return t_unknown; - } - - /** - * @brief Some specializations that convert type to element type. - */ - template<> inline ElementType getElementType<bool>() { return t_bool; } - template<> inline ElementType getElementType<int8_t>() { return t_int8; } - template<> inline ElementType getElementType<int16_t>() - { return t_int16; } - template<> inline ElementType getElementType<int32_t>() - { return t_int32; } - template<> inline ElementType getElementType<int64_t>() - { return t_int64; } - template<> inline ElementType getElementType<uint8_t>() - { return t_uint8; } - template<> inline ElementType getElementType<uint16_t>() - { return t_uint16; } - template<> inline ElementType getElementType<uint32_t>() - { return t_uint32; } - template<> inline ElementType getElementType<uint64_t>() - { return t_uint64; } - template<> inline ElementType getElementType<float>() - { return t_float32; } - template<> inline ElementType getElementType<double>() - { return t_float64; } - template<> inline ElementType getElementType<long double>() - { return t_float128; } - template<> inline ElementType getElementType<std::complex<float> >() - { return t_complex64; } - template<> inline ElementType getElementType<std::complex<double> >() - { return t_complex128; } - template<> inline ElementType getElementType<std::complex<long double> >() - { return t_complex256; } - - /** - * @brief These are some type to element size conversions - */ - template<typename T> size_t getElementSize() { - return 0; - } - - /** - * @brief Some specializations that convert the types we handle properly - */ - template<> inline size_t getElementSize<bool>() { return sizeof(bool); } - template<> inline size_t getElementSize<int8_t>() - { return sizeof(int8_t); } - template<> inline size_t getElementSize<int16_t>() - { return sizeof(int16_t); } - template<> inline size_t getElementSize<int32_t>() - { return sizeof(int32_t); } - template<> inline size_t getElementSize<int64_t>() - { return sizeof(int64_t); } - template<> inline size_t getElementSize<uint8_t>() - { return sizeof(uint8_t); } - template<> inline size_t getElementSize<uint16_t>() - { return sizeof(uint16_t); } - template<> inline size_t getElementSize<uint32_t>() - { return sizeof(uint32_t); } - template<> inline size_t getElementSize<uint64_t>() - { return sizeof(uint64_t); } - template<> inline size_t getElementSize<float>() - { return sizeof(float); } - template<> inline size_t getElementSize<double>() - { return sizeof(double); } - template<> inline size_t getElementSize<long double>() - { return sizeof(long double); } - template<> inline size_t getElementSize<std::complex<float> >() - { return sizeof(std::complex<float>); } - template<> inline size_t getElementSize<std::complex<double> >() - { return sizeof(std::complex<double>); } - template<> inline size_t getElementSize<std::complex<long double> >() - { return sizeof(std::complex<long double>); } - - /** - * @brief Returns the type size given the enumeration - */ - size_t getElementSize(ElementType t); - - /** - * @brief Gets a string representation of an element type value - */ - const char* stringize(ElementType t); - - /** - * @brief Equivalent to call stringize() on the result of - * getElementType<T>(). - */ - template<typename T> const char* stringize() { - return stringize(getElementType<T>()); - } - - /** - * @brief Returns the ElementType given the string representation - */ - ElementType unstringize(const char* name); - -}}}} - -#endif /* BOB_IO_BASE_ARRAY_TYPE_H */ diff --git a/bob/io/base/include/bob.io.base/array_utils.h b/bob/io/base/include/bob.io.base/array_utils.h deleted file mode 100644 index 8fdfa77b4d6a1bb181031152255ab4a5fd685153..0000000000000000000000000000000000000000 --- a/bob/io/base/include/bob.io.base/array_utils.h +++ /dev/null @@ -1,133 +0,0 @@ -/** - * @date Tue Nov 8 15:34:31 2011 +0100 - * @author Andre Anjos <andre.anjos@idiap.ch> - * - * @brief Utilities for converting data to-from blitz::Arrays and other - * goodies. - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_IO_BASE_ARRAY_UTILS_H -#define BOB_IO_BASE_ARRAY_UTILS_H - -#include <blitz/array.h> -#include <stdint.h> -#include <stdexcept> -#include <boost/format.hpp> - -#include <bob.core/cast.h> -#include <bob.io.base/array.h> - -namespace bob { namespace io { namespace base { namespace array { - - /** - * @brief Fills in shape and stride starting from a typeinfo object - */ - template <int N> void set_shape_and_stride(const typeinfo& info, - blitz::TinyVector<int,N>& shape, blitz::TinyVector<int,N>& stride) { - for (int k=0; k<N; ++k) { - shape[k] = info.shape[k]; - stride[k] = info.stride[k]; - } - } - - - /** - * @brief Takes a data pointer and assumes it is a C-style array for the - * defined type. Creates a wrapper as a blitz::Array<T,N> with the same - * number of dimensions and type. Notice that the blitz::Array<> created - * will have its memory tied to the passed buffer. In other words you have - * to make sure that the buffer outlives the returned blitz::Array<>. - */ - template <typename T, int N> - blitz::Array<T,N> wrap(const interface& buf) { - - const typeinfo& type = buf.type(); - - if (!buf.ptr()) throw std::runtime_error("empty buffer"); - - if (type.dtype != bob::io::base::array::getElementType<T>()) { - boost::format m("cannot efficiently retrieve blitz::Array<%s,%d> from buffer of type '%s'"); - m % stringize<T>() % N % type.str(); - throw std::runtime_error(m.str()); - } - - if (type.nd != N) { - boost::format m("cannot retrieve blitz::Array<%s,%d> from buffer of type '%s'"); - m % stringize<T>() % N % type.str(); - throw std::runtime_error(m.str()); - } - - blitz::TinyVector<int,N> shape; - blitz::TinyVector<int,N> stride; - set_shape_and_stride(type, shape, stride); - - return blitz::Array<T,N>((T*)buf.ptr(), - shape, stride, blitz::neverDeleteData); - } - - - /** - * @brief Takes a data pointer and assumes it is a C-style array for the - * defined type. Creates a copy as a blitz::Array<T,N> with the same number - * of dimensions, but with a type as specified by you. If the type does not - * match the type of the original C-style array, a cast will happen. - * - * If a certain type cast is not supported. An appropriate exception will - * be raised. - */ - template <typename T, int N> - blitz::Array<T,N> cast(const interface& buf) { - - const typeinfo& type = buf.type(); - - if (type.nd != N) { - boost::format m("cannot cast blitz::Array<%s,%d> from buffer of type '%s'"); - m % stringize<T>() % N % type.str(); - throw std::runtime_error(m.str()); - } - - switch (type.dtype) { - case bob::io::base::array::t_bool: - return bob::core::array::cast<T>(wrap<bool,N>(buf)); - case bob::io::base::array::t_int8: - return bob::core::array::cast<T>(wrap<int8_t,N>(buf)); - case bob::io::base::array::t_int16: - return bob::core::array::cast<T>(wrap<int16_t,N>(buf)); - case bob::io::base::array::t_int32: - return bob::core::array::cast<T>(wrap<int32_t,N>(buf)); - case bob::io::base::array::t_int64: - return bob::core::array::cast<T>(wrap<int64_t,N>(buf)); - case bob::io::base::array::t_uint8: - return bob::core::array::cast<T>(wrap<uint8_t,N>(buf)); - case bob::io::base::array::t_uint16: - return bob::core::array::cast<T>(wrap<uint16_t,N>(buf)); - case bob::io::base::array::t_uint32: - return bob::core::array::cast<T>(wrap<uint32_t,N>(buf)); - case bob::io::base::array::t_uint64: - return bob::core::array::cast<T>(wrap<uint64_t,N>(buf)); - case bob::io::base::array::t_float32: - return bob::core::array::cast<T>(wrap<float,N>(buf)); - case bob::io::base::array::t_float64: - return bob::core::array::cast<T>(wrap<double,N>(buf)); - case bob::io::base::array::t_float128: - return bob::core::array::cast<T>(wrap<long double,N>(buf)); - case bob::io::base::array::t_complex64: - return bob::core::array::cast<T>(wrap<std::complex<float>,N>(buf)); - case bob::io::base::array::t_complex128: - return bob::core::array::cast<T>(wrap<std::complex<double>,N>(buf)); - case bob::io::base::array::t_complex256: - return bob::core::array::cast<T>(wrap<std::complex<long double>,N>(buf)); - default: - break; - } - - //if we get to this point, there is nothing much we can do... - throw std::runtime_error("invalid type on blitz buffer array casting -- debug me"); - - } - -}}}} - -#endif /* BOB_IO_BASE_ARRAY_UTILS_H */ diff --git a/bob/io/base/include/bob.io.base/blitz_array.h b/bob/io/base/include/bob.io.base/blitz_array.h deleted file mode 100644 index 083ec1d3245d2b3bc1f92e821b71eaeffe1de0b3..0000000000000000000000000000000000000000 --- a/bob/io/base/include/bob.io.base/blitz_array.h +++ /dev/null @@ -1,261 +0,0 @@ -/** - * @date Tue Nov 8 15:34:31 2011 +0100 - * @author Andre Anjos <andre.anjos@idiap.ch> - * - * @brief A class that implements the polimorphic behaviour required when - * reading and writing blitz arrays to disk or memory. - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_IO_BASE_BLITZ_ARRAY_H -#define BOB_IO_BASE_BLITZ_ARRAY_H - -#include <stdexcept> -#include <boost/make_shared.hpp> -#include <boost/format.hpp> -#include <blitz/array.h> - -#include <bob.core/check.h> -#include <bob.core/cast.h> -#include <bob.core/array_copy.h> - -#include <bob.io.base/array.h> -#include <bob.io.base/array_utils.h> -#include <bob.io.base/array_type.h> - -namespace bob { namespace io { namespace base { namespace array { - - /** - * @brief A blitz::Array representation of an array. - */ - class blitz_array: public interface { - - public: - - /** - * @brief Starts by refering to the data from another blitz array. - */ - blitz_array(boost::shared_ptr<blitz_array> other); - - /** - * @brief Starts by copying the data from another blitz array. - */ - blitz_array(const blitz_array& other); - - /** - * @brief Starts by refering to the data from another buffer. - */ - blitz_array(boost::shared_ptr<interface> other); - - /** - * @brief Starts by copying the data from another buffer. - */ - blitz_array(const interface& other); - - /** - * @brief Starts with an uninitialized, pre-allocated array. - */ - blitz_array(const typeinfo& info); - - /** - * @brief Borrows the given pointer - if you use this constructor, you - * must make sure the pointed data outlives this object. - */ - blitz_array(void* data, const typeinfo& info); - - /** - * @brief Destroyes me - */ - virtual ~blitz_array(); - - /** - * @brief Copies the data from another buffer. - */ - virtual void set(const interface& other); - - /** - * @brief Refers to the data of another buffer. - */ - virtual void set(boost::shared_ptr<interface> other); - - /** - * @brief Re-allocates this buffer taking into consideration new - * requirements. The internal memory should be considered uninitialized. - */ - virtual void set (const typeinfo& req); - - /** - * @brief Refers to the data of another blitz array. - */ - void set(boost::shared_ptr<blitz_array> other); - - /** - * @brief Element type - */ - virtual const typeinfo& type() const { return m_type; } - - /** - * @brief Borrows a reference from the underlying memory. This means - * this object continues to be responsible for deleting the memory and - * you should make sure that it outlives the usage of the returned - * pointer. - */ - virtual void* ptr() { return m_ptr; } - virtual const void* ptr() const { return m_ptr; } - - virtual boost::shared_ptr<void> owner() { return m_data; } - virtual boost::shared_ptr<const void> owner() const { return m_data; } - - - /****************************************************************** - * Blitz Array specific manipulations - ******************************************************************/ - - - /** - * @brief Starts me with new arbitrary data. Please note we refer to the - * given array. External modifications to the array memory will affect - * me. If you don't want that to be the case, use the const variant. - */ - template <typename T, int N> - blitz_array(boost::shared_ptr<blitz::Array<T,N> > data) { - set(data); - } - - /** - * @brief Starts me with new arbitrary data. Please note we copy the - * given array. External modifications to the array memory will not - * affect me. If you don't want that to be the case, start with a - * non-const reference. - */ - template <typename T, int N> - blitz_array(const blitz::Array<T,N>& data) { - set(data); - } - - /** - * @brief Starts me with new arbitrary data. Please note we don't copy - * the given array. - * @warning Any resize of the given blitz::Array after this call leads to - * unexpected results - */ - template <typename T, int N> - blitz_array(blitz::Array<T,N>& data) { - set(data); - } - - /** - * @brief This method will set my internal data to the value you - * specify. We will do this by referring to the data you gave. - */ - template <typename T, int N> - void set(boost::shared_ptr<blitz::Array<T,N> > data) { - - if (getElementType<T>() == t_unknown) - throw std::runtime_error("unsupported element type on blitz::Array<>"); - if (N > BOB_MAX_DIM) - throw std::runtime_error("unsupported number of dimensions on blitz::Array<>"); - - if (!bob::core::array::isCContiguous(*data.get())) - throw std::runtime_error("cannot buffer'ize non-c contiguous array"); - - m_type.set(data); - - m_data = data; - m_ptr = reinterpret_cast<void*>(data->data()); - m_is_blitz = true; - } - - /** - * @brief This method will set my internal data to the value you - * specify. We will do this by copying the data you gave. - */ - template <typename T, int N> void set(const blitz::Array<T,N>& data) { - set(boost::make_shared<blitz::Array<T,N> >(bob::core::array::ccopy(data))); - } - - /** - * @brief This method will set my internal data to the value you specify. - * We will do this by referencing the data you gave. - * @warning Any resize of the given blitz::Array after this call leads to - * unexpected results - */ - template <typename T, int N> void set(blitz::Array<T,N>& data) { - set(boost::make_shared<blitz::Array<T,N> >(data)); - } - - /** - * @brief This method returns a reference to my internal data. It is the - * fastest way to get access to my data because it involves no data - * copying. This method has two limitations: - * - * 1) You need to know the correct type and number of dimensions or I'll - * throw an exception. - * - * 2) If this buffer was started by refering to another buffer's data - * which is not a blitz array, an exception will be raised. - * Unfortunately, blitz::Array<>'s do not offer a management mechanism - * for tracking external data allocation. The exception can be avoided - * and the referencing mechanism forced if you set the flag "temporary" - * to "true". In this mode, this method will always suceed, but the - * object returned will have its lifetime associated to this buffer. In - * other words, you should make sure this buffer outlives the returned - * blitz::Array<T,N>. - */ - template <typename T, int N> blitz::Array<T,N> get(bool temporary=false) { - - if (m_is_blitz) { - - if (!m_data) throw std::runtime_error("empty blitz array"); - - if (m_type.dtype != getElementType<T>()) { - boost::format m("cannot efficiently retrieve blitz::Array<%s,%d> from buffer of type '%s'"); - m % stringize<T>() % N % m_type.str(); - throw std::runtime_error(m.str()); - } - - if (m_type.nd != N) { - boost::format m("cannot retrieve blitz::Array<%s,%d> from buffer of type '%s'"); - m % stringize<T>() % N % m_type.str(); - throw std::runtime_error(m.str()); - } - - return *boost::static_pointer_cast<blitz::Array<T,N> >(m_data).get(); - } - - else { - - if (temporary) { //returns a temporary reference - return bob::io::base::array::wrap<T,N>(*this); - } - - else { - throw std::runtime_error("cannot get() external non-temporary non-blitz array buffer -- for a temporary object, set temporary=true; if you need the returned object to outlive this buffer; use copy() or cast()"); - } - } - - } - - /** - * @brief This method returns a copy to my internal data (not a - * reference) in the type you wish. It is the easiest method to use - * because I'll never throw, no matter which type you want to receive - * data at. Only get the number of dimensions right! - */ - template <typename T, int N> blitz::Array<T,N> cast() const { - return bob::io::base::array::cast<T,N>(*this); - } - - private: //representation - - typeinfo m_type; ///< type information - void* m_ptr; ///< pointer to the data - bool m_is_blitz; ///< true if initiated with a blitz::Array<> - boost::shared_ptr<void> m_data; ///< Pointer to the data owner - - }; - -}}}} - -#endif /* BOB_IO_BASE_BLITZ_ARRAY_H */ diff --git a/bob/io/base/include/bob.io.base/config.h b/bob/io/base/include/bob.io.base/config.h deleted file mode 100644 index cc07a9a3aae777e470d3db3ce142916b9d4ea859..0000000000000000000000000000000000000000 --- a/bob/io/base/include/bob.io.base/config.h +++ /dev/null @@ -1,47 +0,0 @@ -/** - * @author Andre Anjos <andre.anjos@idiap.ch> - * @date Fri 1 Nov 07:10:59 2013 - * - * @brief General directives for all modules in bob.io - */ - -#ifndef BOB_IO_BASE_CONFIG_H -#define BOB_IO_BASE_CONFIG_H - -/* Macros that define versions and important names */ -#define BOB_IO_BASE_API_VERSION 0x0201 - - -#ifdef BOB_IMPORT_VERSION - - /*************************************** - * Here we define some functions that should be used to build version dictionaries in the version.cpp file - * There will be a compiler warning, when these functions are not used, so use them! - ***************************************/ - - #include <Python.h> - #include <boost/preprocessor/stringize.hpp> - #include <hdf5.h> - - /** - * The version of HDF5 - */ - static PyObject* hdf5_version() { - boost::format f("%s.%s.%s"); - f % BOOST_PP_STRINGIZE(H5_VERS_MAJOR); - f % BOOST_PP_STRINGIZE(H5_VERS_MINOR); - f % BOOST_PP_STRINGIZE(H5_VERS_RELEASE); - return Py_BuildValue("s", f.str().c_str()); - } - - /** - * bob.io.base c/c++ api version - */ - static PyObject* bob_io_base_version() { - return Py_BuildValue("{ss}", "api", BOOST_PP_STRINGIZE(BOB_IO_BASE_API_VERSION)); - } - -#endif // BOB_IMPORT_VERSION - - -#endif /* BOB_IO_BASE_CONFIG_H */ diff --git a/bob/io/base/include/bob.io.base/reorder.h b/bob/io/base/include/bob.io.base/reorder.h deleted file mode 100644 index 09ebf50422392cb6da05b255c4d9738f5d71d445..0000000000000000000000000000000000000000 --- a/bob/io/base/include/bob.io.base/reorder.h +++ /dev/null @@ -1,94 +0,0 @@ -/** - * @date Tue Nov 22 11:24:44 2011 +0100 - * @author Andre Anjos <andre.anjos@idiap.ch> - * - * @brief Row-major to column-major reordering and vice-versa - * - * Copyright (C) Idiap Research Institute, Martigny, Switzerland - */ - -#ifndef BOB_IO_BASE_REORDER_H -#define BOB_IO_BASE_REORDER_H - -#include <stdint.h> - -#include <bob.io.base/array.h> - -namespace bob { namespace io { namespace base { - - /** - * Returns, on the first argument, the linear indexes by calculating the - * linear positions relative to both row-major and column-major order - * matrixes given a certain index accessing a position in the matrix and the - * matrix shape - * - * @param row The resulting row-major linear index. - * (row,col) is a 2-tuple with the results: row-major and - * column-major linear indexes - * @param col The resulting column-major linear index. (see above) - * @param i Index of the column. - * (i,j) a 2-tuple with the indexes as would be accessed - * [col][row]; this is the same as accessing the matrix like - * on directions [y][x] - * @param j Index of the row. (see above) - * @param shape a 2-tuple with the matrix shape like [col][row]; this is the - * same as thinking about the extends of the matrix like on directions - * [y][x] - * - * Detailed arithmetics with graphics and explanations can be found here: - * http://webster.cs.ucr.edu/AoA/Windows/HTML/Arraysa2.html - */ - void rc2d(size_t& row, size_t& col, const size_t i, const size_t j, - const size_t* shape); - - /** - * Same as above, but for a 3D array organized as [depth][column][row] - */ - void rc3d(size_t& row, size_t& col, const size_t i, const size_t j, - const size_t k, const size_t* shape); - - /** - * Same as above, but for a 4D array organized as [time][depth][column][row] - */ - void rc4d(size_t& row, size_t& col, const size_t i, const size_t j, - const size_t k, const size_t l, const size_t* shape); - - /** - * Converts the data from row-major order (C-Style) to column major order - * (Fortran style). Input parameters are the src data in row-major order, the - * destination (pre-allocated) array of the same size and the type - * information. - */ - void row_to_col_order(const void* src_, void* dst_, const - bob::io::base::array::typeinfo& info); - - /** - * Converts the data from column-major order (Fortran-Style) to row major - * order (C style), which is required by bob. Input parameters are the src - * data in column-major order, the destination (pre-allocated) array of the - * same size and the type information. - */ - void col_to_row_order(const void* src_, void* dst_, - const bob::io::base::array::typeinfo& info); - - /** - * Converts the data from row-major order (C-Style) to column major order - * (Fortran style). Input parameters are the src data in row-major order, the - * destination (pre-allocated) array of the same size and the type - * information. - */ - void row_to_col_order_complex(const void* src_, void* dst_re_, - void* dst_im_, const bob::io::base::array::typeinfo& info); - - /** - * Converts the data from column-major order (Fortran-Style) to row major - * order (C style), which is required by bob. Input parameters are the src - * data in column-major order, the destination (pre-allocated) array of the - * same size and the type information. - */ - void col_to_row_order_complex(const void* src_re_, const void* src_im_, - void* dst_, const bob::io::base::array::typeinfo& info); - -}}} - -#endif /* BOB_IO_BASE_REORDER_H */ diff --git a/bob/io/base/include/bob.io.base/utils.h b/bob/io/base/include/bob.io.base/utils.h deleted file mode 100644 index c42b1fac659dca6956dd241916aeeb2670c134c8..0000000000000000000000000000000000000000 --- a/bob/io/base/include/bob.io.base/utils.h +++ /dev/null @@ -1,105 +0,0 @@ -/** - * @author Andre Anjos <andre.anjos@idiap.ch> - * @date Wed 3 Oct 07:46:49 2012 - * - * @brief Utilities for easy manipulation of filed data. - */ - -#ifndef BOB_IO_BASE_BASE_UTILS_H -#define BOB_IO_BASE_BASE_UTILS_H - -#include <boost/shared_ptr.hpp> - -#include <bob.io.base/File.h> - -namespace bob { namespace io { namespace base { - - /** - * Creates a new array codec using the filename extension to determine which - * codec to use. The opening mode is passed to the underlying registered File - * implementation. - * - * Here are the meanings of the mode flag: - * - * 'r': opens for reading only - no modifications can occur; it is an - * error to open a file that does not exist for read-only operations. - * 'w': opens for reading and writing, but truncates the file if it - * exists; it is not an error to open files that do not exist with - * this flag. - * 'a': opens for reading and writing - any type of modification can - * occur. If the file does not exist, this flag is effectively like - * 'w'. - */ - boost::shared_ptr<File> open (const char* filename, char mode); - - /** - * Opens the file pretending it has a different extension (that is, using a - * different codec) then the one expected (if any). This allows you to write - * a file with the extension you want, but still using one of the available - * codecs. - */ - boost::shared_ptr<File> open (const char* filename, char mode, - const char* pretend_extension); - - /** - * Peeks the file and returns the typeinfo for reading individual frames (or - * samples) from the file. - * - * This method is equivalent to calling open() with 'r' as mode flag and then - * calling type() on the returned bob::io::base::File object. - */ - bob::io::base::array::typeinfo peek (const char* filename); - - /** - * Peeks the file and returns the typeinfo for reading the whole contents in - * a single shot. - * - * This method is equivalent to calling open() with 'r' as mode flag and then - * calling type_all() on the returned bob::io::base::File object. - */ - bob::io::base::array::typeinfo peek_all (const char* filename); - - /** - * Opens for reading and load all contents - * - * This method is equivalent to calling open() with 'r' as mode flag and then - * calling read_all() on the returned bob::io::base::File object. - */ - template <typename T, int N> blitz::Array<T,N> load (const char* filename) { - return open(filename, 'r')->read_all<T,N>(); - } - - /** - * Opens for reading and load a particular frame (or sample) - * - * This method is equivalent to calling open() with 'r' as mode flag and then - * calling read(index) on the returned bob::io::base::File object. - */ - template <typename T, int N> blitz::Array<T,N> load (const char* filename, size_t index) { - return open(filename, 'r')->read<T,N>(index); - } - - /** - * Opens for appending and add an array to it - * - * This method is equivalent to calling open() with 'a' as mode flag and then - * calling append(data) on the returned bob::io::base::File object. - */ - template <typename T, int N> void append (const char* filename, const blitz::Array<T,N>& data) { - open(filename, 'a')->append(data); - } - - /** - * Opens for writing and write an array to it. If the file exists before the - * call to this method, it is truncated. - * - * This method is equivalent to calling open() with 'w' as mode flag and then - * calling write(data) on the returned bob::io::base::File object. - */ - template <typename T, int N> void save (const char* filename, const blitz::Array<T,N>& data) { - open(filename, 'w')->write(data); - } - -}}} - -#endif /* BOB_IO_BASE_BASE_UTILS_H */ diff --git a/bob/io/base/main.cpp b/bob/io/base/main.cpp deleted file mode 100644 index 01a82d992e510b3c85ff5aad299e0c6b1347f487..0000000000000000000000000000000000000000 --- a/bob/io/base/main.cpp +++ /dev/null @@ -1,177 +0,0 @@ -/** - * @author Andre Anjos <andre.anjos@idiap.ch> - * @date Fri 25 Oct 16:54:55 2013 - * - * @brief Bindings to bob::io - */ - -#define BOB_IO_BASE_MODULE -#include <bob.io.base/api.h> - -#ifdef NO_IMPORT_ARRAY -#undef NO_IMPORT_ARRAY -#endif -#include <bob.blitz/capi.h> -#include <bob.blitz/cleanup.h> -#include <bob.extension/documentation.h> - -extern bool init_File(PyObject* module); -extern bool init_HDF5File(PyObject* module); - -/** - * Creates an str object, from a C or C++ string. Returns a **new - * reference**. - */ -static PyObject* make_object(const char* s) { - return Py_BuildValue("s", s); -} - -static auto s_extensions = bob::extension::FunctionDoc( - "extensions", - "Returns a dictionary containing all extensions and descriptions currently stored on the global codec registry", - "The extensions are returned as a dictionary from the filename extension to a description of the data format." -) -.add_prototype("", "extensions") -.add_return("extensions", "{str : str}", "A dictionary of supported extensions"); -static PyObject* PyBobIo_Extensions(PyObject*) { -BOB_TRY - typedef std::map<std::string, std::string> map_type; - const map_type& table = bob::io::base::CodecRegistry::getExtensions(); - - PyObject* retval = PyDict_New(); - if (!retval) return 0; - auto retval_ = make_safe(retval); - - for (auto it=table.begin(); it!=table.end(); ++it) { - PyObject* pyvalue = make_object(it->second.c_str()); - if (!pyvalue) return 0; - auto p_ = make_safe(pyvalue); - if (PyDict_SetItemString(retval, it->first.c_str(), pyvalue) != 0) { - return 0; - } - } - - return Py_BuildValue("O", retval); -BOB_CATCH_FUNCTION("extensions", 0); -} - -static PyMethodDef module_methods[] = { - { - s_extensions.name(), - (PyCFunction)PyBobIo_Extensions, - METH_NOARGS, - s_extensions.doc(), - }, - {0} /* Sentinel */ -}; - -PyDoc_STRVAR(module_docstr, "Core bob::io classes and methods"); - -int PyBobIo_APIVersion = BOB_IO_BASE_API_VERSION; - -#if PY_VERSION_HEX >= 0x03000000 -static PyModuleDef module_definition = { - PyModuleDef_HEAD_INIT, - BOB_EXT_MODULE_NAME, - module_docstr, - -1, - module_methods, - 0, 0, 0, 0 -}; -#endif - -static PyObject* create_module (void) { - -# if PY_VERSION_HEX >= 0x03000000 - PyObject* m = PyModule_Create(&module_definition); - auto m_ = make_xsafe(m); - const char* ret = "O"; -# else - PyObject* m = Py_InitModule3(BOB_EXT_MODULE_NAME, module_methods, module_docstr); - const char* ret = "N"; -# endif - if (!m) return 0; - - /* register some constants */ - if (!init_File(m)) return 0; - if (!init_HDF5File(m)) return 0; - - static void* PyBobIo_API[PyBobIo_API_pointers]; - - /* exhaustive list of C APIs */ - - /************** - * Versioning * - **************/ - - PyBobIo_API[PyBobIo_APIVersion_NUM] = (void *)&PyBobIo_APIVersion; - - /********************************** - * Bindings for bob.io.base.File * - **********************************/ - - PyBobIo_API[PyBobIoFile_Type_NUM] = (void *)&PyBobIoFile_Type; - - PyBobIo_API[PyBobIoFileIterator_Type_NUM] = (void *)&PyBobIoFileIterator_Type; - - /************************ - * I/O generic bindings * - ************************/ - - PyBobIo_API[PyBobIo_AsTypenum_NUM] = (void *)PyBobIo_AsTypenum; - - PyBobIo_API[PyBobIo_TypeInfoAsTuple_NUM] = (void *)PyBobIo_TypeInfoAsTuple; - - PyBobIo_API[PyBobIo_FilenameConverter_NUM] = (void *)PyBobIo_FilenameConverter; - - /***************** - * HDF5 bindings * - *****************/ - - PyBobIo_API[PyBobIoHDF5File_Type_NUM] = (void *)&PyBobIoHDF5File_Type; - - PyBobIo_API[PyBobIoHDF5File_Check_NUM] = (void *)&PyBobIoHDF5File_Check; - - PyBobIo_API[PyBobIoHDF5File_Converter_NUM] = (void *)&PyBobIoHDF5File_Converter; - -/***************************************** - * Code Registration and De-registration * - *****************************************/ - - PyBobIo_API[PyBobIoCodec_Register_NUM] = (void *)&PyBobIoCodec_Register; - - PyBobIo_API[PyBobIoCodec_Deregister_NUM] = (void *)&PyBobIoCodec_Deregister; - - PyBobIo_API[PyBobIoCodec_IsRegistered_NUM] = (void *)&PyBobIoCodec_IsRegistered; - - PyBobIo_API[PyBobIoCodec_GetDescription_NUM] = (void *)&PyBobIoCodec_GetDescription; - -#if PY_VERSION_HEX >= 0x02070000 - - /* defines the PyCapsule */ - - PyObject* c_api_object = PyCapsule_New((void *)PyBobIo_API, - BOB_EXT_MODULE_PREFIX "." BOB_EXT_MODULE_NAME "._C_API", 0); - -#else - - PyObject* c_api_object = PyCObject_FromVoidPtr((void *)PyBobIo_API, 0); - -#endif - - if (!c_api_object) return 0; - - if (PyModule_AddObject(m, "_C_API", c_api_object) < 0) return 0; - - /* imports dependencies */ - if (import_bob_blitz() < 0) return 0; - - return Py_BuildValue(ret, m); -} - -PyMODINIT_FUNC BOB_EXT_ENTRY_NAME (void) { -# if PY_VERSION_HEX >= 0x03000000 - return -# endif - create_module(); -} diff --git a/bob/io/base/test.cpp b/bob/io/base/test.cpp deleted file mode 100644 index 559535a05ce6f8adbbbfc9cdbc7c81c41044bb2a..0000000000000000000000000000000000000000 --- a/bob/io/base/test.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/** - * @author Manuel Gunther - * @date Tue Sep 13 13:01:31 MDT 2016 - * - * @brief Tests for bob::io::base - */ - -#include <bob.io.base/api.h> -#include <bob.blitz/cleanup.h> -#include <bob.extension/documentation.h> - -#include <boost/format.hpp> -#include <boost/filesystem.hpp> - -static auto s_test_api = bob::extension::FunctionDoc( - "_test_api", - "Some tests for API functions" -) -.add_prototype("tempdir") -.add_parameter("tempdir", "str", "A temporary directory to write data to") -; -static PyObject* _test_api(PyObject*, PyObject *args, PyObject* kwds){ -BOB_TRY - static char** kwlist = s_test_api.kwlist(); - - const char* tempdir; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s", kwlist, &tempdir)) return 0; - - blitz::Array<uint8_t, 1> test_data(5); - for (int i = 0; i < 5; ++i){ - test_data(i) = i+1; - } - - auto h5file = bob::io::base::CodecRegistry::instance()->findByExtension(".hdf5"); - - boost::filesystem::path hdf5(tempdir); hdf5 /= std::string("test.h5"); - - auto output = h5file(hdf5.string().c_str(), 'w'); - output->write(test_data); - output.reset(); - - auto input = h5file(hdf5.string().c_str(), 'r'); - blitz::Array<uint8_t,1> read_data(input->read<uint8_t,1>(0)); - - // Does not compile at the moment - blitz::Array<uint16_t,1> read_data_2(input->cast<uint16_t,1>(0)); - - input.reset(); - - if (blitz::any(test_data - read_data)) - throw std::runtime_error("The HDF5 IO test did not succeed"); - - if (blitz::any(test_data - read_data_2)) - throw std::runtime_error("The HDF5 IO test did not succeed"); - - Py_RETURN_NONE; -BOB_CATCH_FUNCTION("_test_api", 0) -} - -static PyMethodDef module_methods[] = { - { - s_test_api.name(), - (PyCFunction)_test_api, - METH_VARARGS|METH_KEYWORDS, - s_test_api.doc(), - }, - {0} /* Sentinel */ -}; - -PyDoc_STRVAR(module_docstr, "Tests for bob::io::base"); - -#if PY_VERSION_HEX >= 0x03000000 -static PyModuleDef module_definition = { - PyModuleDef_HEAD_INIT, - BOB_EXT_MODULE_NAME, - module_docstr, - -1, - module_methods, - 0, 0, 0, 0 -}; -#endif - -static PyObject* create_module (void) { - -# if PY_VERSION_HEX >= 0x03000000 - PyObject* m = PyModule_Create(&module_definition); - auto m_ = make_xsafe(m); - const char* ret = "O"; -# else - PyObject* m = Py_InitModule3(BOB_EXT_MODULE_NAME, module_methods, module_docstr); - const char* ret = "N"; -# endif - if (!m) return 0; - - return Py_BuildValue(ret, m); -} - -PyMODINIT_FUNC BOB_EXT_ENTRY_NAME (void) { -# if PY_VERSION_HEX >= 0x03000000 - return -# endif - create_module(); -} diff --git a/bob/io/base/test/__init__.py b/bob/io/base/test/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/bob/io/base/test/data/cmyk.jpg b/bob/io/base/test/data/cmyk.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3ed9423c9e19ec5e61298dc7dfb963e31f02a5b4 Binary files /dev/null and b/bob/io/base/test/data/cmyk.jpg differ diff --git a/bob/io/base/test/data/grace_hopper.png b/bob/io/base/test/data/grace_hopper.png new file mode 100644 index 0000000000000000000000000000000000000000..4a63320ab28dc6812e5eb89b1d7d50af0dbb0dcc Binary files /dev/null and b/bob/io/base/test/data/grace_hopper.png differ diff --git a/bob/io/base/test/data/img_gray_alpha.png b/bob/io/base/test/data/img_gray_alpha.png new file mode 100644 index 0000000000000000000000000000000000000000..7643ce025d21ec8385a93836180167d3ce62167e Binary files /dev/null and b/bob/io/base/test/data/img_gray_alpha.png differ diff --git a/bob/io/base/test/data/img_indexed_color.png b/bob/io/base/test/data/img_indexed_color.png new file mode 100644 index 0000000000000000000000000000000000000000..c21427b328350a26155841013e461fa46e406be5 Binary files /dev/null and b/bob/io/base/test/data/img_indexed_color.png differ diff --git a/bob/io/base/test/data/img_indexed_color_alpha.png b/bob/io/base/test/data/img_indexed_color_alpha.png new file mode 100644 index 0000000000000000000000000000000000000000..defabb829d44bcd28b8939afbc64c1b3f9143342 Binary files /dev/null and b/bob/io/base/test/data/img_indexed_color_alpha.png differ diff --git a/bob/io/base/test/data/img_rgba_color.png b/bob/io/base/test/data/img_rgba_color.png new file mode 100644 index 0000000000000000000000000000000000000000..0e6d2a10a91f3c36cb64f94ca00e6b971109f259 Binary files /dev/null and b/bob/io/base/test/data/img_rgba_color.png differ diff --git a/bob/io/base/test/data/img_trns.png b/bob/io/base/test/data/img_trns.png new file mode 100644 index 0000000000000000000000000000000000000000..7c16aab16960149a4762610eb8c6827c0814600d Binary files /dev/null and b/bob/io/base/test/data/img_trns.png differ diff --git a/bob/io/base/data/matlab_1d.hdf5 b/bob/io/base/test/data/matlab_1d.hdf5 similarity index 100% rename from bob/io/base/data/matlab_1d.hdf5 rename to bob/io/base/test/data/matlab_1d.hdf5 diff --git a/bob/io/base/data/matlab_2d.hdf5 b/bob/io/base/test/data/matlab_2d.hdf5 similarity index 100% rename from bob/io/base/data/matlab_2d.hdf5 rename to bob/io/base/test/data/matlab_2d.hdf5 diff --git a/bob/io/base/test/data/test.gif b/bob/io/base/test/data/test.gif new file mode 100644 index 0000000000000000000000000000000000000000..8c770fb7b60d43b03b89dc695425e811339963b3 Binary files /dev/null and b/bob/io/base/test/data/test.gif differ diff --git a/bob/io/base/test/data/test.jpg b/bob/io/base/test/data/test.jpg new file mode 100644 index 0000000000000000000000000000000000000000..0bf2deb6a8f29793c1ae15a880aef370c43d01fc Binary files /dev/null and b/bob/io/base/test/data/test.jpg differ diff --git a/bob/io/base/test/data/test.pbm b/bob/io/base/test/data/test.pbm new file mode 100644 index 0000000000000000000000000000000000000000..0902b226f358f3b4703342c59f93200c3263d880 --- /dev/null +++ b/bob/io/base/test/data/test.pbm @@ -0,0 +1,3 @@ +P4 +4 6 +�@ @ \ No newline at end of file diff --git a/bob/io/base/test/data/test.pgm b/bob/io/base/test/data/test.pgm new file mode 100644 index 0000000000000000000000000000000000000000..32cd7fae38dc8850cb7ce244908ba749eb364327 Binary files /dev/null and b/bob/io/base/test/data/test.pgm differ diff --git a/bob/io/base/test/data/test.ppm b/bob/io/base/test/data/test.ppm new file mode 100644 index 0000000000000000000000000000000000000000..a5baf843114a68f76cdc36e96658bfbcd782b3eb Binary files /dev/null and b/bob/io/base/test/data/test.ppm differ diff --git a/bob/io/base/data/test1.hdf5 b/bob/io/base/test/data/test1.hdf5 similarity index 100% rename from bob/io/base/data/test1.hdf5 rename to bob/io/base/test/data/test1.hdf5 diff --git a/bob/io/base/data/test7_unlimited.hdf5 b/bob/io/base/test/data/test7_unlimited.hdf5 similarity index 100% rename from bob/io/base/data/test7_unlimited.hdf5 rename to bob/io/base/test/data/test7_unlimited.hdf5 diff --git a/bob/io/base/test/data/test_2.pgm b/bob/io/base/test/data/test_2.pgm new file mode 100644 index 0000000000000000000000000000000000000000..863c6e80fd1144a2612fd5cd1044476c21f096d1 Binary files /dev/null and b/bob/io/base/test/data/test_2.pgm differ diff --git a/bob/io/base/test/data/test_2.ppm b/bob/io/base/test/data/test_2.ppm new file mode 100644 index 0000000000000000000000000000000000000000..a285afec5845554bfff4f6845393cccccbff4b46 Binary files /dev/null and b/bob/io/base/test/data/test_2.ppm differ diff --git a/bob/io/base/data/test_array_codec.txt b/bob/io/base/test/data/test_array_codec.txt similarity index 100% rename from bob/io/base/data/test_array_codec.txt rename to bob/io/base/test/data/test_array_codec.txt diff --git a/bob/io/base/test/data/test_corrupted.pbm b/bob/io/base/test/data/test_corrupted.pbm new file mode 100644 index 0000000000000000000000000000000000000000..5d28f04a058d99b95b7d813898dafdef75e9c2fa --- /dev/null +++ b/bob/io/base/test/data/test_corrupted.pbm @@ -0,0 +1,3 @@ +P4 +4 6 +�@ @a diff --git a/bob/io/base/test/data/test_corrupted.pgm b/bob/io/base/test/data/test_corrupted.pgm new file mode 100644 index 0000000000000000000000000000000000000000..8f34579e2f6c6710677b5689d15099638912a948 Binary files /dev/null and b/bob/io/base/test/data/test_corrupted.pgm differ diff --git a/bob/io/base/test/data/test_corrupted.ppm b/bob/io/base/test/data/test_corrupted.ppm new file mode 100644 index 0000000000000000000000000000000000000000..fa528857de00ad3392bee8a35be1e94e06ffa500 Binary files /dev/null and b/bob/io/base/test/data/test_corrupted.ppm differ diff --git a/bob/io/base/test/data/test_spaces.pgm b/bob/io/base/test/data/test_spaces.pgm new file mode 100644 index 0000000000000000000000000000000000000000..e1d116b5e620659222a461abf0a1f139db853242 --- /dev/null +++ b/bob/io/base/test/data/test_spaces.pgm @@ -0,0 +1,6 @@ +P5 +# CREATOR: GIMP PNM Filter Version 1.1 + +100 100 +255 +[\[YXY\[^^]`]aaa`d_`ba_b`aad`ddage��jhilpkjsuqnkqquypmstqrk{wrtxuxttvvww{{zxz{{w{|}}���~��������XYYYZ[^_]\_[\^^]\baabb^bbfg`aggiii}��ooitt}�x~tq|xq�lpozupt�stzuu{uywxzyzxz}zz{{zz�}�|~����������X\Z]_[][\^__^^_`__a]f_ca_``\bee`dhw�ypp~�k��op��zw~wpu|�}vvwvwwvx|wy{{}y}|z~}}�}��~}�����~�����YZ[[\]][\]]\_]^```bc`_acbaaccbadwr{x��rx~|uy��~�|z���yqs|ux�}{yyy~vuxux{wy}zz{z{}}�}~�������������WZ\\[[Z_aZ^]^_a^]]_``a_cbccdcbfn`mvw|ggdgo{y�ot�������uw{v����{~x�v{yxzy}x||{{z}~�~~|���~��������Z]]X^`^\^]`_``a_`a_^cbbbbhaeabhlninoTAE>;_]lok^gtm����y����������vwzywxyz{zxwy~{|}y}�~�����������_[[[]]\```]]`a_]cbaa_`ccabdfbhlvxuqUA:9/36=CMRX_|wo~����^`�su{w���~�zzxz{|y{{||}}~~|��~����������XZ[\_]]``a[]_^\__`Zdaa__eddbdabfxv\;6@ADB:2<D@J\d�~�no�p}���������}�}}}xyyxz|��{}{|~~��������������^\[Y\\Z\\^^^`^^^^^b^baacccegbfqil[D;EA:S@PLNMOakXlrxlmvtlQa��zy��������Ëzyxy|z{{|�|~��|}}������X\\][^]]Z^]\``_`_aab`abbcaefdheqYSE:NF28:;:GIKLGlfY`lo]MM>eoexi�����������~y{||{~{||�}����~��������]`]Z\\`^^^]b_^a`aa]b`aaab`bccem^FJL?K4:QPdA;E[J@UJKWNehN]\Vgkns����ڲ�����z|{}z~||}}~��~��������YY^]^]\a`^_a^````^d_acbbfabdbfcYZ;9MKEPXu~f?]?YQl^G^>4>LK>QWSfjlz�����������zzz|~�|�|}���}��������\][][\\a\_`\^[a^_b`b^bdabbg`gbWRHE<>RQ_rr��rB<PfTQcNE=8=7:?SCPkbki���ǫ������z|}}{~{�~~����~�����]]^\[_^\_Z]_adac]`bc_c`hfbefgdROI;A7NN\hs���UK_UIKc@640-060<Vethgg{���ǻ����{xx}z�|z~��~}���|���[\\]]\Z^_^_^__a`\aa``^d`ddfggUAFZLI57LALkz{q^XhlbD:D7/5(3)-?<>YDa_qw������ȼ��y|{|~�||���~���~���\Y[\[Y`c_]\\_b^^]a``cccdgebg_I?CTZJG87B=Ubig^U\GO^P525F)/9::1B?^VhHgz������ҝ�~}{{{||�~�������Z\\\^b^\]a`b`da_a^_`bbebcbda^n_LMRLC<2+<MPXIDL@L`XV..8+0+I1"!9E33nuNWt�����ͷ��}z}{��|~}��}�������`\_^_\^]\Zcb`__`]`[j\bbadbg^VPZWHA<F;;/8>M@H;=BGF&6<>4**>(%35,87U�\SRf����ɹ����zz~}�~���~�������[\ZaaZ^a^c^cdc`b_bbedecdee`IJ@CC@FNE?94*%7D4;59B4.+$2 %2?,.86239=6EZhk�����|��}}~}}�|����������^\\a\[`^][b__bad[ad``geedgZFLNID@:?27601 09/NENCUWA=;(%%&8)6+),:0.?\DSfr���л����|{|{|~|�~�������]WZ]b`]]aa_ba`c_cbbdb_edf`IRHXD878.14($&0$./LIYOPVk_?/ 3C/"0/:<94Yea`ax����Ǒ����{}}z�}~{�}~~���][[Z^]]]]^_b\c_aa_d^_cffgUPPT=3/85-'#40)46411YVi^j{�s+(,334(252::Db�vp|~����ؙ��ë�~���{|����������]]\]^^`_ab`^`]`c__eebbdg`VHK323812/&%*975.+309AFVTX;=P05+'8-618CNCx~a������ù�����͇��|}~�����z����\[`_`_Y[Z\_a\`_a^cbjdf`cGLF@/129*10-**,363CG+/;177+"12%91%*99407kuf~�w~sw���������֣�����}}|~�����\^\]\^__b`__```dac`eadcRILB87398:*$/&(,1+/;5."2;/$%#5)-->( 306<6W�ivIRWjwl{������������}�~�~����\]]]]]_]`^b`_b_a]bc_c\PHCE:;.3,=4)/.,&!(5=BL4)+'0%$#+,.5@(8/75KGM�~aX\oY_JSl�������Ѷ���~}�|��~����Y\]_`^a[^a^\c^]c`afc_VHGH@A843=:,0*+&,.0&?J7;7)+.*,#/+3><66177?V^�t@Ll�JRIX`x�¦}��ͣ����|��~��~����\\Z[]a_[^]cb`abdaace`ME2E<?5<<;6:/2/*1440::G;7+$)3*)*+=580F:;ATV�]]g=<UBDDG^~������Ʈ�Ț�}~�~���~~�]]^]``]^]`ca^b]ab_d^ZQ0-B57/<0A?==9@F88;@?;/(.+710/1-4@9;HC?EDUR_hh@18AJGXZpq���������Ӗ���~���}����\_\_][^\a\[acb_bccaaP2&0=55C5<>9<I<.4;H:25,&&14,172.0J437%8?LU_MYyV5;7@XbL[viy�������������}������\`]^b^]_aa^_a^abdb_\V8:7101@35G:P>*:A=40.9%./<95750-9DAN4/<>0LeVCPS`P,J`lnqSTw���Ȥ���������{}}~~^]^_a]]cbb__]\^^`aa[QN9>&&,0,3IHL:/%-159345;5>B773.6IC4<=O246+_jFQPQfKZx�sjj�������������|�~~~��`]`bc]\^b`bbab^bea`VHH/1H%4,09?C<.2-26<8;""<GX>@;7<M?8>F78A>4:h?DMVNI^����n��������������~~~|�~~�[]^`a]^`aaa`bb_bb[ZKEK@+A61'*HFI2)7HE@>:,/*4DF:A=<7;K:DXhM?<<<3=B4?HRLRf}~�zx�������Ŵ��}{}~z}�|��~]\Z]aab``d_aa`]b^QM>=TG-@>/&4IBZ28;;FQ:'202HH>CIIB>7F@>DZtsaDK7_kC<D<TQ`kx�����������ʓ����}|�����\Y[^]`^`\_^bbb`a[C>F3O>7=92<7CKN7=;F?:=?:JF=FGCMNG?7L9FBRUmpry~�etfGJKs������d�������С��}z}�}|��|��^^^__b`]a_bdbceb`O@7.H;;@6;@G>PN-*+/8+$ -4DNQWSQLKD9M4EKTUYjrx�roo��_UU~�x�ci���s����հ�~}�~}}~��~[^]^`[[aacbc`bcbcO@4?;81=>,6O=JH6*-)4#'1FP\^caWSLRH9B4R_[W^[]}�|�ny��IYpw��r]t`~����ظ�}}~{{}}~�]a_^a_a```_^c_bf`AAK246$=4'.S>EI5-4+8-9GUiqmkgZWTPU?EJXZ_f_YHSGPl���lDg|��~ajvTi����ʢ�~~�||�~{�`^````b^_bdbb`bh`OMN263)0/''B24@D.-26@LZanqprkYVUW_HIRXQiaefWHNOihl���R]���suiJG\����ƚ��z�|}|}|��`^a^a^cb_]`c\_cfTVYT:@5%(6+340IN23;:GWahrovqo^S_]dNAJ]dijkkcL_S_\CYv��m���xaf7Sg����Н|���|x�z|{�}][`^]^c__aaccbbeNWV;[M5%$(0052?R67GCDQ\lqqosq\Y\ccSNGUfbowocRN[eGY|��}����xR[<.mk��ӵ�|�}}}|zy|�]a^_`]_^_c`cccdcH\RI=;4'+)-%:,78>=KUKNbioos|sfg[ec^cQTWncmzYjpinXX����~n�ukYEO+wo���Λ}�}�~�}}z�~`a`\a]c_`__aae`YMRE;=7?2-!,4:,&4JTJRTRVlvzw{ymkadoi_dY]asugTc_qkqI\�|VVt�v`B:F:^s���¦���~~~�~~�}�_aa_d__]_dbd`ceY@>D8:==10/%17% :9OTSVgkqy{y��qs�w\t`pq`\ZQVQkebjx�hNTZhpsGF79AT@u��ѱ�x|x|�||}��``_^dbf^aaibdca^6@?9QC"\tE 1;ELS_ijplry��xz�}uhcw�yJY_RVTss����eU{qtS?88GTE_��ѧ�}}y�|||}}||}]^_]b]_]^_b^cbejG9=@7!% )ZbiN?6&<?FFMhwvro~|}������y|���|_Qpslop�����ǖP:;9UbJS~�գ�zz|y|}~|~z}`^_^^``_`caaQPZVL52/$!,!#GOxsm`^P4?JRUQScvtyxz�������y�|��zW_u��ĸ����ۮ�\-:PMHXbo�ڕy~{yz}}|~~z~^a`a_aacbbbefQ:31--&))4' >qcJZdUJW^J^ic_[TR_kf}��������pon^K[b���̾�����ǔjQB4;\cWa�ԓ�|{{{}{{}z{~|}```_]`ffbbccefUB7-/8B>1%<�|iw{���~nZy�}zhjc`_o�}�������ysmz��l|�������ȸ�\:70:QaQW�ɓy{{||{}{{z}|}`]_^^aanle``]_d]OFWKI;!"$V�vWh���~|�x~}}ylnnpucv���������tmhgcvxp�������ɫmQK/;QfSi���|yz|||y}{|}||^]\_a`]adeeeebac]_YZJ(7X��b�������~������{}�wm~������sl����������������ƑYT.DKiL���~z{yyxz~}y|}]^_^_`aaabb]bbc`d_`K1(@Y��w��������������uhivru�����n����������������߽�woF6BNc^t��x�v{yyy{{}}{y}\\\aaaa_]ab`da`dcabK* .>d��v�}~�ztlnhkfZgnlZPuvy���s�������������������~��D8GM_i���|�uxzzxzz~xwxv[_]_^^_\^b``cbaa`b^?0@Ak��w�xvfn���y{usiSWMPlynq�����wfbdo{�������������9@AQic���|xz{u{wzzu{z{}x][\b__^_^]a_cbddfcb;&<L8k��s�{zx[Tml[XVONEU]Y`dw������xils{�����������ȍ��1F@Ws|w��xwyy{uu{{~xxys|^]^]aa]`]a^\dddecdi63JiBg��y����heQ<6;HIKPUhh}po���Ǔzd^RG=HWl���������r�8OIm}�~�yyxxvww~yuxxxzxx`[___b^a_cab``abddn@(<^n6^��{������wWPX^X]dagdrFn���Н�xfelmsx�����������]�^LU�����suvwuuxvz{x{wyvy\][[Z\_]_`^^_d^c`acK6CPc?n��~���������{�~{qio��N_����ž�~����������������U��Tl�����xvwvuvutwtwtzywy]\\\\_`[^^\``^`d`bkV=7NAAr��������������������wBx�����߾����������������ƽ[��S����~zwytvxwxvwywyxxvv`]^]^[^^^^_`ac^b^biMB??23�}��z����������������J[����Ǭ��IJ��������������ӥt��V��ij�zuvuvwuzxqrwvwvx{_]_[__`_^[_b__abbbi`LBA:.tv������������������jMs����ֶ���Ƽ�������������ےl�zX��Ӯ�|vusuxzwyyyswyuwx[]]]]_^_c``^a^_`bdagI>BH4hb�����������������{Jq�����������̸�������������}m��S�ͥ��twuwvuuwvtyyuwvuw[[[\^Z[_aa_ba^a_bd_deJHV7i������������������Vh��������������������������xpz�S��Ů�}vwwtsvwsvtwuuvwy[\[_]^_^a^_^`^`c`bdccWPJ=jav���|uz��������w`ey�������������ʽ����������宀u��Z��ͣ�~uxwuutuusvtutzuwY]^\_^][aab`eac`[_debh\K7Tmw����|oqnqvspi__oz{��������������Ƚ���������띆���^�����}wqrwxvsrruvxxwxuZ[_Z]][\\]]^^]`\cbachd`Z=KZs����~wxohvtrtx�|rms�������|���������������㪜���_�����yxqutsorrsrrtptvr\^[[ZZb]]^^`_bab^_]`ad_^MNGE��������������yWfq��������|q|�ɾ�����������ʳŴ���{}yrusrossssruusouwvxXXX]]^]``\^^bc`_bb_`bab^XA@=���������������qIr}��������n���������������ɯ��f��|rnrnonlrnsosqtrvpsvuZUa^[Y`_]]_]c\bacb_cc`ba_-83��������������~dQ{����������f|�������������俼��P�twqsrnpnmqorutrrqquvyu_][][W^_\^[b_a^][_`]bb_\Y,B/q������{������~bR����������ht�������������m�trmlorvponoonsntorsvsqtYZ]]Y\[]\\a__]^[`^daac_SI,F?U�������������wk]nkjv����ߣ��~��������������hm�|}pqonopmqprsqprptpqrsqqnYY\[_]]^\^]\_[^`a[^__b__UZ0\6������~�}���}zt[YHhouÝ}�����������������a�W��oppnnmlnoquoqqprssqsqtx]\\_^Y_\^[\a\^a`]^___^`_ag)`4�����|}����~yvsbb_m����������������������hgowrklmootornpopqpnotsqpsqrX]Z\\][[\X\\^_]\_a_a]d_`bbEWIs������z����{|w{v|��Ǿ������������������Srmmnlollnomprspnqrurqrqrso\Y[\YZ\Z^\]]\^]__^[[[ac``]_.[C�����|zx��������������ʿ����������������~ZtknkmllnolqmppqronsrqppoppuVX\Y[[UV\_\^b[]\^a^]_^``abd6^T������uy}����������������®�������������ljnmllmqnnomlnpmnomqprtqpporp]Y[[Y[^][[Y][]_Y[\]]^^^_\\`\&gl�����~xux~��~������������װ�������������MomkhmljpnnoloonnpopqmnpnqmomXWWZW[Z\_Y\][`YZ\[]c]^^_c^cbL8������yvy{�}�������������ο�֤��������Grlimjkjhihljjlllnooppqopmmpos[YXWX\X[ZZ\\\[\\\]]]\``__c_bd(l�������~������������������¶�������l\qkehigkkjklinlmmpoompplpnspmV[W[XYZ[\][[X]X]]Z]Z^]^]c_cb$��������~~t�s][_o����������̥���������Dk�rhkhkhkmjnlmommromnolminqsuX[YXYY\Y\\[^\[]W^][a\\_`cbS&"a�������|om[UN:))<HE@,3Ks������������Z<��hlffijhmijknnlhkknplmlkmmnmZZW\Y\[W\YX[^]`[^]a^]`c]cB$!)��������mkhNOLB-'.)1>Q���Ө���������R5u�VYspiiikhlllklmklknlllkkknmYW[`Z[YVX^\^ZX\Z]ZZZ][[eA!"# "2d����}yojlpfj[GMJDBBt���Ϯ�������� X]rNPa7_mpmjfhomplpnlhkkmlillkV[WXXZ]_[V[[[YZ^Y]\\__a=$# !3R{�}yxzumnppnkmdiejfd�����ë�������6inWeATgNBCOkjljjiknkojoonqmmkkoVXZZYWXTY[YZ\]^[Z\Z[bK,.<Wm}zwvwvswsmbhbjsvlgz�į���Ϫ�����+)Mg_>OYgFG?GdomjhjkimkhqllgmlolXZZWWV]ZXZ\ZZZ[[\aa`6(!"+;Sdouxstqnyxonhjmo�����������չ����F**J\2MXgOHADCMgmjikjjllmkmkjmmmWXW\XYZZYZ\\Z[\\[^G' "/:Qaqqnrtxw|zvsniiqs}~�������������B'%-JT2AZZEJIBC>>HcijijhiigjkjlmjYWZV[ZZWZ[YX[\Z^T4!):VZgrkiov}���}zokms~������������ϑ; (Ea/=NSL?BDC?A?DRdkmhmokkkkjilWYVWYZWYWXZY\`Z=&!+;:[]ormgou�}���}{w~����������������</I]1@FER9=FA>:@B@JYljeikkkjhjiUWV]XZZ\ZYZ\_E'!!-=6TXlkmunqy~��y�z}��������������y5! *>^7<?7N79=?>>;;;>BPjrmjiihkkjXWUW]XZZXX`B*""(:5MZgimoktqz��������������������ۙd) !+C_6::7I16898:73:8;BHexrllnhieXVSZX[Y_YE' %#&2:LSbehoojmwx|�w����������������χQ! #,JT4645C-2857316/273<IcoipphjfWVXW[^]@.& 3G>W]addhmkjru{{{��������������xP&"&.PV0730<+334210//03377?Xz`OdkkTWYXY4**!7C<QXfe``gihokosv{rqx�����ҷ���שcE.LT1.3.6.12//.+0.,.2/69;QgsdZkVY\>,.# 7D=LU[kb[hgcmncimpkho|vp�ɫ����N>%#2XT,,,42,*/-(+,,),/-3128>PWhyaXT4(#!2ABMRTcd_[_hfommjd_]gt��满���ƠiA4"(6ZJ0*(-0+,(,0&)/))+*+++68?IUftP.*! 4AF>YR]fjcb_dkqt�~zux���ޭ���Ӯ�U<)!&7\D0),/0.*+')*+%+(()(')/08=KXd+" !(AG;JTYfmlfc_am~�xmry}��ү��κ��O9';Y<+(/070*+%')++)%'(((**05=AKZ"# !>DF@TY^gnmhjefjxww{}���������tK< ,?O6)$+..1'')*&)'(''&'$'&,/9;AK diff --git a/bob/io/base/test/test_hdf5.py b/bob/io/base/test/test_hdf5.py new file mode 100644 index 0000000000000000000000000000000000000000..437709ff465a79c37619a004054f03b47e48b3f2 --- /dev/null +++ b/bob/io/base/test/test_hdf5.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 : +# Tiago de Freitas Pereira <tiago.pereira@idiap.ch> +# +# Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland + +"""Tests for the base HDF5 infrastructure +""" + +import os +from bob.io.base import load, save +from .test_utils import temporary_filename + + +import numpy as np +import random + + +def read_write_check(data): + """Testing loading and save different file types""" + + tmpname = temporary_filename() + + try: + + save(data, tmpname) + data2 = load(tmpname) + finally: + os.unlink(tmpname) + + assert np.allclose(data, data2, atol=10e-5, rtol=10e-5) + + +def test_type_support(): + + # This test will go through all supported types for reading/writing data + # from to HDF5 files. One single file will hold all data for this test. + # This is also supported with HDF5: multiple variables in a single file. + + N = 100 + + data = [int(random.uniform(0, 100)) for z in range(N)] + + read_write_check(np.array(data, np.int8)) + read_write_check(np.array(data, np.uint8)) + read_write_check(np.array(data, np.int16)) + read_write_check(np.array(data, np.uint16)) + read_write_check(np.array(data, np.int32)) + read_write_check(np.array(data, np.uint32)) + read_write_check(np.array(data, np.int64)) + read_write_check(np.array(data, np.uint64)) + read_write_check(np.array(data, np.float32)) + read_write_check(np.array(data, np.float64)) + read_write_check(np.array(data, np.complex64)) + read_write_check(np.array(data, np.complex128)) diff --git a/bob/io/base/test/test_image_support.py b/bob/io/base/test/test_image_support.py new file mode 100644 index 0000000000000000000000000000000000000000..437169912ff226a588a30e2285b7e9b21d8977bf --- /dev/null +++ b/bob/io/base/test/test_image_support.py @@ -0,0 +1,152 @@ +#!/usr/bin/env python +# vim: set fileencoding=utf-8 : +# Laurent El Shafey <laurent.el-shafey@idiap.ch> +# Wed Aug 14 12:27:57 CEST 2013 +# +# Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland + +"""Runs some image tests +""" + +import os +import numpy + +from bob.io.base import load, write +from .test_utils import datafile, temporary_filename + +# import bob.io.image +import nose + + +# These are some global parameters for the test. +PNG_INDEXED_COLOR = datafile("img_indexed_color.png", __name__) +PNG_INDEXED_COLOR_ALPHA = datafile("img_indexed_color_alpha.png", __name__) +PNG_RGBA_COLOR = datafile("img_rgba_color.png", __name__) +PNG_GRAY_ALPHA = datafile("img_gray_alpha.png", __name__) +PNG_tRNS = datafile("img_trns.png", __name__) + + +def test_png_indexed_color(): + # Read an indexed color PNG image, and compared with hardcoded values + + img = load(PNG_INDEXED_COLOR) + assert img.shape == (3, 22, 32) + assert img[0, 0, 0] == 255 + assert img[0, 17, 17] == 117 + + +def test_png_rgba_color(): + # Read an indexed color PNG image, and compared with hardcoded values + img = load(PNG_RGBA_COLOR) + assert img.shape == (3, 22, 32) + assert img[0, 0, 0] == 255 + assert img[0, 17, 17] == 117 + + +def test_png_indexed_color_alpha(): + # Read an indexed color+alpha PNG image, and compared with hardcoded values + img = load(PNG_INDEXED_COLOR_ALPHA) + assert img.shape == (3, 22, 32) + assert img[0, 0, 0] == 255 + assert img[0, 17, 17] == 117 + + +def test_png_indexed_trns(): + # Read an tRNS PNG image (without alpha), and compared with hardcoded values + img = load(PNG_tRNS) + assert img.shape == (3, 22, 32) + assert img[0, 0, 0] == 255 + assert img[0, 17, 17] == 117 + + +def test_png_gray_alpha(): + # Read a gray+alpha PNG image, and compared with hardcoded values + + img = load(PNG_GRAY_ALPHA) + + assert img.shape == (22, 32) + assert img[0, 0] == 255 + assert img[17, 17] == 51 + + +def transcode(filename): + + tmpname = temporary_filename(suffix=os.path.splitext(filename)[1]) + tmpnam_ = temporary_filename(suffix=os.path.splitext(filename)[1]) + + try: + # complete transcoding test + image = load(filename) + + # save with the same extension + write(image, tmpname) + + # reload the image from the file + image2 = load(tmpname) + + assert numpy.array_equal(image, image2) + + # test getting part of the image as well + if len(image.shape) == 3: + subsample = image[:, ::2, ::2] + else: + subsample = image[::2, ::2] + + assert not subsample.flags.contiguous + write(subsample, tmpnam_) + image3 = load(tmpnam_) + assert numpy.array_equal(subsample, image3) + + finally: + if os.path.exists(tmpname): + os.unlink(tmpname) + if os.path.exists(tmpnam_): + os.unlink(tmpnam_) + + +def test_netpbm(): + + transcode(datafile("test.pbm", __name__)) # indexed, works fine + transcode(datafile("test.pgm", __name__)) # indexed, works fine + transcode(datafile("test.ppm", __name__)) # indexed, works fine + transcode(datafile("test_2.pgm", __name__)) # indexed, works fine + # transcode(datafile("test_2.ppm", __name__)) # indexed, works fine ----> THIS DOES NOT WORK + transcode(datafile("test_spaces.pgm", __name__)) # indexed, works fine + + # transcode(datafile("test.jpg", __name__)) # does not work + # because of re-compression + + +def notest_gif(): + transcode(datafile("test.gif", __name__)) + + +def test_image_load(): + # test that the generic bob.io.image.load function works as expected + for filename in ( + "test.jpg", + "cmyk.jpg", + "test.pbm", + "test_corrupted.pbm", + "test.pgm", + "test_corrupted.pgm", + "test.ppm", + "test_corrupted.ppm", + "test.gif", + ): + + full_file = datafile(filename, __name__) + + # load with just image name + i1 = load(full_file) + + assert i1.shape == (6, 4) + + # Loading the last pgm file + full_file = datafile("test_spaces.pgm", __name__) + load(full_file).shape == (100, 100) + + # Testing exception + nose.tools.assert_raises( + RuntimeError, lambda x: load(os.path.splitext(x)[0] + ".unknown"), full_file + ) diff --git a/bob/io/base/test/test_io.py b/bob/io/base/test/test_io.py new file mode 100644 index 0000000000000000000000000000000000000000..7a31cda62c3d29180e155d192f6d82fda1c05fa1 --- /dev/null +++ b/bob/io/base/test/test_io.py @@ -0,0 +1,96 @@ +import nose +import numpy as np +import os +from bob.io.base import vstack_features, save, load +from .test_utils import temporary_filename + + +def test_io_vstack(): + + paths = [1, 2, 3, 4, 5] + + def oracle(reader, paths): + return np.vstack([reader(p) for p in paths]) + + def reader_same_size_C(path): + return np.arange(10).reshape(5, 2) + + def reader_different_size_C(path): + return np.arange(2 * path).reshape(path, 2) + + def reader_same_size_F(path): + return np.asfortranarray(np.arange(10).reshape(5, 2)) + + def reader_different_size_F(path): + return np.asfortranarray(np.arange(2 * path).reshape(path, 2)) + + def reader_same_size_C2(path): + return np.arange(30).reshape(5, 2, 3) + + def reader_different_size_C2(path): + return np.arange(6 * path).reshape(path, 2, 3) + + def reader_same_size_F2(path): + return np.asfortranarray(np.arange(30).reshape(5, 2, 3)) + + def reader_different_size_F2(path): + return np.asfortranarray(np.arange(6 * path).reshape(path, 2, 3)) + + def reader_wrong_size(path): + return np.arange(2 * path).reshape(2, path) + + # when same_size is False + for reader in [ + reader_different_size_C, + reader_different_size_F, + reader_same_size_C, + reader_same_size_F, + reader_different_size_C2, + reader_different_size_F2, + reader_same_size_C2, + reader_same_size_F2, + ]: + np.all(vstack_features(reader, paths) == oracle(reader, paths)) + + # when same_size is True + for reader in [ + reader_same_size_C, + reader_same_size_F, + reader_same_size_C2, + reader_same_size_F2, + ]: + np.all(vstack_features(reader, paths, True) == oracle(reader, paths)) + + with nose.tools.assert_raises(AssertionError): + vstack_features(reader_wrong_size, paths) + + # test actual files + paths = [temporary_filename(), temporary_filename(), temporary_filename()] + try: + # try different readers: + for reader in [ + reader_different_size_C, + reader_different_size_F, + reader_same_size_C, + reader_same_size_F, + reader_different_size_C2, + reader_different_size_F2, + reader_same_size_C2, + reader_same_size_F2, + ]: + # save some data in files + for i, path in enumerate(paths): + save(reader(i + 1), path) + # test when all data is present + reference = oracle(load, paths) + np.all(vstack_features(load, paths) == reference) + os.remove(paths[0]) + # Check if RuntimeError is raised when one of the files is missing + with nose.tools.assert_raises(RuntimeError): + vstack_features(load, paths) + finally: + try: + for path in paths: + os.remove(path) + except Exception: + pass diff --git a/bob/io/base/test_utils.py b/bob/io/base/test/test_utils.py similarity index 100% rename from bob/io/base/test_utils.py rename to bob/io/base/test/test_utils.py diff --git a/bob/io/base/test_cpp.py b/bob/io/base/test_cpp.py deleted file mode 100644 index a9f4e06bea775e012ede089dbc9034918a9414c0..0000000000000000000000000000000000000000 --- a/bob/io/base/test_cpp.py +++ /dev/null @@ -1,11 +0,0 @@ -from bob.io.base._test import _test_api - -import tempfile -import shutil - -def test_api(): - temp_dir = tempfile.mkdtemp() - try: - _test_api(temp_dir) - finally: - shutil.rmtree(temp_dir) diff --git a/bob/io/base/test_file.py b/bob/io/base/test_file.py deleted file mode 100644 index 12b24850e618e3036273a9a71263161804ab913e..0000000000000000000000000000000000000000 --- a/bob/io/base/test_file.py +++ /dev/null @@ -1,232 +0,0 @@ -#!/usr/bin/env python -# vim: set fileencoding=utf-8 : -# Andre Anjos <andre.anjos@idiap.ch> -# Wed Nov 16 13:27:15 2011 +0100 -# -# Copyright (C) 2011-2013 Idiap Research Institute, Martigny, Switzerland - -"""A combined test for all built-in types of Array/interaction in -python. -""" - -import os -import sys -import numpy -import nose.tools - -from . import load, write, peek, peek_all, File, test_utils - -def test_peek(): - - f = test_utils.datafile('test1.hdf5', __name__) - assert peek(f) == (numpy.uint16, (3,), (1,)) - assert peek_all(f) == (numpy.uint16, (3,3), (3,1)) - -def test_iteration(): - - fname = test_utils.datafile('matlab_2d.hdf5', __name__) - f = File(fname, 'r') - nose.tools.eq_(len(f), 512) - - objs = load(fname) - - for l, i in zip(objs, f): - assert numpy.allclose(l, i) - -def test_indexing(): - - fname = test_utils.datafile('matlab_2d.hdf5', __name__) - f = File(fname, 'r') - nose.tools.eq_(len(f), 512) - - objs = load(fname) - nose.tools.eq_(len(f), len(objs)) - - # simple indexing - assert numpy.allclose(f[0], objs[0]) - assert numpy.allclose(f[1], objs[1]) - assert numpy.allclose(f[-1], objs[-1]) - assert numpy.allclose(f[-2], objs[-2]) - -def test_slicing_empty(): - - fname = test_utils.datafile('matlab_2d.hdf5', __name__) - f = File(fname, 'r') - - objs = f[1:1] - assert objs.shape == tuple() - -def test_slicing_0(): - - fname = test_utils.datafile('matlab_2d.hdf5', __name__) - f = File(fname, 'r') - - objs = f[:] - for i, k in enumerate(load(fname)): - assert numpy.allclose(k, objs[i]) - -def test_slicing_1(): - - fname = test_utils.datafile('matlab_2d.hdf5', __name__) - f = File(fname, 'r') - - # get slice - s1 = f[3:10:2] - nose.tools.eq_(len(s1), 4) - assert numpy.allclose(s1[0], f[3]) - assert numpy.allclose(s1[1], f[5]) - assert numpy.allclose(s1[2], f[7]) - assert numpy.allclose(s1[3], f[9]) - -def test_slicing_2(): - - fname = test_utils.datafile('matlab_2d.hdf5', __name__) - f = File(fname, 'r') - - # get negative slicing - s = f[-10:-2:3] - nose.tools.eq_(len(s), 3) - assert numpy.allclose(s[0], f[len(f)-10]) - assert numpy.allclose(s[1], f[len(f)-7]) - assert numpy.allclose(s[2], f[len(f)-4]) - -def test_slicing_3(): - - fname = test_utils.datafile('matlab_2d.hdf5', __name__) - f = File(fname, 'r') - - # get negative stepping slice - s = f[20:10:-3] - nose.tools.eq_(len(s), 4) - assert numpy.allclose(s[0], f[20]) - assert numpy.allclose(s[1], f[17]) - assert numpy.allclose(s[2], f[14]) - assert numpy.allclose(s[3], f[11]) - -def test_slicing_4(): - - fname = test_utils.datafile('matlab_2d.hdf5', __name__) - f = File(fname, 'r') - - # get all negative slice - s = f[-10:-20:-3] - nose.tools.eq_(len(s), 4) - assert numpy.allclose(s[0], f[len(f)-10]) - assert numpy.allclose(s[1], f[len(f)-13]) - assert numpy.allclose(s[2], f[len(f)-16]) - assert numpy.allclose(s[3], f[len(f)-19]) - -@nose.tools.raises(TypeError) -def test_indexing_type_check(): - - f = File(test_utils.datafile('matlab_2d.hdf5', __name__), 'r') - nose.tools.eq_(len(f), 512) - f[4.5] - -@nose.tools.raises(IndexError) -def test_indexing_boundaries(): - - f = File(test_utils.datafile('matlab_2d.hdf5', __name__), 'r') - nose.tools.eq_(len(f), 512) - f[512] - -@nose.tools.raises(IndexError) -def test_indexing_negative_boundaries(): - f = File(test_utils.datafile('matlab_2d.hdf5', __name__), 'r') - nose.tools.eq_(len(f), 512) - f[-513] - -def transcode(filename): - """Runs a complete transcoding test, to and from the binary format.""" - - tmpname = test_utils.temporary_filename(suffix=os.path.splitext(filename)[1]) - - try: - # transcode from test format into the test format -- test array access modes - orig_data = load(filename) - write(orig_data, tmpname) - rewritten_data = load(tmpname) - - assert numpy.array_equal(orig_data, rewritten_data) - - # transcode to test format -- test arrayset access modes - trans_file = File(tmpname, 'w') - index = [slice(orig_data.shape[k]) for k in range(len(orig_data.shape))] - for k in range(orig_data.shape[0]): - index[0] = k - trans_file.append(orig_data[index]) #slice from first dimension - del trans_file - - rewritten_file = File(tmpname, 'r') - - for k in range(orig_data.shape[0]): - rewritten_data = rewritten_file.read(k) - index[0] = k - assert numpy.array_equal(orig_data[index], rewritten_data) - - finally: - # And we erase both files after this - if os.path.exists(tmpname): os.unlink(tmpname) - -def array_readwrite(extension, arr, close=False): - """Runs a read/write verify step using the given numpy data""" - tmpname = test_utils.temporary_filename(suffix=extension) - try: - write(arr, tmpname) - reloaded = load(tmpname) - if close: assert numpy.allclose(arr, reloaded) - else: assert numpy.array_equal(arr, reloaded) - finally: - if os.path.exists(tmpname): os.unlink(tmpname) - -def arrayset_readwrite(extension, arrays, close=False): - """Runs a read/write verify step using the given numpy data""" - tmpname = test_utils.temporary_filename(suffix=extension) - try: - f = File(tmpname, 'w') - for k in arrays: - f.append(k) - del f - f = File(tmpname, 'r') - for k, array in enumerate(arrays): - reloaded = f.read(k) #read the contents - if close: - assert numpy.allclose(array, reloaded) - else: assert numpy.array_equal(array, reloaded) - finally: - if os.path.exists(tmpname): os.unlink(tmpname) - -def test_hdf5(): - - # array writing tests - a1 = numpy.random.normal(size=(2,3)).astype('float32') - a2 = numpy.random.normal(size=(2,3,4)).astype('float64') - a3 = numpy.random.normal(size=(2,3,4,5)).astype('complex128') - a4 = (10 * numpy.random.normal(size=(3,3))).astype('uint64') - - array_readwrite('.hdf5', a1) # extensions: .hdf5 or .h5 - array_readwrite(".h5", a2) - array_readwrite('.h5', a3) - array_readwrite(".h5", a4) - array_readwrite('.h5', a3[:,::2,::2,::2]) #test non-contiguous - - # arrayset writing tests - a1 = [] - a2 = [] - a3 = [] - a4 = [] - for k in range(10): - a1.append(numpy.random.normal(size=(2,3)).astype('float32')) - a2.append(numpy.random.normal(size=(2,3,4)).astype('float64')) - a3.append(numpy.random.normal(size=(2,3,4,5)).astype('complex128')) - a4.append((10*numpy.random.normal(size=(3,3))).astype('uint64')) - - arrayset_readwrite('.h5', a1) - arrayset_readwrite(".h5", a2) - arrayset_readwrite('.h5', a3) - arrayset_readwrite(".h5", a4) - - # complete transcoding tests - transcode(test_utils.datafile('test1.hdf5', __name__)) - transcode(test_utils.datafile('matlab_1d.hdf5', __name__)) - transcode(test_utils.datafile('matlab_2d.hdf5', __name__)) diff --git a/bob/io/base/test_hdf5.py b/bob/io/base/test_hdf5.py deleted file mode 100644 index a1ed619b3b415e63485300067d669a3c2f05970e..0000000000000000000000000000000000000000 --- a/bob/io/base/test_hdf5.py +++ /dev/null @@ -1,546 +0,0 @@ -#!/usr/bin/env python -# vim: set fileencoding=utf-8 : -# Andre Anjos <andre.anjos@idiap.ch> -# Wed Jun 22 17:50:08 2011 +0200 -# -# Copyright (C) 2011-2014 Idiap Research Institute, Martigny, Switzerland - -"""Tests for the base HDF5 infrastructure -""" - -import os -import sys -import numpy -import random -import nose.tools - -from . import HDF5File, load, save, peek_all, test_utils - -def read_write_check(outfile, dname, data, dtype=None): - """Tests scalar input/output on HDF5 files""" - - if dtype is not None: data = [dtype(k) for k in data] - - # First, we test that we can read and write 1 single element - outfile.append(dname + '_single', data[0]) - - # Set attributes on the dataset and current path (single scalar) - outfile.set_attribute(dname + '_single_attr', data[0], dname + '_single') - outfile.set_attribute(dname + '_single_attr', data[0]) - - # Makes sure we can read the value out - assert numpy.array_equal(outfile.lread(dname + '_single', 0), data[0]) - - # Makes sure we can read the attributes out - assert numpy.array_equal(outfile.get_attribute(dname + '_single_attr', dname + '_single'), data[0]) - assert numpy.array_equal(outfile.get_attribute(dname + '_single_attr'), data[0]) - - # Now we go for the full set - outfile.append(dname, data) - - # Also create big attributes to see if that works - outfile.set_attribute(dname + '_attr', data, dname + '_single') - outfile.set_attribute(dname + '_attr', data) - - # And that we can read it back - back = outfile.lread(dname) #we read all at once as it is simpler - for i, b in enumerate(back): assert numpy.array_equal(b, data[i]) - - # Check the attributes - assert numpy.array_equal(outfile.get_attribute(dname + '_attr', dname + '_single'), data) - assert numpy.array_equal(outfile.get_attribute(dname + '_attr'), data) - -def read_write_array_check(outfile, dtype): - N = 10 - SHAPE = (2, 3, 4, 2) #48 elements in arrays - arrays = [] - for k in range(N): - data = [random.uniform(0,N) for z in range(numpy.product(SHAPE))] - nparray = numpy.array(data, dtype=dtype).reshape(SHAPE) - arrays.append(nparray) - read_write_check(outfile, dtype.__name__ + '_array', arrays) - -def read_write_subarray_check(outfile, dtype): - N = 10 - SHAPE = (2, 3, 4, 2) #48 elements in arrays - arrays = [] - for k in range(N): - data = [random.uniform(0,N) for z in range(numpy.product(SHAPE))] - nparray = numpy.array(data, dtype=dtype).reshape(SHAPE) - usearray = nparray[:,1,1:2,:] - assert not usearray.flags.contiguous - arrays.append(usearray) - read_write_check(outfile, dtype.__name__ + '_subarray', arrays) - -def test_can_create(): - - # This test demonstrates how to create HDF5 files from scratch, - # starting from blitz::Arrays - - try: - - # We start by creating some arrays to play with. Please note that in - # normal cases you are either generating these arrays or reading from - # other binary files or datasets. - N = 2 - SHAPE = (3, 2) #6 elements - NELEMENT = SHAPE[0] * SHAPE[1] - arrays = [] - for k in range(N): - data = [int(random.uniform(0,10)) for z in range(NELEMENT)] - arrays.append(numpy.array(data, 'int32').reshape(SHAPE)) - - # Now we create a new binary output file in a temporary location and save - # the data there. - tmpname = test_utils.temporary_filename() - outfile = HDF5File(tmpname, 'w') - outfile.append('testdata', arrays) - - # Data that is thrown in the file is immediately accessible, so you can - # interleave read and write operations without any problems. - # There is a single variable in the file, which is a bob arrayset: - nose.tools.eq_(outfile.paths(), ['/testdata']) - - # And all the data is *exactly* the same recorded, bit by bit - back = outfile.lread('testdata') # this is how to read the whole data back - for i, b in enumerate(back): - assert numpy.array_equal(b, arrays[i]) - - # If you want to immediately close the HDF5 file, just delete the object - del outfile - - # You can open the file in read-only mode using the 'r' flag. Writing - # operations on this file will fail. - readonly = HDF5File(tmpname, 'r') - - # There is a single variable in the file, which is a bob arrayset: - nose.tools.eq_(readonly.paths(), ['/testdata']) - - # You can get an overview of what is in the HDF5 dataset using the - # describe() method - description = readonly.describe('testdata') - - nose.tools.eq_(description[0][0][0], arrays[0].dtype) - nose.tools.eq_(description[0][0][1], arrays[0].shape) - nose.tools.eq_(description[0][1], N) #number of elements - nose.tools.eq_(description[0][2], True) #expandable - - # Test that writing will really fail - nose.tools.assert_raises(RuntimeError, readonly.append, "testdata", arrays[0]) - - - # And all the data is *exactly* the same recorded, bit by bit - back = readonly.lread('testdata') # how to read the whole data back - for i, b in enumerate(back): - assert numpy.array_equal(b, arrays[i]) - - finally: - os.unlink(tmpname) - -def test_type_support(): - - # This test will go through all supported types for reading/writing data - # from to HDF5 files. One single file will hold all data for this test. - # This is also supported with HDF5: multiple variables in a single file. - - try: - - N = 100 - - tmpname = test_utils.temporary_filename() - outfile = HDF5File(tmpname, 'w') - - data = [bool(int(random.uniform(0,2))) for z in range(N)] - read_write_check(outfile, 'bool_data', data) - data = [int(random.uniform(0,100)) for z in range(N)] - read_write_check(outfile, 'int_data', data) - read_write_check(outfile, 'int8_data', data, numpy.int8) - read_write_check(outfile, 'uint8_data', data, numpy.uint8) - read_write_check(outfile, 'int16_data', data, numpy.int16) - read_write_check(outfile, 'uint16_data', data, numpy.uint16) - read_write_check(outfile, 'int32_data', data, numpy.int32) - read_write_check(outfile, 'uint32_data', data, numpy.uint32) - - if sys.version_info[0] < 3: - data = [long(random.uniform(0,1000000000)) for z in range(N)] - else: - data = [int(random.uniform(0,1000000000)) for z in range(N)] - read_write_check(outfile, 'long_data', data) - read_write_check(outfile, 'int64_data', data, numpy.int64) - read_write_check(outfile, 'uint64_data', data, numpy.uint64) - - data = [float(random.uniform(0,1)) for z in range(N)] - read_write_check(outfile, 'float_data', data, float) - #Note that because of double => float precision issues, the next test will - #fail. Python floats are actually double precision. - #read_write_check(outfile, 'float32_data', data, numpy.float32) - read_write_check(outfile, 'float64_data', data, numpy.float64) - #The next construction is not supported by bob - #read_write_check(outfile, 'float128_data', data, numpy.float128) - - data = [complex(random.uniform(0,1),random.uniform(-1,0)) for z in range(N)] - read_write_check(outfile, 'complex_data', data, complex) - #Note that because of double => float precision issues, the next test will - #fail. Python floats are actually double precision. - #read_write_check(outfile, 'complex64_data', data, numpy.complex64) - read_write_check(outfile, 'complex128_data', data, numpy.complex128) - #The next construction is not supported by bob - #read_write_check(outfile, 'complex256_data', data, numpy.complex256) - - read_write_array_check(outfile, numpy.int8) - read_write_array_check(outfile, numpy.int16) - read_write_array_check(outfile, numpy.int32) - read_write_array_check(outfile, numpy.int64) - read_write_array_check(outfile, numpy.uint8) - read_write_array_check(outfile, numpy.uint16) - read_write_array_check(outfile, numpy.uint32) - read_write_array_check(outfile, numpy.uint64) - read_write_array_check(outfile, numpy.float32) - read_write_array_check(outfile, numpy.float64) - #read_write_array_check(outfile, numpy.float128) #no numpy conversion - read_write_array_check(outfile, numpy.complex64) - read_write_array_check(outfile, numpy.complex128) - #read_write_array_check(outfile, numpy.complex256) #no numpy conversion - - read_write_subarray_check(outfile, numpy.int8) - read_write_subarray_check(outfile, numpy.int16) - read_write_subarray_check(outfile, numpy.int32) - read_write_subarray_check(outfile, numpy.int64) - read_write_subarray_check(outfile, numpy.uint8) - read_write_subarray_check(outfile, numpy.uint16) - read_write_subarray_check(outfile, numpy.uint32) - read_write_subarray_check(outfile, numpy.uint64) - read_write_subarray_check(outfile, numpy.float32) - read_write_subarray_check(outfile, numpy.float64) - #read_write_subarray_check(outfile, numpy.float128) #no numpy conversion - read_write_subarray_check(outfile, numpy.complex64) - read_write_subarray_check(outfile, numpy.complex128) - #read_write_subarray_check(outfile, numpy.complex256) #no numpy conversion - - finally: - os.unlink(tmpname) - -def test_dataset_management(): - - try: - - # This test examplifies dataset management within HDF5 files and how to - # copy, delete and move data around. - - # Let's just create some dummy data to play with - N = 100 - - tmpname = test_utils.temporary_filename() - outfile = HDF5File(tmpname, 'w') - - data = [int(random.uniform(0,N)) for z in range(N)] - outfile.append('int_data', data) - - # This is how to rename a dataset. - outfile.rename('int_data', 'MyRenamedDataset') - - # You can move the Dataset to any other hierarchy in the HDF5 file. The - # directory structure within the file (i.e. the HDF5 groups) will be - # created on demand. - outfile.rename('MyRenamedDataset', 'NewDirectory1/Dir2/MyDataset') - - # Let's move the MyDataset dataset to another directory - outfile.rename('NewDirectory1/Dir2/MyDataset', 'Test2/Bla') - - # So, now the original dataset name does not exist anymore - nose.tools.eq_(outfile.paths(), ['/Test2/Bla']) - - # We can also unlink the dataset from the file. Please note this will not - # erase the data in the file, just make it inaccessible - outfile.unlink('Test2/Bla') - - # Finally, nothing is there anymore - nose.tools.eq_(outfile.paths(), []) - - finally: - os.unlink(tmpname) - -def test_resize_and_preserve(): - - # This test checks that non-contiguous C-style array can be saved - # into an HDF5 file. - - try: - # Let's just create some dummy data to play with - SHAPE = (2, 3) #6 elements - NELEMENT = SHAPE[0] * SHAPE[1] - data = [int(random.uniform(0,10)) for z in range(NELEMENT)] - array = numpy.array(data, 'int32').reshape(SHAPE) - - # Try to save a slice - tmpname = test_utils.temporary_filename() - save(array[:,0], tmpname) - - finally: - os.unlink(tmpname) - -def test_can_load_hdf5_from_matlab(): - - # shows we can load a 2D matlab array and interpret it as a bunch of 1D - # arrays, correctly - - t = load(test_utils.datafile('matlab_1d.hdf5', __name__)) - nose.tools.eq_(t.shape, (512,)) - nose.tools.eq_(t.dtype, numpy.float64) - - t = load(test_utils.datafile('matlab_2d.hdf5', __name__)) - nose.tools.eq_(t.shape, (512, 2)) - nose.tools.eq_(t.dtype, numpy.float64) - - # interestingly enough, if you load those files as arrays, you will read - # the whole data at once: - - dtype, shape, stride = peek_all(test_utils.datafile('matlab_1d.hdf5', __name__)) - nose.tools.eq_(shape, (512,)) - nose.tools.eq_(dtype, numpy.dtype('float64')) - - dtype, shape, stride = peek_all(test_utils.datafile('matlab_2d.hdf5', __name__)) - nose.tools.eq_(shape, (512, 2)) - nose.tools.eq_(dtype, numpy.dtype('float64')) - -def test_matlab_import(): - - # This test verifies we can import HDF5 datasets generated in Matlab - mfile = HDF5File(test_utils.datafile('matlab_1d.hdf5', __name__)) - nose.tools.eq_(mfile.paths(), ['/array']) - -def test_ioload_unlimited(): - - # This test verifies that a 3D array whose first dimension is unlimited - # and size equal to 1 can be read as a 2D array - mfile = load(test_utils.datafile('test7_unlimited.hdf5', __name__)) - nose.tools.eq_(mfile.ndim, 2) - -def test_attribute_version(): - - try: - tmpname = test_utils.temporary_filename() - outfile = HDF5File(tmpname, 'w') - outfile.set_attribute('version', 32) - nose.tools.eq_(outfile.get_attribute('version'), 32) - - finally: - os.unlink(tmpname) - -def test_string_support(): - - try: - tmpname = test_utils.temporary_filename() - outfile = HDF5File(tmpname, 'w') - attribute = 'this is my long test string with \nNew lines' - outfile.set('string', attribute) - recovered = outfile.read('string') - #nose.tools.eq_(attribute, recovered) - - finally: - del outfile - os.unlink(tmpname) - -def test_string_attribute_support(): - - try: - tmpname = test_utils.temporary_filename() - outfile = HDF5File(tmpname, 'w') - attribute = 'this is my long test string with \nNew lines' - outfile.set_attribute('string', attribute) - recovered = outfile.get_attribute('string') - nose.tools.eq_(attribute, recovered) - - data = [1,2,3,4,5] - outfile.set('data', data) - outfile.set_attribute('string', attribute, 'data') - recovered = outfile.get_attribute('string', 'data') - nose.tools.eq_(attribute, recovered) - - finally: - os.unlink(tmpname) - -def test_can_use_set_with_iterables(): - - try: - tmpname = test_utils.temporary_filename() - outfile = HDF5File(tmpname, 'w') - data = [1, 34.5, True] - outfile.set('data', data) - assert numpy.array_equal(data, outfile.read('data')) - - finally: - os.unlink(tmpname) - -def test_has_attribute(): - - try: - tmpname = test_utils.temporary_filename() - outfile = HDF5File(tmpname, 'w') - i = 35 - f = 3.14 - outfile.set_attribute('int', i) - outfile.set_attribute('float', f) - assert outfile.has_attribute('int') - nose.tools.eq_(outfile.get_attribute('int'), 35) - assert outfile.has_attribute('float') - nose.tools.eq_(outfile.get_attribute('float'), 3.14) - - finally: - os.unlink(tmpname) - -def test_get_attributes(): - - try: - tmpname = test_utils.temporary_filename() - outfile = HDF5File(tmpname, 'w') - nothing = outfile.get_attributes() - nose.tools.eq_(len(nothing), 0) - assert isinstance(nothing, dict) - i = 35 - f = 3.14 - outfile.set_attribute('int', i) - outfile.set_attribute('float', f) - d = outfile.get_attributes() - nose.tools.eq_(d['int'], i) - nose.tools.eq_(d['float'], f) - - finally: - os.unlink(tmpname) - -def test_set_compression(): - - try: - - tmpname = test_utils.temporary_filename() - outfile = HDF5File(tmpname, 'w') - data = numpy.random.random((50,50)) - outfile.set('data', data, compression=9) - recovered = outfile.read('data') - assert numpy.array_equal(data, recovered) - del outfile - - finally: - - os.unlink(tmpname) - -def test_append_compression(): - - try: - - tmpname = test_utils.temporary_filename() - outfile = HDF5File(tmpname, 'w') - data = numpy.random.random((50,50)) - for k in range(len(data)): outfile.append('data', data[k], compression=9) - recovered = outfile.read('data') - assert numpy.array_equal(data, recovered) - - finally: - - os.unlink(tmpname) - - -def test_close(): - try: - tmpname = test_utils.temporary_filename() - outfile = HDF5File(tmpname, 'w') - outfile.close() - - def test_set(): - outfile.set("Test", numpy.array([1,2])) - nose.tools.assert_raises(RuntimeError, test_set) - - def test_read(): - test = outfile.read("Test") - nose.tools.assert_raises(RuntimeError, test_read) - - def test_filename(): - fn = outfile.filename - nose.tools.assert_raises(RuntimeError, test_filename) - - finally: - os.unlink(tmpname) - -def test_copy_constructor(): - try: - tmpname = test_utils.temporary_filename() - tmpname2 = test_utils.temporary_filename() - hdf5 = HDF5File(tmpname, 'w') - shallow = HDF5File(hdf5) - deep = HDF5File(tmpname2, 'w') - hdf5.copy(deep) - - hdf5.create_group("Test") - hdf5.cd("Test") - hdf5.set("Data", numpy.random.random((10,10))) - hdf5.flush() - - assert shallow.has_group("/Test") - assert shallow.has_key("/Test/Data") - assert hdf5.filename == shallow.filename - assert hdf5.keys() == shallow.keys() - assert hdf5.cwd == shallow.cwd - - assert not deep.has_group("/Test") - assert hdf5.filename != deep.filename - assert hdf5.keys() != deep.keys() - assert hdf5.cwd != deep.cwd - assert str(shallow) - - hdf5.cd("..") - - assert hdf5.sub_groups() == shallow.sub_groups() - assert hdf5.sub_groups() != deep.sub_groups() - - assert hdf5.writable - assert shallow.writable - assert deep.writable - - - hdf5.close() - deep.close() - - def test_filename(): - fn = shallow.filename - nose.tools.assert_raises(RuntimeError, test_filename) - def test_repr(): - fn = str(shallow) - nose.tools.assert_raises(RuntimeError, test_repr) - - finally: - os.unlink(tmpname) - os.unlink(tmpname2) - - -def test_python_interfaces(): - try: - tmpname = test_utils.temporary_filename() - with HDF5File(tmpname, 'w') as hdf5: - a = numpy.arange(10) - b = a * 2 - hdf5['Data'] = a - hdf5.create_group('Group1') - hdf5['Group1/Data'] = b - assert "/Group1/Data" in hdf5 - assert [key for key in hdf5] == hdf5.keys() - assert numpy.allclose(hdf5['Data'], hdf5.get('Data')) - assert all(numpy.allclose(c, d) for c, d in zip(hdf5.values(), (a, b))) - for key, value in hdf5.items(): - assert numpy.allclose(value, hdf5[key]) - - finally: - os.unlink(tmpname) - -def unicode_test(): - filename = u"Φîłèñäϻæ.hdf5" - - # writing using unicode filename - hdf5 = HDF5File(filename, 'w') - hdf5.set('Test', range(10)) - del hdf5 - - # writing using unicode filename - hdf5 = HDF5File(filename) - assert numpy.allclose(hdf5["Test"], range(10)) - os.remove(filename) - diff --git a/bob/io/base/test_io.py b/bob/io/base/test_io.py deleted file mode 100644 index f9092289667c1e6fd83bac7be9ea383fcedfb580..0000000000000000000000000000000000000000 --- a/bob/io/base/test_io.py +++ /dev/null @@ -1,96 +0,0 @@ -import nose -import numpy as np -import os -from . import vstack_features, save, load -from .test_utils import temporary_filename - - -def test_io_vstack(): - - paths = [1, 2, 3, 4, 5] - - def oracle(reader, paths): - return np.vstack([reader(p) for p in paths]) - - def reader_same_size_C(path): - return np.arange(10).reshape(5, 2) - - def reader_different_size_C(path): - return np.arange(2 * path).reshape(path, 2) - - def reader_same_size_F(path): - return np.asfortranarray(np.arange(10).reshape(5, 2)) - - def reader_different_size_F(path): - return np.asfortranarray(np.arange(2 * path).reshape(path, 2)) - - def reader_same_size_C2(path): - return np.arange(30).reshape(5, 2, 3) - - def reader_different_size_C2(path): - return np.arange(6 * path).reshape(path, 2, 3) - - def reader_same_size_F2(path): - return np.asfortranarray(np.arange(30).reshape(5, 2, 3)) - - def reader_different_size_F2(path): - return np.asfortranarray(np.arange(6 * path).reshape(path, 2, 3)) - - def reader_wrong_size(path): - return np.arange(2 * path).reshape(2, path) - - # when same_size is False - for reader in [ - reader_different_size_C, - reader_different_size_F, - reader_same_size_C, - reader_same_size_F, - reader_different_size_C2, - reader_different_size_F2, - reader_same_size_C2, - reader_same_size_F2, - ]: - np.all(vstack_features(reader, paths) == oracle(reader, paths)) - - # when same_size is True - for reader in [ - reader_same_size_C, - reader_same_size_F, - reader_same_size_C2, - reader_same_size_F2, - ]: - np.all(vstack_features(reader, paths, True) == oracle(reader, paths)) - - with nose.tools.assert_raises(AssertionError): - vstack_features(reader_wrong_size, paths) - - # test actual files - paths = [temporary_filename(), temporary_filename(), temporary_filename()] - try: - # try different readers: - for reader in [ - reader_different_size_C, - reader_different_size_F, - reader_same_size_C, - reader_same_size_F, - reader_different_size_C2, - reader_different_size_F2, - reader_same_size_C2, - reader_same_size_F2, - ]: - # save some data in files - for i, path in enumerate(paths): - save(reader(i + 1), path) - # test when all data is present - reference = oracle(load, paths) - np.all(vstack_features(load, paths) == reference) - os.remove(paths[0]) - # Check if RuntimeError is raised when one of the files is missing - with nose.tools.assert_raises(RuntimeError): - vstack_features(load, paths) - finally: - try: - for path in paths: - os.remove(path) - except Exception: - pass diff --git a/bob/io/base/utils.py b/bob/io/base/utils.py new file mode 100644 index 0000000000000000000000000000000000000000..16ccb62a660808c3b09685de599e2a17afa8152c --- /dev/null +++ b/bob/io/base/utils.py @@ -0,0 +1,126 @@ +import numpy as np + + +def to_matplotlib(img): + """Returns a view of the image from Bob format to matplotlib format. + This function works with images, batches of images, videos, and higher + dimensional arrays that contain images. + + Parameters + ---------- + img : numpy.ndarray + A N dimensional array containing an image in Bob format (channels + first): For an ND array (N >= 3), the image should have the following + format: ``(..., c, h, w)``. + + Returns + ------- + numpy.ndarray + A view of the ``img`` compatible with + :py:func:`matplotlib.pyplot.imshow`. + """ + if img.ndim < 3: + return img + return np.moveaxis(img, -3, -1) + + +def to_bob(img): + """Returns a view of the image from matplotlib format to Bob format. + This function works with images, batches of images, videos, and higher + dimensional arrays that contain images. + + Parameters + ---------- + img : numpy.ndarray + An image in matplotlib format (channels last): For an ND array (N >= 3), + the image should have the following format: ``(..., h, w, c)``. + + Returns + ------- + numpy.ndarray + A view of the ``img`` compatible with Bob. + """ + if img.ndim < 3: + return img + return np.moveaxis(img, -1, -3) + + +def opencvbgr_to_bob(img): + """Returns a view of the image from OpenCV BGR format to Bob RGB format. + This function works with images, batches of images, videos, and higher + dimensional arrays that contain images. + + Parameters + ---------- + img : numpy.ndarray + An image loaded by OpenCV. It needs to have at least 3 dimensions. + + Returns + ------- + numpy.ndarray + A view of the ``img`` compatible with Bob. + + Raises + ------ + ValueError + If the image dimension is less than 3. + """ + if img.ndim < 3: + raise ValueError("You need to provide at least a 3 dimensional image") + img = img[..., ::-1] + return to_bob(img) + + +def bob_to_opencvbgr(img): + """Returns a view of the image from Bob format to OpenCV BGR format. + This function works with images, batches of images, videos, and higher + dimensional arrays that contain images. + + Parameters + ---------- + img : numpy.ndarray + An image loaded by Bob. It needs to have at least 3 dimensions. + + Returns + ------- + numpy.ndarray + A view of the ``img`` compatible with OpenCV. + + Raises + ------ + ValueError + If the image dimension is less than 3. + """ + if img.ndim < 3: + raise ValueError("You need to provide at least a 3 dimensional image") + img = img[..., ::-1, :, :] + return to_matplotlib(img) + + +def imshow(img, cmap=None, **kwargs): + """Plots the images that are returned by :py:func:`bob.io.base.load` + + Parameters + ---------- + img : numpy.ndarray + A 2 or 3 dimensional array containing an image in + bob style: For a 2D array (grayscale image) should be ``(h, w)``; + A 3D array (color image) should be in the ``(c, h, w)`` format. + cmap : matplotlib.colors.Colormap + Colormap, optional, default: ``None``. + If ``cmap`` is ``None`` and ``img.ndim`` is 2, defaults to 'gray'. + ``cmap`` is ignored when ``img`` has RGB(A) information. + **kwargs + These are passed directly to :py:func:`matplotlib.pyplot.imshow` + + Returns + ------- + object + Returns whatever ``plt.imshow`` returns. + """ + import matplotlib.pyplot as plt + + if cmap is None and img.ndim == 2: + cmap = "gray" + + return plt.imshow(to_matplotlib(img), cmap=cmap, **kwargs) diff --git a/bob/io/base/version.cpp b/bob/io/base/version.cpp deleted file mode 100644 index 91ccc1d8dea0d399e87458031e0e649314f09378..0000000000000000000000000000000000000000 --- a/bob/io/base/version.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/** - * @author Andre Anjos <andre.anjos@idiap.ch> - * @date Thu 7 Nov 13:50:16 2013 - * - * @brief Binds configuration information available from bob - */ - -#define BOB_IMPORT_VERSION -#include <bob.blitz/config.h> -#include <bob.blitz/cleanup.h> -#include <bob.core/config.h> -#include <bob.io.base/config.h> - -static PyObject* build_version_dictionary() { - - PyObject* retval = PyDict_New(); - if (!retval) return 0; - auto retval_ = make_safe(retval); - - if (!dict_steal(retval, "HDF5", hdf5_version())) return 0; - if (!dict_steal(retval, "Boost", boost_version())) return 0; - if (!dict_steal(retval, "Compiler", compiler_version())) return 0; - if (!dict_steal(retval, "Python", python_version())) return 0; - if (!dict_steal(retval, "NumPy", numpy_version())) return 0; - if (!dict_steal(retval, "Blitz++", blitz_version())) return 0; - if (!dict_steal(retval, "bob.blitz", bob_blitz_version())) return 0; - if (!dict_steal(retval, "bob.core", bob_core_version())) return 0; - - return Py_BuildValue("O", retval); -} - -static PyMethodDef module_methods[] = { - {0} /* Sentinel */ -}; - -PyDoc_STRVAR(module_docstr, -"Information about software used to compile the C++ Bob API" -); - -#if PY_VERSION_HEX >= 0x03000000 -static PyModuleDef module_definition = { - PyModuleDef_HEAD_INIT, - BOB_EXT_MODULE_NAME, - module_docstr, - -1, - module_methods, - 0, 0, 0, 0 -}; -#endif - -static PyObject* create_module (void) { - -# if PY_VERSION_HEX >= 0x03000000 - PyObject* m = PyModule_Create(&module_definition); - auto m_ = make_xsafe(m); - const char* ret = "O"; -# else - PyObject* m = Py_InitModule3(BOB_EXT_MODULE_NAME, module_methods, module_docstr); - const char* ret = "N"; -# endif - if (!m) return 0; - - /* register version numbers and constants */ - if (PyModule_AddIntConstant(m, "api", BOB_IO_BASE_API_VERSION) < 0) - return 0; - if (PyModule_AddStringConstant(m, "module", BOB_EXT_MODULE_VERSION) < 0) - return 0; - if (PyModule_AddObject(m, "externals", build_version_dictionary()) < 0) return 0; - - // call bob_io_base_version once to avoid compiler warning - auto _ = make_safe(bob_io_base_version()); - - return Py_BuildValue(ret, m); -} - -PyMODINIT_FUNC BOB_EXT_ENTRY_NAME (void) { -# if PY_VERSION_HEX >= 0x03000000 - return -# endif - create_module(); -} diff --git a/conda/meta.yaml b/conda/meta.yaml index 815ac14fb9d24d6cebda0f711c75f8954a06cf80..debadfadd6c2ca6b7bb206de1a8cc77943155c06 100644 --- a/conda/meta.yaml +++ b/conda/meta.yaml @@ -17,27 +17,16 @@ build: - "{{ PYTHON }} -m pip install . -vv" requirements: - build: - - {{ compiler('c') }} - - {{ compiler('cxx') }} - - pkg-config {{ pkg_config }} - - cmake {{ cmake }} - - make {{ make }} host: - python {{ python }} - setuptools {{ setuptools }} - pip {{ pip }} - bob.extension - - bob.blitz - - bob.core - - libblitz {{ libblitz }} - - hdf5 {{ hdf5 }} - - boost {{ boost }} + - h5py {{ h5py }} - numpy {{ numpy }} run: - python - setuptools - - boost - {{ pin_compatible('numpy') }} test: diff --git a/doc/c_cpp_api.rst b/doc/c_cpp_api.rst deleted file mode 100644 index 95ea2401f514b1140766803b8aba5c5ffffdef87..0000000000000000000000000000000000000000 --- a/doc/c_cpp_api.rst +++ /dev/null @@ -1,168 +0,0 @@ -.. vim: set fileencoding=utf-8 : -.. Andre Anjos <andre.dos.anjos@gmail.com> -.. Tue 15 Oct 14:59:05 2013 - -========= - C++ API -========= - -The C++ API of ``bob.io.base`` allows users to leverage from automatic converters -for classes in :py:class:`bob.io.base`. To use the C API, clients should first, -include the header file ``<bob.io.base/api.h>`` on their compilation units and -then, make sure to call once ``import_bob_io_base()`` at their module -instantiation, as explained at the `Python manual -<http://docs.python.org/2/extending/extending.html#using-capsules>`_. - -Here is a dummy C example showing how to include the header and where to call -the import function: - -.. code-block:: c++ - - #include <bob.io.base/api.h> - - PyMODINIT_FUNC initclient(void) { - - PyObject* m Py_InitModule("client", ClientMethods); - - if (!m) return; - - /* imports dependencies */ - if (import_bob_blitz() < 0) { - PyErr_Print(); - PyErr_SetString(PyExc_ImportError, "cannot import extension"); - return 0; - } - - if (import_bob_io_base() < 0) { - PyErr_Print(); - PyErr_SetString(PyExc_ImportError, "cannot import extension"); - return 0; - } - - } - - -Generic Functions ------------------ - -.. cpp:function:: int PyBobIo_AsTypenum(bob::core::array::ElementType et) - - Converts the input Bob element type into a ``NPY_<TYPE>`` enumeration value. - Returns ``NPY_NOTYPE`` in case of problems, and sets a - :py:exc:`RuntimeError`. - -.. cpp:function:: PyObject* PyBobIo_TypeInfoAsTuple (const bob::core::array::typeinfo& ti) - - Converts the ``bob::core::array::typeinfo&`` object into a **new reference** - to a :py:class:`tuple` with 3 elements: - - [0] - The data type as a :py:class:`numpy.dtype` object - - [1] - The shape of the object, as a tuple of integers - - [2] - The strides of the object, as a tuple of integers - - Returns ``0`` in case of failure, or a **new reference** to the tuple - described above in case of success. - - -.. cpp:function:: int PyBobIo_FilenameConverter (PyObject* o, const char** b) - - This function is meant to be used with :c:func:`PyArg_ParseTupleAndKeywords` - family of functions in the Python C-API. It converts an arbitrary input - object into a ``const char*`` If the input object is of type - ``PyUnicodeObject`` (which is the default in Python3.x) the unicode code is - properly decoded using :c:func:`PyUnicode_AsEncodedString` with ``encoding`` - set to ``Py_FileSystemDefaultEncoding`` and ``errors`` set to ``"strict"``. - - Objects which are not ``PyUnicodeObject`` are first coerced into a - bytes/string before converting to the ``const char*`` object using - :c:func:`PyObject_Bytes` (on Python3.x) and :c:func:`PyObject_Str` - (on Python 2.x). - - Returns 0 if an error is detected, 1 on success. - - .. note:: - Since version 2.2, this function converts into ``const char*`` directly. - Before version 2.2, it was returning either ``PyBytesObject`` (Python 3) - or ``PyStringObject`` (Python 2). - - -Bob File Support ----------------- - -.. cpp:type:: PyBobIoFileObject - - The pythonic object representation for a ``bob::io::base::File`` object. - - .. code-block:: cpp - - typedef struct { - PyObject_HEAD - boost::shared_ptr<bob::io::base::File> f; - } PyBobIoFileObject; - - .. cpp:member:: boost::shared_ptr<bob::io::base::File> f - - A pointer to a file being read or written. - -.. cpp:type:: PyBobIoFileIteratorObject - - The pythonic object representation for an iterator over a - ``bob::io::base::File`` object. - - .. code-block:: cpp - - typedef struct { - PyObject_HEAD - PyBobIoFileObject* pyfile; - Py_ssize_t curpos; - } PyBobIoFileIteratorObject; - - .. cpp:member:: PyBobIoFileObject* pyfile - - A pointer to the pythonic representation of a file. - - .. cpp:member:: Py_ssize_t curpos - - The current position at the file being pointed to. - - -Bob HDF5 Support ----------------- - -.. cpp:type:: PyBobIoHDF5FileObject - - The pythonic object representation for a ``bob::io::base::HDF5File`` object. - - .. code-block:: cpp - - typedef struct { - PyObject_HEAD - boost::shared_ptr<bob::io::base::HDF5File> f; - } PyBobIoHDF5FileObject; - - .. cpp:member:: boost::shared_ptr<bob::io::base::HDF5File> f - - A pointer to a Bob object being used to read/write data into an HDF5 - file. - - -.. cpp:function:: int PyBobIoHDF5File_Check(PyObject* o) - - Checks if the input object ``o`` is a ``PyBobIoHDF5FileObject``. Returns - ``1`` if it is, and ``0`` otherwise. - - -.. cpp:function:: int PyBobIoHDF5File_Converter(PyObject* o, PyBobIoHDF5FileObject** a) - - This function is meant to be used with :c:func:`PyArg_ParseTupleAndKeywords` - family of functions in the Python C-API. It checks the input object to be of - type ``PyBobIoHDF5FileObject`` and sets a **new reference** to it (in - ``*a``) if it is the case. Returns ``0`` in case of failure, ``1`` in case - of success. - -.. include:: links.rst diff --git a/doc/extra-intersphinx.txt b/doc/extra-intersphinx.txt index 4a36b0b7319763e14836e18b5c569771a8498678..9c61c73639974afe3eafae36df0f4c8f36a72206 100644 --- a/doc/extra-intersphinx.txt +++ b/doc/extra-intersphinx.txt @@ -1,2 +1 @@ -scipy -bob.io.image +scipy \ No newline at end of file diff --git a/doc/guide.rst b/doc/guide.rst deleted file mode 100644 index 0c20a86418a07a15a83a09467ae05ded6ba94987..0000000000000000000000000000000000000000 --- a/doc/guide.rst +++ /dev/null @@ -1,382 +0,0 @@ -.. vim: set fileencoding=utf-8 : -.. Andre Anjos <andre.dos.anjos@gmail.com> -.. Fri 16 May 11:48:13 2014 CEST - -============ - User Guide -============ - -This section gives an overview of the operations for storing and retrieving the -basic data structures in |project|, such as `NumPy`_ arrays. |project| uses -`HDF5`_ format for storing binary coded data. Using the |project| support for -`HDF5`_, it is very simple to import and export data. - -`HDF5`_ uses a neat descriptive language for representing the data in the HDF5 -files, called Data Description Language (`DDL`_). - -To perform the functionalities given in this section, you should have `NumPy`_ -and |project| loaded into the `Python`_ environment. - -.. testsetup:: * - - import numpy - import bob.io.base - import tempfile - import os - - current_directory = os.path.realpath(os.curdir) - temp_dir = tempfile.mkdtemp(prefix='bob_doctest_') - os.chdir(temp_dir) - -HDF5 standard utilities ------------------------ - -Before explaining the basics of reading and writing to `HDF5`_ files, it is -important to list some `HDF5`_ standard utilities for checking the content of -an `HDF5`_ file. These are supplied by the `HDF5`_ project. - -``h5dump`` - Dumps the content of the file using the DDL. - -``h5ls`` - Lists the content of the file using DDL, but does not show the data. - -``h5diff`` - Finds the differences between HDF5 files. - -I/O operations using the class `bob.io.base.HDF5File` ------------------------------------------------------- - -Writing operations -~~~~~~~~~~~~~~~~~~ - -Let's take a look at how to write simple scalar data such as integers or -floats. - -.. doctest:: - - >>> an_integer = 5 - >>> a_float = 3.1416 - >>> f = bob.io.base.HDF5File('testfile1.hdf5', 'w') - >>> f.set('my_integer', an_integer) - >>> f.set('my_float', a_float) - >>> del f - -If after this you use the **h5dump** utility on the file ``testfile1.hdf5``, -you will verify that the file now contains: - -.. code-block:: none - - HDF5 "testfile1.hdf5" { - GROUP "/" { - DATASET "my_float" { - DATATYPE H5T_IEEE_F64LE - DATASPACE SIMPLE { ( 1 ) / ( 1 ) } - DATA { - (0): 3.1416 - } - } - DATASET "my_integer" { - DATATYPE H5T_STD_I32LE - DATASPACE SIMPLE { ( 1 ) / ( 1 ) } - DATA { - (0): 5 - } - } - } - } - -.. note:: - - In |project|, when you open a HDF5 file, you can choose one of the following - options: - - **'r'** Open the file in reading mode; writing operations will fail (this is the default). - - **'a'** Open the file in reading and writing mode with appending. - - **'w'** Open the file in reading and writing mode, but truncate it. - - **'x'** Read/write/append with exclusive access. - -The dump shows that there are two datasets inside a group named ``/`` in the -file. HDF5 groups are like file system directories. They create namespaces for -the data. In the root group (or directory), you will find the two variables, -named as you set them to be. The variable names are the complete path to the -location where they live. You could write a new variable in the same file but -in a different directory like this: - -.. doctest:: - - >>> f = bob.io.base.HDF5File('testfile1.hdf5', 'a') - >>> f.create_group('/test') - >>> f.set('/test/my_float', numpy.float32(6.28)) - >>> del f - -Line 1 opens the file for reading and writing, but without truncating it. This -will allow you to access the file contents. Next, the directory ``/test`` is -created and a new variable is written inside the subdirectory. As you can -verify, **for simple scalars**, you can also force the storage type. Where -normally one would have a 64-bit real value, you can impose that this variable -is saved as a 32-bit real value. You can verify the dump correctness with -``h5dump``: - -.. code-block:: none - - GROUP "/" { - ... - GROUP "test" { - DATASET "my_float" { - DATATYPE H5T_IEEE_F32LE - DATASPACE SIMPLE { ( 1 ) / ( 1 ) } - DATA { - (0): 6.28 - } - } - } - } - -Notice the subdirectory ``test`` has been created and inside it a floating -point number has been stored. Such a float point number has a 32-bit precision -as it was defined. - -.. note:: - - If you need to place lots of variables in a subfolder, it may be better to - setup the prefix folder before starting the writing operations on the - :py:class:`bob.io.base.HDF5File` object. You can do this using the method - :py:meth:`bob.io.base.HDF5File.cd`. Look up its help for more information and usage - instructions. - -Writing arrays is a little simpler as the :py:class:`numpy.ndarray` objects -encode all the type information we need to write and read them correctly. Here -is an example: - -.. doctest:: - - >>> A = numpy.array(range(4), 'int8').reshape(2,2) - >>> f = bob.io.base.HDF5File('testfile1.hdf5', 'a') - >>> f.set('my_array', A) - >>> f.close() - -The result of running ``h5dump`` on the file ``testfile1.hdf5`` should be: - -.. code-block:: none - - ... - DATASET "my_array" { - DATATYPE H5T_STD_I8LE - DATASPACE SIMPLE { ( 2, 2 ) / ( 2, 2 ) } - DATA { - (0,0): 0, 1, - (1,0): 2, 3 - } - } - ... - -You don't need to limit yourself to single variables, you can also save lists -of scalars and arrays using the function :py:meth:`bob.io.base.HDF5File.append` -instead of :py:meth:`bob.io.base.HDF5File.set`. - -Reading operations -~~~~~~~~~~~~~~~~~~ - -Reading data from a file that you just wrote to is just as easy. For this task -you should use :py:meth:`bob.io.base.HDF5File.read`. The read method will read -all the contents of the variable pointed to by the given path. This is the -normal way to read a variable you have written with -:py:meth:`bob.io.base.HDF5File.set`. If you decided to create a list of scalar -or arrays, the way to read that up would be using -:py:meth:`bob.io.base.HDF5File.lread` instead. Here is an example: - -.. doctest:: - - >>> f = bob.io.base.HDF5File('testfile1.hdf5') #read only - >>> f.read('my_integer') #reads integer - 5 - >>> print(f.read('my_array')) # reads the array - [[0 1] - [2 3]] - >>> del f - -Now let's look at an example where we have used -:py:meth:`bob.io.base.HDF5File.append` instead of -:py:meth:`bob.io.base.HDF5File.set` to write data to a file. That is normally -the case when you write lists of variables to a dataset. - -.. doctest:: - - >>> f = bob.io.base.HDF5File('testfile2.hdf5', 'w') - >>> f.append('arrayset', numpy.array(range(10), 'float64')) - >>> f.append('arrayset', 2*numpy.array(range(10), 'float64')) - >>> f.append('arrayset', 3*numpy.array(range(10), 'float64')) - >>> numpy.allclose((f.lread('arrayset', 0)),[ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.]) - True - >>> numpy.allclose( (f.lread('arrayset', 2)), [ 0., 3., 6., 9., 12., 15., 18., 21., 24., 27.]) - True - >>> del f - -This is what the ``h5dump`` of the file would look like: - -.. code-block:: none - - HDF5 "testfile4.hdf5" { - GROUP "/" { - DATASET "arrayset" { - DATATYPE H5T_IEEE_F64LE - DATASPACE SIMPLE { ( 3, 10 ) / ( H5S_UNLIMITED, 10 ) } - DATA { - (0,0): 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, - (1,0): 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, - (2,0): 0, 3, 6, 9, 12, 15, 18, 21, 24, 27 - } - } - } - } - -Notice that the expansion limits for the first dimension have been correctly -set by |project| so you can insert an *unlimited* number of 1D float vectors. -Of course, you can also read the whole contents of the arrayset in a single -shot: - -.. doctest:: - - >>> f = bob.io.base.HDF5File('testfile2.hdf5') - >>> numpy.allclose((f.read('arrayset')),[[ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.],[ 0., 2., 4., 6., 8., 10., 12., 14., 16., 18.],[ 0., 3., 6., 9., 12., 15., 18., 21., 24., 27.]]) - True - -As you can see, the only difference between -:py:meth:`bob.io.base.HDF5File.read` and -:py:meth:`bob.io.base.HDF5File.lread` is on how |project| considers the -available data (as a single array with N dimensions or as a set of arrays with -N-1 dimensions). In the first example, you would have also been able to read -the variable `my_array` as an arrayset using -:py:meth:`bob.io.base.HDF5File.lread` instead of -:py:meth:`bob.io.base.HDF5File.read`. In this case, each position readout -would return a 1D uint8 array instead of a 2D array. - - -Pythonic operations on HDF5 files -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -You can use some Pythonic opertations on :py:class:`bob.io.base.HDF5File`: - -* Use the ``with`` statement to open (and automatically close) HDF5 files. -* iterate over :py:class:`bob.io.base.HDF5File` objects to get an - iterable of keys instead of calling :py:meth:`bob.io.base.HDF5File.keys`. -* use the ``in`` keyword instead of calling - :py:meth:`bob.io.base.HDF5File.has_key`. -* use Python's dictionary syntax instead of :py:meth:`bob.io.base.HDF5File.set` - and :py:meth:`bob.io.base.HDF5File.get`. - -For example: - - -.. doctest:: - - >>> f = bob.io.base.HDF5File('testfile3.hdf5', 'w') - >>> array = numpy.arange(5) - >>> f['my_array'] = array # f.set('my_array', array) - >>> f['my_array'] # f.get('my_array') - array([0, 1, 2, 3, 4]) - >>> 'my_array' in f # f.has_key('my_array') - True - >>> [key for key in f] # f.keys() - ['/my_array'] - >>> f.create_group('group1') - >>> f.cd('group1') - >>> f['my_array_in_group'] = array - >>> f.cd('/') - >>> # keys(), values(), and items() just like a dictionary - >>> [key for key in f.keys()] - ['/my_array', '/group1/my_array_in_group'] - >>> [value for value in f.values()] - [array([0, 1, 2, 3, 4]), array([0, 1, 2, 3, 4])] - >>> [(key, value) for key, value in f.items()] - [('/my_array', array([0, 1, 2, 3, 4])), ('/group1/my_array_in_group', array([0, 1, 2, 3, 4]))] - >>> f.close() - >>> # using a with statement to open and close files - >>> with bob.io.base.HDF5File('testfile3.hdf5', 'a') as f: - ... f['second_array'] = array - >>> f = bob.io.base.HDF5File('testfile3.hdf5', 'r') - >>> 'second_array' in f - True - -Array interfaces ----------------- - -What we have shown so far is the generic API to read and write data using HDF5. -You will use it when you want to import or export data from |project| into -other software frameworks, debug your data or just implement your own classes -that can serialize and de-serialize from HDF5 file containers. In |project|, -most of the time you will be working with :py:class:`numpy.ndarray`\s. In -special situations though, you may be asked to handle -:py:class:`bob.io.base.File`\s. :py:class:`bob.io.base.File` objects create a -transparent connection between C++ (`Blitz++`_) / Python (`NumPy`_) arrays and -file access. You specify the filename from which you want to input data and -the :py:class:`bob.io.base.File` object decides what is the best codec to be -used (from the extension) and how to read the data back into your array. - -To create an :py:class:`bob.io.base.File` from a file path, just do the -following: - -.. doctest:: - - >>> a = bob.io.base.File('testfile2.hdf5', 'r') - >>> a.filename - 'testfile2.hdf5' - -:py:class:`bob.io.base.File`\s simulate containers for -:py:class:`numpy.ndarray`\s, transparently accessing the file data when -requested. Note, however, that when you instantiate an -:py:class:`bob.io.base.File` it does **not** load the file contents into -memory. It waits until you emit another explicit instruction to do so. We do -this with the :py:meth:`bob.io.base.File.read` method: - -.. doctest:: - - >>> array = a.read() - >>> numpy.allclose(array, [[ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.],[ 0., 2., 4., 6., 8., 10., 12., 14., 16., 18.],[ 0., 3., 6., 9., 12., 15., 18., 21., 24., 27.]]) - True - -Every time you say :py:meth:`bob.io.base.File.read`, the file contents will be -read from the file and into a new array. - -Saving arrays to the :py:class:`bob.io.base.File` is as easy, just call the -:py:meth:`bob.io.base.File.write` method: - -.. doctest:: - - >>> f = bob.io.base.File('copy1.hdf5', 'w') - >>> f.write(array) - -Numpy ndarray shortcuts ------------------------ - -To just load an :py:class:`numpy.ndarray` in memory, you can use a short cut -that lives at :py:func:`bob.io.base.load`. With it, you don't have to go -through the :py:class:`bob.io.base.File` container: - -.. doctest:: - - >>> t = bob.io.base.load('testfile2.hdf5') - >>> numpy.allclose(t, [[ 0., 1., 2., 3., 4., 5., 6., 7., 8., 9.], [ 0., 2., 4., 6., 8., 10., 12., 14., 16., 18.],[ 0., 3., 6., 9., 12., 15., 18., 21., 24., 27.]]) - True - -You can also directly save :py:class:`numpy.ndarray`\s without going through -the :py:class:`bob.io.base.File` container: - -.. doctest:: - - >>> bob.io.base.save(t, 'copy2.hdf5') - -.. note:: - - Under the hood, we still use the :py:class:`bob.io.base.File` API to execute - the read and write operations. Have a look at the manual section for - :py:mod:`bob.io.base` for more details and other shortcuts available. - - -.. Place here your external references -.. include:: links.rst -.. _ddl: http://www.hdfgroup.org/HDF5/doc/ddl.html diff --git a/doc/index.rst b/doc/index.rst index c24f65185d8b46f4ae7b482ff5ba5ee694b11490..74ade76611a9b7954f0f7e8fdfd6a44817f9f477 100644 --- a/doc/index.rst +++ b/doc/index.rst @@ -13,12 +13,10 @@ Below is the old documentation. This module contains a basic interface to read and write files of various types. It provides generic functions :py:func:`bob.io.base.save` and -:py:func:`bob.io.base.load` to write and read various types of data. In this -interface, data is mainly written using the :py:class:`bob.io.base.HDF5File` -interface. To enable further types of IO, please import one of the following +:py:func:`bob.io.base.load` to write and read various types of data. +To enable further types of IO, please import one of the following packages (the list might not be exhaustive): -* :ref:`bob.io.image` to load and save images of various kinds Documentation @@ -27,9 +25,7 @@ Documentation .. toctree:: :maxdepth: 2 - guide - py_api - c_cpp_api + py_api TODO ---- diff --git a/doc/nitpick-exceptions.txt b/doc/nitpick-exceptions.txt index 97040cc3e01e18ad17e72a44d841e4a36b663f7e..f61551fb3429356607e4f0c7f299aa2537fcc3e1 100644 --- a/doc/nitpick-exceptions.txt +++ b/doc/nitpick-exceptions.txt @@ -1,37 +1,6 @@ -# these are actually c types -cpp:type PyObject -cpp:type Py_ssize_t -cpp:typeOrConcept PyObject -cpp:typeOrConcept Py_ssize_t - -# no reference exists for these -cpp:type bob -cpp:type bob::core -cpp:type bob::core::array -cpp:type bob::core::array::typeinfo -cpp:type bob::core::array::ElementType -cpp:type boost -cpp:type boost::shared_ptr -cpp:type bob::io -cpp:type bob::io::base -cpp:type bob::io::base::File -cpp:type bob::io::base::HDF5File -cpp:typeOrConcept bob -cpp:typeOrConcept bob::core -cpp:typeOrConcept bob::core::array -cpp:typeOrConcept bob::core::array::typeinfo -cpp:typeOrConcept bob::core::array::ElementType -cpp:typeOrConcept boost -cpp:typeOrConcept boost::shared_ptr -cpp:typeOrConcept bob::io -cpp:typeOrConcept bob::io::base -cpp:typeOrConcept bob::io::base::File -cpp:typeOrConcept bob::io::base::HDF5File - # exceptions are not found in python 2.7 py:exc RuntimeError py:class tuple -c:func PyUnicode_FSConverter # these don't exists on numpy's manual py:class numpy.uint8 diff --git a/doc/py_api.rst b/doc/py_api.rst index 512c928a6cc045817a8fb067bdeac926530cc066..bec56c499f404a46c25d909bdad0e191c5d57959 100644 --- a/doc/py_api.rst +++ b/doc/py_api.rst @@ -8,46 +8,14 @@ This section includes information for using the pure Python API of ``bob.io.base``. - -Classes -------- - -.. autosummary:: - bob.io.base.File - bob.io.base.HDF5File - Functions --------- .. autosummary:: bob.io.base.load - bob.io.base.merge bob.io.base.save - bob.io.base.append - bob.io.base.peek - bob.io.base.peek_all bob.io.base.create_directories_safe bob.io.base.vstack_features - bob.io.base.extensions - bob.io.base.get_config - -Test Utilities --------------- - -These functions might be useful when you are writing your nose tests. -Please note that this is not part of the default ``bob.io.base`` API, so in order to use it, you have to ``import bob.io.base.test_utils`` separately. - -.. autosummary:: - bob.io.base.test_utils.datafile - bob.io.base.test_utils.temporary_filename - bob.io.base.test_utils.extension_available - - -Details -------- -.. automodule:: bob.io.base - :inherited-members: -.. automodule:: bob.io.base.test_utils diff --git a/requirements.txt b/requirements.txt index f2e31dbe624eabd83f221582a1e9862ccf937535..8fd79bb91084c43678b904bdba2638a0a481bcda 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1 @@ bob.extension -bob.blitz -bob.core > 2.1.3 diff --git a/setup.py b/setup.py index 76389924fd4a5b8b7ee470e0b787c90cb6ea5d66..99c943d9a5f182e1ec0025264f3fb9ceb9fa9444 100644 --- a/setup.py +++ b/setup.py @@ -2,217 +2,44 @@ # vim: set fileencoding=utf-8 : # Andre Anjos <andre.anjos@idiap.ch> # Mon 16 Apr 08:18:08 2012 CEST +# +from setuptools import setup, dist -bob_packages = ['bob.core'] +dist.Distribution(dict(setup_requires=["bob.extension"])) -from setuptools import setup, find_packages, dist -dist.Distribution(dict(setup_requires=['bob.extension', 'bob.blitz'] + bob_packages)) -from bob.extension.utils import egrep, find_header, find_library -from bob.extension import pkgconfig -from bob.blitz.extension import Extension, Library, build_ext - -from bob.extension.utils import load_requirements -build_requires = load_requirements() - -# Define package version -version = open("version.txt").read().rstrip() - -packages = ['boost'] -boost_modules = ['system', 'filesystem'] - -def libhdf5_version(header): - - vv = egrep(header, r"#\s*define\s+H5_VERSION\s+\"([\d\.]+)\"") - if not len(vv): return None - return vv[0].group(1) - -class hdf5: - - def __init__ (self): - """ - Searches for libhdf5 in stock locations. Allows user to override. - - If the user sets the environment variable BOB_PREFIX_PATH, that prefixes - the standard path locations. - - """ - import os - - self.name = 'hdf5' - - # try to locate pkg-config on our own first - try: - - header = 'hdf5.h' - - candidates = find_header(header) - - if not candidates: - raise RuntimeError("could not find %s's `%s' - have you installed %s on this machine?" % (self.name, header, self.name)) - - self.include_directories = [os.path.dirname(candidates[0])] - directory = os.path.dirname(candidates[0]) - version_header = os.path.join(directory, 'H5pubconf.h') - self.version = libhdf5_version(version_header) - - # normalize - self.include_directories = [os.path.normpath(i) for i in self.include_directories] - - # find library - prefix = os.path.dirname(os.path.dirname(self.include_directories[0])) - module = 'hdf5' - candidates = find_library(module, version=self.version, prefixes=[prefix], only_static=False) - - if not candidates: - raise RuntimeError("cannot find required %s binary module `%s' - make sure libhdf5 is installed on `%s'" % (self.name, module, prefix)) - - # libraries - self.libraries = [] - name, ext = os.path.splitext(os.path.basename(candidates[0])) - if ext in ['.so', '.a', '.dylib', '.dll']: - self.libraries.append(name[3:]) #strip 'lib' from the name - else: #link against the whole thing - self.libraries.append(':' + os.path.basename(candidates[0])) - - # library path - self.library_directories = [os.path.dirname(candidates[0])] - - except RuntimeError: - # now, we try to use pkg-config, which seems to be only available on Debian - pkg = pkgconfig('hdf5') - self.include_directories = pkg.include_directories() - version_header = os.path.join(self.include_directories[0], 'H5pubconf.h') - self.version = libhdf5_version(version_header) - self.libraries = pkg.libraries() - self.library_directories = pkg.library_directories() - - - def macros(self): - return [ - ('HAVE_%s' % self.name.upper(), '1'), - # see https://portal.hdfgroup.org/display/HDF5/Migrating+from+HDF5+1.10+to+HDF5+1.12 - ('H5_USE_110_API', '1'), - ] - - -hdf5_pkg = hdf5() - -system_include_dirs = hdf5_pkg.include_directories - -library_dirs = hdf5_pkg.library_directories - -libraries = hdf5_pkg.libraries - -define_macros = hdf5_pkg.macros() +from bob.extension.utils import load_requirements, find_packages +install_requires = load_requirements() +# The only thing we do in this file is to call the setup() function with all +# parameters that define our package. setup( - - name='bob.io.base', - version=version, - description='Basic IO for Bob', - url='http://gitlab.idiap.ch/bob/bob.io.base', - license='BSD', - author='Andre Anjos', - author_email='andre.anjos@idiap.ch', - - long_description=open('README.rst').read(), - + # This is the basic information about your project. Modify all this + # information before releasing code publicly. + name="bob.io.base", + version=open("version.txt").read().rstrip(), + description="Basic IO for Bob", + url="http://gitlab.idiap.ch/bob/bob.io.base", + license="BSD", + author="Andre Anjos", + author_email="andre.anjos@idiap.ch", + long_description=open("README.rst").read(), packages=find_packages(), include_package_data=True, zip_safe=False, - - setup_requires = build_requires, - install_requires = build_requires, - - - - ext_modules = [ - Extension("bob.io.base.version", - [ - "bob/io/base/version.cpp", - ], - define_macros = define_macros, - system_include_dirs = system_include_dirs, - version = version, - bob_packages = bob_packages, - packages = packages, - boost_modules = boost_modules, - ), - - Library("bob.io.base.bob_io_base", - [ - "bob/io/base/cpp/CodecRegistry.cpp", - "bob/io/base/cpp/File.cpp", - "bob/io/base/cpp/HDF5ArrayFile.cpp", - "bob/io/base/cpp/HDF5Attribute.cpp", - "bob/io/base/cpp/HDF5Dataset.cpp", - "bob/io/base/cpp/HDF5File.cpp", - "bob/io/base/cpp/HDF5Group.cpp", - "bob/io/base/cpp/HDF5Types.cpp", - "bob/io/base/cpp/HDF5Utils.cpp", - "bob/io/base/cpp/reorder.cpp", - "bob/io/base/cpp/utils.cpp", - "bob/io/base/cpp/array.cpp", - "bob/io/base/cpp/array_type.cpp", - "bob/io/base/cpp/blitz_array.cpp", - ], - libraries = libraries, - library_dirs = library_dirs, - system_include_dirs = system_include_dirs, - define_macros = define_macros, - version = version, - bob_packages = bob_packages, - packages = packages, - boost_modules = boost_modules, - ), - - Extension("bob.io.base._library", - [ - "bob/io/base/bobskin.cpp", - "bob/io/base/codec.cpp", - "bob/io/base/file.cpp", - "bob/io/base/hdf5.cpp", - "bob/io/base/main.cpp", - ], - library_dirs = library_dirs, - libraries = libraries, - define_macros = define_macros, - system_include_dirs = system_include_dirs, - version = version, - bob_packages = bob_packages, - packages = packages, - boost_modules = boost_modules, - ), - - Extension("bob.io.base._test", - [ - "bob/io/base/test.cpp", - ], - library_dirs = library_dirs, - libraries = libraries, - define_macros = define_macros, - system_include_dirs = system_include_dirs, - version = version, - bob_packages = bob_packages, - packages = packages, - boost_modules = boost_modules, - ), + setup_requires=install_requires, + install_requires=install_requires, + # Classifiers are important if you plan to distribute this package through + # PyPI. You can find the complete list of classifiers that are valid and + # useful here (http://pypi.python.org/pypi?%3Aaction=list_classifiers). + classifiers=[ + "Framework :: Bob", + "Development Status :: 4 - Beta", + "Intended Audience :: Developers", + "License :: OSI Approved :: BSD License", + "Natural Language :: English", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Topic :: Software Development :: Libraries :: Python Modules", ], - - cmdclass = { - 'build_ext': build_ext - }, - - classifiers = [ - 'Framework :: Bob', - 'Development Status :: 4 - Beta', - 'Intended Audience :: Developers', - 'License :: OSI Approved :: BSD License', - 'Natural Language :: English', - 'Programming Language :: Python', - 'Programming Language :: Python :: 3', - 'Topic :: Software Development :: Libraries :: Python Modules', - ], - - ) +)