GNU Octave 10.1.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 
Loading...
Searching...
No Matches
ov-base-int.cc
Go to the documentation of this file.
1////////////////////////////////////////////////////////////////////////
2//
3// Copyright (C) 2004-2025 The Octave Project Developers
4//
5// See the file COPYRIGHT.md in the top-level directory of this
6// distribution or <https://octave.org/copyright/>.
7//
8// This file is part of Octave.
9//
10// Octave is free software: you can redistribute it and/or modify it
11// under the terms of the GNU General Public License as published by
12// the Free Software Foundation, either version 3 of the License, or
13// (at your option) any later version.
14//
15// Octave is distributed in the hope that it will be useful, but
16// WITHOUT ANY WARRANTY; without even the implied warranty of
17// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18// GNU General Public License for more details.
19//
20// You should have received a copy of the GNU General Public License
21// along with Octave; see the file COPYING. If not, see
22// <https://www.gnu.org/licenses/>.
23//
24////////////////////////////////////////////////////////////////////////
25
26// This file should not include config.h. It is only included in other
27// C++ source files that should have included config.h before including
28// this file.
29
30#include <istream>
31#include <limits>
32#include <ostream>
33#include <sstream>
34#include <vector>
35
36#include "dNDArray.h"
37#include "fNDArray.h"
38#include "int8NDArray.h"
39#include "int16NDArray.h"
40#include "int32NDArray.h"
41#include "int64NDArray.h"
42#include "uint8NDArray.h"
43#include "uint16NDArray.h"
44#include "uint32NDArray.h"
45#include "uint64NDArray.h"
46
47#include "lo-ieee.h"
48#include "lo-utils.h"
49#include "mx-base.h"
50#include "quit.h"
51#include "oct-locbuf.h"
52
53#include "defun.h"
54#include "errwarn.h"
55#include "ovl.h"
56#include "oct-lvalue.h"
57#include "oct-hdf5.h"
58#include "oct-stream.h"
59#include "ops.h"
60#include "ov-base.h"
61#include "ov-base-int.h"
62#include "ov-int-traits.h"
63#include "pr-output.h"
64#include "variables.h"
65
66#include "byte-swap.h"
67#include "ls-oct-text.h"
68#include "ls-utils.h"
69#include "ls-hdf5.h"
70
71// We have all the machinery below (octave_base_int_helper and
72// octave_base_int_helper_traits) to avoid a few warnings from GCC
73// about comparisons always false due to limited range of data types.
74// Ugh. The cure may be worse than the disease.
75
76template <typename T, bool is_signed = true, bool can_be_too_big = true>
77struct octave_base_int_helper
78{
79public:
80 static bool
81 char_value_out_of_range (T val)
82 {
83 return val < 0 || val > std::numeric_limits<unsigned char>::max ();
84 }
85};
87template <typename T>
88struct octave_base_int_helper<T, false, false>
90public:
91 static bool char_value_out_of_range (T) { return false; }
92};
93
94template <typename T>
95struct octave_base_int_helper<T, false, true>
97public:
98 static bool char_value_out_of_range (T val)
99 {
100 return val > std::numeric_limits<unsigned char>::max ();
103
104template <typename T>
105struct octave_base_int_helper<T, true, false>
106{
107public:
108 static bool char_value_out_of_range (T val) { return val < 0; }
109};
111// For all types other than char, signed char, and unsigned char, we
112// assume that the upper limit for the range of allowable values is
113// larger than the range for unsigned char. If that's not true, we
114// are still OK, but will see the warnings again for any other types
115// that do not meet this assumption.
116
117template <typename T>
118struct octave_base_int_helper_traits
119{
120 static const bool can_be_larger_than_uchar_max = true;
121};
122
123template <>
124struct octave_base_int_helper_traits<char>
125{
126 static const bool can_be_larger_than_uchar_max = false;
127};
128
129template <>
130struct octave_base_int_helper_traits<signed char>
131{
132 static const bool can_be_larger_than_uchar_max = false;
133};
134
135template <>
136struct octave_base_int_helper_traits<unsigned char>
137{
138 static const bool can_be_larger_than_uchar_max = false;
139};
140
141template <typename T>
144{
145 octave_base_value *retval = nullptr;
146
147 if (this->m_matrix.numel () == 1)
148 retval = new typename octave_value_int_traits<T>::scalar_type
149 (this->m_matrix (0));
150
151 return retval;
152}
153
154template <typename T>
157{
158 octave_value retval;
159 const dim_vector& dv = this->dims ();
160 octave_idx_type nel = dv.numel ();
161
162 charNDArray chm (dv);
163
164 bool warned = false;
165
166 for (octave_idx_type i = 0; i < nel; i++)
167 {
168 octave_quit ();
169
170 typename T::element_type tmp = this->m_matrix(i);
171
172 typedef typename T::element_type::val_type val_type;
173
174 val_type ival = tmp.value ();
176 static constexpr bool is_signed = std::numeric_limits<val_type>::is_signed;
177 static constexpr bool can_be_larger_than_uchar_max
178 = octave_base_int_helper_traits<val_type>::can_be_larger_than_uchar_max;
179
180 if (octave_base_int_helper<val_type, is_signed,
181 can_be_larger_than_uchar_max>::char_value_out_of_range (ival))
183 // FIXME: is there something better we could do?
184
185 ival = 0;
187 if (! warned)
189 ::warning ("range error for conversion to character value");
190 warned = true;
192 }
193 else
194 chm (i) = static_cast<char> (ival);
195 }
197 retval = octave_value (chm, type);
199 return retval;
201
202template <typename MT>
206 return NDArray (this->m_matrix);
207}
208
209template <typename MT>
212{
213 return FloatNDArray (this->m_matrix);
214}
215
216template <typename MT>
219{
220 return int8NDArray (this->m_matrix);
221}
222
223template <typename MT>
226{
227 return int16NDArray (this->m_matrix);
228}
229
230template <typename MT>
233{
234 return int32NDArray (this->m_matrix);
235}
236
237template <typename MT>
240{
241 return int64NDArray (this->m_matrix);
242}
243
244template <typename MT>
247{
248 return uint8NDArray (this->m_matrix);
249}
250
251template <typename MT>
254{
255 return uint16NDArray (this->m_matrix);
256}
257
258template <typename MT>
261{
262 return uint32NDArray (this->m_matrix);
263}
264
265template <typename MT>
268{
269 return uint64NDArray (this->m_matrix);
270}
271
272template <typename T>
273std::string
276 octave_idx_type j) const
277{
278 std::ostringstream buf;
279 octave_print_internal (buf, fmt, this->m_matrix(i, j));
280 return buf.str ();
281}
282
283template <typename T>
284bool
286{
287 const dim_vector& dv = this->dims ();
288
289 os << "# ndims: " << dv.ndims () << "\n";
290
291 for (int i = 0; i < dv.ndims (); i++)
292 os << ' ' << dv(i);
293
294 os << "\n" << this->m_matrix;
295
296 return true;
297}
298
299template <typename T>
300bool
302{
303 int mdims = 0;
304
305 if (! extract_keyword (is, "ndims", mdims, true))
306 error ("load: failed to extract number of dimensions");
307
308 if (mdims < 0)
309 error ("load: failed to extract number of rows and columns");
310
311 dim_vector dv;
312 dv.resize (mdims);
313
314 for (int i = 0; i < mdims; i++)
315 is >> dv(i);
316
317 T tmp(dv);
318
319 is >> tmp;
320
321 if (! is)
322 error ("load: failed to load matrix constant");
323
324 this->m_matrix = tmp;
325
326 return true;
327}
328
329template <typename T>
330bool
332{
333 const dim_vector& dv = this->dims ();
334 if (dv.ndims () < 1)
335 return false;
336
337 // Use negative value for ndims to differentiate with old format!!
338 int32_t tmp = - dv.ndims ();
339 os.write (reinterpret_cast<char *> (&tmp), 4);
340 for (int i=0; i < dv.ndims (); i++)
341 {
342 tmp = dv(i);
343 os.write (reinterpret_cast<char *> (&tmp), 4);
344 }
345
346 os.write (reinterpret_cast<const char *> (this->m_matrix.data ()),
347 this->byte_size ());
348
349 return true;
350}
351
352template <typename T>
353bool
354octave_base_int_matrix<T>::load_binary (std::istream& is, bool swap,
355 octave::mach_info::float_format)
356{
357 int32_t mdims;
358 if (! is.read (reinterpret_cast<char *> (&mdims), 4))
359 return false;
360 if (swap)
361 swap_bytes<4> (&mdims);
362 if (mdims >= 0)
363 return false;
364
365 mdims = - mdims;
366 int32_t di;
367 dim_vector dv;
368 dv.resize (mdims);
369
370 for (int i = 0; i < mdims; i++)
371 {
372 if (! is.read (reinterpret_cast<char *> (&di), 4))
373 return false;
374 if (swap)
375 swap_bytes<4> (&di);
376 dv(i) = di;
377 }
378
379 // Convert an array with a single dimension to be a row vector.
380 // Octave should never write files like this, other software
381 // might.
382
383 if (mdims == 1)
384 {
385 mdims = 2;
386 dv.resize (mdims);
387 dv(1) = dv(0);
388 dv(0) = 1;
389 }
390
391 T m (dv);
392
393 if (! is.read (reinterpret_cast<char *> (m.rwdata ()), m.byte_size ()))
394 return false;
395
396 if (swap)
397 {
398 int nel = dv.numel ();
399 int bytes = nel / m.byte_size ();
400 for (int i = 0; i < nel; i++)
401 switch (bytes)
402 {
403 case 8:
404 swap_bytes<8> (&m(i));
405 break;
406 case 4:
407 swap_bytes<4> (&m(i));
408 break;
409 case 2:
410 swap_bytes<2> (&m(i));
411 break;
412 case 1:
413 default:
414 break;
415 }
416 }
417
418 this->m_matrix = m;
419 return true;
420}
421
422template <typename T>
423bool
426 const char *name, bool)
427{
428 bool retval = false;
429
430#if defined (HAVE_HDF5)
431
432 hid_t save_type_hid = save_type;
433 const dim_vector& dv = this->dims ();
434 int empty = save_hdf5_empty (loc_id, name, dv);
435 if (empty)
436 return (empty > 0);
437
438 int rank = dv.ndims ();
439 hid_t space_hid, data_hid;
440 space_hid = data_hid = -1;
441 OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
442
443 // Octave uses column-major, while HDF5 uses row-major ordering
444 for (int i = 0; i < rank; i++)
445 hdims[i] = dv(rank-i-1);
446
447 space_hid = H5Screate_simple (rank, hdims, nullptr);
448
449 if (space_hid < 0) return false;
450#if defined (HAVE_HDF5_18)
451 data_hid = H5Dcreate (loc_id, name, save_type_hid, space_hid,
454#else
455 data_hid = H5Dcreate (loc_id, name, save_type_hid, space_hid,
457#endif
458 if (data_hid < 0)
459 {
460 H5Sclose (space_hid);
461 return false;
462 }
463
464 retval = H5Dwrite (data_hid, save_type_hid, octave_H5S_ALL, octave_H5S_ALL,
465 octave_H5P_DEFAULT, this->m_matrix.data ()) >= 0;
466
467 H5Dclose (data_hid);
468 H5Sclose (space_hid);
469
470#else
471 octave_unused_parameter (loc_id);
472 octave_unused_parameter (save_type);
473 octave_unused_parameter (name);
474
475 this->warn_save ("hdf5");
476#endif
477
478 return retval;
479}
480
481template <typename T>
482bool
485 const char *name)
486{
487 bool retval = false;
488
489#if defined (HAVE_HDF5)
490
491 hid_t save_type_hid = save_type;
492 dim_vector dv;
493 int empty = load_hdf5_empty (loc_id, name, dv);
494 if (empty > 0)
495 this->m_matrix.resize (dv);
496 if (empty)
497 return (empty > 0);
498
499#if defined (HAVE_HDF5_18)
500 hid_t data_hid = H5Dopen (loc_id, name, octave_H5P_DEFAULT);
501#else
502 hid_t data_hid = H5Dopen (loc_id, name);
503#endif
504 hid_t space_id = H5Dget_space (data_hid);
505
506 hsize_t rank = H5Sget_simple_extent_ndims (space_id);
507
508 if (rank < 1)
509 {
510 H5Sclose (space_id);
511 H5Dclose (data_hid);
512 return false;
513 }
514
515 OCTAVE_LOCAL_BUFFER (hsize_t, hdims, rank);
516 OCTAVE_LOCAL_BUFFER (hsize_t, maxdims, rank);
517
518 H5Sget_simple_extent_dims (space_id, hdims, maxdims);
519
520 // Octave uses column-major, while HDF5 uses row-major ordering
521 if (rank == 1)
522 {
523 dv.resize (2);
524 dv(0) = 1;
525 dv(1) = hdims[0];
526 }
527 else
528 {
529 dv.resize (rank);
530 for (hsize_t i = 0, j = rank - 1; i < rank; i++, j--)
531 dv(j) = hdims[i];
532 }
533
534 T m (dv);
535 if (H5Dread (data_hid, save_type_hid, octave_H5S_ALL, octave_H5S_ALL,
536 octave_H5P_DEFAULT, m.rwdata ()) >= 0)
537 {
538 retval = true;
539 this->m_matrix = m;
540 }
541
542 H5Sclose (space_id);
543 H5Dclose (data_hid);
544
545#else
546 octave_unused_parameter (loc_id);
547 octave_unused_parameter (save_type);
548 octave_unused_parameter (name);
549
550 this->warn_load ("hdf5");
551#endif
552
553 return retval;
554}
555
556template <typename T>
557void
559 bool pr_as_read_syntax) const
560{
561 octave_print_internal (os, this->m_matrix, pr_as_read_syntax,
562 this->current_print_indent_level ());
563}
564
565template <typename T>
568{
569 octave_value retval;
570
571 T tmp = this->scalar;
572
573 typedef typename T::val_type val_type;
574
575 val_type ival = tmp.value ();
576
577 static constexpr bool is_signed = std::numeric_limits<val_type>::is_signed;
578 static constexpr bool can_be_larger_than_uchar_max
579 = octave_base_int_helper_traits<val_type>::can_be_larger_than_uchar_max;
580
581 if (octave_base_int_helper<val_type, is_signed,
582 can_be_larger_than_uchar_max>::char_value_out_of_range (ival))
583 {
584 // FIXME: is there something better we could do?
585
586 ival = 0;
587
588 ::warning ("range error for conversion to character value");
589 }
590 else
591 retval = octave_value (std::string (1, static_cast<char> (ival)), type);
592
593 return retval;
594}
595
596template <typename T>
599{
600 return static_cast<double> (this->scalar);
601}
602
603template <typename T>
606{
607 return static_cast<float> (this->scalar);
608}
609
610template <typename T>
613{
614 return octave_int8 (this->scalar);
615}
616
617template <typename T>
620{
621 return octave_int16 (this->scalar);
622}
623
624template <typename T>
627{
628 return octave_int32 (this->scalar);
629}
630
631template <typename T>
634{
635 return octave_int64 (this->scalar);
636}
637
638template <typename T>
641{
642 return octave_uint8 (this->scalar);
643}
644
645template <typename T>
648{
649 return octave_uint16 (this->scalar);
650}
651
652template <typename T>
655{
656 return octave_uint32 (this->scalar);
657}
658
659template <typename T>
662{
663 return octave_uint64 (this->scalar);
664}
665
666template <typename ST>
667std::string
670 octave_idx_type) const
671{
672 std::ostringstream buf;
673 octave_print_internal (buf, fmt, this->scalar);
674 return buf.str ();
675}
676
677template <typename T>
678bool
680{
681 os << this->scalar << "\n";
682 return true;
683}
684
685template <typename T>
686bool
688{
689 is >> this->scalar;
690 if (! is)
691 error ("load: failed to load scalar constant");
692
693 return true;
694}
695
696template <typename T>
697bool
699{
700 os.write (reinterpret_cast<char *> (&(this->scalar)), this->byte_size ());
701 return true;
702}
703
704template <typename T>
705bool
706octave_base_int_scalar<T>::load_binary (std::istream& is, bool swap,
707 octave::mach_info::float_format)
708{
709 T tmp;
710
711 if (! is.read (reinterpret_cast<char *> (&tmp), this->byte_size ()))
712 return false;
713
714 if (swap)
715 swap_bytes<sizeof (T)> (&tmp);
716
717 this->scalar = tmp;
718
719 return true;
720}
721
722template <typename T>
723bool
726 const char *name, bool)
727{
728 bool retval = false;
729
730#if defined (HAVE_HDF5)
731
732 hid_t save_type_hid = save_type;
733 hsize_t dimens[3] = {0};
734 hid_t space_hid, data_hid;
735 space_hid = data_hid = -1;
736
737 space_hid = H5Screate_simple (0, dimens, nullptr);
738 if (space_hid < 0) return false;
739
740#if defined (HAVE_HDF5_18)
741 data_hid = H5Dcreate (loc_id, name, save_type_hid, space_hid,
744#else
745 data_hid = H5Dcreate (loc_id, name, save_type_hid, space_hid,
747#endif
748 if (data_hid < 0)
749 {
750 H5Sclose (space_hid);
751 return false;
752 }
753
754 retval = H5Dwrite (data_hid, save_type_hid, octave_H5S_ALL, octave_H5S_ALL,
755 octave_H5P_DEFAULT, &(this->scalar)) >= 0;
756
757 H5Dclose (data_hid);
758 H5Sclose (space_hid);
759
760#else
761 octave_unused_parameter (loc_id);
762 octave_unused_parameter (save_type);
763 octave_unused_parameter (name);
764
765 this->warn_save ("hdf5");
766#endif
767
768 return retval;
769}
770
771template <typename T>
772bool
775 const char *name)
776{
777#if defined (HAVE_HDF5)
778
779 hid_t save_type_hid = save_type;
780#if defined (HAVE_HDF5_18)
781 hid_t data_hid = H5Dopen (loc_id, name, octave_H5P_DEFAULT);
782#else
783 hid_t data_hid = H5Dopen (loc_id, name);
784#endif
785 hid_t space_id = H5Dget_space (data_hid);
786
787 hsize_t rank = H5Sget_simple_extent_ndims (space_id);
788
789 if (rank != 0)
790 {
791 H5Dclose (data_hid);
792 return false;
793 }
794
795 T tmp;
796 if (H5Dread (data_hid, save_type_hid, octave_H5S_ALL, octave_H5S_ALL,
797 octave_H5P_DEFAULT, &tmp) < 0)
798 {
799 H5Dclose (data_hid);
800 return false;
801 }
802
803 this->scalar = tmp;
804
805 H5Dclose (data_hid);
806
807 return true;
808
809#else
810 octave_unused_parameter (loc_id);
811 octave_unused_parameter (save_type);
812 octave_unused_parameter (name);
813
814 this->warn_load ("hdf5");
815
816 return false;
817#endif
818}
void swap_bytes< 2 >(void *ptr)
Definition byte-swap.h:56
void swap_bytes< 8 >(void *ptr)
Definition byte-swap.h:71
void swap_bytes< 4 >(void *ptr)
Definition byte-swap.h:63
Vector representing the dimensions (size) of an Array.
Definition dim-vector.h:90
octave_idx_type numel(int n=0) const
Number of elements that a matrix with this dimensions would have.
Definition dim-vector.h:331
void resize(int n, int fill_value=0)
Definition dim-vector.h:268
octave_idx_type ndims() const
Number of dimensions.
Definition dim-vector.h:253
octave_value as_uint64() const
octave_value as_int64() const
void print_raw(std::ostream &os, bool pr_as_read_syntax=false) const
octave_value as_int8() const
octave_value as_int16() const
octave_base_value * try_narrowing_conversion()
octave_value as_uint16() const
octave_value as_single() const
bool save_ascii(std::ostream &os)
bool load_ascii(std::istream &is)
std::string edit_display(const float_display_format &fmt, octave_idx_type i, octave_idx_type j) const
bool save_hdf5_internal(octave_hdf5_id loc_id, octave_hdf5_id save_type, const char *name, bool)
bool load_binary(std::istream &is, bool swap, octave::mach_info::float_format)
octave_value as_uint8() const
octave_value as_uint32() const
octave_value convert_to_str_internal(bool, bool, char type) const
bool save_binary(std::ostream &os, bool)
octave_value as_double() const
octave_value as_int32() const
bool load_hdf5_internal(octave_hdf5_id loc_id, octave_hdf5_id save_type, const char *name)
octave_value as_int8() const
octave_value as_double() const
octave_value as_single() const
bool load_ascii(std::istream &is)
octave_value as_int16() const
bool save_hdf5_internal(octave_hdf5_id loc_id, octave_hdf5_id save_type, const char *name, bool)
bool load_hdf5_internal(octave_hdf5_id loc_id, octave_hdf5_id save_type, const char *name)
octave_value convert_to_str_internal(bool, bool, char type) const
octave_value as_int32() const
octave_value as_int64() const
octave_value as_uint16() const
std::string edit_display(const float_display_format &fmt, octave_idx_type i, octave_idx_type j) const
octave_value as_uint8() const
octave_value as_uint64() const
bool load_binary(std::istream &is, bool swap, octave::mach_info::float_format)
octave_value as_uint32() const
bool save_ascii(std::ostream &os)
bool save_binary(std::ostream &os, bool)
const octave_hdf5_id octave_H5P_DEFAULT
const octave_hdf5_id octave_H5S_ALL
save_type
Definition data-conv.h:85
void warning(const char *fmt,...)
Definition error.cc:1078
void error(const char *fmt,...)
Definition error.cc:1003
intNDArray< octave_int16 > int16NDArray
intNDArray< octave_int32 > int32NDArray
intNDArray< octave_int64 > int64NDArray
intNDArray< octave_int8 > int8NDArray
Definition int8NDArray.h:36
int save_hdf5_empty(octave_hdf5_id loc_id, const char *name, const dim_vector &d)
Definition ls-hdf5.cc:1254
int load_hdf5_empty(octave_hdf5_id loc_id, const char *name, dim_vector &d)
Definition ls-hdf5.cc:1311
std::string extract_keyword(std::istream &is, const char *keyword, const bool next_only)
int64_t octave_hdf5_id
octave_int< uint32_t > octave_uint32
octave_int< int32_t > octave_int32
octave_int< int16_t > octave_int16
octave_int< int8_t > octave_int8
octave_int< int64_t > octave_int64
octave_int< uint64_t > octave_uint64
octave_int< uint16_t > octave_uint16
octave_int< uint8_t > octave_uint8
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition oct-locbuf.h:44
void octave_print_internal(std::ostream &os, const float_display_format &fmt, bool d, bool pr_as_read_syntax)
intNDArray< octave_uint16 > uint16NDArray
intNDArray< octave_uint32 > uint32NDArray
intNDArray< octave_uint64 > uint64NDArray
intNDArray< octave_uint8 > uint8NDArray