~ubuntu-branches/debian/sid/octave3.0/sid

« back to all changes in this revision

Viewing changes to src/ov-struct.cc

  • Committer: Bazaar Package Importer
  • Author(s): Rafael Laboissiere
  • Date: 2007-12-23 16:04:15 UTC
  • Revision ID: james.westby@ubuntu.com-20071223160415-n4gk468dihy22e9v
Tags: upstream-3.0.0
ImportĀ upstreamĀ versionĀ 3.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 
 
3
Copyright (C) 1996, 1997, 1998, 2000, 2002, 2003, 2004, 2005, 2006,
 
4
              2007 John W. Eaton
 
5
 
 
6
This file is part of Octave.
 
7
 
 
8
Octave is free software; you can redistribute it and/or modify it
 
9
under the terms of the GNU General Public License as published by the
 
10
Free Software Foundation; either version 3 of the License, or (at your
 
11
option) any later version.
 
12
 
 
13
Octave is distributed in the hope that it will be useful, but WITHOUT
 
14
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 
15
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 
16
for more details.
 
17
 
 
18
You should have received a copy of the GNU General Public License
 
19
along with Octave; see the file COPYING.  If not, see
 
20
<http://www.gnu.org/licenses/>.
 
21
 
 
22
*/
 
23
 
 
24
#ifdef HAVE_CONFIG_H
 
25
#include <config.h>
 
26
#endif
 
27
 
 
28
#include <iostream>
 
29
 
 
30
#include "Cell.h"
 
31
#include "defun.h"
 
32
#include "error.h"
 
33
#include "gripes.h"
 
34
#include "oct-lvalue.h"
 
35
#include "ov-list.h"
 
36
#include "ov-struct.h"
 
37
#include "unwind-prot.h"
 
38
#include "utils.h"
 
39
#include "variables.h"
 
40
 
 
41
#include "Array-util.h"
 
42
 
 
43
#include "byte-swap.h"
 
44
#include "ls-oct-ascii.h"
 
45
#include "ls-oct-binary.h"
 
46
#include "ls-hdf5.h"
 
47
#include "ls-utils.h"
 
48
#include "pr-output.h"
 
49
 
 
50
DEFINE_OCTAVE_ALLOCATOR(octave_struct);
 
51
 
 
52
DEFINE_OV_TYPEID_FUNCTIONS_AND_DATA(octave_struct, "struct", "struct");
 
53
 
 
54
Cell
 
55
octave_struct::dotref (const octave_value_list& idx)
 
56
{
 
57
  Cell retval;
 
58
 
 
59
  assert (idx.length () == 1);
 
60
 
 
61
  std::string nm = idx(0).string_value ();
 
62
 
 
63
  Octave_map::const_iterator p = map.seek (nm);
 
64
 
 
65
  if (p != map.end ())
 
66
    retval = map.contents (p);
 
67
  else
 
68
    error ("structure has no member `%s'", nm.c_str ());
 
69
 
 
70
  return retval;
 
71
}
 
72
 
 
73
#if 0
 
74
static void
 
75
gripe_invalid_index (void)
 
76
{
 
77
  error ("invalid index for structure array");
 
78
}
 
79
#endif
 
80
 
 
81
static void
 
82
gripe_invalid_index_for_assignment (void)
 
83
{
 
84
  error ("invalid index for structure array assignment");
 
85
}
 
86
 
 
87
static void
 
88
gripe_invalid_index_type (const std::string& nm, char t)
 
89
{
 
90
  error ("%s cannot be indexed with %c", nm.c_str (), t);
 
91
}
 
92
 
 
93
static void
 
94
gripe_failed_assignment (void)
 
95
{
 
96
  error ("assignment to structure element failed");
 
97
}
 
98
 
 
99
octave_value_list
 
100
octave_struct::subsref (const std::string& type,
 
101
                        const std::list<octave_value_list>& idx,
 
102
                        int nargout)
 
103
{
 
104
  octave_value_list retval;
 
105
 
 
106
  int skip = 1;
 
107
 
 
108
  switch (type[0])
 
109
    {
 
110
    case '(':
 
111
      {
 
112
        if (type.length () > 1 && type[1] == '.')
 
113
          {
 
114
            std::list<octave_value_list>::const_iterator p = idx.begin ();
 
115
            octave_value_list key_idx = *++p;
 
116
 
 
117
            Cell tmp = dotref (key_idx);
 
118
 
 
119
            if (! error_state)
 
120
              {
 
121
                Cell t = tmp.index (idx.front ());
 
122
 
 
123
                retval(0) = (t.length () == 1) ? t(0) : octave_value (t, true);
 
124
 
 
125
                // We handled two index elements, so tell
 
126
                // next_subsref to skip both of them.
 
127
 
 
128
                skip++;
 
129
              }
 
130
          }
 
131
        else
 
132
          retval(0) = map.index (idx.front ());
 
133
      }
 
134
      break;
 
135
 
 
136
    case '.':
 
137
      {
 
138
        if (map.numel() > 0)
 
139
          {
 
140
            Cell t = dotref (idx.front ());
 
141
 
 
142
            retval(0) = (t.length () == 1) ? t(0) : octave_value (t, true);
 
143
          }
 
144
      }
 
145
      break;
 
146
 
 
147
    case '{':
 
148
      gripe_invalid_index_type (type_name (), type[0]);
 
149
      break;
 
150
 
 
151
    default:
 
152
      panic_impossible ();
 
153
    }
 
154
 
 
155
  // FIXME -- perhaps there should be an
 
156
  // octave_value_list::next_subsref member function?  See also
 
157
  // octave_user_function::subsref.
 
158
 
 
159
  if (idx.size () > 1)
 
160
    retval = retval(0).next_subsref (nargout, type, idx, skip);
 
161
 
 
162
  return retval;
 
163
}
 
164
 
 
165
octave_value
 
166
octave_struct::numeric_conv (const Cell& val,
 
167
                             const std::string& type)
 
