Houston, we have a trunk.
[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., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, 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_dict *
95 _dict(pmt_t x)
96 {
97   return dynamic_cast<pmt_dict*>(x.get());
98 }
99
100 ////////////////////////////////////////////////////////////////////////////
101 //                           Booleans
102 ////////////////////////////////////////////////////////////////////////////
103
104 const pmt_t PMT_BOOL_T = pmt_t(new pmt_bool());         // singleton
105 const pmt_t PMT_BOOL_F = pmt_t(new pmt_bool());         // singleton
106
107 pmt_bool::pmt_bool(){}
108
109 bool
110 pmt_is_true(pmt_t obj)
111 {
112   return obj != PMT_BOOL_F;
113 }
114
115 bool
116 pmt_is_false(pmt_t obj)
117 {
118   return obj == PMT_BOOL_F;
119 }
120
121 bool
122 pmt_is_bool(pmt_t obj)
123 {
124   return obj->is_bool();
125 }
126
127 pmt_t
128 pmt_from_bool(bool val)
129 {
130   return val ? PMT_BOOL_T : PMT_BOOL_F;
131 }
132
133 bool
134 pmt_to_bool(pmt_t val)
135 {
136   if (val == PMT_BOOL_T)
137     return true;
138   if (val == PMT_BOOL_F)
139     return false;
140   throw pmt_wrong_type("pmt_to_bool", val);
141 }
142
143 ////////////////////////////////////////////////////////////////////////////
144 //                             Symbols
145 ////////////////////////////////////////////////////////////////////////////
146
147 static const unsigned int SYMBOL_HASH_TABLE_SIZE = 701;
148 static std::vector<pmt_t> s_symbol_hash_table(SYMBOL_HASH_TABLE_SIZE);
149
150 pmt_symbol::pmt_symbol(const std::string &name) : d_name(name){}
151
152
153 static unsigned int
154 hash_string(const std::string &s)
155 {
156   unsigned int h = 0;
157   unsigned int g = 0;
158
159   for (std::string::const_iterator p = s.begin(); p != s.end(); p++){
160     h = (h << 4) + (*p & 0xff);
161     g = h & 0xf0000000;
162     if (g){
163       h = h ^ (g >> 24);
164       h = h ^ g;
165     }
166   }
167   return h;
168 }
169
170 bool 
171 pmt_is_symbol(pmt_t obj)
172 {
173   return obj->is_symbol();
174 }
175
176 pmt_t 
177 pmt_string_to_symbol(const std::string &name)
178 {
179   unsigned hash = hash_string(name) % SYMBOL_HASH_TABLE_SIZE;
180
181   // Does a symbol with this name already exist?
182   for (pmt_t sym = s_symbol_hash_table[hash]; sym; sym = _symbol(sym)->next()){
183     if (name == _symbol(sym)->name())
184       return sym;               // Yes.  Return it
185   }
186
187   // Nope.  Make a new one.
188   pmt_t sym = pmt_t(new pmt_symbol(name));
189   _symbol(sym)->set_next(s_symbol_hash_table[hash]);
190   s_symbol_hash_table[hash] = sym;
191   return sym;
192 }
193
194 const std::string
195 pmt_symbol_to_string(pmt_t sym)
196 {
197   if (!sym->is_symbol())
198     throw pmt_wrong_type("pmt_symbol_to_string", sym);
199
200   return _symbol(sym)->name();
201 }
202
203 ////////////////////////////////////////////////////////////////////////////
204 //                             Number
205 ////////////////////////////////////////////////////////////////////////////
206
207 bool
208 pmt_is_number(pmt_t x)
209 {
210   return x->is_number();
211 }
212
213 ////////////////////////////////////////////////////////////////////////////
214 //                             Integer
215 ////////////////////////////////////////////////////////////////////////////
216
217 pmt_integer::pmt_integer(long value) : d_value(value) {}
218
219 bool
220 pmt_is_integer(pmt_t x)
221 {
222   return x->is_integer();
223 }
224
225
226 pmt_t
227 pmt_from_long(long x)
228 {
229   return pmt_t(new pmt_integer(x));
230 }
231
232 long
233 pmt_to_long(pmt_t x)
234 {
235   if (x->is_integer())
236     return _integer(x)->value();
237
238   throw pmt_wrong_type("pmt_to_long", x);
239 }
240
241 ////////////////////////////////////////////////////////////////////////////
242 //                              Real
243 ////////////////////////////////////////////////////////////////////////////
244
245 pmt_real::pmt_real(double value) : d_value(value) {}
246
247 bool 
248 pmt_is_real(pmt_t x)
249 {
250   return x->is_real();
251 }
252
253 pmt_t
254 pmt_from_double(double x)
255 {
256   return pmt_t(new pmt_real(x));
257 }
258
259 double
260 pmt_to_double(pmt_t x)
261 {
262   if (x->is_real())
263     return _real(x)->value();
264   if (x->is_integer())
265     return _integer(x)->value();
266
267   throw pmt_wrong_type("pmt_to_double", x);
268 }
269
270 ////////////////////////////////////////////////////////////////////////////
271 //                              Complex
272 ////////////////////////////////////////////////////////////////////////////
273
274 pmt_complex::pmt_complex(std::complex<double> value) : d_value(value) {}
275
276 bool 
277 pmt_is_complex(pmt_t x)
278 {
279   return x->is_complex();
280 }
281
282 pmt_t
283 pmt_make_rectangular(double re, double im)
284 {
285   return pmt_t(new pmt_complex(std::complex<double>(re, im)));
286 }
287
288 std::complex<double>
289 pmt_to_complex(pmt_t x)
290 {
291   if (x->is_complex())
292     return _complex(x)->value();
293   if (x->is_real())
294     return _real(x)->value();
295   if (x->is_integer())
296     return _integer(x)->value();
297
298   throw pmt_wrong_type("pmt_to_complex", x);
299 }
300
301 ////////////////////////////////////////////////////////////////////////////
302 //                              Pairs
303 ////////////////////////////////////////////////////////////////////////////
304
305 const pmt_t PMT_NIL = pmt_t(new pmt_null());            // singleton
306
307 pmt_null::pmt_null() {}
308 pmt_pair::pmt_pair(pmt_t car, pmt_t cdr) : d_car(car), d_cdr(cdr) {}
309
310 bool
311 pmt_is_null(pmt_t x)
312 {
313   return x == PMT_NIL;
314 }
315
316 bool
317 pmt_is_pair(pmt_t obj)
318 {
319   return obj->is_pair();
320 }
321
322 pmt_t
323 pmt_cons(pmt_t x, pmt_t y)
324 {
325   return pmt_t(new pmt_pair(x, y));
326 }
327
328 pmt_t
329 pmt_car(pmt_t pair)
330 {
331   if (pair->is_pair())
332     return _pair(pair)->car();
333   
334   throw pmt_wrong_type("pmt_car", pair);
335 }
336
337 pmt_t
338 pmt_cdr(pmt_t pair)
339 {
340   if (pair->is_pair())
341     return _pair(pair)->cdr();
342   
343   throw pmt_wrong_type("pmt_cdr", pair);
344 }
345
346 void
347 pmt_set_car(pmt_t pair, pmt_t obj)
348 {
349   if (pair->is_pair())
350     _pair(pair)->set_car(obj);
351   else
352     throw pmt_wrong_type("pmt_set_car", pair);
353 }
354
355 void
356 pmt_set_cdr(pmt_t pair, pmt_t obj)
357 {
358   if (pair->is_pair())
359     _pair(pair)->set_cdr(obj);
360   else
361     throw pmt_wrong_type("pmt_set_cdr", pair);
362 }
363
364 ////////////////////////////////////////////////////////////////////////////
365 //                             Vectors
366 ////////////////////////////////////////////////////////////////////////////
367
368 pmt_vector::pmt_vector(size_t len, pmt_t fill)
369   : d_v(len)
370 {
371   for (size_t i = 0; i < len; i++)
372     d_v[i] = fill;
373 }
374
375 pmt_t
376 pmt_vector::ref(size_t k) const
377 {
378   if (k >= length())
379     throw pmt_out_of_range("pmt_vector_ref", pmt_from_long(k));
380   return d_v[k];
381 }
382
383 void
384 pmt_vector::set(size_t k, pmt_t obj)
385 {
386   if (k >= length())
387     throw pmt_out_of_range("pmt_vector_set", pmt_from_long(k));
388   d_v[k] = obj;
389 }
390
391 void
392 pmt_vector::fill(pmt_t obj)
393 {
394   for (size_t i = 0; i < length(); i++)
395     d_v[i] = obj;
396 }
397
398 bool
399 pmt_is_vector(pmt_t obj)
400 {
401   return obj->is_vector();
402 }
403
404 pmt_t
405 pmt_make_vector(size_t k, pmt_t fill)
406 {
407   return pmt_t(new pmt_vector(k, fill));
408 }
409
410 pmt_t
411 pmt_vector_ref(pmt_t vector, size_t k)
412 {
413   if (!vector->is_vector())
414     throw pmt_wrong_type("pmt_vector_ref", vector);
415   return _vector(vector)->ref(k);
416 }
417
418 void
419 pmt_vector_set(pmt_t vector, size_t k, pmt_t obj)
420 {
421   if (!vector->is_vector())
422     throw pmt_wrong_type("pmt_vector_set", vector);
423   _vector(vector)->set(k, obj);
424 }
425
426 void
427 pmt_vector_fill(pmt_t vector, pmt_t obj)
428 {
429   if (!vector->is_vector())
430     throw pmt_wrong_type("pmt_vector_set", vector);
431   _vector(vector)->fill(obj);
432 }
433
434 ////////////////////////////////////////////////////////////////////////////
435 //                            Dictionaries
436 ////////////////////////////////////////////////////////////////////////////
437
438 pmt_dict::pmt_dict()
439   : d_alist(PMT_NIL)
440 {
441 }
442
443 void
444 pmt_dict::set(pmt_t key, pmt_t value)
445 {
446   pmt_t p = pmt_assv(key, d_alist);     // look for (key . value) pair
447   if (pmt_is_pair(p)){                  // found existing pair...
448     pmt_set_cdr(p, value);              // overrwrite cdr with new value
449   }
450   else {                                // not in the dict
451     d_alist = pmt_cons(pmt_cons(key, value), d_alist);  // add new (key . value) pair
452   }
453 }
454
455 pmt_t
456 pmt_dict::ref(pmt_t key, pmt_t not_found) const
457 {
458   pmt_t p = pmt_assv(key, d_alist);     // look for (key . value) pair
459   if (pmt_is_pair(p))
460     return pmt_cdr(p);
461   else
462     return not_found;
463 }
464
465 bool
466 pmt_dict::has_key(pmt_t key) const
467 {
468   return pmt_is_pair(pmt_assv(key, d_alist));
469 }
470
471 pmt_t
472 pmt_dict::items() const
473 {
474   return d_alist;
475 }
476
477 pmt_t
478 pmt_dict::keys() const
479 {
480   return pmt_map(pmt_car, d_alist);
481 }
482
483 pmt_t
484 pmt_dict::values() const
485 {
486   return pmt_map(pmt_cdr, d_alist);
487 }
488
489 bool
490 pmt_is_dict(pmt_t obj)
491 {
492   return obj->is_dict();
493 }
494
495 pmt_t
496 pmt_make_dict()
497 {
498   return pmt_t(new pmt_dict());
499 }
500
501 void
502 pmt_dict_set(pmt_t dict, pmt_t key, pmt_t value)
503 {
504   if (!dict->is_dict())
505     throw pmt_wrong_type("pmt_dict_set", dict);
506
507   _dict(dict)->set(key, value);
508 }
509
510 bool
511 pmt_dict_has_key(pmt_t dict, pmt_t key)
512 {
513   if (!dict->is_dict())
514     throw pmt_wrong_type("pmt_dict_has_key", dict);
515
516   return _dict(dict)->has_key(key);
517 }
518
519 pmt_t
520 pmt_dict_ref(pmt_t dict, pmt_t key, pmt_t not_found)
521 {
522   if (!dict->is_dict())
523     throw pmt_wrong_type("pmt_dict_ref", dict);
524
525   return _dict(dict)->ref(key, not_found);
526 }
527
528 pmt_t
529 pmt_dict_items(pmt_t dict)
530 {
531   if (!dict->is_dict())
532     throw pmt_wrong_type("pmt_dict_items", dict);
533
534   return _dict(dict)->items();
535 }
536
537 pmt_t
538 pmt_dict_keys(pmt_t dict)
539 {
540   if (!dict->is_dict())
541     throw pmt_wrong_type("pmt_dict_keys", dict);
542
543   return _dict(dict)->keys();
544 }
545
546 pmt_t
547 pmt_dict_values(pmt_t dict)
548 {
549   if (!dict->is_dict())
550     throw pmt_wrong_type("pmt_dict_values", dict);
551
552   return _dict(dict)->values();
553 }
554
555 ////////////////////////////////////////////////////////////////////////////
556 //                          General Functions
557 ////////////////////////////////////////////////////////////////////////////
558
559 bool
560 pmt_eq(pmt_t x, pmt_t y)
561 {
562   return x == y;
563 }
564
565 bool
566 pmt_eqv(pmt_t x, pmt_t y)
567 {
568   if (x == y)
569     return true;
570
571   if (x->is_integer() && y->is_integer())
572     return _integer(x)->value() == _integer(y)->value();
573
574   if (x->is_real() && y->is_real())
575     return _real(x)->value() == _real(y)->value();
576
577   if (x->is_complex() && y->is_complex())
578     return _complex(x)->value() == _complex(y)->value();
579
580   return false;
581 }
582
583 bool
584 pmt_equal(pmt_t x, pmt_t y)
585 {
586   if (pmt_eqv(x, y))
587     return true;
588
589   if (x->is_pair() && y->is_pair())
590     return pmt_equal(pmt_car(x), pmt_car(y)) && pmt_equal(pmt_cdr(x), pmt_cdr(y));
591
592   if (x->is_vector() && y->is_vector()){
593     pmt_vector *xv = _vector(x);
594     pmt_vector *yv = _vector(y);
595     if (xv->length() != yv->length())
596       return false;
597
598     for (unsigned i = 0; i < xv->length(); i++)
599       if (!pmt_equal(xv->_ref(i), yv->_ref(i)))
600         return false;
601
602     return true;
603   }
604
605   // FIXME add other cases here...
606
607   return false;
608 }
609
610 size_t
611 pmt_length(pmt_t x)
612 {
613   if (x->is_vector())
614     return _vector(x)->length();
615
616   // FIXME list length
617   // FIXME uniform vector length
618   // FIXME dictionary length (number of entries)
619
620   throw pmt_wrong_type("pmt_length", x);
621 }
622
623 pmt_t
624 pmt_assq(pmt_t obj, pmt_t alist)
625 {
626   while (pmt_is_pair(alist)){
627     pmt_t p = pmt_car(alist);
628     if (!pmt_is_pair(p))        // malformed alist
629       return PMT_BOOL_F;
630
631     if (pmt_eq(obj, pmt_car(p)))
632       return p;
633
634     alist = pmt_cdr(alist);
635   }
636   return PMT_BOOL_F;
637 }
638
639 pmt_t
640 pmt_assv(pmt_t obj, pmt_t alist)
641 {
642   while (pmt_is_pair(alist)){
643     pmt_t p = pmt_car(alist);
644     if (!pmt_is_pair(p))        // malformed alist
645       return PMT_BOOL_F;
646
647     if (pmt_eqv(obj, pmt_car(p)))
648       return p;
649
650     alist = pmt_cdr(alist);
651   }
652   return PMT_BOOL_F;
653 }
654
655 pmt_t
656 pmt_assoc(pmt_t obj, pmt_t alist)
657 {
658   while (pmt_is_pair(alist)){
659     pmt_t p = pmt_car(alist);
660     if (!pmt_is_pair(p))        // malformed alist
661       return PMT_BOOL_F;
662
663     if (pmt_equal(obj, pmt_car(p)))
664       return p;
665
666     alist = pmt_cdr(alist);
667   }
668   return PMT_BOOL_F;
669 }
670
671 pmt_t
672 pmt_map(pmt_t proc(pmt_t), pmt_t list)
673 {
674   pmt_t r = PMT_NIL;
675
676   while(pmt_is_pair(list)){
677     r = pmt_cons(proc(pmt_car(list)), r);
678     list = pmt_cdr(list);
679   }
680
681   return pmt_reverse_x(r);
682 }
683
684 pmt_t
685 pmt_reverse(pmt_t listx)
686 {
687   pmt_t list = listx;
688   pmt_t r = PMT_NIL;
689
690   while(pmt_is_pair(list)){
691     r = pmt_cons(pmt_car(list), r);
692     list = pmt_cdr(list);
693   }
694   if (pmt_is_null(list))
695     return r;
696   else
697     throw pmt_wrong_type("pmt_reverse", listx);
698 }
699
700 pmt_t
701 pmt_reverse_x(pmt_t list)
702 {
703   // FIXME do it destructively
704   return pmt_reverse(list);
705 }