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