168
{
 
169
  octave_value retval;
 
170
 
 
171
  if (val.length () == 1)
 
172
    {
 
173
      retval = val(0);
 
174
 
 
175
      if (type.length () > 0 && type[0] == '.' && ! retval.is_map ())
 
176
        retval = Octave_map ();
 
177
    }
 
178
  else
 
179
    gripe_invalid_index_for_assignment ();
 
180
 
 
181
  return retval;
 
182
}
 
183
 
 
184
octave_value
 
185
octave_struct::subsasgn (const std::string& type,
 
186
                         const std::list<octave_value_list>& idx,
 
187
                         const octave_value& rhs)
 
188
{
 
189
  octave_value retval;
 
190
 
 
191
  int n = type.length ();
 
192
 
 
193
  octave_value t_rhs = rhs;
 
194
 
 
195
  if (n > 1 && ! (type.length () == 2 && type[0] == '(' && type[1] == '.'))
 
196
    {
 
197
      switch (type[0])
 
198
        {
 
199
        case '(':
 
200
          {
 
201
            if (type.length () > 1 && type[1] == '.')
 
202
              {
 
203
                std::list<octave_value_list>::const_iterator p = idx.begin ();
 
204
                octave_value_list t_idx = *p;
 
205
 
 
206
                octave_value_list key_idx = *++p;
 
207
 
 
208
                assert (key_idx.length () == 1);
 
209
 
 
210
                std::string key = key_idx(0).string_value ();
 
211
 
 
212
                octave_value u;
 
213
 
 
214
                if (! map.contains (key))
 
215
                  u = octave_value::empty_conv (type.substr (2), rhs);
 
216
                else
 
217
                  {
 
218
                    Cell map_val = map.contents (key);
 
219
 
 
220
                    Cell map_elt = map_val.index (idx.front (), true);
 
221
 
 
222
                    u = numeric_conv (map_elt, type.substr (2));
 
223
                  }
 
224
 
 
225
                if (! error_state)
 
226
                  {
 
227
                    std::list<octave_value_list> next_idx (idx);
 
228
 
 
229
                    // We handled two index elements, so subsasgn to
 
230
                    // needs to skip both of them.
 
231
 
 
232
                    next_idx.erase (next_idx.begin ());
 
233
                    next_idx.erase (next_idx.begin ());
 
234
 
 
235
                    u.make_unique ();
 
236
 
 
237
                    t_rhs = u.subsasgn (type.substr (2), next_idx, rhs);
 
238
                  }
 
239
              }
 
240
            else
 
241
              gripe_invalid_index_for_assignment ();
 
242
          }
 
243
          break;
 
244
 
 
245
        case '.':
 
246
          {
 
247
            octave_value_list key_idx = idx.front ();
 
248
 
 
249
            assert (key_idx.length () == 1);
 
250
 
 
251
            std::string key = key_idx(0).string_value ();
 
252
 
 
253
            octave_value u;
 
254
 
 
255
            if (! map.contains (key))
 
256
              u = octave_value::empty_conv (type.substr (1), rhs);
 
257
            else
 
258
              {
 
259
                Cell map_val = map.contents (key);
 
260
 
 
261
                u = numeric_conv (map_val, type.substr (1));
 
262
              }
 
263
 
 
264
            if (! error_state)
 
265
              {
 
266
                std::list<octave_value_list> next_idx (idx);
 
267
 
 
268
                next_idx.erase (next_idx.begin ());
 
269
 
 
270
                u.make_unique ();
 
271
 
 
272
                t_rhs = u.subsasgn (type.substr (1), next_idx, rhs);
 
273
              }
 
274
          }
 
275
          break;
 
276
 
 
277
        case '{':
 
278
          gripe_invalid_index_type (type_name (), type[0]);
 
279
          break;
 
280
 
 
281
        default:
 
282
          panic_impossible ();
 
283
        }
 
284
    }
 
285
 
 
286
  if (! error_state)
 
287
    {
 
288
      switch (type[0])
 
289
        {
 
290
        case '(':
 
291
          {
 
292
            if (n > 1 && type[1] == '.')
 
293
              {
 
294
                std::list<octave_value_list>::const_iterator p = idx.begin ();
 
295
                octave_value_list key_idx = *++p;
 
296
 
 
297
                assert (key_idx.length () == 1);
 
298
 
 
299
                std::string key = key_idx(0).string_value ();
 
300
 
 
301
                if (! error_state)
 
302
                  {
 
303
                    map.assign (idx.front (), key, t_rhs);
 
304
 
 
305
                    if (! error_state)
 
306
                      {
 
307
                        count++;
 
308
                        retval = octave_value (this);
 
309
                      }
 
310
                    else
 
311
                      gripe_failed_assignment ();
 
312
                  }
 
313
                else
 
314
                  gripe_failed_assignment ();
 
315
              }
 
316
            else
 
317
              {
 
318
                if (t_rhs.is_map())
 
319
                  {
 
320
                    Octave_map rhs_map = t_rhs.map_value ();
 
321
 
 
322
                    if (! error_state)
 
323
                      {
 
324
                        map.assign (idx.front (), rhs_map);
 
325
 
 
326
                        if (! error_state)
 
327
                          {
 
328
                            count++;
 
329
                            retval = octave_value (this);
 
330
                          }
 
331
                        else
 
332
                          gripe_failed_assignment ();
 
333
                      }
 
334
                    else
 
335
                      error ("invalid structure assignment");
 
336
                  }
 
337
                else
 
338
                  {
 
339
                    if (t_rhs.is_empty()) 
 
340
                      {
 
341
                        map.maybe_delete_elements (idx.front());
 
342
 
 
343
                        if (! error_state)
 
344
                          {
 
345
                            count++;
 
346
                            retval = octave_value (this);
 
347
                          }
 
348
                        else
 
349
                          gripe_failed_assignment ();
 
350
                      }
 
351
                    else
 
352
                      error ("invalid structure assignment");
 
353
                  }
 
354
              }
 
355
          }
 
356
          break;
 
357
 
 
358
        case '.':
 
359
          {
 
360
            octave_value_list key_idx = idx.front ();
 
361
 
 
362
            assert (key_idx.length () == 1);
 
363
 
 
364
            std::string key = key_idx(0).string_value ();
 
365
 
 
366
            if (t_rhs.is_cs_list ())
 
367
              {
 
368
                Cell tmp_cell = Cell (t_rhs.list_value ());
 
369
 
 
370
                // The shape of the RHS is irrelevant, we just want
 
371
                // the number of elements to agree and to preserve the
 
372
                // shape of the left hand side of the assignment.
 
373
 
 
374
                if (numel () == tmp_cell.numel ())
 
375
                  tmp_cell = tmp_cell.reshape (dims ());
 
376
 
 
377
                map.assign (key, tmp_cell);
 
378
              }
 
379
            else
 
380
              map.assign (key, t_rhs);
 
381
 
 
382
            if (! error_state)
 
383
              {
 
384
                count++;
 
385
                retval = octave_value (this);
 
386
              }
 
387
            else
 
388
              gripe_failed_assignment ();
 
389
          }
 
390
          break;
 
391
 
 
392
        case '{':
 
393
          gripe_invalid_index_type (type_name (), type[0]);
 
394
          break;
 
395
 
 
396
        default:
 
397
          panic_impossible ();
 
398
        }
 
399
    }
 
400
  else
 
401
    gripe_failed_assignment ();
 
402
 
 
403
  return retval;
 
404
}
 
