Updated FSF address in all files. Fixes ticket:51
[debian/gnuradio] / pmt / src / lib / pmt.cc
1 /* -*- c++ -*- */
2 /*
3  * Copyright 2006 Free Software Foundation, Inc.
4  * 
5  * This file is part of GNU Radio
6  * 
7  * GNU Radio 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 2, or (at your option)
10  * any later version.
11  * 
12  * GNU Radio 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 GNU Radio; see the file COPYING.  If not, write to
19  * the Free Software Foundation, Inc., 51 Franklin Street,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26 #include <vector>
27 #include <pmt.h>
28 #include "pmt_int.h"
29
30 pmt_base::~pmt_base()
31 {
32   // nop -- out of line virtual destructor
33 }
34
35 ////////////////////////////////////////////////////////////////////////////
36 //                         Exceptions
37 ////////////////////////////////////////////////////////////////////////////
38
39 pmt_exception::pmt_exception(const char *msg, pmt_t obj)
40   : d_msg(msg), d_obj(obj)
41 {
42 }
43
44 pmt_wrong_type::pmt_wrong_type(const char *msg, pmt_t obj)
45   : pmt_exception(msg, obj)
46 {
47 }
48
49 pmt_out_of_range::pmt_out_of_range(const char *msg, pmt_t obj)
50   : pmt_exception(msg, obj)
51 {
52 }
53
54 ////////////////////////////////////////////////////////////////////////////
55 //                          Dynamic Casts
56 ////////////////////////////////////////////////////////////////////////////
57
58 static pmt_symbol *
59 _symbol(pmt_t x)
60 {
61   return dynamic_cast<pmt_symbol*>(x.get());
62 }
63
64 static pmt_integer *
65 _integer(pmt_t x)
66 {
67   return dynamic_cast<pmt_integer*>(x.get());
68 }
69
70 static pmt_real *
71 _real(pmt_t x)
72 {
73   return dynamic_cast<pmt_real*>(x.get());
74 }
75
76 static pmt_complex *
77 _complex(pmt_t x)
78 {
79   return dynamic_cast<pmt_complex*>(x.get());
80 }
81
82 static pmt_pair *
83 _pair(pmt_t x)
84 {
85   return dynamic_cast<pmt_pair*>(x.get());
86 }
87
88 static pmt_vector *
89 _vector(pmt_t x)
90 {
91   return dynamic_cast<pmt_vector*>(x.get());
92 }
93
94 static pmt_uniform_vector *
95 _uniform_vector(pmt_t x)
96 {
97   return dynamic_cast<pmt_uniform_vector*>(x.get());
98 }
99
100 static pmt_dict *
101 _dict(pmt_t x)
102 {
103   return dynamic_cast<pmt_dict*>(x.get());
104 }
105
106 ////////////////////////////////////////////////////////////////////////////
107 //                           Booleans
108 ////////////////////////////////////////////////////////////////////////////
109
110 const pmt_t PMT_BOOL_T = pmt_t(new pmt_bool());         // singleton
111 const pmt_t PMT_BOOL_F = pmt_t(new pmt_bool());         // singleton
112
113 pmt_bool::pmt_bool(){}
114
115 bool
116 pmt_is_true(pmt_t obj)
117 {
118   return obj != PMT_BOOL_F;
119 }
120
121 bool
122 pmt_is_false(pmt_t obj)
123 {
124   return obj == PMT_BOOL_F;
125 }
126
127 bool
128 pmt_is_bool(pmt_t obj)
129 {
130   return obj->is_bool();
131 }
132
133 pmt_t
134 pmt_from_bool(bool val)
135 {
136   return val ? PMT_BOOL_T : PMT_BOOL_F;
137 }
138
139 bool
140 pmt_to_bool(pmt_t val)
141 {
142   if (val == PMT_BOOL_T)
143     return true;
144   if (val == PMT_BOOL_F)
145     return false;
146   throw pmt_wrong_type("pmt_to_bool", val);
147 }
148
149 ////////////////////////////////////////////////////////////////////////////
150 //                             Symbols
151 ////////////////////////////////////////////////////////////////////////////
152
153 static const unsigned int SYMBOL_HASH_TABLE_SIZE = 701;
154 static std::vector<pmt_t> s_symbol_hash_table(SYMBOL_HASH_TABLE_SIZE);
155
156 pmt_symbol::pmt_symbol(const std::string &name) : d_name(name){}
157
158
159 static unsigned int
160 hash_string(const std::string &s)
161 {
162   unsigned int h = 0;
163   unsigned int g = 0;
164
165   for (std::string::const_iterator p = s.begin(); p != s.end(); p++){
166     h = (h << 4) + (*p & 0xff);
167     g = h & 0xf0000000;
168     if (g){
169       h = h ^ (g >> 24);
170       h = h ^ g;
171     }
172   }
173   return h;
174 }
175
176 bool 
177 pmt_is_symbol(pmt_t obj)
178 {
179   return obj->is_symbol();
180 }
181
182 pmt_t 
183 pmt_string_to_symbol(const std::string &name)
184 {
185   unsigned hash = hash_string(name) % SYMBOL_HASH_TABLE_SIZE;
186
187   // Does a symbol with this name already exist?
188   for (pmt_t sym = s_symbol_hash_table[hash]; sym; sym = _symbol(sym)->next()){
189     if (name == _symbol(sym)->name())
190       return sym;               // Yes.  Return it
191   }
192
193   // Nope.  Make a new one.
194   pmt_t sym = pmt_t(new pmt_symbol(name));
195   _symbol(sym)->set_next(s_symbol_hash_table[hash]);
196   s_symbol_hash_table[hash] = sym;
197   return sym;
198 }
199
200 const std::string
201 pmt_symbol_to_string(pmt_t sym)
202 {
203   if (!sym->is_symbol())
204     throw pmt_wrong_type("pmt_symbol_to_string", sym);
205
206   return _symbol(sym)->name();
207 }
208
209 ////////////////////////////////////////////////////////////////////////////
210 //                             Number
211 ////////////////////////////////////////////////////////////////////////////
212
213 bool
214 pmt_is_number(pmt_t x)
215 {
216   return x->is_number();
217 }
218
219 ////////////////////////////////////////////////////////////////////////////
220 //                             Integer
221 ////////////////////////////////////////////////////////////////////////////
222
223 pmt_integer::pmt_integer(long value) : d_value(value) {}
224
225 bool
226 pmt_is_integer(pmt_t x)
227 {
228   return x->is_integer();
229 }
230
231
232 pmt_t
233 pmt_from_long(long x)
234 {
235   return pmt_t(new pmt_integer(x));
236 }
237
238 long
239 pmt_to_long(pmt_t x)
240 {
241   if (x->is_integer())
242     return _integer(x)->value();
243
244   throw pmt_wrong_type("pmt_to_long", x);
245 }
246
247 ////////////////////////////////////////////////////////////////////////////
248 //                              Real
249 ////////////////////////////////////////////////////////////////////////////
250
251 pmt_real::pmt_real(double value) : d_value(value) {}
252
253 bool 
254 pmt_is_real(pmt_t x)
255 {
256   return x->is_real();
257 }
258
259 pmt_t
260 pmt_from_double(double x)
261 {
262   return pmt_t(new pmt_real(x));
263 }
264
265 double
266 pmt_to_double(pmt_t x)
267 {
268   if (x->is_real())
269     return _real(x)->value();
270   if (x->is_integer())
271     return _integer(x)->value();
272
273   throw pmt_wrong_type("pmt_to_double", x);
274 }
275
276 ////////////////////////////////////////////////////////////////////////////
277 //                              Complex
278 ////////////////////////////////////////////////////////////////////////////
279
280 pmt_complex::pmt_complex(std::complex<double> value) : d_value(value) {}
281
282 bool 
283 pmt_is_complex(pmt_t x)
284 {
285   return x->is_complex();
286 }
287
288 pmt_t
289 pmt_make_rectangular(double re, double im)
290 {
291   return pmt_t(new pmt_complex(std::complex<double>(re, im)));
292 }
293
294 std::complex<double>
295 pmt_to_complex(pmt_t x)
296 {
297   if (x->is_complex())
298     return _complex(x)->value();
299   if (x->is_real())
300     return _real(x)->value();
301   if (x->is_integer())
302     return _integer(x)->value();
303
304   throw pmt_wrong_type("pmt_to_complex", x);
305 }
306
307 ////////////////////////////////////////////////////////////////////////////
308 //                              Pairs
309 ////////////////////////////////////////////////////////////////////////////
310
311 const pmt_t PMT_NIL = pmt_t(new pmt_null());            // singleton
312
313 pmt_null::pmt_null() {}
314 pmt_pair::pmt_pair(pmt_t car, pmt_t cdr) : d_car(car), d_cdr(cdr) {}
315
316 bool
317 pmt_is_null(pmt_t x)
318 {
319   return x == PMT_NIL;
320 }
321
322 bool
323 pmt_is_pair(pmt_t obj)
324 {
325   return obj->is_pair();
326 }
327
328 pmt_t
329 pmt_cons(pmt_t x, pmt_t y)
330 {
331   return pmt_t(new pmt_pair(x, y));
332 }
333
334 pmt_t
335 pmt_car(pmt_t pair)
336 {
337   if (pair->is_pair())
338     return _pair(pair)->car();
339   
340   throw pmt_wrong_type("pmt_car", pair);
341 }
342
343 pmt_t
344 pmt_cdr(pmt_t pair)
345 {
346   if (pair->is_pair())
347     return _pair(pair)->cdr();
348   
349   throw pmt_wrong_type("pmt_cdr", pair);
350 }
351
352 void
353 pmt_set_car(pmt_t pair, pmt_t obj)
354 {
355   if (pair->is_pair())
356     _pair(pair)->set_car(obj);
357   else
358     throw pmt_wrong_type("pmt_set_car", pair);
359 }
360
361 void
362 pmt_set_cdr(pmt_t pair, pmt_t obj)
363 {
364   if (pair->is_pair())
365     _pair(pair)->set_cdr(obj);
366   else
367     throw pmt_wrong_type("pmt_set_cdr", pair);
368 }
369
370 ////////////////////////////////////////////////////////////////////////////
371 //                             Vectors
372 ////////////////////////////////////////////////////////////////////////////
373
374 pmt_vector::pmt_vector(size_t len, pmt_t fill)
375   : d_v(len)
376 {
377   for (size_t i = 0; i < len; i++)
378     d_v[i] = fill;
379 }
380
381 pmt_t
382 pmt_vector::ref(size_t k) const
383 {
384   if (k >= length())
385     throw pmt_out_of_range("pmt_vector_ref", pmt_from_long(k));
386   return d_v[k];
387 }
388
389 void
390 pmt_vector::set(size_t k, pmt_t obj)
391 {
392   if (k >= length())
393     throw pmt_out_of_range("pmt_vector_set", pmt_from_long(k));
394   d_v[k] = obj;
395 }
396
397 void
398 pmt_vector::fill(pmt_t obj)
399 {
400   for (size_t i = 0; i < length(); i++)
401     d_v[i] = obj;
402 }
403
404 bool
405 pmt_is_vector(pmt_t obj)
406 {
407   return obj->is_vector();
408 }
409
410 pmt_t
411 pmt_make_vector(size_t k, pmt_t fill)
412 {
413   return pmt_t(new pmt_vector(k, fill));
414 }
415
416 pmt_t
417 pmt_vector_ref(pmt_t vector, size_t k)
418 {
419   if (!vector->is_vector())
420     throw pmt_wrong_type("pmt_vector_ref", vector);
421   return _vector(vector)->ref(k);
422 }
423
424 void
425 pmt_vector_set(pmt_t vector, size_t k, pmt_t obj)
426 {
427   if (!vector->is_vector())
428     throw pmt_wrong_type("pmt_vector_set", vector);
429   _vector(vector)->set(k, obj);
430 }
431
432 void
433 pmt_vector_fill(pmt_t vector, pmt_t obj)
434 {
435   if (!vector->is_vector())
436     throw pmt_wrong_type("pmt_vector_set", vector);
437   _vector(vector)->fill(obj);
438 }
439
440 ////////////////////////////////////////////////////////////////////////////
441 //                       Uniform Numeric Vectors
442 ////////////////////////////////////////////////////////////////////////////
443
444 bool
445 pmt_is_uniform_vector(pmt_t x)
446 {
447   return x->is_uniform_vector();
448 }
449
450 const void *
451 pmt_uniform_vector_elements(pmt_t vector, size_t &len)
452 {
453   if (!vector->is_uniform_vector())
454     throw pmt_wrong_type("pmt_uniform_vector_elements", vector);
455   return _uniform_vector(vector)->uniform_elements(len);
456 }
457
458 void *
459 pmt_uniform_vector_writeable_elements(pmt_t vector, size_t &len)
460 {
461   if (!vector->is_uniform_vector())
462     throw pmt_wrong_type("pmt_uniform_vector_writeable_elements", vector);
463   return _uniform_vector(vector)->uniform_writeable_elements(len);
464 }
465
466 ////////////////////////////////////////////////////////////////////////////
467 //                            Dictionaries
468 ////////////////////////////////////////////////////////////////////////////
469
470 pmt_dict::pmt_dict()
471   : d_alist(PMT_NIL)
472 {
473 }
474
475 void
476 pmt_dict::set(pmt_t key, pmt_t value)
477 {
478   pmt_t p = pmt_assv(key, d_alist);     // look for (key . value) pair
479   if (pmt_is_pair(p)){                  // found existing pair...
480     pmt_set_cdr(p, value);              // overrwrite cdr with new value
481   }
482   else {                                // not in the dict
483     d_alist = pmt_cons(pmt_cons(key, value), d_alist);  // add new (key . value) pair
484   }
485 }
486
487 pmt_t
488 pmt_dict::ref(pmt_t key, pmt_t not_found) const
489 {
490   pmt_t p = pmt_assv(key, d_alist);     // look for (key . value) pair
491   if (pmt_is_pair(p))
492     return pmt_cdr(p);
493   else
494     return not_found;
495 }
496
497 bool
498 pmt_dict::has_key(pmt_t key) const
499 {
500   return pmt_is_pair(pmt_assv(key, d_alist));
501 }
502
503 pmt_t
504 pmt_dict::items() const
505 {
506   return d_alist;
507 }
508
509 pmt_t
510 pmt_dict::keys() const
511 {
512   return pmt_map(pmt_car, d_alist);
513 }
514
515 pmt_t
516 pmt_dict::values() const
517 {
518   return pmt_map(pmt_cdr, d_alist);
519 }
520
521 bool
522 pmt_is_dict(pmt_t obj)
523 {
524   return obj->is_dict();
525 }
526
527 pmt_t
528 pmt_make_dict()
529 {
530   return pmt_t(new pmt_dict());
531 }
532
533 void
534 pmt_dict_set(pmt_t dict, pmt_t key, pmt_t value)
535 {
536   if (!dict->is_dict())
537     throw pmt_wrong_type("pmt_dict_set", dict);
538
539   _dict(dict)->set(key, value);
540 }
541
542 bool
543 pmt_dict_has_key(pmt_t dict, pmt_t key)
544 {
545   if (!dict->is_dict())
546     throw pmt_wrong_type("pmt_dict_has_key", dict);
547
548   return _dict(dict)->has_key(key);
549 }
550
551 pmt_t
552 pmt_dict_ref(pmt_t dict, pmt_t key, pmt_t not_found)
553 {
554   if (!dict->is_dict())
555     throw pmt_wrong_type("pmt_dict_ref", dict);
556
557   return _dict(dict)->ref(key, not_found);
558 }
559
560 pmt_t
561 pmt_dict_items(pmt_t dict)
562 {
563   if (!dict->is_dict())
564     throw pmt_wrong_type("pmt_dict_items", dict);
565
566   return _dict(dict)->items();
567 }
568
569 pmt_t
570 pmt_dict_keys(pmt_t dict)
571 {
572   if (!dict->is_dict())
573     throw pmt_wrong_type("pmt_dict_keys", dict);
574
575   return _dict(dict)->keys();
576 }
577
578 pmt_t
579 pmt_dict_values(pmt_t dict)
580 {
581   if (!dict->is_dict())
582     throw pmt_wrong_type("pmt_dict_values", dict);
583
584   return _dict(dict)->values();
585 }
586
587 ////////////////////////////////////////////////////////////////////////////
588 //                          General Functions
589 ////////////////////////////////////////////////////////////////////////////
590
591 bool
592 pmt_eq(pmt_t x, pmt_t y)
593 {
594   return x == y;
595 }
596
597 bool
598 pmt_eqv(pmt_t x, pmt_t y)
599 {
600   if (x == y)
601     return true;
602
603   if (x->is_integer() && y->is_integer())
604     return _integer(x)->value() == _integer(y)->value();
605
606   if (x->is_real() && y->is_real())
607     return _real(x)->value() == _real(y)->value();
608
609   if (x->is_complex() && y->is_complex())
610     return _complex(x)->value() == _complex(y)->value();
611
612   return false;
613 }
614
615 bool
616 pmt_equal(pmt_t x, pmt_t y)
617 {
618   if (pmt_eqv(x, y))
619     return true;
620
621   if (x->is_pair() && y->is_pair())
622     return pmt_equal(pmt_car(x), pmt_car(y)) && pmt_equal(pmt_cdr(x), pmt_cdr(y));
623
624   if (x->is_vector() && y->is_vector()){
625     pmt_vector *xv = _vector(x);
626     pmt_vector *yv = _vector(y);
627     if (xv->length() != yv->length())
628       return false;
629
630     for (unsigned i = 0; i < xv->length(); i++)
631       if (!pmt_equal(xv->_ref(i), yv->_ref(i)))
632         return false;
633
634     return true;
635   }
636
637   if (x->is_uniform_vector() && y->is_uniform_vector()){
638     pmt_uniform_vector *xv = _uniform_vector(x);
639     pmt_uniform_vector *yv = _uniform_vector(y);
640     if (xv->length() != yv->length())
641       return false;
642
643     size_t len_x, len_y;
644     if (memcmp(xv->uniform_elements(len_x),
645                yv->uniform_elements(len_y),
646                len_x) == 0)
647       return true;
648
649     return true;
650   }
651
652   // FIXME add other cases here...
653
654   return false;
655 }
656
657 size_t
658 pmt_length(pmt_t x)
659 {
660   if (x->is_vector())
661     return _vector(x)->length();
662
663   if (x->is_uniform_vector())
664     return _uniform_vector(x)->length();
665
666   // FIXME list length
667   // FIXME dictionary length (number of entries)
668
669   throw pmt_wrong_type("pmt_length", x);
670 }
671
672 pmt_t
673 pmt_assq(pmt_t obj, pmt_t alist)
674 {
675   while (pmt_is_pair(alist)){
676     pmt_t p = pmt_car(alist);
677     if (!pmt_is_pair(p))        // malformed alist
678       return PMT_BOOL_F;
679
680     if (pmt_eq(obj, pmt_car(p)))
681       return p;
682
683     alist = pmt_cdr(alist);
684   }
685   return PMT_BOOL_F;
686 }
687
688 pmt_t
689 pmt_assv(pmt_t obj, pmt_t alist)
690 {
691   while (pmt_is_pair(alist)){
692     pmt_t p = pmt_car(alist);
693     if (!pmt_is_pair(p))        // malformed alist
694       return PMT_BOOL_F;
695
696     if (pmt_eqv(obj, pmt_car(p)))
697       return p;
698
699     alist = pmt_cdr(alist);
700   }
701   return PMT_BOOL_F;
702 }
703
704 pmt_t
705 pmt_assoc(pmt_t obj, pmt_t alist)
706 {
707   while (pmt_is_pair(alist)){
708     pmt_t p = pmt_car(alist);
709     if (!pmt_is_pair(p))        // malformed alist
710       return PMT_BOOL_F;
711
712     if (pmt_equal(obj, pmt_car(p)))
713       return p;
714
715     alist = pmt_cdr(alist);
716   }
717   return PMT_BOOL_F;
718 }
719
720 pmt_t
721 pmt_map(pmt_t proc(pmt_t), pmt_t list)
722 {
723   pmt_t r = PMT_NIL;
724
725   while(pmt_is_pair(list)){
726     r = pmt_cons(proc(pmt_car(list)), r);
727     list = pmt_cdr(list);
728   }
729
730   return pmt_reverse_x(r);
731 }
732
733 pmt_t
734 pmt_reverse(pmt_t listx)
735 {
736   pmt_t list = listx;
737   pmt_t r = PMT_NIL;
738
739   while(pmt_is_pair(list)){
740     r = pmt_cons(pmt_car(list), r);
741     list = pmt_cdr(list);
742   }
743   if (pmt_is_null(list))
744     return r;
745   else
746     throw pmt_wrong_type("pmt_reverse", listx);
747 }
748
749 pmt_t
750 pmt_reverse_x(pmt_t list)
751 {
752   // FIXME do it destructively
753   return pmt_reverse(list);
754 }
755