1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 1994-2021 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 #if defined (HAVE_CONFIG_H)
27 #  include "config.h"
28 #endif
29 
30 // Instantiate Arrays of double values.
31 
32 #include "lo-mappers.h"
33 #include "Array.h"
34 #include "Array.cc"
35 #include "oct-locbuf.h"
36 
37 #define INLINE_ASCENDING_SORT 1
38 #define INLINE_DESCENDING_SORT 1
39 #include "oct-sort.cc"
40 
41 // Prevent implicit instantiations on some systems (Windows, others?)
42 // that can lead to duplicate definitions of static data members.
43 
44 extern template class OCTAVE_API Array<idx_vector>;
45 extern template class OCTAVE_API Array<octave_idx_type>;
46 
47 template <>
48 inline bool
sort_isnan(double x)49 sort_isnan<double> (double x)
50 {
51   return octave::math::isnan (x);
52 }
53 
54 static bool
nan_ascending_compare(double x,double y)55 nan_ascending_compare (double x, double y)
56 {
57   return octave::math::isnan (y) ? ! octave::math::isnan (x) : x < y;
58 }
59 
60 static bool
nan_descending_compare(double x,double y)61 nan_descending_compare (double x, double y)
62 {
63   return octave::math::isnan (x) ? ! octave::math::isnan (y) : x > y;
64 }
65 
66 Array<double>::compare_fcn_type
safe_comparator(sortmode mode,const Array<double> & a,bool allow_chk)67 safe_comparator (sortmode mode, const Array<double>& a, bool allow_chk)
68 {
69   Array<double>::compare_fcn_type result = nullptr;
70 
71   if (allow_chk)
72     {
73       octave_idx_type k = 0;
74       for (; k < a.numel () && ! octave::math::isnan (a(k)); k++) ;
75       if (k == a.numel ())
76         {
77           if (mode == ASCENDING)
78             result = octave_sort<double>::ascending_compare;
79           else if (mode == DESCENDING)
80             result = octave_sort<double>::descending_compare;
81         }
82     }
83 
84   if (! result)
85     {
86       if (mode == ASCENDING)
87         result = nan_ascending_compare;
88       else if (mode == DESCENDING)
89         result = nan_descending_compare;
90     }
91 
92   return result;
93 }
94 
95 // The default solution using NaN-safe comparator is OK, but almost twice as
96 // slow than this code.
97 template <>
98 OCTAVE_API
99 sortmode
issorted(sortmode mode) const100 Array<double>::issorted (sortmode mode) const
101 {
102   octave_idx_type n = numel ();
103 
104   const double *el = data ();
105 
106   if (n <= 1)
107     return (mode == UNSORTED) ? ASCENDING : mode;
108 
109   if (mode == UNSORTED)
110     {
111       // Auto-detect mode.
112       if (el[n-1] < el[0] || octave::math::isnan (el[0]))
113         mode = DESCENDING;
114       else
115         mode = ASCENDING;
116     }
117 
118   if (mode == DESCENDING)
119     {
120       octave_idx_type j = 0;
121       double r;
122       // Sort out NaNs.
123       do
124         r = el[j++];
125       while (octave::math::isnan (r) && j < n);
126 
127       // Orient the test so that NaN will not pass through.
128       for (; j < n; j++)
129         {
130           if (r >= el[j])
131             r = el[j];
132           else
133             {
134               mode = UNSORTED;
135               break;
136             }
137         }
138 
139     }
140   else  // mode == ASCENDING
141     {
142       // Sort out NaNs.
143       while (n > 0 && octave::math::isnan (el[n-1]))
144         n--;
145 
146       if (n > 0)
147         {
148           // Orient the test so that NaN will not pass through.
149           double r = el[0];
150           for (octave_idx_type j = 1; j < n; j++)
151             {
152               if (r <= el[j])
153                 r = el[j];
154               else
155                 {
156                   mode = UNSORTED;
157                   break;
158                 }
159             }
160         }
161     }
162 
163   return mode;
164 }
165 
166 template class OCTAVE_API octave_sort<double>;
167 
168 INSTANTIATE_ARRAY (double, OCTAVE_API);
169 
170 template OCTAVE_API std::ostream& operator << (std::ostream&,
171                                                const Array<double>&);
172 
173 #include "DiagArray2.h"
174 #include "DiagArray2.cc"
175 
176 template class OCTAVE_API DiagArray2<double>;
177