405
 
 
406
octave_value
 
407
octave_struct::do_index_op (const octave_value_list& idx, bool resize_ok)
 
408
{
 
409
  octave_value retval;
 
410
 
 
411
  octave_idx_type n_idx = idx.length ();
 
412
 
 
413
  int nd = map.ndims ();
 
414
 
 
415
  switch (n_idx)
 
416
    {
 
417
    case 0:
 
418
      retval = map;
 
419
      break;
 
420
 
 
421
    case 1:
 
422
      {
 
423
        idx_vector i = idx (0).index_vector ();
 
424
 
 
425
        if (! error_state)
 
426
          retval = map.index (i, resize_ok, Cell::resize_fill_value ());
 
427
      }
 
428
      break;
 
429
 
 
430
    default:
 
431
      {
 
432
        if (n_idx == 2 && nd == 2)
 
433
          {
 
434
            idx_vector i = idx (0).index_vector ();
 
435
 
 
436
            if (! error_state)
 
437
              {
 
438
                idx_vector j = idx (1).index_vector ();
 
439
 
 
440
                if (! error_state)
 
441
                  retval = map.index (i, j, resize_ok,
 
442
                                      Cell::resize_fill_value ());
 
443
              }
 
444
          }
 
445
        else
 
446
          {
 
447
            Array<idx_vector> idx_vec (n_idx);
 
448
 
 
449
            for (octave_idx_type i = 0; i < n_idx; i++)
 
450
              {
 
451
                idx_vec(i) = idx(i).index_vector ();
 
452
 
 
453
                if (error_state)
 
454
                  break;
 
455
              }
 
456
 
 
457
            if (! error_state)
 
458
              retval = map.index (idx_vec, resize_ok,
 
459
                                  Cell::resize_fill_value ());
 
460
          }
 
461
      }
 
462
      break;
 
463
    }
 
464
 
 
465
  return retval;
 
466
}
 
467
 
 
468
size_t
 
469
octave_struct::byte_size (void) const
 
470
{
 
471
  // Neglect the size of the fieldnames.
 
472
 
 
473
  size_t retval = 0;
 
474
 
 
475
  for (Octave_map::const_iterator p = map.begin (); p != map.end (); p++)
 
476
    {
 
477
      std::string key = map.key (p);
 
478
 
 
479
      octave_value val = octave_value (map.contents (p));
 
480
 
 
481
      retval += val.byte_size ();
 
482
    }
 
483
 
 
484
  return retval;
 
485
}
 
486
 
 
487
void
 
488
octave_struct::print (std::ostream& os, bool) const
 
489
{
 
490
  print_raw (os);
 
491
}
 
492
 
 
493
void
 
494
octave_struct::print_raw (std::ostream& os, bool) const
 
495
{
 
496
  unwind_protect::begin_frame ("octave_struct_print");
 
497
 
 
498
  unwind_protect_int (Vstruct_levels_to_print);
 
499
 
 
500
  if (Vstruct_levels_to_print >= 0)
 
501
    {
 
502
      bool print_keys_only = (Vstruct_levels_to_print == 0
 
503
                              || map.numel () == 0);
 
504
 
 
505
      Vstruct_levels_to_print--;
 
506
 
 
507
      indent (os);
 
508
      os << "{";
 
509
      newline (os);
 
510
 
 
511
      increment_indent_level ();
 
512
 
 
513
      octave_idx_type n = map.numel ();
 
514
 
 
515
      if (n == 0 || (n > 1 && print_keys_only))
 
516
        {
 
517
          indent (os);
 
518
          dim_vector dv = dims ();
 
519
          os << dv.str () << " struct array containing the fields:";
 
520
          newline (os);
 
521
          newline (os);
 
522
 
 
523
          increment_indent_level ();
 
524
        }
 
525
 
 
526
      string_vector key_list = map.keys ();
 
527
 
 
528
      for (octave_idx_type i = 0; i < key_list.length (); i++)
 
529
        {
 
530
          std::string key = key_list[i];
 
531
 
 
532
          Cell val = map.contents (key);
 
533
 
 
534
          octave_value tmp = (n == 1) ? val(0) : octave_value (val, true);
 
535
 
 
536
          if (print_keys_only)
 
537
            {
 
538
              indent (os);
 
539
              os << key;
 
540
              if (n == 1)
 
541
                {
 
542
                  dim_vector dv = tmp.dims ();
 
543
                  os << ": " << dv.str () << " " << tmp.type_name ();
 
544
                }
 
545
              newline (os);
 
546
            }
 
547
          else
 
548
            tmp.print_with_name (os, key);
 
549
        }
 
550
 
 
551
      if (n == 0 || (n > 1 && print_keys_only))
 
552
        decrement_indent_level ();
 
553
 
 
554
      decrement_indent_level ();
 
555
 
 
556
      indent (os);
 
557
      os << "}";
 
558
      newline (os);
 
559
    }
 
560
  else
 
561
    {
 
562
      indent (os);
 
563
      os << "<structure>";
 
564
      newline (os);
 
565
    }
 
566
 
 
567
  unwind_protect::run_frame ("octave_struct_print");
 
568
}
 
