diff --git a/src/constants.cc b/src/constants.cc index 1100ba0..00205be 100644 --- a/src/constants.cc +++ b/src/constants.cc @@ -10,18 +10,32 @@ namespace php_arma { - template + template zend_always_inline - void const_declare(zend_class_entry *ce, Ts&&... constants) + void const_declare(zend_class_entry *ce, F&& func, Ts&&... constants) { for (auto&& [name, val] : { constants... }) { - zend_declare_class_constant_long(ce, name, strlen(name), val); + func(ce, name, strlen(name), val); } } + template + zend_always_inline + void long_const_declare(zend_class_entry *ce, Ts&&... constants) + { + const_declare(ce, zend_declare_class_constant_long, std::forward(constants)...); + } + + template + zend_always_inline + void bool_const_declare(zend_class_entry *ce, Ts&&... constants) + { + const_declare(ce, zend_declare_class_constant_bool, std::forward(constants)...); + } + void constants_init() { - const_declare(fill_ce = abstract_class_register(), + long_const_declare(fill_ce = abstract_class_register(), std::make_tuple("NONE", fill::none), std::make_tuple("ZEROS", fill::zeros), std::make_tuple("ONES", fill::ones), @@ -29,7 +43,7 @@ namespace php_arma std::make_tuple("RANDU", fill::randu), std::make_tuple("RANDN", fill::randn) ); - const_declare(file_type_ce = abstract_class_register(), + long_const_declare(file_type_ce = abstract_class_register(), std::make_tuple("AUTO_DETECT", file_type::auto_detect), std::make_tuple("ARMA_BINARY", file_type::arma_binary), std::make_tuple("ARMA_ASCII", file_type::arma_ascii), @@ -40,23 +54,24 @@ namespace php_arma std::make_tuple("PGM_BINARY", file_type::pgm_binary), std::make_tuple("HDF5_BINARY", file_type::hdf5_binary) ); - const_declare(sort_direction_ce = abstract_class_register(), + long_const_declare(sort_direction_ce = abstract_class_register(), std::make_tuple("ASCEND", sort_direction::ascend), std::make_tuple("DESCEND", sort_direction::descend), std::make_tuple("STRICT_ASCEND", sort_direction::strict_ascend), std::make_tuple("STRICT_DESCEND", sort_direction::strict_descend) ); #ifdef ARMA_USE_HDF5 - const_declare(hdf5_opts_ce = abstract_class_register(), + long_const_declare(hdf5_opts_ce = abstract_class_register(), std::make_tuple("NONE", hdf5_opts::none), std::make_tuple("TRANS", hdf5_opts::trans), std::make_tuple("APPEND", hdf5_opts::append), std::make_tuple("REPLACE", hdf5_opts::replace) ); #endif // ARMA_USE_HDF5 - const_declare(features_ce = abstract_class_register(), + bool_const_declare(features_ce = abstract_class_register(), std::make_tuple("OPERATORS", features::operators), - std::make_tuple("HDF5", features::hdf5) + std::make_tuple("HDF5", features::hdf5), + std::make_tuple("STREAM_RES", features::stream_res) ); } } diff --git a/src/constants.hh b/src/constants.hh index f1c0d71..1b23dbf 100644 --- a/src/constants.hh +++ b/src/constants.hh @@ -133,7 +133,7 @@ namespace php_arma static constexpr auto replace = 1u << 2; }; - constexpr const char hdf5_opts_php_name[] = "HDF5Opts"; + constexpr const char hdf5_opts_php_name[] = "Hdf5Opts"; inline zend_class_entry *hdf5_opts_ce; #endif // ARMA_USE_HDF5 @@ -149,6 +149,11 @@ namespace php_arma #else static constexpr auto hdf5 = false; #endif // ARMA_USE_HDF5 +#if defined(__GNUC__) && !defined(__clang__) + static constexpr auto stream_res = true; +#else + static constexpr auto stream_res = false; +#endif }; constexpr const char features_php_name[] = "Features"; diff --git a/stubs/Features.php b/stubs/Features.php index ad0e61c..db90408 100644 --- a/stubs/Features.php +++ b/stubs/Features.php @@ -20,4 +20,9 @@ abstract class Features * Whether data can be saved into or loaded from files in HDF5 format. */ const HDF5 = true; + + /** + * Whether this extension supports PHP stream resource I/O. + */ + const STREAM_RES = true; } diff --git a/stubs/HDF5Opts.php b/stubs/Hdf5Opts.php similarity index 96% rename from stubs/HDF5Opts.php rename to stubs/Hdf5Opts.php index 6a14faf..19fbc3c 100644 --- a/stubs/HDF5Opts.php +++ b/stubs/Hdf5Opts.php @@ -7,7 +7,7 @@ namespace Arma; * * @package Arma */ -abstract class HDF5Opts +abstract class Hdf5Opts { /** * No extra options. diff --git a/stubs/internal/Base.php b/stubs/internal/Base.php index 0e06002..93eedc9 100644 --- a/stubs/internal/Base.php +++ b/stubs/internal/Base.php @@ -156,7 +156,9 @@ interface Base extends Countable function hasNan(); /** - * Print the contents of the object to a stream. + * Print the contents of the object to a stream resource. + * + * Feature\STREAM_RES must be true if $stream is specified. * * @param resource $stream[optional] * @return void @@ -165,6 +167,8 @@ interface Base extends Countable /** * Similar to the print() member function, with the difference that no formatting of the output is done. + * + * Feature\STREAM_RES must be true if $stream is specified. * * @param resource $stream[optional] * @return void diff --git a/stubs/internal/Resizable.php b/stubs/internal/Resizable.php index 2bb915c..38e4e47 100644 --- a/stubs/internal/Resizable.php +++ b/stubs/internal/Resizable.php @@ -55,7 +55,7 @@ interface Resizable // Saving/loading /** - * Store data in a file or stream (the stream must be opened in binary mode). + * Store data in a file or stream resource (Feature\STREAM_RES must be true). * * Data will be saved to $dest, which can be the file name, stream handle, or (HDF5 only) an array which * specifies HDF5 names and options (['file_name' => string, 'dataset_name' => string, 'options' => int]). @@ -67,7 +67,7 @@ interface Resizable function save($dest, $file_type = FileType::ARMA_BINARY); /** - * Retrieve data from a file or stream (the stream must be opened in binary mode). + * Retrieve data from a file or stream resource (Feature\STREAM_RES must be true). * * Data will be read from $from, which can be the source file name, stream handle, or (HDF5 only) * an array which specifies HDF5 names and options. diff --git a/tests/000-constants.phpt b/tests/000-constants.phpt index c95ba5e..fd53717 100644 --- a/tests/000-constants.phpt +++ b/tests/000-constants.phpt @@ -11,7 +11,7 @@ is_php_arma_loaded(); require_once 'includes/assert.php'; use Arma\ { - Fill, FileType, SortDirection, HDF5Opts + Fill, FileType, SortDirection, Hdf5Opts }; $fill = [Fill::NONE, Fill::ZEROS, Fill::ONES, Fill::EYE, Fill::RANDU, Fill::RANDN]; @@ -24,7 +24,7 @@ $sort_direction = [ SortDirection::ASCEND, SortDirection::DESCEND, SortDirection::STRICT_ASCEND, SortDirection::STRICT_DESCEND ]; -$hdf5_opts = [HDF5Opts::TRANS >> 0, HDF5Opts::APPEND >> 1, HDF5Opts::REPLACE >> 2]; +$hdf5_opts = [Hdf5Opts::TRANS >> 0, Hdf5Opts::APPEND >> 1, Hdf5Opts::REPLACE >> 2]; batch_assert('constants', [range(0, 5), $fill], diff --git a/tests/004-mat-save-load.phpt b/tests/004-mat-save-load.phpt index 4e27b21..fdf42ed 100644 --- a/tests/004-mat-save-load.phpt +++ b/tests/004-mat-save-load.phpt @@ -3,7 +3,10 @@ Test save/load for `Arma\Mat`. --SKIPIF-- --ENV-- TMP_FILE=/tmp/php_arma_test.tmp diff --git a/tests/008-save-load-hdf5.phpt b/tests/008-save-load-hdf5.phpt index 2a4a24e..d8f36bf 100644 --- a/tests/008-save-load-hdf5.phpt +++ b/tests/008-save-load-hdf5.phpt @@ -3,6 +3,7 @@ Test save/load with HDF5 format for `Arma\Mat`. --SKIPIF-- $file_name, 'dataset_name' => 'tmp_dataset', - 'options' => Arma\HDF5Opts::TRANS + 'options' => Arma\Hdf5Opts::TRANS ]; $mat = Arma\IMat::init(3, 3, Arma\Fill::RANDN); diff --git a/tests/includes/supports.php b/tests/includes/supports.php index 5337b11..59f6a23 100644 --- a/tests/includes/supports.php +++ b/tests/includes/supports.php @@ -24,6 +24,15 @@ function supports_operator_overloading() { return arma_supports(Arma\Features::OPERATORS, 'operator overloading'); } +/** + * Check whether I/O with PHP stream resource is supported. + * + * @return bool + */ +function supports_stream_resource() { + return arma_supports(Arma\Features::STREAM_RES, 'stream resource'); +} + /** * Check whether HDF5 data format is supported. *