1 /*
2     This file is part of GNU APL, a free implementation of the
3     ISO/IEC Standard 13751, "Programming Language APL, Extended"
4 
5     Copyright (C) 2008-2015  Dr. Jürgen Sauermann
6 
7     This program is free software: you can redistribute it and/or modify
8     it under the terms of the GNU General Public License as published by
9     the Free Software Foundation, either version 3 of the License, or
10     (at your option) any later version.
11 
12     This program is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 
17     You should have received a copy of the GNU General Public License
18     along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 */
20 
21 #ifndef __VALUE_HH_DEFINED__
22 #define __VALUE_HH_DEFINED__
23 
24 #include "CharCell.hh"
25 #include "DynamicObject.hh"
26 #include "FloatCell.hh"
27 #include "IntCell.hh"
28 #include "LvalCell.hh"
29 #include "PointerCell.hh"
30 #include "Shape.hh"
31 
32 using namespace std;
33 
34 class CDR_string;
35 class Error;
36 class IndexExpr;
37 class PrintBuffer;
38 class Value_P;
39 class Thread_context;
40 
41 /// a linked list of deleted values
42 struct _deleted_value
43 {
44    /// the next deleted value
45   _deleted_value * next;
46 };
47 
48 //=============================================================================
49 /**
50     An APL value. It consists of a fixed header (rank, shape) and
51     and a ravel (a sequence of cells). If the ravel is short, then it
52     is contained in the value itself; otherwise the value uses a pointer
53     to a loner ravel.
54  */
55 /// An APL Value (essentially a Shape and a ravel)
56 class Value : public DynamicObject
57 {
58    friend class Value_P;
59    friend class Value_P_Base;
60    friend class PointerCell;   // needs & for &cell_owner
61 
62 protected:
63    // constructors. Values should not be constructed directly but via their
64    // counterparts in class Value_P.
65    //
66    /// constructor: scalar value (i.e. a value with rank 0).
67    Value(const char * loc);
68 
69    /// constructor: a scalar value (i.e. a value with rank 0) from a cell
70    Value(const Cell & cell, const char * loc);
71 
72    /// constructor: a true vector (i.e. a value with rank 1) with shape \b sh
73    Value(ShapeItem sh, const char * loc);
74 
75    /// constructor: a general array with shape \b sh
76    Value(const Shape & sh, const char * loc);
77 
78    /// constructor: a simple character vector from a UCS string
79    Value(const UCS_string & ucs, const char * loc);
80 
81    /// constructor: a simple character vector from a UTF8 string
82    Value(const UTF8_string & utf, const char * loc);
83 
84    /// constructor: a simple character vector from a CDR string
85    Value(const CDR_string & cdr, const char * loc);
86 
87    /// constructor: a character matrix from a PrintBuffer
88    Value(const PrintBuffer & pb, const char * loc);
89 
90    /// constructor: a integer vector containing the items of a shape
91    Value(const char * loc, const Shape * sh);
92 
93 public:
94    /// destructor
95    virtual ~Value();
96 
97    /// return \b true iff \b this value is a scalar.
is_scalar() const98    bool is_scalar() const
99       { return shape.get_rank() == 0; }
100 
101    /// return \b true iff \b this value is a simple (i.e. depth 0) scalar.
is_simple_scalar() const102    bool is_simple_scalar() const
103       { return is_scalar() &&
104               !(get_ravel(0).is_pointer_cell() || get_lval_cellowner()); }
105 
106    /// return \b true iff \b this value is empty (some dimension is 0).
is_empty() const107    bool is_empty() const
108       { return shape.is_empty(); }
109 
110    /// return \b true iff \b this value is a numeric scalar.
is_numeric_scalar() const111    bool is_numeric_scalar() const
112       { return  is_scalar() && get_ravel(0).is_numeric(); }
113 
114    /// return \b true iff \b this value is a character scalar
is_character_scalar() const115    bool is_character_scalar() const
116       { return  is_scalar() && get_ravel(0).is_character_cell(); }
117 
118    /// return \b true iff \b this value is a scalar or vector
is_scalar_or_vector() const119    bool is_scalar_or_vector() const
120       { return  get_rank() < 2; }
121 
122    /// return \b true iff \b this value is a vector.
is_vector() const123    bool is_vector() const
124       { return  get_rank() == 1; }
125 
126    /// return \b true iff \b this value is a scalar or vector of length 1.
is_scalar_or_len1_vector() const127    bool is_scalar_or_len1_vector() const
128       { return is_scalar() || (is_vector() && (get_shape_item(0) == 1)); }
129 
130    /// return \b true iff \b this value can be scalar-extended
is_scalar_extensible() const131    bool is_scalar_extensible() const
132       { return element_count() == 1; }
133 
134    /// return the increment for iterators of this value. The increment is used
135    /// for scalar-extension of 1-element values
get_increment() const136    int get_increment() const
137       { return element_count() == 1 ? 0 : 1; }
138 
139    /// return \b true iff \b this value is a simple character scalar or vector.
is_char_string() const140    bool is_char_string() const
141       { return get_rank() <= 1 && is_char_array(); }
142 
143    /// return \b true iff \b this value is a simple character vector.
is_char_vector() const144    bool is_char_vector() const
145       { return get_rank() == 1 && is_char_array(); }
146 
147    /// return \b true iff \b this value is a simple character vector
148    /// containing only APL characters (from ⎕AV)
149    bool is_apl_char_vector() const;
150 
151    /// return \b true iff \b all ravel elements of this value are characters
152    bool is_char_array() const;
153 
154    /// return \b true iff \b this value is a simple character scalar.
is_char_scalar() const155    bool is_char_scalar() const
156       { return get_rank() == 0 && get_ravel(0).is_character_cell(); }
157 
158    /// return \b true iff \b this value is a simple integer scalar.
is_int_scalar() const159    bool is_int_scalar() const
160       { return get_rank() == 0 && get_ravel(0).is_near_int(); }
161 
162    /// return the number of elements (the product of the shapes).
element_count() const163    ShapeItem element_count() const
164       { return shape.get_volume(); }
165 
166    /// return the number of elements, but at least 1 (for the prototype).
nz_element_count() const167    ShapeItem nz_element_count() const
168       { return shape.get_volume() ? shape.get_volume() : 1; }
169 
170    /// return the rank of \b this value
get_rank() const171    uRank get_rank() const
172      { return shape.get_rank(); }
173 
174    /// return the shape of \b this value
get_shape() const175    const Shape & get_shape() const
176      { return shape; }
177 
178    /// return the r'th shape element of \b this value
get_shape_item(Rank r) const179    ShapeItem get_shape_item(Rank r) const
180       { return shape.get_shape_item(r); }
181 
182    /// return the length of the last dimension of \b this value
get_last_shape_item() const183    ShapeItem get_last_shape_item() const
184       { return shape.get_last_shape_item(); }
185 
186    /// return the length of the last dimension, or 1 for scalars
get_cols() const187    ShapeItem get_cols() const
188       { return shape.get_cols(); }
189 
190    /// return the product of all but the the last dimension, or 1 for scalars
get_rows() const191    ShapeItem get_rows() const
192       { return shape.get_rows(); }
193 
194    /// set the length of dimension \b r to \b sh.
set_shape_item(Rank r,ShapeItem sh)195    void set_shape_item(Rank r, ShapeItem sh)
196       { shape.set_shape_item(r, sh); }
197 
198    /// reshape this value in place. The element count must not increase
set_shape(const Shape & sh)199    void set_shape(const Shape & sh)
200       { Assert(sh.get_volume() <= shape.get_volume());   shape = sh; }
201 
202    /// return the position of cell in the ravel of \b this value.
get_offset(const Cell * cell) const203    ShapeItem get_offset(const Cell * cell) const
204       { return cell - &get_ravel(0); }
205 
206    /// return the next byte after the ravel
get_ravel_end() const207    const Cell * get_ravel_end() const
208       { return &ravel[nz_element_count()]; }
209 
210    /// return the integer of a value that is supposed to have (exactly) one
get_sole_integer() const211    APL_Integer get_sole_integer() const
212       { if (element_count() == 1)   return get_ravel(0).get_near_int();
213         if (get_rank() > 1)   RANK_ERROR;
214         else                  LENGTH_ERROR;
215       }
216 
217    /// return the first integer of a value (the line number of →Value).
get_line_number() const218    Function_Line get_line_number() const
219       { const APL_Integer line(ravel[0].get_near_int());
220         Log(LOG_execute_goto)   CERR << "goto line " << line << endl;
221         return Function_Line(line); }
222 
223    /// return \b true iff \b this value is simple (i.e. not nested).
224    bool is_simple() const;
225 
226    /// return \b true iff \b this value and its ravel items have rank < 2
227    bool is_one_dimensional() const;
228 
229    /// return \b true iff \b this value is a simple integer vector.
230    bool is_int_vector() const;
231 
232    /// return true, if this value has complex cells, false iff it has only
233    /// real cells. Throw domain error for other cells (char, nested etc.)
234    /// if check_numeric is \b true.
235    bool is_complex(bool check_numeric) const;
236 
237    /// return true if this value can be compared. This is the case when all
238    /// cells (including nested ones) are not complex
239    bool can_be_compared() const;
240 
241    /// return a value containing pointers to all ravel cells of this value.
242    Value_P get_cellrefs(const char * loc);
243 
244    /// assign \b val to the cell references in this value.
245    void assign_cellrefs(Value_P val);
246 
247    /// return the idx'th element of the ravel.
get_ravel(ShapeItem idx)248    Cell & get_ravel(ShapeItem idx)
249       { Assert1(idx < nz_element_count());   return ravel[idx]; }
250 
251    /// return the idx'th element of the ravel.
get_ravel(ShapeItem idx) const252    const Cell & get_ravel(ShapeItem idx) const
253       { Assert1(idx < nz_element_count());   return ravel[idx]; }
254 
255    /// set the prototype (according to B) if this value is empty.
256    inline void set_default(const Value & B, const char * loc);
257 
258    /// set the prototype to ' '
259    inline void set_proto_Spc();
260 
261    /// set the prototype to ' ' if this value is empty.
262    inline void set_default_Spc();
263 
264    /// set the prototype to 0 if this value is empty.
265    inline void set_default_Int();
266 
267    /// Return the number of scalars in this value (enlist).
268    ShapeItem get_enlist_count() const;
269 
270    /// compute the depth of this value.
271    Depth compute_depth() const;
272 
273    /// store the scalars in this value into dest...
274    void enlist(Cell * & dest, Value & dest_owner, bool left) const;
275 
276    /// compute the cell types contained in the top level of \b this value
277    CellType flat_cell_types() const;
278 
279    /// compute the cell subtypes contained in the top level of \b this value
280    CellType flat_cell_subtypes() const;
281 
282    /// compute the CellType contained in \b this value (recursively)
283    CellType deep_cell_types() const;
284 
285    /// recursive set of Cell types in this value
286    CellType deep_cell_subtypes() const;
287 
288    /// print \b this value (line break at Workspace::get_PW())
289    ostream & print(ostream & out) const;
290 
291    /// print \b this value (line break at print_width)
292    ostream & print1(ostream & out, PrintContext pctx) const;
293 
294    /// print the properties (shape, flags etc) of \b this value
295    ostream & print_properties(ostream & out, int indent, bool help) const;
296 
297    /// debug-print \b this value
298    void debug(const char * info) const;
299 
300    /// print this value in 4 ⎕CR style
301    ostream & print_boxed(ostream & out, const char * info = 0) const;
302 
303    /// return \b this indexed by (multi-dimensional) \b IDX.
304    Value_P index(const IndexExpr & IDX) const;
305 
306    /// return \b this indexed by (one-dimensional) \b IDX.
307    Value_P index(Value_P IDX) const;
308 
309    /// If this value is a single axis between ⎕IO and ⎕IO + max_axis then
310    /// return that axis. Otherwise throw AXIS_ERROR.
311    static Rank get_single_axis(const Value * val, Rank max_axis);
312 
313    /// convert the ravel of \b val to a shape
314    static Shape to_shape(const Value * val);
315 
316    /// glue two values.
317    static void glue(Token & token, Token & token_A, Token & token_B,
318                     const char * loc);
319 
320    /// glue strands A and B
321    static void glue_strand_strand(Token & result, Value_P A, Value_P B,
322                                   const char * loc);
323 
324    /// glue strands A and strand B
325    static void glue_strand_closed(Token & result, Value_P A, Value_P B,
326                                   const char * loc);
327 
328    /// glue closed A and closed B
329    static void glue_closed_strand(Token & result, Value_P A, Value_P B,
330                                   const char * loc);
331 
332    /// glue closed A and closed B
333    static void glue_closed_closed(Token & result, Value_P A, Value_P B,
334                                   const char * loc);
335 
336    /// return the number of Value_P pointing to \b this value
get_owner_count() const337    int get_owner_count() const
338       { return owner_count; }
339 
340    /// return \b true iff this value is an lval (selective assignment)
341    /// i.e. return true if at least one leaf value is an lval.
342    Value * get_lval_cellowner() const;
343 
344    /// return true iff more ravel items (as per shape) need to be initialized.
345    /// (the prototype of empty values may still be missing)
more()346    bool more()
347       { return valid_ravel_items < element_count(); }
348 
349    /// return the next ravel cell to be initialized (excluding prototype)
next_ravel()350    Cell * next_ravel()
351       { return more() ? &ravel[valid_ravel_items++] : 0; }
352 
353    /// initialize the next ravel cell with a character value
354    inline void next_ravel_Char(Unicode u);
355 
356    /// initialize the next ravel cell with an integer value
357    inline void next_ravel_Int(APL_Integer i);
358 
359    /// initialize the next ravel cell with an floating-point value
360    inline void next_ravel_Float(APL_Float f);
361 
362    /// initialize the next ravel cell with an APL sub-value
363    inline void next_ravel_Pointer(Value * val);
364 
365    /// return the NOTCHAR property of the value. NOTCHAR is false for simple
366    /// char arrays and true if any element is numeric or nested. The NOTCHAR
367    /// property of empty arrays is the NOTCHAR property of its prototype.
368    /// see also lrm p. 138.
369    bool NOTCHAR() const;
370 
371    /// convert chars to ints and ints to chars (recursively).
372    /// return the number of cells that are neither char nor int.
373    int toggle_UCS();
374 
375    /// return \b true iff \b this value has the same rank as \b other.
same_rank(const Value & other) const376    bool same_rank(const Value & other) const
377       { return get_rank() == other.get_rank(); }
378 
379    /// return \b true iff \b this value has the same shape as \b other.
same_shape(const Value & other) const380    bool same_shape(const Value & other) const
381       { if (get_rank() != other.get_rank())   return false;
382         loop (r, get_rank())
383             if (get_shape_item(r) != other.get_shape_item(r))   return false;
384         return true;
385       }
386 
387    /// return \b true iff \b this value has the same shape as \b other or one
388    /// of the values is a scalar
scalar_matching_shape(const Value & other) const389    bool scalar_matching_shape(const Value & other) const
390       { return is_scalar_extensible()
391             || other.is_scalar_extensible()
392             || same_shape(other);
393       }
394 
395    /// returen true if \b sub == \b val or sub is contained in \b val
396    static bool is_or_contains(const Value * val, const Value & sub);
397 
398    /// print debug info about setting or clearing of flags to CERR
399    void flag_info(const char * loc, ValueFlags flag, const char * flag_name,
400                   bool set) const;
401 
402    /// initialize value related variables and print some statistics.
403    static void init();
404 
405 /// maybe enable LOC for set/clear of flags
406 #if defined(VF_TRACING_WANTED) || defined(VALUE_HISTORY_WANTED)   // enable LOC
407 # define _LOC LOC
408 # define _loc loc
409 # define _loc_type const char *
410 #else                                                           // disable LOC
411 # define _LOC
412 # define _loc
413 # define _loc_type
414 #endif
415 
416 #ifdef VF_TRACING_WANTED
417  # define FLAG_TRACE(f, b) flag_info(loc, VF_ ## f, #f, b);
418 #else
419  # define FLAG_TRACE(_f, _b)
420 #endif
421 
422    /// set the Value flag \b complete
SET_complete(_loc_type _loc) const423    void SET_complete(_loc_type _loc) const
424       { FLAG_TRACE(complete, true)   flags |=  VF_complete;
425         ADD_EVENT(this, VHE_SetFlag, VF_complete, _loc); }
426 
427    /// true if Value flag \b complete is set
is_complete() const428    bool is_complete() const      { return (flags & VF_complete) != 0; }
429 
430 # define set_complete() SET_complete(_LOC)
431 
432    /// set the Value flag \b marked
SET_marked(_loc_type _loc) const433    void SET_marked(_loc_type _loc) const
434       { FLAG_TRACE(marked, true)   flags |=  VF_marked;
435         ADD_EVENT(this, VHE_SetFlag, VF_marked, _loc); }
436 
437    /// clear the Value flag \b marked
CLEAR_marked(_loc_type _loc) const438    void CLEAR_marked(_loc_type _loc) const
439       { FLAG_TRACE(marked, false)   flags &=  ~VF_marked;
440         ADD_EVENT(this, VHE_ClearFlag, VF_marked, _loc); }
441 
442    /// true if Value flag \b marked is set
is_marked() const443    bool is_marked() const
444       { return (flags & VF_marked) != 0; }
445 
446 # define set_marked()   SET_marked(_LOC)
447 # define clear_marked() CLEAR_marked(_LOC)
448 
449    /// mark all values, except static values
450    static void mark_all_dynamic_values();
451 
452    /// clear marked flag on this value and its nested sub-values
453    void unmark() const;
454 
455    /// rollback initialization of this value
456    void rollback(ShapeItem items, const char * loc);
457 
458    /// the prototype of this value
459    Value_P prototype(const char * loc) const;
460 
461    /// return a deep copy of \b this value
462    Value_P clone(const char * loc) const;
463 
464    /// get the min spacing for this column and set/clear if there
465    /// is/isn't a numeric item in the column.
466    /// are/ain't numeric items in col.
467    int32_t get_col_spacing(bool & numeric, ShapeItem col, bool framed) const;
468 
469    /// list a value
470    ostream & list_one(ostream & out, bool show_owners) const;
471 
472    /// check \b that this value is completely initialized, and set complete flag
473    void check_value(const char * loc);
474 
475    /// return the total CDR size (header + data + padding) for \b this value.
total_size_brutto(CDR_type cdr_type) const476    int total_size_brutto(CDR_type cdr_type) const
477       { return (total_size_netto(cdr_type) + 15) & ~15; }
478 
479    /// return the total CDR size in bytes (header + data),
480    ///  not including any except padding for \b this value.
481    int total_size_netto(CDR_type cdr_type) const;
482 
483    /// return the CDR size in bytes for the data of \b value,
484    /// not including the CDR header and padding
485    int data_size(CDR_type cdr_type) const;
486 
487    /// return the CDR type for \b this value
488    CDR_type get_CDR_type() const;
489 
490    /// erase stale values
491    static int erase_stale(const char * loc);
492 
493    /// re-initialize incomplete values
494    static int finish_incomplete(const char * loc);
495 
496    /// erase all values (clean-up after )CLEAR)
497    static void erase_all(ostream & out);
498 
499    /// list all values
500    static ostream & list_all(ostream & out, bool show_owners);
501 
502    /// return the ravel of \b this value as UCS string, or throw DOMAIN error
503    /// if the ravel contains non-char or nested cells.
504    UCS_string get_UCS_ravel() const;
505 
506    /// recursively replace all ravel elements with 0
507    void to_proto();
508 
509    /// print address, shape, and flags of this value
510    void print_structure(ostream & out, int indent, ShapeItem idx) const;
511 
512    /// return the current flags
get_flags() const513    ValueFlags get_flags() const   { return ValueFlags(flags); }
514 
515    /// print info related to a stale value
516    void print_stale_info(ostream & out, const DynamicObject * dob) const;
517 
518    /// number of Value_P objects pointing to this value
519    int owner_count;
520 
521    /// print incomplete Values, and return the number of incomplete Values.
522    static int print_incomplete(ostream & out);
523 
524    /// print stale Values, and return the number of stale Values.
525    static int print_stale(ostream & out);
526 
527    /// total nz_element_counts of all non-short values
528    static uint64_t total_ravel_count;
529 
530    /// the number of values created
531    static uint64_t value_count;
532 
533    /// a "checksum" to detect deleted values
534    const void * check_ptr;
535 
536    /// increment the PointerCell count
increment_pointer_cell_count()537    void increment_pointer_cell_count()
538       { ++pointer_cell_count; }
539 
540    /// decrement the PointerCell count
decrement_pointer_cell_count()541    void decrement_pointer_cell_count()
542       { --pointer_cell_count; }
543 
544    /// return the PointerCell count
get_pointer_cell_count() const545    ShapeItem get_pointer_cell_count() const
546       { return pointer_cell_count; }
547 
548    /// increase \b nz_subcell_count by \b count
add_subcount(ShapeItem count)549    void add_subcount(ShapeItem count)
550       { nz_subcell_count += count; }
551 
552       /// increment the number of (smart-) pointers to this value
increment_owner_count(const char * loc)553    void increment_owner_count(const char * loc)
554       {
555         Assert1(reinterpret_cast<void *>(this) != 0);
556         if (check_ptr == charP(this) + 7)
557            ++owner_count;
558       }
559 
560       /// decrement the number of (smart-) pointers to this value and delete
561       /// this value if no more pointers exist
decrement_owner_count(const char * loc)562       void decrement_owner_count(const char * loc)
563          {
564            Assert1(reinterpret_cast<void *>(this) != 0);
565            if (check_ptr == charP(this) + 7)
566               {
567                 Assert1(owner_count > 0);
568                 --owner_count;
569 
570                 if (owner_count == 0) delete this;
571               }
572          }
573 
574    /// check if WS is FULL after allocating value with \b cell_count items
575    static bool check_WS_FULL(const char * args, ShapeItem cell_count,
576                              const char * loc);
577 
578    /// handler for catch(Error) in init_ravel() (never called)
579    static void catch_Error(const Error & error, const char * args,
580                            const char * loc);
581 
582    /// handler for catch(exception) in init_ravel() (never called)
583    static void catch_exception(const exception & ex, const char * args,
584                         const char * caller,  const char * loc);
585 
586    /// handler for catch(...) in init_ravel() (never called)
587    static void catch_ANY(const char * args, const char * caller,
588                          const char * loc);
589 
590    /// the number of fast (recycled) new() calls
591    static uint64_t fast_new;
592 
593    /// the number of slow (malloc() based) new() calls
594    static uint64_t slow_new;
595 
596 protected:
597    /// init the ravel of an APL value, return the ravel length
598    inline void init_ravel();
599 
600    /// the shape of \b this value (only the first \b rank values are valid.
601    Shape shape;
602 
603    /// the value that has a PointerCell pointing to \b this value (if any)
604    ShapeItem pointer_cell_count;
605 
606    /// valueFlags for this value.
607    mutable uint16_t flags;
608 
609    /// number of initialized cells in the ravel
610    ShapeItem valid_ravel_items;
611 
612    /// the number of cells in nested sub-values
613    ShapeItem nz_subcell_count;
614 
615    /// The ravel of \b this value.
616    Cell * ravel;
617 
618    /// the cells of a short (i.e. ⍴,value ≤ SHORT_VALUE_LENGTH_WANTED) value
619    Cell short_value[SHORT_VALUE_LENGTH_WANTED];
620 
621    /// a linked list of values that have been deleted
622    static _deleted_value * deleted_values;
623 
624    /// number values that have been deleted
625    static int deleted_values_count;
626 
627    /// the size of the next allocation
628    static uint64_t alloc_size;
629 
630    /// max. number values that have been deleted
631    enum { deleted_values_MAX = 10000 };
632 
633 #if 1 // enable/disable deleted values chain for faster memory allocation
634 
635    /// allocate space for a new Value. For performance reasons, a pool of
636    /// deleted_values_MAX is kept and Value objects in that pool are reused
637    /// before calling new().
operator new(size_t sz)638    static void * operator new(size_t sz)
639       {
640         if (deleted_values)   // we have deleted values: recycle one
641            {
642              --deleted_values_count;
643              void * ret = deleted_values;
644              deleted_values = deleted_values->next;
645              ++fast_new;
646              return ret;
647            }
648 
649         ++slow_new;
650         return ::operator new(sz);
651       }
652 
653    /// free space for a new Value
operator delete(void * ptr)654    static void operator delete(void * ptr)
655       {
656         if (deleted_values_count < deleted_values_MAX)   // we have space
657            {
658              ++deleted_values_count;
659              reinterpret_cast<_deleted_value *>(ptr)->next = deleted_values;
660              deleted_values = reinterpret_cast<_deleted_value *>(ptr);
661            }
662         else                                             // no more space
663            {
664              free(ptr);
665            }
666       }
667 
668 #endif
669 
670 private:
671    /// prevent new[] of Value
672    static void * operator new[](size_t sz);
673 
674    /// prevent delete[] of Value
675    static void operator delete[](void* ptr);
676 
677    /// restrict use of & (which is frequently a mistake)
operator &()678    Value * operator &()   { return this; }
679 };
680 // ----------------------------------------------------------------------------
681 
682 extern void print_history(ostream & out, const Value * val, const char * loc);
683 
684 // shortcuts for frequently used APL values...
685 
686 /// integer scalar
687 Value_P IntScalar(APL_Integer val, const char * loc);
688 
689 /// floating-point scalar
690 Value_P FloatScalar(APL_Float val, const char * loc);
691 
692 /// character scalar
693 Value_P CharScalar(Unicode uni, const char * loc);
694 
695 /// complex scalar
696 Value_P ComplexScalar(APL_Complex cpx, const char * loc);
697 
698 /// ⍳0 (aka. ⍬)
699 Value_P Idx0(const char * loc);
700 
701 /// ''
702 Value_P Str0(const char * loc);
703 
704 /// 0 0⍴''
705 Value_P Str0_0(const char * loc);
706 
707 /// 0 0⍴0
708 Value_P Idx0_0(const char * loc);
709 
710 // ----------------------------------------------------------------------------
711 
712 // NOTE: there exist cross-dependencies between Value.hh and Value_P.hh on
713 // one hand and Value.icc and Value_P.icc on the other. It is therefore
714 // important that the declarations in both .hh files (i.e. this file and
715 // Value_P.hh occur before any of the .icc files.
716 //
717 #include "Value_P.hh"
718 
719 #include "Value.icc"
720 #include "Value_P.icc"
721 
722 #endif // __VALUE_HH_DEFINED__
723 
724