569
 
 
570
bool
 
571
octave_struct::print_name_tag (std::ostream& os, const std::string& name) const
 
572
{
 
573
  bool retval = false;
 
574
 
 
575
  indent (os);
 
576
 
 
577
  if (Vstruct_levels_to_print < 0)
 
578
    os << name << " = ";
 
579
  else
 
580
    {
 
581
      os << name << " =";
 
582
      newline (os);
 
583
      retval = true;
 
584
    }
 
585
 
 
586
  return retval;
 
587
}
 
588
 
 
589
static bool 
 
590
scalar (const dim_vector& dims) 
 
591
{
 
592
  return dims.length () == 2 && dims (0) == 1 && dims (1) == 1;
 
593
}
 
594
 
 
595
/*
 
596
%!shared x
 
597
%! x(1).a=1; x(2).a=2; x(1).b=3; x(2).b=3;
 
598
%!assert(struct('a',1,'b',3),x(1))
 
599
%!assert(isempty(x([])))
 
600
%!assert(isempty(struct('a',{},'b',{})))
 
601
%!assert(struct('a',{1,2},'b',{3,3}),x)
 
602
%!assert(struct('a',{1,2},'b',3),x)
 
603
%!assert(struct('a',{1,2},'b',{3}),x)
 
604
%!assert(struct('b',3,'a',{1,2}),x)
 
605
%!assert(struct('b',{3},'a',{1,2}),x) 
 
606
%!test x=struct([]);
 
607
%!assert(size(x),[0,0]);
 
608
%!assert(isstruct(x));
 
609
%!assert(isempty(fieldnames(x)));
 
610
%!fail("struct('a',{1,2},'b',{1,2,3})","dimensions of parameter 2 do not match those of parameter 4")
 
611
%!fail("struct(1,2,3,4)","struct expects alternating \"field\", VALUE pairs");
 
612
%!fail("struct('1',2,'3')","struct expects alternating \"field\", VALUE pairs");
 
613
*/
 
614
 
 
615
DEFUN (struct, args, ,
 
616
  "-*- texinfo -*-\n\
 
617
@deftypefn {Built-in Function} {} struct (\"field\", @var{value}, \"field\", @var{value}, @dots{})\n\
 
618
\n\
 
619
Create a structure and initialize its value.\n\
 
620
\n\
 
621
If the values are cell arrays, create a structure array and initialize\n\
 
622
its values.  The dimensions of each cell array of values must match.\n\
 
623
Singleton cells and non-cell values are repeated so that they fill\n\
 
624
the entire array.  If the cells are empty, create an empty structure\n\
 
625
array with the specified field names.\n\
 
626
@end deftypefn")
 
627
{
 
628
  octave_value retval;
 
629
 
 
630
  int nargin = args.length ();
 
631
 
 
632
  // struct ([]) returns an empty struct.
 
633
 
 
634
  // struct (empty_matrix) returns an empty struct with the same
 
635
  // dimensions as the empty matrix.
 
636
 
 
637
  // Note that struct () creates a 1x1 struct with no fields for
 
638
  // compatibility with Matlab.
 
639
 
 
640
  if ((nargin == 1 || nargin == 2)
 
641
      && args(0).is_empty () && args(0).is_real_matrix ())
 
642
    {
 
643
      Cell fields;
 
644
 
 
645
      if (nargin == 2)
 
646
        {
 
647
          if (args(1).is_cellstr ())
 
648
            retval = Octave_map (args(0).dims (), args(1).cell_value ());
 
649
          else
 
650
            error ("struct: expecting cell array of field names as second argument");
 
651
        }
 
652
      else
 
653
        retval = Octave_map (args(0).dims ());
 
654
 
 
655
      return retval;
 
656
    }
 
657
    
 
658
  // Check for "field", VALUE pairs.
 
659
 
 
660
  for (int i = 0; i < nargin; i += 2) 
 
661
    {
 
662
      if (! args(i).is_string () || i + 1 >= nargin)
 
663
        {
 
664
          error ("struct expects alternating \"field\", VALUE pairs");
 
665
          return retval;
 
666
        }
 
667
    }
 
668
 
 
669
  // Check that the dimensions of the values correspond.
 
670
 
 
671
  dim_vector dims (1, 1);
 
672
 
 
673
  int first_dimensioned_value = 0;
 
674
 
 
675
  for (int i = 1; i < nargin; i += 2) 
 
676
    {
 
677
      if (args(i).is_cell ()) 
 
678
        {
 
679
          dim_vector argdims (args(i).dims ());
 
680
 
 
681
          if (! scalar (argdims))
 
682
            {
 
683
              if (! first_dimensioned_value)
 
684
                {
 
685
                  dims = argdims;
 
686
                  first_dimensioned_value = i + 1;
 
687
                }
 
688
              else if (dims != argdims)
 
689
                {
 
690
                  error ("struct: dimensions of parameter %d do not match those of parameter %d",
 
691
                         first_dimensioned_value, i+1);
 
692
                  return retval;
 
693
                }
 
694
            }
 
695
        }
 
696
    }
 
697
 
 
698
  // Create the return value.
 
699
 
 
700
  Octave_map map (dims);
 
701
 
 
702
  for (int i = 0; i < nargin; i+= 2) 
 
703
    {
 
704
      // Get key.
 
705
 
 
706
      std::string key (args(i).string_value ());
 
707
 
 
708
      if (error_state)
 
709
        return retval;
 
710
 
 
711
      if (! valid_identifier (key))
 
712
        {
 
713
          error ("struct: invalid structure field name `%s'", key.c_str ());
 
714
          return retval;
 
715
        }
 
716
 
 
717
      // Value may be v, { v }, or { v1, v2, ... }
 
718
      // In the first two cases, we need to create a cell array of
 
719
      // the appropriate dimensions filled with v.  In the last case, 
 
720
      // the cell array has already been determined to be of the
 
721
      // correct dimensions.
 
722
 
 
723
      if (args(i+1).is_cell ()) 
 
724
        {
 
725
          const Cell c (args(i+1).cell_value ());
 
726
 
 
727
          if (error_state)
 
728
            return retval;
 
729
 
 
730
          if (scalar (c.dims ())) 
 
731
            map.assign (key, Cell (dims, c(0)));
 
732
          else 
 
733
            map.assign (key, c);
 
734
        }
 
735
      else 
 
736
        map.assign (key, Cell (dims, args(i+1)));
 
737
 
 
738
      if (error_state)
 
739
        return retval;
 
740
    }
 
741
 
 
742
  return octave_value (map);
 
743
}
 
744
 
 
745
DEFUN (isstruct, args, ,
 
746
  "-*- texinfo -*-\n\
 
747
@deftypefn {Built-in Function} {} isstruct (@var{expr})\n\
 
748
Return 1 if the value of the expression @var{expr} is a structure.\n\
 
749
@end deftypefn")
 
750
{
 
751
  octave_value retval;
 
752
 
 
753
  if (args.length () == 1)
 
754
    retval = args(0).is_map ();
 
755
  else
 
756
    print_usage ();
 
757
 
 
758
  return retval;
 
759
}
 
760
 
 
761
DEFUN (fieldnames, args, ,
 
762
  "-*- texinfo -*-\n\
 
763
@deftypefn {Built-in Function} {} fieldnames (@var{struct})\n\
 
764
Return a cell array of strings naming the elements of the structure\n\
 
765
@var{struct}.  It is an error to call @code{fieldnames} with an\n\
 
766
argument that is not a structure.\n\
 
767
@end deftypefn")
 
768
{
 
769
  octave_value retval;
 
770
 
 
771
  int nargin = args.length ();
 
772
 
 
773
  if (nargin == 1)
 
774
    {
 
775
      if (args(0).is_map ())
 
776
        {
 
777
          Octave_map m = args(0).map_value ();
 
778
          string_vector keys = m.keys ();
 
779
          if (keys.length () == 0)
 
780
            retval = Cell (0, 1);
 
781
          else
 
782
            retval = Cell (m.keys ());
 
783
        }
 
784
      else
 
785
        gripe_wrong_type_arg ("fieldnames", args(0));
 
786
    }
 
787
  else
 
788
    print_usage ();
 
789
 
 
790
  return retval;
 
791
}
 
792
 
 
793
DEFUN (isfield, args, ,
 
794
  "-*- texinfo -*-\n\
 
795
@deftypefn {Built-in Function} {} isfield (@var{expr}, @var{name})\n\
 
796
Return true if the expression @var{expr} is a structure and it includes an\n\
 
797
element named @var{name}.  The first argument must be a structure and\n\
 
798
the second must be a string.\n\
 
799
@end deftypefn")
 
800
{
 
801
  octave_value retval;
 
802
 
 
803
  int nargin = args.length ();
 
804
 
 
805
  if (nargin == 2)
 
806
    {
 
807
      retval = false;
 
808
 
 
809
      // FIXME -- should this work for all types that can do
 
810
      // structure reference operations?
 
811
 
 
812
      if (args(0).is_map () && args(1).is_string ())
 
813
        {
 
814
          std::string key = args(1).string_value ();
 
815
 
 
816
          Octave_map m = args(0).map_value ();
 
817
 
 
818
          retval = m.contains (key) != 0;
 
819
        }
 
820
    }
 
821
  else
 
822
    print_usage ();
 
823
 
 
824
  return retval;
 
825
}
 
826
 
 
827
// Check that the dimensions of the input arguments are correct.
 
828
 
 
829
static bool
 
830
cell2struct_check_args (const dim_vector& c_dv, const dim_vector& f_dv,
 
831
                        bool is_cell, int dim)
 
832
{
 
833
  bool retval = true;
 
834
 
 
835
  if (dim >= 0 && dim < c_dv.length ())
 
836
    {
 
837
      if (is_cell)
 
838
        {
 
839
          if (f_dv.numel () != c_dv(dim))
 
840
            {
 
841
              error ("cell2struct: numel (FIELD) != size (CELL, DIM)");
 
842
 
 
843
              retval = false;
 
844
            }
 
845
        }
 
846
      else
 
847
        {
 
848
          if (f_dv.length () > 2)
 
849
            {
 
850
              error ("cell2struct: field array must be a 2-d matrix");
 
851
 
 
852
              retval = false;
 
853
            }
 
854
          else if (f_dv(0) != c_dv(dim))
 
855
            {
 
856
              error ("cell2struct: size (FIELD, 1) != length (C, DIM)");
 
857
 
 
858
              retval = false;
 
859
            }
 
860
        }
 
861
    }
 
862
  else
 
863
    {
 
864
      error ("cell2struct: DIM out of range");
 
865
 
 
866
      retval = false;
 
867
    }
 
868
 
 
869
  return retval;
 
870
}
 
871
 
 
872
static void
 
873
cell2struct_construct_idx (Array<octave_idx_type>& ra_idx1,
 
874
                           const Array<octave_idx_type>& ra_idx2,
 
875
                           octave_idx_type dim, octave_idx_type fill_value)
 
876
{
 
877
  octave_idx_type iidx = 0;
 
878
 
 
879
  for (octave_idx_type idx = 0; idx < ra_idx1.length (); idx++)
 
880
    {
 
881
      if (idx == dim)
 
882
        ra_idx1.elem (idx) = fill_value;
 
883
      else
 
884
        ra_idx1.elem (idx) = ra_idx2(iidx++);
 
885
    }
 
886
}
 
887
 
 
888
DEFUN (cell2struct, args, ,
 
889
       "-*- texinfo -*-\n\
 
890
@deftypefn {Built-in Function} {} cell2struct (@var{cell}, @var{fields}, @var{dim})\n\
 
891
Convert @var{cell} to a structure. The number of fields in @var{fields}\n\
 
892
must match the number of elements in @var{cell} along dimension @var{dim},\n\
 
893
that is @code{numel (@var{fields}) == size (@var{cell}, @var{dim})}.\n\
 
894
\n\
 
895
@example\n\
 
896
@group\n\
 
897
A = cell2struct (@{'Peter', 'Hannah', 'Robert';\n\
 
898
                   185, 170, 168@},\n\
 
899
                 @{'Name','Height'@}, 1);\n\
 
900
A(1)\n\
 
901
@result{} ans =\n\
 
902
      @{\n\
 
903
        Height = 185\n\
 
904
        Name   = Peter\n\
 
905
      @}\n\
 
906
\n\
 
907
@end group\n\
 
908
@end example\n\
 
909
@end deftypefn")
 
910
{
 
911
  octave_value retval;
 
912
 
 
913
  if (args.length () == 3)
 
914
    {
 
915
      Cell c = args(0).cell_value ();
 
916
 
 
917
      if (! error_state)
 
918
        {
 
919
          octave_value field = args(1);
 
920
 
 
921
          // Field is either cell or character matrix.
 
922
 
 
923
          // FIXME -- this could be simplified if we had
 
924
          // cellstr and iscellstr functions available.
 
925
 
 
926
          bool field_is_cell = field.is_cell ();
 
927
 
 
928
          Cell field_cell;
 
929
          charMatrix field_char;
 
930
 
 
931
          if (field_is_cell)
 
932
            field_cell = field.cell_value ();
 
933
          else
 
934
            field_char = field.char_matrix_value ();
 
935
 
 
936
          if (! error_state)
 
937
            {
 
938
              // Retrieve the dimension value.
 
939
 
 
940
              // FIXME --  int_value () should print out the
 
941
              // conversions it does to be Matlab compatible.
 
942
 
 
943
              octave_idx_type dim = args(2).int_value () - 1;
 
944
 
 
945
              if (! error_state)
 
946
                {
 
947
                  dim_vector c_dv = c.dims ();
 
948
                  dim_vector field_dv = field.dims ();
 
949
 
 
950
                  if (cell2struct_check_args (c_dv, field_dv, field_is_cell,
 
951
                                              dim))
 
952
                    {
 
953
                      octave_idx_type c_dv_length = c_dv.length ();
 
954
 
 
955
                      // Dimension vector for the Cell arrays to be
 
956
                      // put into the structure.
 
957
 
 
958
                      dim_vector value_dv;
 
959
 
 
960
                      // Initialize c_value_dv.
 
961
 
 
962
                      if (c_dv_length == 2)
 
963
                        value_dv = dim_vector (1, 1);
 
964
                      else
 
965
                        value_dv.resize (c_dv_length - 1);
 
966
 
 
967
                      octave_idx_type idx_tmp = 0;
 
968
 
 
969
                      for (octave_idx_type i = 0; i < c_dv_length; i++)
 
970
                        {
 
971
                          if (i != dim)
 
972
                            value_dv.elem (idx_tmp++) = c_dv.elem (i);
 
973
                        }
 
974
 
 
975
                      // All initializing is done, we can start moving
 
976
                      // values.
 
977
 
 
978
                      Octave_map map;
 
979
 
 
980
                      // If field is a cell array then we use all
 
981
                      // elements in array, on the other hand when
 
982
                      // field is a character array the number of
 
983
                      // elements is equals the number of rows.
 
984
 
 
985
                      octave_idx_type field_numel
 
986
                        = field_is_cell ? field_dv.numel (): field_dv(0);
 
987
 
 
988
                      // For matlab compatibility.
 
989
 
 
990
                      if (field_numel == 0)
 
991
                        map.reshape (dim_vector (0, 1));
 
992
 
 
993
                      for (octave_idx_type i = 0; i < field_numel; i++)
 
994
                        {
 
995
                          // Construct cell array which goes into the
 
996
                          // structure together with the appropriate
 
997
                          // field name.
 
998
 
 
999
                          Cell c_value (value_dv);
 
1000
 
 
1001
                          Array<octave_idx_type> value_idx (value_dv.length (), 0);
 
1002
                          Array<octave_idx_type> c_idx (c_dv_length, 0);
 
1003
 
 
1004
                          for (octave_idx_type j = 0; j < value_dv.numel (); j++)
 
1005
                            {
 
1006
                              // Need to do this to construct the
 
1007
                              // appropriate idx for getting elements
 
1008
                              // from the original cell array.
 
1009
 
 
1010
                              cell2struct_construct_idx (c_idx, value_idx,
 
1011
                                                         dim, i);
 
1012
 
 
1013
                              c_value.elem (value_idx) = c.elem (c_idx);
 
1014
 
 
1015
                              increment_index (value_idx, value_dv);
 
1016
                            }
 
1017
 
 
1018
                          std::string field_str;
 
1019
 
 
1020
                          if (field_is_cell)
 
1021
                            {
 
1022
                              // Matlab retrieves the field values
 
1023
                              // column by column.
 
1024
 
 
1025
                              octave_value field_tmp = field_cell.elem (i);
 
1026
 
 
1027
                              field_str = field_tmp.string_value ();
 
1028
 
 
1029
                              if (error_state)
 
1030
                                {
 
1031
                                  error ("cell2struct: fields have to be of type string");
 
1032
                                  break;
 
1033
                                }
 
1034
                            }
 
1035
                          else
 
1036
                            {
 
1037
                              field_str = field_char.row_as_string (i);
 
1038
 
 
1039
                              if (error_state)
 
1040
                                return retval;
 
1041
                            }
 
1042
 
 
1043
                          if (! valid_identifier (field_str))
 
1044
                            {
 
1045
                              error ("cell2struct: invalid field name `%s'",
 
1046
                                     field_str.c_str ());
 
1047
                              break;
 
1048
                            }
 
1049
 
 
1050
                          map.reshape (value_dv);
 
1051
 
 
1052
                          map.assign (field_str, c_value);
 
1053
                        }
 
1054
 
 
1055
                      if (! error_state)
 
1056
                        retval = map;
 
1057
                    }
 
1058
                }
 
1059
              else
 
1060
                error ("cell2struct: expecting third argument to be an integer");
 
1061
            }
 
1062
          else
 
1063
            error ("cell2struct: expecting second argument to be a cell or character array");
 
1064
        }
 
1065
      else
 
1066
        error ("cell2struct: expecting first argument to be a cell array");
 
1067
    }
 
1068
  else
 
1069
    print_usage ();
 
1070
 
 
1071
  return retval;
 
1072
}
 
1073
 
 
1074
// So we can call Fcellstr directly.
 
1075
extern octave_value_list Fcellstr (const octave_value_list& args, int);
 
1076
 
 
1077
DEFUN (rmfield, args, ,
 
1078
       "-*- texinfo -*-\n\
 
1079
@deftypefn {Built-in Function} {} rmfield (@var{s}, @var{f})\n\
 
1080
Remove field @var{f} from the structure @var{s}.  If @var{f} is a\n\
 
1081
cell array of character strings or a character array, remove the\n\
 
1082
named fields.\n\
 
1083
@seealso{cellstr, iscellstr, setfield}\n\
 
1084
@end deftypefn")
 
1085
{
 
1086
  octave_value retval;
 
1087
 
 
1088
  int nargin = args.length ();
 
1089
 
 
1090
  if (nargin == 2)
 
1091
    {
 
1092
      Octave_map m = args(0).map_value ();
 
1093
 
 
1094
      octave_value_list fval = Fcellstr (args(1), 1);
 
1095
 
 
1096
      if (! error_state)
 
1097
        {
 
1098
          Cell fcell = fval(0).cell_value ();
 
1099
 
 
1100
          for (int i = 0; i < fcell.numel (); i++)
 
1101
            {
 
1102
              std::string key = fcell(i).string_value ();
 
1103
 
 
1104
              if (m.contains (key))
 
1105
                m.del (key);
 
1106
              else
 
1107
                {
 
1108
                  error ("rmfield: structure does not contain field %s",
 
1109
                         key.c_str ());
 
1110
 
 
1111
                  break;
 
1112
                }
 
1113
            }
 
1114
 
 
1115
          if (! error_state)
 
1116
            retval = m;
 
1117
        }
 
1118
    }
 
1119
  else
 
1120
    print_usage ();
 
1121
 
 
1122
  return retval;
 
1123
}
 
1124
 
 
1125
bool
 
1126
octave_struct::save_ascii (std::ostream& os)
 
1127
{
 
1128
  Octave_map m = map_value ();
 
1129
  os << "# length: " << m.nfields () << "\n";
 
1130
 
 
1131
  Octave_map::iterator i = m.begin ();
 
1132
  while (i != m.end ())
 
1133
    {
 
1134
      octave_value val = map.contents (i);
 
1135
 
 
1136
      bool b = save_ascii_data (os, val, m.key (i), false, 0);
 
1137
      
 
1138
      if (! b)
 
1139
        return os;
 
1140
 
 
1141
      i++;
 
1142
    }
 
1143
 
 
1144
  return true;
 
1145
}
 
1146
 
 
1147
bool 
 
1148
octave_struct::load_ascii (std::istream& is)
 
1149
{
 
1150
  octave_idx_type len = 0;
 
1151
  bool success = true;
 
1152
 
 
1153
  if (extract_keyword (is, "length", len) && len >= 0)
 
1154
    {
 
1155
      if (len > 0)
 
1156
        {
 
1157
          Octave_map m (map);
 
1158
 
 
1159
          for (octave_idx_type j = 0; j < len; j++)
 
1160
            {
 
1161
              octave_value t2;
 
1162
              bool dummy;
 
1163
 
 
1164
              // recurse to read cell elements
 
1165
              std::string nm
 
1166
                = read_ascii_data (is, std::string (), dummy, t2, j);
 
1167
 
 
1168
              if (!is)
 
1169
                break;
 
1170
 
 
1171
              Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
 
1172
 
 
1173
              if (error_state)
 
1174
                {
 
1175
                  error ("load: internal error loading struct elements");
 
1176
                  return false;
 
1177
                }
 
1178
 
 
1179
              m.assign (nm, tcell);
 
1180
            }
 
1181
 
 
1182
          if (is) 
 
1183
            map = m;
 
1184
          else
 
1185
            {
 
1186
              error ("load: failed to load structure");
 
1187
              success = false;
 
1188
            }
 
1189
        }
 
1190
      else if (len == 0 )
 
1191
        map = Octave_map (dim_vector (1, 1));
 
1192
      else
 
1193
        panic_impossible ();
 
1194
    }
 
1195
  else {
 
1196
    error ("load: failed to extract number of elements in structure");
 
1197
    success = false;
 
1198
  }
 
1199
 
 
1200
  return success;
 
1201
}
 
1202
 
 
1203
bool 
 
1204
octave_struct::save_binary (std::ostream& os, bool& save_as_floats)
 
1205
{
 
1206
  Octave_map m = map_value ();
 
1207
 
 
1208
  int32_t len = m.nfields ();
 
1209
  os.write (reinterpret_cast<char *> (&len), 4);
 
1210
  
 
1211
  Octave_map::iterator i = m.begin ();
 
1212
  while (i != m.end ())
 
1213
    {
 
1214
      octave_value val = map.contents (i);
 
1215
 
 
1216
      bool b = save_binary_data (os, val, m.key (i), "", 0, save_as_floats);
 
1217
      
 
1218
      if (! b)
 
1219
        return os;
 
1220
 
 
1221
      i++;
 
1222
    }
 
1223
 
 
1224
  return true;
 
1225
}
 
1226
 
 
1227
bool 
 
1228
octave_struct::load_binary (std::istream& is, bool swap,
 
1229
                            oct_mach_info::float_format fmt)
 
1230
{
 
1231
  bool success = true;
 
1232
  int32_t len;
 
1233
  if (! is.read (reinterpret_cast<char *> (&len), 4))
 
1234
    return false;
 
1235
  if (swap)
 
1236
    swap_bytes<4> (&len);
 
1237
 
 
1238
  if (len > 0)
 
1239
    {
 
1240
      Octave_map m (map);
 
1241
 
 
1242
      for (octave_idx_type j = 0; j < len; j++)
 
1243
        {
 
1244
          octave_value t2;
 
1245
          bool dummy;
 
1246
          std::string doc;
 
1247
 
 
1248
          // recurse to read cell elements
 
1249
          std::string nm = read_binary_data (is, swap, fmt, std::string (), 
 
1250
                                             dummy, t2, doc);
 
1251
 
 
1252
          if (!is)
 
1253
            break;
 
1254
 
 
1255
          Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
 
1256
 
 
1257
          if (error_state)
 
1258
            {
 
1259
              error ("load: internal error loading struct elements");
 
1260
              return false;
 
1261
            }
 
1262
 
 
1263
          m.assign (nm, tcell);
 
1264
        }
 
1265
 
 
1266
      if (is) 
 
1267
        map = m;
 
1268
      else
 
1269
        {
 
1270
          error ("load: failed to load structure");
 
1271
          success = false;
 
1272
        }
 
1273
    }
 
1274
  else if (len == 0 )
 
1275
    map = Octave_map (dim_vector (1, 1));
 
1276
  else
 
1277
    panic_impossible ();
 
1278
 
 
1279
  return success;
 
1280
}
 
1281
 
 
1282
#if defined (HAVE_HDF5)
 
1283
 
 
1284
bool
 
1285
octave_struct::save_hdf5 (hid_t loc_id, const char *name, bool save_as_floats)
 
1286
{
 
1287
  hid_t data_hid = -1;
 
1288
 
 
1289
  data_hid = H5Gcreate (loc_id, name, 0);
 
1290
  if (data_hid < 0) return false;
 
1291
 
 
1292
  // recursively add each element of the structure to this group
 
1293
  Octave_map m = map_value ();
 
1294
  Octave_map::iterator i = m.begin ();
 
1295
  while (i != m.end ())
 
1296
    {
 
1297
      octave_value val = map.contents (i);
 
1298
 
 
1299
      bool retval2 = add_hdf5_data (data_hid, val, m.key (i), "", false, 
 
1300
                                    save_as_floats);
 
1301
 
 
1302
      if (! retval2)
 
1303
        break;
 
1304
 
 
1305
      i++;
 
1306
    }
 
1307
 
 
1308
  H5Gclose (data_hid);
 
1309
 
 
1310
  return true;
 
1311
}
 
1312
 
 
1313
bool 
 
1314
octave_struct::load_hdf5 (hid_t loc_id, const char *name,
 
1315
                          bool have_h5giterate_bug)
 
1316
{
 
1317
  bool retval = false;
 
1318
 
 
1319
  hdf5_callback_data dsub;
 
1320
 
 
1321
  herr_t retval2 = 0;
 
1322
  Octave_map m (dim_vector (1, 1));
 
1323
  int current_item = 0;
 
1324
#ifdef HAVE_H5GGET_NUM_OBJS
 
1325
  hsize_t num_obj = 0;
 
1326
  hid_t group_id = H5Gopen (loc_id, name); 
 
1327
  H5Gget_num_objs (group_id, &num_obj);
 
1328
  H5Gclose (group_id);
 
1329
 
 
1330
  while (current_item < static_cast<int> (num_obj)
 
1331
         && (retval2 = H5Giterate (loc_id, name, &current_item,
 
1332
                                   hdf5_read_next_data, &dsub)) > 0)
 
1333
#else
 
1334
  while ((retval2 = H5Giterate (loc_id, name, &current_item,
 
1335
                                hdf5_read_next_data, &dsub)) > 0)
 
1336
#endif
 
1337
    {
 
1338
      octave_value t2 = dsub.tc;
 
1339
 
 
1340
      Cell tcell = t2.is_cell () ? t2.cell_value () : Cell (t2);
 
1341
 
 
1342
      if (error_state)
 
1343
        {
 
1344
          error ("load: internal error loading struct elements");
 
1345
          return false;
 
1346
        }
 
1347
 
 
1348
      m.assign (dsub.name, tcell);
 
1349
 
 
1350
      if (have_h5giterate_bug)
 
1351
        current_item++;  // H5Giterate returned the last index processed
 
1352
    }
 
1353
 
 
1354
  if (retval2 >= 0)
 
1355
    {
 
1356
      map = m;
 
1357
      retval = true;
 
1358
    }
 
1359
  
 
1360
  return retval;
 
1361
}
 
1362
 
 
1363
#endif
 
1364
 
 
1365
mxArray *
 
1366
octave_struct::as_mxArray (void) const
 
1367
{
 
1368
  int nf = nfields ();
 
1369
  string_vector kv = map_keys ();
 
1370
 
 
1371
  OCTAVE_LOCAL_BUFFER (const char *, f, nf);
 
1372
 
 
1373
  for (int i = 0; i < nf; i++)
 
1374
    f[i] = kv[i].c_str ();
 
1375
 
 
1376
  mxArray *retval = new mxArray (dims (), nf, f);
 
1377
 
 
1378
  mxArray **elts = static_cast<mxArray **> (retval->get_data ());
 
1379
 
 
1380
  mwSize nel = numel ();
 
1381
 
 
1382
  mwSize ntot = nf * nel;
 
1383
 
 
1384
  for (int i = 0; i < nf; i++)
 
1385
    {
 
1386
      Cell c = map.contents (kv[i]);
 
1387
 
 
1388
      const octave_value *p = c.data ();
 
1389
 
 
1390
      mwIndex k = 0;
 
1391
      for (mwIndex j = i; j < ntot; j += nf)
 
1392
        elts[j] = new mxArray (p[k++]);
 
1393
    }
 
1394
 
 
1395
  return retval;
 
1396
}
 
1397
 
 
1398
/*
 
1399
;;; Local Variables: ***
 
1400
;;; mode: C++ ***
 
1401
;;; End: ***
 
1402
*/