diff options
Diffstat (limited to 'gruel/src/lib/pmt')
-rw-r--r-- | gruel/src/lib/pmt/CMakeLists.txt | 89 | ||||
-rw-r--r-- | gruel/src/lib/pmt/gen-serial-tags.py | 53 | ||||
-rwxr-xr-x | gruel/src/lib/pmt/generate_unv.py | 190 | ||||
-rw-r--r-- | gruel/src/lib/pmt/pmt-serial-tags.scm | 77 | ||||
-rw-r--r-- | gruel/src/lib/pmt/pmt.cc | 1428 | ||||
-rw-r--r-- | gruel/src/lib/pmt/pmt_int.h | 247 | ||||
-rw-r--r-- | gruel/src/lib/pmt/pmt_io.cc | 168 | ||||
-rw-r--r-- | gruel/src/lib/pmt/pmt_pool.cc | 112 | ||||
-rw-r--r-- | gruel/src/lib/pmt/pmt_serialize.cc | 830 | ||||
-rw-r--r-- | gruel/src/lib/pmt/qa_pmt.cc | 40 | ||||
-rw-r--r-- | gruel/src/lib/pmt/qa_pmt.h | 37 | ||||
-rw-r--r-- | gruel/src/lib/pmt/qa_pmt_prims.cc | 603 | ||||
-rw-r--r-- | gruel/src/lib/pmt/qa_pmt_prims.h | 77 | ||||
-rw-r--r-- | gruel/src/lib/pmt/unv_qa_template.cc.t | 35 | ||||
-rw-r--r-- | gruel/src/lib/pmt/unv_template.cc.t | 141 | ||||
-rw-r--r-- | gruel/src/lib/pmt/unv_template.h.t | 23 |
16 files changed, 4150 insertions, 0 deletions
diff --git a/gruel/src/lib/pmt/CMakeLists.txt b/gruel/src/lib/pmt/CMakeLists.txt new file mode 100644 index 000000000..6ea616e10 --- /dev/null +++ b/gruel/src/lib/pmt/CMakeLists.txt @@ -0,0 +1,89 @@ +# Copyright 2010-2012 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. + +######################################################################## +# This file included, use CMake directory variables +######################################################################## +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +include_directories(${CMAKE_CURRENT_BINARY_DIR}) + +######################################################################## +# Generate serial tags header file +######################################################################## + +get_filename_component(PMT_SERIAL_TAGS_H + ${CMAKE_CURRENT_BINARY_DIR}/../../include/gruel/pmt_serial_tags.h ABSOLUTE +) + +add_custom_command( + OUTPUT ${PMT_SERIAL_TAGS_H} + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/gen-serial-tags.py + DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/pmt-serial-tags.scm + COMMAND ${PYTHON_EXECUTABLE} + ${CMAKE_CURRENT_SOURCE_DIR}/gen-serial-tags.py + ${CMAKE_CURRENT_SOURCE_DIR}/pmt-serial-tags.scm + ${PMT_SERIAL_TAGS_H} +) + +install( + FILES ${PMT_SERIAL_TAGS_H} + DESTINATION ${GR_INCLUDE_DIR}/gruel + COMPONENT "gruel_devel" +) + +include(AddFileDependencies) +ADD_FILE_DEPENDENCIES( + ${CMAKE_CURRENT_SOURCE_DIR}/pmt_serialize.cc + ${PMT_SERIAL_TAGS_H} +) + +add_custom_target(pmt_generated DEPENDS ${PMT_SERIAL_TAGS_H}) + +######################################################################## +# Generate other pmt stuff +######################################################################## +add_custom_command( + OUTPUT + ${CMAKE_CURRENT_BINARY_DIR}/pmt_unv_int.h + ${CMAKE_CURRENT_BINARY_DIR}/qa_pmt_unv.h + ${CMAKE_CURRENT_BINARY_DIR}/pmt_unv.cc + ${CMAKE_CURRENT_BINARY_DIR}/qa_pmt_unv.cc + DEPENDS + ${CMAKE_CURRENT_SOURCE_DIR}/generate_unv.py + ${CMAKE_CURRENT_SOURCE_DIR}/unv_template.h.t + ${CMAKE_CURRENT_SOURCE_DIR}/unv_template.cc.t + ${CMAKE_CURRENT_SOURCE_DIR}/unv_qa_template.cc.t + COMMAND ${PYTHON_EXECUTABLE} ${PYTHON_DASH_B} -c + \"import os,sys\;srcdir='${CMAKE_CURRENT_SOURCE_DIR}'\;sys.path.append(srcdir)\;os.environ['srcdir']=srcdir\;from generate_unv import main\;main()\" + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} +) + +list(APPEND gruel_sources + ${CMAKE_CURRENT_BINARY_DIR}/pmt_unv.cc + ${CMAKE_CURRENT_SOURCE_DIR}/pmt.cc + ${CMAKE_CURRENT_SOURCE_DIR}/pmt_io.cc + ${CMAKE_CURRENT_SOURCE_DIR}/pmt_pool.cc + ${CMAKE_CURRENT_SOURCE_DIR}/pmt_serialize.cc +) + +list(APPEND test_gruel_sources + ${CMAKE_CURRENT_BINARY_DIR}/qa_pmt_unv.cc + ${CMAKE_CURRENT_SOURCE_DIR}/qa_pmt_prims.cc + ${CMAKE_CURRENT_SOURCE_DIR}/qa_pmt.cc +) diff --git a/gruel/src/lib/pmt/gen-serial-tags.py b/gruel/src/lib/pmt/gen-serial-tags.py new file mode 100644 index 000000000..18e927beb --- /dev/null +++ b/gruel/src/lib/pmt/gen-serial-tags.py @@ -0,0 +1,53 @@ +""" +// +// Copyright 2011 Free Software Foundation, Inc. +// +// This file is part of GNU Radio +// +// GNU Radio is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 3, or (at your option) +// any later version. +// +// GNU Radio is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// +// THIS FILE IS MACHINE GENERATED FROM %s. DO NOT EDIT BY HAND. +// See %s for additional commentary. +// + +#ifndef INCLUDED_PMT_SERIAL_TAGS_H +#define INCLUDED_PMT_SERIAL_TAGS_H + +enum pst_tags { +%s +}; +#endif /* INCLUDED_PMT_SERIAL_TAGS_H */ +""" + +import sys, os, re + +if __name__ == '__main__': + if len(sys.argv) != 3: + print "Usage %s <input_scm_file> <output_hdr_file>"%__file__ + exit() + input_scm_file, output_hdr_file = sys.argv[1:] + enums = list() + for line in open(input_scm_file).readlines(): + match = re.match('^\s*\(define\s+([\w|-]+)\s+#x([0-9a-fA-F]+)\)', line) + if not match: continue + name, value = match.groups() + name = name.upper().replace('-', '_') + enums.append(' %s = 0x%s'%(name, value)) + open(output_hdr_file, 'w').write(__doc__%( + os.path.basename(__file__), + os.path.basename(input_scm_file), + ',\n'.join(enums), + )) diff --git a/gruel/src/lib/pmt/generate_unv.py b/gruel/src/lib/pmt/generate_unv.py new file mode 100755 index 000000000..42b57e245 --- /dev/null +++ b/gruel/src/lib/pmt/generate_unv.py @@ -0,0 +1,190 @@ +#!/usr/bin/env python +# +# Copyright 2006,2009 Free Software Foundation, Inc. +# +# This file is part of GNU Radio +# +# GNU Radio is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3, or (at your option) +# any later version. +# +# GNU Radio is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with GNU Radio; see the file COPYING. If not, write to +# the Free Software Foundation, Inc., 51 Franklin Street, +# Boston, MA 02110-1301, USA. +# + +""" +Generate code for uniform numeric vectors +""" + +import re, os, os.path + + +unv_types = ( + ('u8', 'uint8_t'), + ('s8', 'int8_t'), + ('u16', 'uint16_t'), + ('s16', 'int16_t'), + ('u32', 'uint32_t'), + ('s32', 'int32_t'), + ('u64', 'uint64_t'), + ('s64', 'int64_t'), + ('f32', 'float'), + ('f64', 'double'), + ('c32', 'std::complex<float>'), + ('c64', 'std::complex<double>') + ) + +header = """\ +/* -*- c++ -*- */ +/* + * Copyright 2006,2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +""" + +guard_tail = """ +#endif +""" + +includes = """ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <vector> +#include <gruel/pmt.h> +#include "pmt_int.h" +""" + +qa_includes = """ +#include <qa_pmt_unv.h> +#include <cppunit/TestAssert.h> +#include <gruel/pmt.h> +#include <stdio.h> + +using namespace pmt; +""" + + +# set srcdir to the directory that contains Makefile.am +try: + srcdir = os.environ['srcdir'] +except KeyError, e: + srcdir = "." +srcdir = srcdir + '/' + + +def open_src (name, mode): + global srcdir + return open(os.path.join (srcdir, name), mode) + + +def guard_name(filename): + return 'INCLUDED_' + re.sub('\.', '_', filename.upper()) + +def guard_head(filename): + guard = guard_name(filename) + return """ +#ifndef %s +#define %s +""" % (guard, guard) + + +def do_substitution (d, input, out_file): + def repl (match_obj): + key = match_obj.group (1) + # print key + return d[key] + + out = re.sub (r"@([a-zA-Z0-9_]+)@", repl, input) + out_file.write (out) + + +def generate_h(): + template = open_src('unv_template.h.t', 'r').read() + output_filename = 'pmt_unv_int.h' + output = open(output_filename, 'w') + output.write(header) + output.write(guard_head(output_filename)) + for tag, typ in unv_types: + d = { 'TAG' : tag, 'TYPE' : typ } + do_substitution(d, template, output) + output.write(guard_tail) + +def generate_cc(): + template = open_src('unv_template.cc.t', 'r').read() + output = open('pmt_unv.cc', 'w') + output.write(header) + output.write(includes) + for tag, typ in unv_types: + d = { 'TAG' : tag, 'TYPE' : typ } + do_substitution(d, template, output) + + +def generate_qa_h(): + output_filename = 'qa_pmt_unv.h' + output = open(output_filename, 'w') + output.write(header) + output.write(guard_head(output_filename)) + + output.write(''' +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/TestCase.h> + +class qa_pmt_unv : public CppUnit::TestCase { + + CPPUNIT_TEST_SUITE(qa_pmt_unv); +''') + for tag, typ in unv_types: + output.write(' CPPUNIT_TEST(test_%svector);\n' % (tag,)) + output.write('''\ + CPPUNIT_TEST_SUITE_END(); + + private: +''') + for tag, typ in unv_types: + output.write(' void test_%svector();\n' % (tag,)) + output.write('};\n') + output.write(guard_tail) + +def generate_qa_cc(): + template = open_src('unv_qa_template.cc.t', 'r').read() + output = open('qa_pmt_unv.cc', 'w') + output.write(header) + output.write(qa_includes) + for tag, typ in unv_types: + d = { 'TAG' : tag, 'TYPE' : typ } + do_substitution(d, template, output) + + +def main(): + generate_h() + generate_cc() + generate_qa_h() + generate_qa_cc() + +if __name__ == '__main__': + main() diff --git a/gruel/src/lib/pmt/pmt-serial-tags.scm b/gruel/src/lib/pmt/pmt-serial-tags.scm new file mode 100644 index 000000000..4f06bf75f --- /dev/null +++ b/gruel/src/lib/pmt/pmt-serial-tags.scm @@ -0,0 +1,77 @@ +;;; -*-scheme-*- +;;; +;;; Copyright 2007 Free Software Foundation, Inc. +;;; +;;; This file is part of GNU Radio +;;; +;;; GNU Radio is free software; you can redistribute it and/or modify +;;; it under the terms of the GNU General Public License as published by +;;; the Free Software Foundation; either version 3, or (define at your option) +;;; any later version. +;;; +;;; GNU Radio is distributed in the hope that it will be useful, +;;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;;; GNU General Public License for more details. +;;; +;;; You should have received a copy of the GNU General Public License along +;;; with this program; if not, write to the Free Software Foundation, Inc., +;;; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +;;; + +;;; definitions of tag values used for marshalling pmt data + +(define pst-true #x00) +(define pst-false #x01) +(define pst-symbol #x02) ; untagged-int16 n; followed by n bytes of symbol name +(define pst-int32 #x03) +(define pst-double #x04) +(define pst-complex #x05) ; complex<double>: real, imag +(define pst-null #x06) +(define pst-pair #x07) ; followed by two objects +(define pst-vector #x08) ; untagged-int32 n; followed by n objects +(define pst-dict #x09) ; untagged-int32 n; followed by n key/value tuples + +(define pst-uniform-vector #x0a) +(define pst-uint64 #x0b) +(define pst-tuple #x0c) + +;; u8, s8, u16, s16, u32, s32, u64, s64, f32, f64, c32, c64 +;; +;; untagged-uint8 tag +;; untagged-uint8 uvi (define uniform vector info, see below) +;; untagged-int32 n-items +;; untagged-uint8 npad +;; npad bytes of zeros to align binary data +;; n-items binary numeric items +;; +;; uvi: +;; +-+-+-+-+-+-+-+-+ +;; |B| subtype | +;; +-+-+-+-+-+-+-+-+ +;; +;; B == 0, numeric data is little-endian. +;; B == 1, numeric data is big-endian. + + (define uvi-endian-mask #x80) + (define uvi-subtype-mask #x7f) + + (define uvi-little-endian #x00) + (define uvi-big-endian #x80) + + (define uvi-u8 #x00) + (define uvi-s8 #x01) + (define uvi-u16 #x02) + (define uvi-s16 #x03) + (define uvi-u32 #x04) + (define uvi-s32 #x05) + (define uvi-u64 #x06) + (define uvi-s64 #x07) + (define uvi-f32 #x08) + (define uvi-f64 #x09) + (define uvi-c32 #x0a) + (define uvi-c64 #x0b) + + +(define pst-comment #x3b) ; ascii ';' +(define pst-comment-end #x0a) ; ascii '\n' diff --git a/gruel/src/lib/pmt/pmt.cc b/gruel/src/lib/pmt/pmt.cc new file mode 100644 index 000000000..1d1e9ba7c --- /dev/null +++ b/gruel/src/lib/pmt/pmt.cc @@ -0,0 +1,1428 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2009,2010 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <vector> +#include <gruel/pmt.h> +#include "pmt_int.h" +#include <gruel/msg_accepter.h> +#include <gruel/pmt_pool.h> +#include <stdio.h> +#include <string.h> + +namespace pmt { + +static const int CACHE_LINE_SIZE = 64; // good guess + +# if (PMT_LOCAL_ALLOCATOR) + +static pmt_pool global_pmt_pool(sizeof(pmt_pair), CACHE_LINE_SIZE); + +void * +pmt_base::operator new(size_t size) +{ + void *p = global_pmt_pool.malloc(); + + // fprintf(stderr, "pmt_base::new p = %p\n", p); + assert((reinterpret_cast<intptr_t>(p) & (CACHE_LINE_SIZE - 1)) == 0); + return p; +} + +void +pmt_base::operator delete(void *p, size_t size) +{ + global_pmt_pool.free(p); +} + +#endif + +void intrusive_ptr_add_ref(pmt_base* p) { ++(p->count_); } +void intrusive_ptr_release(pmt_base* p) { if (--(p->count_) == 0 ) delete p; } + +pmt_base::~pmt_base() +{ + // nop -- out of line virtual destructor +} + +//////////////////////////////////////////////////////////////////////////// +// Exceptions +//////////////////////////////////////////////////////////////////////////// + +pmt_exception::pmt_exception(const std::string &msg, pmt_t obj) + : logic_error(msg + ": " + pmt_write_string(obj)) +{ +} + +pmt_wrong_type::pmt_wrong_type(const std::string &msg, pmt_t obj) + : pmt_exception(msg + ": wrong_type ", obj) +{ +} + +pmt_out_of_range::pmt_out_of_range(const std::string &msg, pmt_t obj) + : pmt_exception(msg + ": out of range ", obj) +{ +} + +pmt_notimplemented::pmt_notimplemented(const std::string &msg, pmt_t obj) + : pmt_exception(msg + ": notimplemented ", obj) +{ +} + +//////////////////////////////////////////////////////////////////////////// +// Dynamic Casts +//////////////////////////////////////////////////////////////////////////// + +static pmt_symbol * +_symbol(pmt_t x) +{ + return dynamic_cast<pmt_symbol*>(x.get()); +} + +static pmt_integer * +_integer(pmt_t x) +{ + return dynamic_cast<pmt_integer*>(x.get()); +} + +static pmt_uint64 * +_uint64(pmt_t x) +{ + return dynamic_cast<pmt_uint64*>(x.get()); +} + +static pmt_real * +_real(pmt_t x) +{ + return dynamic_cast<pmt_real*>(x.get()); +} + +static pmt_complex * +_complex(pmt_t x) +{ + return dynamic_cast<pmt_complex*>(x.get()); +} + +static pmt_pair * +_pair(pmt_t x) +{ + return dynamic_cast<pmt_pair*>(x.get()); +} + +static pmt_vector * +_vector(pmt_t x) +{ + return dynamic_cast<pmt_vector*>(x.get()); +} + +static pmt_tuple * +_tuple(pmt_t x) +{ + return dynamic_cast<pmt_tuple*>(x.get()); +} + +static pmt_uniform_vector * +_uniform_vector(pmt_t x) +{ + return dynamic_cast<pmt_uniform_vector*>(x.get()); +} + +static pmt_any * +_any(pmt_t x) +{ + return dynamic_cast<pmt_any*>(x.get()); +} + +//////////////////////////////////////////////////////////////////////////// +// Globals +//////////////////////////////////////////////////////////////////////////// + +const pmt_t PMT_T = pmt_t(new pmt_bool()); // singleton +const pmt_t PMT_F = pmt_t(new pmt_bool()); // singleton +const pmt_t PMT_NIL = pmt_t(new pmt_null()); // singleton +const pmt_t PMT_EOF = pmt_cons(PMT_NIL, PMT_NIL); // singleton + +//////////////////////////////////////////////////////////////////////////// +// Booleans +//////////////////////////////////////////////////////////////////////////// + +pmt_bool::pmt_bool(){} + +bool +pmt_is_true(pmt_t obj) +{ + return obj != PMT_F; +} + +bool +pmt_is_false(pmt_t obj) +{ + return obj == PMT_F; +} + +bool +pmt_is_bool(pmt_t obj) +{ + return obj->is_bool(); +} + +pmt_t +pmt_from_bool(bool val) +{ + return val ? PMT_T : PMT_F; +} + +bool +pmt_to_bool(pmt_t val) +{ + if (val == PMT_T) + return true; + if (val == PMT_F) + return false; + throw pmt_wrong_type("pmt_to_bool", val); +} + +//////////////////////////////////////////////////////////////////////////// +// Symbols +//////////////////////////////////////////////////////////////////////////// + +static const unsigned int SYMBOL_HASH_TABLE_SIZE = 701; +static std::vector<pmt_t> s_symbol_hash_table(SYMBOL_HASH_TABLE_SIZE); + +pmt_symbol::pmt_symbol(const std::string &name) : d_name(name){} + + +static unsigned int +hash_string(const std::string &s) +{ + unsigned int h = 0; + unsigned int g = 0; + + for (std::string::const_iterator p = s.begin(); p != s.end(); ++p){ + h = (h << 4) + (*p & 0xff); + g = h & 0xf0000000; + if (g){ + h = h ^ (g >> 24); + h = h ^ g; + } + } + return h; +} + +bool +pmt_is_symbol(const pmt_t& obj) +{ + return obj->is_symbol(); +} + +pmt_t +pmt_string_to_symbol(const std::string &name) +{ + unsigned hash = hash_string(name) % SYMBOL_HASH_TABLE_SIZE; + + // Does a symbol with this name already exist? + for (pmt_t sym = s_symbol_hash_table[hash]; sym; sym = _symbol(sym)->next()){ + if (name == _symbol(sym)->name()) + return sym; // Yes. Return it + } + + // Nope. Make a new one. + pmt_t sym = pmt_t(new pmt_symbol(name)); + _symbol(sym)->set_next(s_symbol_hash_table[hash]); + s_symbol_hash_table[hash] = sym; + return sym; +} + +// alias... +pmt_t +pmt_intern(const std::string &name) +{ + return pmt_string_to_symbol(name); +} + +const std::string +pmt_symbol_to_string(const pmt_t& sym) +{ + if (!sym->is_symbol()) + throw pmt_wrong_type("pmt_symbol_to_string", sym); + + return _symbol(sym)->name(); +} + + + +//////////////////////////////////////////////////////////////////////////// +// Number +//////////////////////////////////////////////////////////////////////////// + +bool +pmt_is_number(pmt_t x) +{ + return x->is_number(); +} + +//////////////////////////////////////////////////////////////////////////// +// Integer +//////////////////////////////////////////////////////////////////////////// + +pmt_integer::pmt_integer(long value) : d_value(value) {} + +bool +pmt_is_integer(pmt_t x) +{ + return x->is_integer(); +} + + +pmt_t +pmt_from_long(long x) +{ + return pmt_t(new pmt_integer(x)); +} + +long +pmt_to_long(pmt_t x) +{ + pmt_integer* i = dynamic_cast<pmt_integer*>(x.get()); + if ( i ) + return i->value(); + + throw pmt_wrong_type("pmt_to_long", x); +} + +//////////////////////////////////////////////////////////////////////////// +// Uint64 +//////////////////////////////////////////////////////////////////////////// + +pmt_uint64::pmt_uint64(uint64_t value) : d_value(value) {} + +bool +pmt_is_uint64(pmt_t x) +{ + return x->is_uint64(); +} + + +pmt_t +pmt_from_uint64(uint64_t x) +{ + return pmt_t(new pmt_uint64(x)); +} + +uint64_t +pmt_to_uint64(pmt_t x) +{ + if(x->is_uint64()) + return _uint64(x)->value(); + if(x->is_integer()) + { + long tmp = _integer(x)->value(); + if(tmp >= 0) + return (uint64_t) tmp; + } + + throw pmt_wrong_type("pmt_to_uint64", x); +} + +//////////////////////////////////////////////////////////////////////////// +// Real +//////////////////////////////////////////////////////////////////////////// + +pmt_real::pmt_real(double value) : d_value(value) {} + +bool +pmt_is_real(pmt_t x) +{ + return x->is_real(); +} + +pmt_t +pmt_from_double(double x) +{ + return pmt_t(new pmt_real(x)); +} + +double +pmt_to_double(pmt_t x) +{ + if (x->is_real()) + return _real(x)->value(); + if (x->is_integer()) + return _integer(x)->value(); + + throw pmt_wrong_type("pmt_to_double", x); +} + +//////////////////////////////////////////////////////////////////////////// +// Complex +//////////////////////////////////////////////////////////////////////////// + +pmt_complex::pmt_complex(std::complex<double> value) : d_value(value) {} + +bool +pmt_is_complex(pmt_t x) +{ + return x->is_complex(); +} + +pmt_t +pmt_make_rectangular(double re, double im) +{ + return pmt_from_complex(re, im); +} + +pmt_t pmt_from_complex(double re, double im) +{ + return pmt_t(new pmt_complex(std::complex<double>(re, im))); +} + +pmt_t pmt_from_complex(const std::complex<double> &z) +{ + return pmt_t(new pmt_complex(z)); +} + +std::complex<double> +pmt_to_complex(pmt_t x) +{ + if (x->is_complex()) + return _complex(x)->value(); + if (x->is_real()) + return _real(x)->value(); + if (x->is_integer()) + return _integer(x)->value(); + + throw pmt_wrong_type("pmt_to_complex", x); +} + +//////////////////////////////////////////////////////////////////////////// +// Pairs +//////////////////////////////////////////////////////////////////////////// + +pmt_null::pmt_null() {} +pmt_pair::pmt_pair(const pmt_t& car, const pmt_t& cdr) : d_car(car), d_cdr(cdr) {} + +bool +pmt_is_null(const pmt_t& x) +{ + return x == PMT_NIL; +} + +bool +pmt_is_pair(const pmt_t& obj) +{ + return obj->is_pair(); +} + +pmt_t +pmt_cons(const pmt_t& x, const pmt_t& y) +{ + return pmt_t(new pmt_pair(x, y)); +} + +pmt_t +pmt_car(const pmt_t& pair) +{ + pmt_pair* p = dynamic_cast<pmt_pair*>(pair.get()); + if ( p ) + return p->car(); + + throw pmt_wrong_type("pmt_car", pair); +} + +pmt_t +pmt_cdr(const pmt_t& pair) +{ + pmt_pair* p = dynamic_cast<pmt_pair*>(pair.get()); + if ( p ) + return p->cdr(); + + throw pmt_wrong_type("pmt_cdr", pair); +} + +void +pmt_set_car(pmt_t pair, pmt_t obj) +{ + if (pair->is_pair()) + _pair(pair)->set_car(obj); + else + throw pmt_wrong_type("pmt_set_car", pair); +} + +void +pmt_set_cdr(pmt_t pair, pmt_t obj) +{ + if (pair->is_pair()) + _pair(pair)->set_cdr(obj); + else + throw pmt_wrong_type("pmt_set_cdr", pair); +} + +//////////////////////////////////////////////////////////////////////////// +// Vectors +//////////////////////////////////////////////////////////////////////////// + +pmt_vector::pmt_vector(size_t len, pmt_t fill) + : d_v(len) +{ + for (size_t i = 0; i < len; i++) + d_v[i] = fill; +} + +pmt_t +pmt_vector::ref(size_t k) const +{ + if (k >= length()) + throw pmt_out_of_range("pmt_vector_ref", pmt_from_long(k)); + return d_v[k]; +} + +void +pmt_vector::set(size_t k, pmt_t obj) +{ + if (k >= length()) + throw pmt_out_of_range("pmt_vector_set", pmt_from_long(k)); + d_v[k] = obj; +} + +void +pmt_vector::fill(pmt_t obj) +{ + for (size_t i = 0; i < length(); i++) + d_v[i] = obj; +} + +bool +pmt_is_vector(pmt_t obj) +{ + return obj->is_vector(); +} + +pmt_t +pmt_make_vector(size_t k, pmt_t fill) +{ + return pmt_t(new pmt_vector(k, fill)); +} + +pmt_t +pmt_vector_ref(pmt_t vector, size_t k) +{ + if (!vector->is_vector()) + throw pmt_wrong_type("pmt_vector_ref", vector); + return _vector(vector)->ref(k); +} + +void +pmt_vector_set(pmt_t vector, size_t k, pmt_t obj) +{ + if (!vector->is_vector()) + throw pmt_wrong_type("pmt_vector_set", vector); + _vector(vector)->set(k, obj); +} + +void +pmt_vector_fill(pmt_t vector, pmt_t obj) +{ + if (!vector->is_vector()) + throw pmt_wrong_type("pmt_vector_set", vector); + _vector(vector)->fill(obj); +} + +//////////////////////////////////////////////////////////////////////////// +// Tuples +//////////////////////////////////////////////////////////////////////////// + +pmt_tuple::pmt_tuple(size_t len) + : d_v(len) +{ +} + +pmt_t +pmt_tuple::ref(size_t k) const +{ + if (k >= length()) + throw pmt_out_of_range("pmt_tuple_ref", pmt_from_long(k)); + return d_v[k]; +} + +bool +pmt_is_tuple(pmt_t obj) +{ + return obj->is_tuple(); +} + +pmt_t +pmt_tuple_ref(const pmt_t &tuple, size_t k) +{ + if (!tuple->is_tuple()) + throw pmt_wrong_type("pmt_tuple_ref", tuple); + return _tuple(tuple)->ref(k); +} + +// for (i=0; i < 10; i++) +// make_constructor() + +pmt_t +pmt_make_tuple() +{ + return pmt_t(new pmt_tuple(0)); +} + +pmt_t +pmt_make_tuple(const pmt_t &e0) +{ + pmt_tuple *t = new pmt_tuple(1); + t->_set(0, e0); + return pmt_t(t); +} + +pmt_t +pmt_make_tuple(const pmt_t &e0, const pmt_t &e1) +{ + pmt_tuple *t = new pmt_tuple(2); + t->_set(0, e0); + t->_set(1, e1); + return pmt_t(t); +} + +pmt_t +pmt_make_tuple(const pmt_t &e0, const pmt_t &e1, const pmt_t &e2) +{ + pmt_tuple *t = new pmt_tuple(3); + t->_set(0, e0); + t->_set(1, e1); + t->_set(2, e2); + return pmt_t(t); +} + +pmt_t +pmt_make_tuple(const pmt_t &e0, const pmt_t &e1, const pmt_t &e2, const pmt_t &e3) +{ + pmt_tuple *t = new pmt_tuple(4); + t->_set(0, e0); + t->_set(1, e1); + t->_set(2, e2); + t->_set(3, e3); + return pmt_t(t); +} + +pmt_t +pmt_make_tuple(const pmt_t &e0, const pmt_t &e1, const pmt_t &e2, const pmt_t &e3, const pmt_t &e4) +{ + pmt_tuple *t = new pmt_tuple(5); + t->_set(0, e0); + t->_set(1, e1); + t->_set(2, e2); + t->_set(3, e3); + t->_set(4, e4); + return pmt_t(t); +} + +pmt_t +pmt_make_tuple(const pmt_t &e0, const pmt_t &e1, const pmt_t &e2, const pmt_t &e3, const pmt_t &e4, const pmt_t &e5) +{ + pmt_tuple *t = new pmt_tuple(6); + t->_set(0, e0); + t->_set(1, e1); + t->_set(2, e2); + t->_set(3, e3); + t->_set(4, e4); + t->_set(5, e5); + return pmt_t(t); +} + +pmt_t +pmt_make_tuple(const pmt_t &e0, const pmt_t &e1, const pmt_t &e2, const pmt_t &e3, const pmt_t &e4, const pmt_t &e5, const pmt_t &e6) +{ + pmt_tuple *t = new pmt_tuple(7); + t->_set(0, e0); + t->_set(1, e1); + t->_set(2, e2); + t->_set(3, e3); + t->_set(4, e4); + t->_set(5, e5); + t->_set(6, e6); + return pmt_t(t); +} + +pmt_t +pmt_make_tuple(const pmt_t &e0, const pmt_t &e1, const pmt_t &e2, const pmt_t &e3, const pmt_t &e4, const pmt_t &e5, const pmt_t &e6, const pmt_t &e7) +{ + pmt_tuple *t = new pmt_tuple(8); + t->_set(0, e0); + t->_set(1, e1); + t->_set(2, e2); + t->_set(3, e3); + t->_set(4, e4); + t->_set(5, e5); + t->_set(6, e6); + t->_set(7, e7); + return pmt_t(t); +} + +pmt_t +pmt_make_tuple(const pmt_t &e0, const pmt_t &e1, const pmt_t &e2, const pmt_t &e3, const pmt_t &e4, const pmt_t &e5, const pmt_t &e6, const pmt_t &e7, const pmt_t &e8) +{ + pmt_tuple *t = new pmt_tuple(9); + t->_set(0, e0); + t->_set(1, e1); + t->_set(2, e2); + t->_set(3, e3); + t->_set(4, e4); + t->_set(5, e5); + t->_set(6, e6); + t->_set(7, e7); + t->_set(8, e8); + return pmt_t(t); +} + +pmt_t +pmt_make_tuple(const pmt_t &e0, const pmt_t &e1, const pmt_t &e2, const pmt_t &e3, const pmt_t &e4, const pmt_t &e5, const pmt_t &e6, const pmt_t &e7, const pmt_t &e8, const pmt_t &e9) +{ + pmt_tuple *t = new pmt_tuple(10); + t->_set(0, e0); + t->_set(1, e1); + t->_set(2, e2); + t->_set(3, e3); + t->_set(4, e4); + t->_set(5, e5); + t->_set(6, e6); + t->_set(7, e7); + t->_set(8, e8); + t->_set(9, e9); + return pmt_t(t); +} + +pmt_t +pmt_to_tuple(const pmt_t &x) +{ + if (x->is_tuple()) // already one + return x; + + size_t len = pmt_length(x); + pmt_tuple *t = new pmt_tuple(len); + pmt_t r = pmt_t(t); + + if (x->is_vector()){ + for (size_t i = 0; i < len; i++) + t->_set(i, _vector(x)->ref(i)); + return r; + } + + if (x->is_pair()){ + pmt_t y = x; + for (size_t i = 0; i < len; i++){ + t->_set(i, pmt_car(y)); + y = pmt_cdr(y); + } + return r; + } + + throw pmt_wrong_type("pmt_to_tuple", x); +} + + + +//////////////////////////////////////////////////////////////////////////// +// Uniform Numeric Vectors +//////////////////////////////////////////////////////////////////////////// + +bool +pmt_is_uniform_vector(pmt_t x) +{ + return x->is_uniform_vector(); +} + +const void * +pmt_uniform_vector_elements(pmt_t vector, size_t &len) +{ + if (!vector->is_uniform_vector()) + throw pmt_wrong_type("pmt_uniform_vector_elements", vector); + return _uniform_vector(vector)->uniform_elements(len); +} + +void * +pmt_uniform_vector_writable_elements(pmt_t vector, size_t &len) +{ + if (!vector->is_uniform_vector()) + throw pmt_wrong_type("pmt_uniform_vector_writable_elements", vector); + return _uniform_vector(vector)->uniform_writable_elements(len); +} + +//////////////////////////////////////////////////////////////////////////// +// Dictionaries +//////////////////////////////////////////////////////////////////////////// + +/* + * This is an a-list implementation. + * + * When we need better performance for large dictionaries, consider implementing + * persistent Red-Black trees as described in "Purely Functional Data Structures", + * Chris Okasaki, 1998, section 3.3. + */ + +bool +pmt_is_dict(const pmt_t &obj) +{ + return pmt_is_null(obj) || pmt_is_pair(obj); +} + +pmt_t +pmt_make_dict() +{ + return PMT_NIL; +} + +pmt_t +pmt_dict_add(const pmt_t &dict, const pmt_t &key, const pmt_t &value) +{ + if (pmt_is_null(dict)) + return pmt_acons(key, value, PMT_NIL); + + if (pmt_dict_has_key(dict, key)) + return pmt_acons(key, value, pmt_dict_delete(dict, key)); + + return pmt_acons(key, value, dict); +} + +pmt_t +pmt_dict_delete(const pmt_t &dict, const pmt_t &key) +{ + if (pmt_is_null(dict)) + return dict; + + if (pmt_eqv(pmt_caar(dict), key)) + return pmt_cdr(dict); + + return pmt_cons(pmt_car(dict), pmt_dict_delete(pmt_cdr(dict), key)); +} + +pmt_t +pmt_dict_ref(const pmt_t &dict, const pmt_t &key, const pmt_t ¬_found) +{ + pmt_t p = pmt_assv(key, dict); // look for (key . value) pair + if (pmt_is_pair(p)) + return pmt_cdr(p); + else + return not_found; +} + +bool +pmt_dict_has_key(const pmt_t &dict, const pmt_t &key) +{ + return pmt_is_pair(pmt_assv(key, dict)); +} + +pmt_t +pmt_dict_items(pmt_t dict) +{ + if (!pmt_is_dict(dict)) + throw pmt_wrong_type("pmt_dict_values", dict); + + return dict; // equivalent to dict in the a-list case +} + +pmt_t +pmt_dict_keys(pmt_t dict) +{ + if (!pmt_is_dict(dict)) + throw pmt_wrong_type("pmt_dict_keys", dict); + + return pmt_map(pmt_car, dict); +} + +pmt_t +pmt_dict_values(pmt_t dict) +{ + if (!pmt_is_dict(dict)) + throw pmt_wrong_type("pmt_dict_keys", dict); + + return pmt_map(pmt_cdr, dict); +} + +//////////////////////////////////////////////////////////////////////////// +// Any +//////////////////////////////////////////////////////////////////////////// + +pmt_any::pmt_any(const boost::any &any) : d_any(any) {} + +bool +pmt_is_any(pmt_t obj) +{ + return obj->is_any(); +} + +pmt_t +pmt_make_any(const boost::any &any) +{ + return pmt_t(new pmt_any(any)); +} + +boost::any +pmt_any_ref(pmt_t obj) +{ + if (!obj->is_any()) + throw pmt_wrong_type("pmt_any_ref", obj); + return _any(obj)->ref(); +} + +void +pmt_any_set(pmt_t obj, const boost::any &any) +{ + if (!obj->is_any()) + throw pmt_wrong_type("pmt_any_set", obj); + _any(obj)->set(any); +} + +//////////////////////////////////////////////////////////////////////////// +// msg_accepter -- built from "any" +//////////////////////////////////////////////////////////////////////////// + +bool +pmt_is_msg_accepter(const pmt_t &obj) +{ + if (!pmt_is_any(obj)) + return false; + + boost::any r = pmt_any_ref(obj); + return boost::any_cast<gruel::msg_accepter_sptr>(&r) != 0; +} + +//! make a msg_accepter +pmt_t +pmt_make_msg_accepter(gruel::msg_accepter_sptr ma) +{ + return pmt_make_any(ma); +} + +//! Return underlying msg_accepter +gruel::msg_accepter_sptr +pmt_msg_accepter_ref(const pmt_t &obj) +{ + try { + return boost::any_cast<gruel::msg_accepter_sptr>(pmt_any_ref(obj)); + } + catch (boost::bad_any_cast &e){ + throw pmt_wrong_type("pmt_msg_accepter_ref", obj); + } +} + + +//////////////////////////////////////////////////////////////////////////// +// Binary Large Object -- currently a u8vector +//////////////////////////////////////////////////////////////////////////// + +bool +pmt_is_blob(pmt_t x) +{ + // return pmt_is_u8vector(x); + return pmt_is_uniform_vector(x); +} + +pmt_t +pmt_make_blob(const void *buf, size_t len_in_bytes) +{ + return pmt_init_u8vector(len_in_bytes, (const uint8_t *) buf); +} + +const void * +pmt_blob_data(pmt_t blob) +{ + size_t len; + return pmt_uniform_vector_elements(blob, len); +} + +size_t +pmt_blob_length(pmt_t blob) +{ + size_t len; + pmt_uniform_vector_elements(blob, len); + return len; +} + + +//////////////////////////////////////////////////////////////////////////// +// General Functions +//////////////////////////////////////////////////////////////////////////// + +bool +pmt_eq(const pmt_t& x, const pmt_t& y) +{ + return x == y; +} + +bool +pmt_eqv(const pmt_t& x, const pmt_t& y) +{ + if (x == y) + return true; + + if (x->is_integer() && y->is_integer()) + return _integer(x)->value() == _integer(y)->value(); + + if (x->is_uint64() && y->is_uint64()) + return _uint64(x)->value() == _uint64(y)->value(); + + if (x->is_real() && y->is_real()) + return _real(x)->value() == _real(y)->value(); + + if (x->is_complex() && y->is_complex()) + return _complex(x)->value() == _complex(y)->value(); + + return false; +} + +bool +pmt_eqv_raw(pmt_base *x, pmt_base *y) +{ + if (x == y) + return true; + + if (x->is_integer() && y->is_integer()) + return _integer(x)->value() == _integer(y)->value(); + + if (x->is_uint64() && y->is_uint64()) + return _uint64(x)->value() == _uint64(y)->value(); + + if (x->is_real() && y->is_real()) + return _real(x)->value() == _real(y)->value(); + + if (x->is_complex() && y->is_complex()) + return _complex(x)->value() == _complex(y)->value(); + + return false; +} + +bool +pmt_equal(const pmt_t& x, const pmt_t& y) +{ + if (pmt_eqv(x, y)) + return true; + + if (x->is_pair() && y->is_pair()) + return pmt_equal(pmt_car(x), pmt_car(y)) && pmt_equal(pmt_cdr(x), pmt_cdr(y)); + + if (x->is_vector() && y->is_vector()){ + pmt_vector *xv = _vector(x); + pmt_vector *yv = _vector(y); + if (xv->length() != yv->length()) + return false; + + for (unsigned i = 0; i < xv->length(); i++) + if (!pmt_equal(xv->_ref(i), yv->_ref(i))) + return false; + + return true; + } + + if (x->is_tuple() && y->is_tuple()){ + pmt_tuple *xv = _tuple(x); + pmt_tuple *yv = _tuple(y); + if (xv->length() != yv->length()) + return false; + + for (unsigned i = 0; i < xv->length(); i++) + if (!pmt_equal(xv->_ref(i), yv->_ref(i))) + return false; + + return true; + } + + if (x->is_uniform_vector() && y->is_uniform_vector()){ + pmt_uniform_vector *xv = _uniform_vector(x); + pmt_uniform_vector *yv = _uniform_vector(y); + if (xv->length() != yv->length()) + return false; + + size_t len_x, len_y; + if (memcmp(xv->uniform_elements(len_x), + yv->uniform_elements(len_y), + len_x) == 0) + return true; + + return true; + } + + // FIXME add other cases here... + + return false; +} + +size_t +pmt_length(const pmt_t& x) +{ + if (x->is_vector()) + return _vector(x)->length(); + + if (x->is_uniform_vector()) + return _uniform_vector(x)->length(); + + if (x->is_tuple()) + return _tuple(x)->length(); + + if (x->is_null()) + return 0; + + if (x->is_pair()) { + size_t length=1; + pmt_t it = pmt_cdr(x); + while (pmt_is_pair(it)){ + length++; + it = pmt_cdr(it); + } + if (pmt_is_null(it)) + return length; + + // not a proper list + throw pmt_wrong_type("pmt_length", x); + } + + // FIXME dictionary length (number of entries) + + throw pmt_wrong_type("pmt_length", x); +} + +pmt_t +pmt_assq(pmt_t obj, pmt_t alist) +{ + while (pmt_is_pair(alist)){ + pmt_t p = pmt_car(alist); + if (!pmt_is_pair(p)) // malformed alist + return PMT_F; + + if (pmt_eq(obj, pmt_car(p))) + return p; + + alist = pmt_cdr(alist); + } + return PMT_F; +} + +/* + * This avoids a bunch of shared_pointer reference count manipulation. + */ +pmt_t +pmt_assv_raw(pmt_base *obj, pmt_base *alist) +{ + while (alist->is_pair()){ + pmt_base *p = ((pmt_pair *)alist)->d_car.get(); + if (!p->is_pair()) // malformed alist + return PMT_F; + + if (pmt_eqv_raw(obj, ((pmt_pair *)p)->d_car.get())) + return ((pmt_pair *)alist)->d_car; + + alist = (((pmt_pair *)alist)->d_cdr).get(); + } + return PMT_F; +} + +#if 1 + +pmt_t +pmt_assv(pmt_t obj, pmt_t alist) +{ + return pmt_assv_raw(obj.get(), alist.get()); +} + +#else + +pmt_t +pmt_assv(pmt_t obj, pmt_t alist) +{ + while (pmt_is_pair(alist)){ + pmt_t p = pmt_car(alist); + if (!pmt_is_pair(p)) // malformed alist + return PMT_F; + + if (pmt_eqv(obj, pmt_car(p))) + return p; + + alist = pmt_cdr(alist); + } + return PMT_F; +} + +#endif + + +pmt_t +pmt_assoc(pmt_t obj, pmt_t alist) +{ + while (pmt_is_pair(alist)){ + pmt_t p = pmt_car(alist); + if (!pmt_is_pair(p)) // malformed alist + return PMT_F; + + if (pmt_equal(obj, pmt_car(p))) + return p; + + alist = pmt_cdr(alist); + } + return PMT_F; +} + +pmt_t +pmt_map(pmt_t proc(const pmt_t&), pmt_t list) +{ + pmt_t r = PMT_NIL; + + while(pmt_is_pair(list)){ + r = pmt_cons(proc(pmt_car(list)), r); + list = pmt_cdr(list); + } + + return pmt_reverse_x(r); +} + +pmt_t +pmt_reverse(pmt_t listx) +{ + pmt_t list = listx; + pmt_t r = PMT_NIL; + + while(pmt_is_pair(list)){ + r = pmt_cons(pmt_car(list), r); + list = pmt_cdr(list); + } + if (pmt_is_null(list)) + return r; + else + throw pmt_wrong_type("pmt_reverse", listx); +} + +pmt_t +pmt_reverse_x(pmt_t list) +{ + // FIXME do it destructively + return pmt_reverse(list); +} + +pmt_t +pmt_nth(size_t n, pmt_t list) +{ + pmt_t t = pmt_nthcdr(n, list); + if (pmt_is_pair(t)) + return pmt_car(t); + else + return PMT_NIL; +} + +pmt_t +pmt_nthcdr(size_t n, pmt_t list) +{ + if (!(pmt_is_pair(list) || pmt_is_null(list))) + throw pmt_wrong_type("pmt_nthcdr", list); + + while (n > 0){ + if (pmt_is_pair(list)){ + list = pmt_cdr(list); + n--; + continue; + } + if (pmt_is_null(list)) + return PMT_NIL; + else + throw pmt_wrong_type("pmt_nthcdr: not a LIST", list); + } + return list; +} + +pmt_t +pmt_memq(pmt_t obj, pmt_t list) +{ + while (pmt_is_pair(list)){ + if (pmt_eq(obj, pmt_car(list))) + return list; + list = pmt_cdr(list); + } + return PMT_F; +} + +pmt_t +pmt_memv(pmt_t obj, pmt_t list) +{ + while (pmt_is_pair(list)){ + if (pmt_eqv(obj, pmt_car(list))) + return list; + list = pmt_cdr(list); + } + return PMT_F; +} + +pmt_t +pmt_member(pmt_t obj, pmt_t list) +{ + while (pmt_is_pair(list)){ + if (pmt_equal(obj, pmt_car(list))) + return list; + list = pmt_cdr(list); + } + return PMT_F; +} + +bool +pmt_subsetp(pmt_t list1, pmt_t list2) +{ + while (pmt_is_pair(list1)){ + pmt_t p = pmt_car(list1); + if (pmt_is_false(pmt_memv(p, list2))) + return false; + list1 = pmt_cdr(list1); + } + return true; +} + +pmt_t +pmt_list1(const pmt_t& x1) +{ + return pmt_cons(x1, PMT_NIL); +} + +pmt_t +pmt_list2(const pmt_t& x1, const pmt_t& x2) +{ + return pmt_cons(x1, pmt_cons(x2, PMT_NIL)); +} + +pmt_t +pmt_list3(const pmt_t& x1, const pmt_t& x2, const pmt_t& x3) +{ + return pmt_cons(x1, pmt_cons(x2, pmt_cons(x3, PMT_NIL))); +} + +pmt_t +pmt_list4(const pmt_t& x1, const pmt_t& x2, const pmt_t& x3, const pmt_t& x4) +{ + return pmt_cons(x1, pmt_cons(x2, pmt_cons(x3, pmt_cons(x4, PMT_NIL)))); +} + +pmt_t +pmt_list5(const pmt_t& x1, const pmt_t& x2, const pmt_t& x3, const pmt_t& x4, const pmt_t& x5) +{ + return pmt_cons(x1, pmt_cons(x2, pmt_cons(x3, pmt_cons(x4, pmt_cons(x5, PMT_NIL))))); +} + +pmt_t +pmt_list6(const pmt_t& x1, const pmt_t& x2, const pmt_t& x3, const pmt_t& x4, const pmt_t& x5, const pmt_t& x6) +{ + return pmt_cons(x1, pmt_cons(x2, pmt_cons(x3, pmt_cons(x4, pmt_cons(x5, pmt_cons(x6, PMT_NIL)))))); +} + +pmt_t +pmt_list_add(pmt_t list, const pmt_t& item) +{ + return pmt_reverse(pmt_cons(item, pmt_reverse(list))); +} + +pmt_t +pmt_list_rm(pmt_t list, const pmt_t& item) +{ + if(pmt_is_pair(list)){ + pmt_t left = pmt_car(list); + pmt_t right = pmt_cdr(list); + if(!pmt_equal(left, item)){ + return pmt_cons(left, pmt_list_rm(right, item)); + } else { + return pmt_list_rm(right, item); + } + } else { + return list; + } +} + +bool +pmt_list_has(pmt_t list, const pmt_t& item) +{ + if(pmt_is_pair(list)){ + pmt_t left = pmt_car(list); + pmt_t right = pmt_cdr(list); + if(pmt_equal(left,item)) + return true; + return pmt_list_has(right, item); + } else { + if(pmt_is_null(list)) + return false; + throw std::runtime_error("list contains invalid format!"); + } +} + +pmt_t +pmt_caar(pmt_t pair) +{ + return (pmt_car(pmt_car(pair))); +} + +pmt_t +pmt_cadr(pmt_t pair) +{ + return pmt_car(pmt_cdr(pair)); +} + +pmt_t +pmt_cdar(pmt_t pair) +{ + return pmt_cdr(pmt_car(pair)); +} + +pmt_t +pmt_cddr(pmt_t pair) +{ + return pmt_cdr(pmt_cdr(pair)); +} + +pmt_t +pmt_caddr(pmt_t pair) +{ + return pmt_car(pmt_cdr(pmt_cdr(pair))); +} + +pmt_t +pmt_cadddr(pmt_t pair) +{ + return pmt_car(pmt_cdr(pmt_cdr(pmt_cdr(pair)))); +} + +bool +pmt_is_eof_object(pmt_t obj) +{ + return pmt_eq(obj, PMT_EOF); +} + +void +pmt_dump_sizeof() +{ + printf("sizeof(pmt_t) = %3zd\n", sizeof(pmt_t)); + printf("sizeof(pmt_base) = %3zd\n", sizeof(pmt_base)); + printf("sizeof(pmt_bool) = %3zd\n", sizeof(pmt_bool)); + printf("sizeof(pmt_symbol) = %3zd\n", sizeof(pmt_symbol)); + printf("sizeof(pmt_integer) = %3zd\n", sizeof(pmt_integer)); + printf("sizeof(pmt_uint64) = %3zd\n", sizeof(pmt_uint64)); + printf("sizeof(pmt_real) = %3zd\n", sizeof(pmt_real)); + printf("sizeof(pmt_complex) = %3zd\n", sizeof(pmt_complex)); + printf("sizeof(pmt_null) = %3zd\n", sizeof(pmt_null)); + printf("sizeof(pmt_pair) = %3zd\n", sizeof(pmt_pair)); + printf("sizeof(pmt_vector) = %3zd\n", sizeof(pmt_vector)); + printf("sizeof(pmt_uniform_vector) = %3zd\n", sizeof(pmt_uniform_vector)); +} + +} /* namespace pmt */ diff --git a/gruel/src/lib/pmt/pmt_int.h b/gruel/src/lib/pmt/pmt_int.h new file mode 100644 index 000000000..d669e1049 --- /dev/null +++ b/gruel/src/lib/pmt/pmt_int.h @@ -0,0 +1,247 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2009,2010 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#ifndef INCLUDED_PMT_INT_H +#define INCLUDED_PMT_INT_H + +#include <gruel/pmt.h> +#include <boost/utility.hpp> +#include <boost/detail/atomic_count.hpp> + +/* + * EVERYTHING IN THIS FILE IS PRIVATE TO THE IMPLEMENTATION! + * + * See pmt.h for the public interface + */ + +#define PMT_LOCAL_ALLOCATOR 0 // define to 0 or 1 +namespace pmt { + +class GRUEL_API pmt_base : boost::noncopyable { + mutable boost::detail::atomic_count count_; + +protected: + pmt_base() : count_(0) {}; + virtual ~pmt_base(); + +public: + virtual bool is_bool() const { return false; } + virtual bool is_symbol() const { return false; } + virtual bool is_number() const { return false; } + virtual bool is_integer() const { return false; } + virtual bool is_uint64() const { return false; } + virtual bool is_real() const { return false; } + virtual bool is_complex() const { return false; } + virtual bool is_null() const { return false; } + virtual bool is_pair() const { return false; } + virtual bool is_tuple() const { return false; } + virtual bool is_vector() const { return false; } + virtual bool is_dict() const { return false; } + virtual bool is_any() const { return false; } + + virtual bool is_uniform_vector() const { return false; } + virtual bool is_u8vector() const { return false; } + virtual bool is_s8vector() const { return false; } + virtual bool is_u16vector() const { return false; } + virtual bool is_s16vector() const { return false; } + virtual bool is_u32vector() const { return false; } + virtual bool is_s32vector() const { return false; } + virtual bool is_u64vector() const { return false; } + virtual bool is_s64vector() const { return false; } + virtual bool is_f32vector() const { return false; } + virtual bool is_f64vector() const { return false; } + virtual bool is_c32vector() const { return false; } + virtual bool is_c64vector() const { return false; } + + friend void intrusive_ptr_add_ref(pmt_base* p); + friend void intrusive_ptr_release(pmt_base* p); + +# if (PMT_LOCAL_ALLOCATOR) + void *operator new(size_t); + void operator delete(void *, size_t); +#endif +}; + +class pmt_bool : public pmt_base +{ +public: + pmt_bool(); + //~pmt_bool(){} + + bool is_bool() const { return true; } +}; + + +class pmt_symbol : public pmt_base +{ + std::string d_name; + pmt_t d_next; + +public: + pmt_symbol(const std::string &name); + //~pmt_symbol(){} + + bool is_symbol() const { return true; } + const std::string name() { return d_name; } + + pmt_t next() { return d_next; } // symbol table link + void set_next(pmt_t next) { d_next = next; } +}; + +class pmt_integer : public pmt_base +{ +public: + long d_value; + + pmt_integer(long value); + //~pmt_integer(){} + + bool is_number() const { return true; } + bool is_integer() const { return true; } + long value() const { return d_value; } +}; + +class pmt_uint64 : public pmt_base +{ +public: + uint64_t d_value; + + pmt_uint64(uint64_t value); + //~pmt_uint64(){} + + bool is_number() const { return true; } + bool is_uint64() const { return true; } + uint64_t value() const { return d_value; } +}; + +class pmt_real : public pmt_base +{ +public: + double d_value; + + pmt_real(double value); + //~pmt_real(){} + + bool is_number() const { return true; } + bool is_real() const { return true; } + double value() const { return d_value; } +}; + +class pmt_complex : public pmt_base +{ +public: + std::complex<double> d_value; + + pmt_complex(std::complex<double> value); + //~pmt_complex(){} + + bool is_number() const { return true; } + bool is_complex() const { return true; } + std::complex<double> value() const { return d_value; } +}; + +class pmt_null : public pmt_base +{ +public: + pmt_null(); + //~pmt_null(){} + + bool is_null() const { return true; } +}; + +class pmt_pair : public pmt_base +{ +public: + pmt_t d_car; + pmt_t d_cdr; + + pmt_pair(const pmt_t& car, const pmt_t& cdr); + //~pmt_pair(){}; + + bool is_pair() const { return true; } + pmt_t car() const { return d_car; } + pmt_t cdr() const { return d_cdr; } + + void set_car(pmt_t car) { d_car = car; } + void set_cdr(pmt_t cdr) { d_cdr = cdr; } +}; + +class pmt_vector : public pmt_base +{ + std::vector<pmt_t> d_v; + +public: + pmt_vector(size_t len, pmt_t fill); + //~pmt_vector(); + + bool is_vector() const { return true; } + pmt_t ref(size_t k) const; + void set(size_t k, pmt_t obj); + void fill(pmt_t fill); + size_t length() const { return d_v.size(); } + + pmt_t _ref(size_t k) const { return d_v[k]; } +}; + +class pmt_tuple : public pmt_base +{ + std::vector<pmt_t> d_v; + +public: + pmt_tuple(size_t len); + //~pmt_tuple(); + + bool is_tuple() const { return true; } + pmt_t ref(size_t k) const; + size_t length() const { return d_v.size(); } + + pmt_t _ref(size_t k) const { return d_v[k]; } + void _set(size_t k, pmt_t v) { d_v[k] = v; } +}; + +class pmt_any : public pmt_base +{ + boost::any d_any; + +public: + pmt_any(const boost::any &any); + //~pmt_any(); + + bool is_any() const { return true; } + const boost::any &ref() const { return d_any; } + void set(const boost::any &any) { d_any = any; } +}; + + +class pmt_uniform_vector : public pmt_base +{ +public: + bool is_uniform_vector() const { return true; } + virtual const void *uniform_elements(size_t &len) = 0; + virtual void *uniform_writable_elements(size_t &len) = 0; + virtual size_t length() const = 0; +}; + +#include "pmt_unv_int.h" + +} /* namespace pmt */ + +#endif /* INCLUDED_PMT_INT_H */ diff --git a/gruel/src/lib/pmt/pmt_io.cc b/gruel/src/lib/pmt/pmt_io.cc new file mode 100644 index 000000000..4bac4a0ec --- /dev/null +++ b/gruel/src/lib/pmt/pmt_io.cc @@ -0,0 +1,168 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <vector> +#include <gruel/pmt.h> +#include "pmt_int.h" +#include <sstream> +#include <iostream> + +namespace pmt { + +static void +pmt_write_list_tail(pmt_t obj, std::ostream &port) +{ + pmt_write(pmt_car(obj), port); // write the car + obj = pmt_cdr(obj); // step to cdr + + if (pmt_is_null(obj)) // () + port << ")"; + + else if (pmt_is_pair(obj)){ // normal list + port << " "; + pmt_write_list_tail(obj, port); + } + else { // dotted pair + port << " . "; + pmt_write(obj, port); + port << ")"; + } +} + +void +pmt_write(pmt_t obj, std::ostream &port) +{ + if (pmt_is_bool(obj)){ + if (pmt_is_true(obj)) + port << "#t"; + else + port << "#f"; + } + else if (pmt_is_symbol(obj)){ + port << pmt_symbol_to_string(obj); + } + else if (pmt_is_number(obj)){ + if (pmt_is_integer(obj)) + port << pmt_to_long(obj); + else if (pmt_is_uint64(obj)) + port << pmt_to_uint64(obj); + else if (pmt_is_real(obj)) + port << pmt_to_double(obj); + else if (pmt_is_complex(obj)){ + std::complex<double> c = pmt_to_complex(obj); + port << c.real() << '+' << c.imag() << 'i'; + } + else + goto error; + } + else if (pmt_is_null(obj)){ + port << "()"; + } + else if (pmt_is_pair(obj)){ + port << "("; + pmt_write_list_tail(obj, port); + } + else if (pmt_is_tuple(obj)){ + port << "{"; + size_t len = pmt_length(obj); + if (len > 0){ + port << pmt_tuple_ref(obj, 0); + for (size_t i = 1; i < len; i++) + port << " " << pmt_tuple_ref(obj, i); + } + port << "}"; + } + else if (pmt_is_vector(obj)){ + port << "#("; + size_t len = pmt_length(obj); + if (len > 0){ + port << pmt_vector_ref(obj, 0); + for (size_t i = 1; i < len; i++) + port << " " << pmt_vector_ref(obj, i); + } + port << ")"; + } + else if (pmt_is_dict(obj)){ + // FIXME + // port << "#<dict " << obj << ">"; + port << "#<dict>"; + } + else if (pmt_is_uniform_vector(obj)){ + // FIXME + // port << "#<uniform-vector " << obj << ">"; + port << "#<uniform-vector>"; + } + else { + error: + // FIXME + // port << "#<" << obj << ">"; + port << "#<unknown>"; + } +} + +std::ostream& operator<<(std::ostream &os, pmt_t obj) +{ + pmt_write(obj, os); + return os; +} + +std::string +pmt_write_string(pmt_t obj) +{ + std::ostringstream s; + s << obj; + return s.str(); +} + +pmt_t +pmt_read(std::istream &port) +{ + throw pmt_notimplemented("notimplemented: pmt_read", PMT_NIL); +} + +void +pmt_serialize(pmt_t obj, std::ostream &sink) +{ + throw pmt_notimplemented("notimplemented: pmt_serialize", obj); +} + +/*! + * \brief Create obj from portable byte-serial representation + */ +pmt_t +pmt_deserialize(std::istream &source) +{ + throw pmt_notimplemented("notimplemented: pmt_deserialize", PMT_NIL); +} + +} /* namespace pmt */ + + +void +pmt::pmt_print(pmt_t v) +{ + std::cout << pmt_write_string(v) << std::endl; +} + + diff --git a/gruel/src/lib/pmt/pmt_pool.cc b/gruel/src/lib/pmt/pmt_pool.cc new file mode 100644 index 000000000..63a681abf --- /dev/null +++ b/gruel/src/lib/pmt/pmt_pool.cc @@ -0,0 +1,112 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <gruel/pmt_pool.h> +#include <algorithm> +#include <stdint.h> + +namespace pmt { + +static inline size_t +ROUNDUP(size_t x, size_t stride) +{ + return ((((x) + (stride) - 1)/(stride)) * (stride)); +} + +pmt_pool::pmt_pool(size_t itemsize, size_t alignment, + size_t allocation_size, size_t max_items) + : d_itemsize(ROUNDUP(itemsize, alignment)), + d_alignment(alignment), + d_allocation_size(std::max(allocation_size, 16 * itemsize)), + d_max_items(max_items), d_n_items(0), + d_freelist(0) +{ +} + +pmt_pool::~pmt_pool() +{ + for (unsigned int i = 0; i < d_allocations.size(); i++){ + delete [] d_allocations[i]; + } +} + +void * +pmt_pool::malloc() +{ + scoped_lock guard(d_mutex); + item *p; + + if (d_max_items != 0){ + while (d_n_items >= d_max_items) + d_cond.wait(guard); + } + + if (d_freelist){ // got something? + p = d_freelist; + d_freelist = p->d_next; + d_n_items++; + return p; + } + + // allocate a new chunk + char *alloc = new char[d_allocation_size + d_alignment - 1]; + d_allocations.push_back(alloc); + + // get the alignment we require + char *start = (char *)(((uintptr_t)alloc + d_alignment-1) & -d_alignment); + char *end = alloc + d_allocation_size + d_alignment - 1; + size_t n = (end - start) / d_itemsize; + + // link the new items onto the free list. + p = (item *) start; + for (size_t i = 0; i < n; i++){ + p->d_next = d_freelist; + d_freelist = p; + p = (item *)((char *) p + d_itemsize); + } + + // now return the first one + p = d_freelist; + d_freelist = p->d_next; + d_n_items++; + return p; +} + +void +pmt_pool::free(void *foo) +{ + if (!foo) + return; + + scoped_lock guard(d_mutex); + + item *p = (item *) foo; + p->d_next = d_freelist; + d_freelist = p; + d_n_items--; + if (d_max_items != 0) + d_cond.notify_one(); +} + +} /* namespace pmt */ diff --git a/gruel/src/lib/pmt/pmt_serialize.cc b/gruel/src/lib/pmt/pmt_serialize.cc new file mode 100644 index 000000000..24be6b772 --- /dev/null +++ b/gruel/src/lib/pmt/pmt_serialize.cc @@ -0,0 +1,830 @@ +/* -*- c++ -*- */ +/* + * Copyright 2007,2009 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include <vector> +#include <gruel/pmt.h> +#include "pmt_int.h" +#include "gruel/pmt_serial_tags.h" + +namespace pmt { + +static pmt_t parse_pair(std::streambuf &sb); + +// ---------------------------------------------------------------- +// output primitives +// ---------------------------------------------------------------- + +static bool +serialize_untagged_u8(unsigned int i, std::streambuf &sb) +{ + return sb.sputc((i >> 0) & 0xff) != std::streambuf::traits_type::eof(); +} + +// always writes big-endian +static bool +serialize_untagged_u16(unsigned int i, std::streambuf &sb) +{ + sb.sputc((i >> 8) & 0xff); + return sb.sputc((i >> 0) & 0xff) != std::streambuf::traits_type::eof(); +} + +// always writes big-endian +static bool +serialize_untagged_u32(unsigned int i, std::streambuf &sb) +{ + sb.sputc((i >> 24) & 0xff); + sb.sputc((i >> 16) & 0xff); + sb.sputc((i >> 8) & 0xff); + return sb.sputc((i >> 0) & 0xff) != std::streambuf::traits_type::eof(); +} + +static bool +serialize_untagged_f64(double i, std::streambuf &sb) +{ + typedef union { + double id; + uint64_t ii; + } iu_t; + iu_t iu; + iu.id = i; + sb.sputc((iu.ii >> 56) & 0xff); + sb.sputc((iu.ii >> 48) & 0xff); + sb.sputc((iu.ii >> 40) & 0xff); + sb.sputc((iu.ii >> 32) & 0xff); + sb.sputc((iu.ii >> 24) & 0xff); + sb.sputc((iu.ii >> 16) & 0xff); + sb.sputc((iu.ii >> 8) & 0xff); + return sb.sputc((iu.ii >> 0) & 0xff) != std::streambuf::traits_type::eof(); +} + + +// always writes big-endian +static bool +serialize_untagged_u64(uint64_t i, std::streambuf &sb) +{ + sb.sputc((i >> 56) & 0xff); + sb.sputc((i >> 48) & 0xff); + sb.sputc((i >> 40) & 0xff); + sb.sputc((i >> 32) & 0xff); + sb.sputc((i >> 24) & 0xff); + sb.sputc((i >> 16) & 0xff); + sb.sputc((i >> 8) & 0xff); + return sb.sputc((i >> 0) & 0xff) != std::streambuf::traits_type::eof(); +} + +// ---------------------------------------------------------------- +// input primitives +// ---------------------------------------------------------------- + + +// always reads big-endian +static bool +deserialize_untagged_u8(uint8_t *ip, std::streambuf &sb) +{ + std::streambuf::traits_type::int_type t; + int i; + + t = sb.sbumpc(); + i = t & 0xff; + + *ip = i; + return t != std::streambuf::traits_type::eof(); +} + +// always reads big-endian +static bool +deserialize_untagged_u16(uint16_t *ip, std::streambuf &sb) +{ + std::streambuf::traits_type::int_type t; + int i; + + t = sb.sbumpc(); + i = t & 0xff; + + t = sb.sbumpc(); + i = (i << 8) | (t & 0xff); + + *ip = i; + return t != std::streambuf::traits_type::eof(); +} + +// always reads big-endian +static bool +deserialize_untagged_u32(uint32_t *ip, std::streambuf &sb) +{ + std::streambuf::traits_type::int_type t; + int i; + + t = sb.sbumpc(); + i = t & 0xff; + + t = sb.sbumpc(); + i = (i << 8) | (t & 0xff); + t = sb.sbumpc(); + i = (i << 8) | (t & 0xff); + t = sb.sbumpc(); + i = (i << 8) | (t & 0xff); + + *ip = i; + return t != std::streambuf::traits_type::eof(); +} + +// always reads big-endian +static bool +deserialize_untagged_u64(uint64_t *ip, std::streambuf &sb) +{ + std::streambuf::traits_type::int_type t; + uint64_t i; + + t = sb.sbumpc(); + i = t & 0xff; + + t = sb.sbumpc(); + i = (i << 8) | (t & 0xff); + t = sb.sbumpc(); + i = (i << 8) | (t & 0xff); + t = sb.sbumpc(); + i = (i << 8) | (t & 0xff); + t = sb.sbumpc(); + i = (i << 8) | (t & 0xff); + t = sb.sbumpc(); + i = (i << 8) | (t & 0xff); + t = sb.sbumpc(); + i = (i << 8) | (t & 0xff); + t = sb.sbumpc(); + i = (i << 8) | (t & 0xff); + + *ip = i; + return t != std::streambuf::traits_type::eof(); +} + +static bool +deserialize_untagged_f64(double *ip, std::streambuf &sb) +{ + std::streambuf::traits_type::int_type t; + + typedef union { + double id; + uint64_t ii; + } iu_t; + + iu_t iu; + + t = sb.sbumpc(); + iu.ii = t & 0xff; + + t = sb.sbumpc(); + iu.ii = (iu.ii<<8) | (t & 0xff); + t = sb.sbumpc(); + iu.ii = (iu.ii<<8) | (t & 0xff); + t = sb.sbumpc(); + iu.ii = (iu.ii<<8) | (t & 0xff); + t = sb.sbumpc(); + iu.ii = (iu.ii<<8) | (t & 0xff); + t = sb.sbumpc(); + iu.ii = (iu.ii<<8) | (t & 0xff); + t = sb.sbumpc(); + iu.ii = (iu.ii<<8) | (t & 0xff); + t = sb.sbumpc(); + iu.ii = (iu.ii<<8) | (t & 0xff); + + *ip = iu.id; + return t != std::streambuf::traits_type::eof(); +} + +static bool +deserialize_tuple(pmt_t *tuple, std::streambuf &sb) +{ + uint32_t nitems; + bool ok = deserialize_untagged_u32(&nitems, sb); + pmt_t list(PMT_NIL); + for(uint32_t i=0; i<nitems; i++){ + pmt_t item = pmt_deserialize( sb ); + if(pmt_eq(list, PMT_NIL)){ + list = pmt_list1(item); + } else { + list = pmt_list_add(list, item); + } + } + (*tuple) = pmt_to_tuple(list); + return ok; +} + + +/* + * Write portable byte-serial representation of \p obj to \p sb + * + * N.B., Circular structures cause infinite recursion. + */ +bool +pmt_serialize(pmt_t obj, std::streambuf &sb) +{ + bool ok = true; + + tail_recursion: + + if (pmt_is_bool(obj)){ + if (pmt_eq(obj, PMT_T)) + return serialize_untagged_u8(PST_TRUE, sb); + else + return serialize_untagged_u8(PST_FALSE, sb); + } + + if (pmt_is_null(obj)) + return serialize_untagged_u8(PST_NULL, sb); + + if (pmt_is_symbol(obj)){ + const std::string s = pmt_symbol_to_string(obj); + size_t len = s.size(); + ok = serialize_untagged_u8(PST_SYMBOL, sb); + ok &= serialize_untagged_u16(len, sb); + for (size_t i = 0; i < len; i++) + ok &= serialize_untagged_u8(s[i], sb); + return ok; + } + + if (pmt_is_pair(obj)){ + ok = serialize_untagged_u8(PST_PAIR, sb); + ok &= pmt_serialize(pmt_car(obj), sb); + if (!ok) + return false; + obj = pmt_cdr(obj); + goto tail_recursion; + } + + if (pmt_is_number(obj)){ + + if (pmt_is_uint64(obj)){ + uint64_t i = pmt_to_uint64(obj); + ok = serialize_untagged_u8(PST_UINT64, sb); + ok &= serialize_untagged_u64(i, sb); + return ok; + } else + if (pmt_is_integer(obj)){ + long i = pmt_to_long(obj); + if (sizeof(long) > 4){ + if (i < -2147483647 || i > 2147483647) + throw pmt_notimplemented("pmt_serialize (64-bit integers)", obj); + } + ok = serialize_untagged_u8(PST_INT32, sb); + ok &= serialize_untagged_u32(i, sb); + return ok; + } + + if (pmt_is_real(obj)){ + float i = pmt_to_double(obj); + ok = serialize_untagged_u8(PST_DOUBLE, sb); + ok &= serialize_untagged_f64(i, sb); + return ok; + } + + if (pmt_is_complex(obj)){ + std::complex<double> i = pmt_to_complex(obj); + ok = serialize_untagged_u8(PST_COMPLEX, sb); + ok &= serialize_untagged_f64(i.real(), sb); + ok &= serialize_untagged_f64(i.imag(), sb); + return ok; + } + + } + + if (pmt_is_vector(obj)) { + size_t vec_len = pmt::pmt_length(obj); + ok = serialize_untagged_u8(PST_VECTOR, sb); + ok &= serialize_untagged_u32(vec_len, sb); + for(size_t i=0; i<vec_len; i++) { + ok &= pmt_serialize(pmt_vector_ref(obj, i), sb); + } + return ok; + } + + if (pmt_is_uniform_vector(obj)) { + size_t npad = 1; + size_t vec_len = pmt::pmt_length(obj); + + if(pmt_is_u8vector(obj)) { + ok = serialize_untagged_u8(PST_UNIFORM_VECTOR, sb); + ok &= serialize_untagged_u8(UVI_U8, sb); + ok &= serialize_untagged_u32(vec_len, sb); + ok &= serialize_untagged_u8(npad, sb); + for(size_t i=0; i<npad; i++) { + ok &= serialize_untagged_u8(0, sb); + } + for(size_t i=0; i<vec_len; i++) { + ok &= serialize_untagged_u8(pmt_u8vector_ref(obj, i), sb); + } + return ok; + } + + if(pmt_is_s8vector(obj)) { + ok = serialize_untagged_u8(PST_UNIFORM_VECTOR, sb); + ok &= serialize_untagged_u8(UVI_S8, sb); + ok &= serialize_untagged_u32(vec_len, sb); + ok &= serialize_untagged_u8(npad, sb); + for(size_t i=0; i<npad; i++) { + ok &= serialize_untagged_u8(0, sb); + } + for(size_t i=0; i<vec_len; i++) { + ok &= serialize_untagged_u8(pmt_s8vector_ref(obj, i), sb); + } + return ok; + } + + if(pmt_is_u16vector(obj)) { + ok = serialize_untagged_u8(PST_UNIFORM_VECTOR, sb); + ok &= serialize_untagged_u8(UVI_U16, sb); + ok &= serialize_untagged_u32(vec_len, sb); + ok &= serialize_untagged_u8(npad, sb); + for(size_t i=0; i<npad; i++) { + ok &= serialize_untagged_u8(0, sb); + } + for(size_t i=0; i<vec_len; i++) { + ok &= serialize_untagged_u16(pmt_u16vector_ref(obj, i), sb); + } + return ok; + } + + if(pmt_is_s16vector(obj)) { + ok = serialize_untagged_u8(PST_UNIFORM_VECTOR, sb); + ok &= serialize_untagged_u8(UVI_S16, sb); + ok &= serialize_untagged_u32(vec_len, sb); + ok &= serialize_untagged_u8(npad, sb); + for(size_t i=0; i<npad; i++) { + ok &= serialize_untagged_u8(0, sb); + } + for(size_t i=0; i<vec_len; i++) { + ok &= serialize_untagged_u16(pmt_s16vector_ref(obj, i), sb); + } + return ok; + } + + if(pmt_is_u32vector(obj)) { + ok = serialize_untagged_u8(PST_UNIFORM_VECTOR, sb); + ok &= serialize_untagged_u8(UVI_U32, sb); + ok &= serialize_untagged_u32(vec_len, sb); + ok &= serialize_untagged_u8(npad, sb); + for(size_t i=0; i<npad; i++) { + ok &= serialize_untagged_u8(0, sb); + } + for(size_t i=0; i<vec_len; i++) { + ok &= serialize_untagged_u32(pmt_u32vector_ref(obj, i), sb); + } + return ok; + } + + if(pmt_is_s32vector(obj)) { + ok = serialize_untagged_u8(PST_UNIFORM_VECTOR, sb); + ok &= serialize_untagged_u8(UVI_S32, sb); + ok &= serialize_untagged_u32(vec_len, sb); + ok &= serialize_untagged_u8(npad, sb); + for(size_t i=0; i<npad; i++) { + ok &= serialize_untagged_u8(0, sb); + } + for(size_t i=0; i<vec_len; i++) { + ok &= serialize_untagged_u32(pmt_s32vector_ref(obj, i), sb); + } + return ok; + } + + if(pmt_is_u64vector(obj)) { + ok = serialize_untagged_u8(PST_UNIFORM_VECTOR, sb); + ok &= serialize_untagged_u8(UVI_U64, sb); + ok &= serialize_untagged_u32(vec_len, sb); + ok &= serialize_untagged_u8(npad, sb); + for(size_t i=0; i<npad; i++) { + ok &= serialize_untagged_u8(0, sb); + } + for(size_t i=0; i<vec_len; i++) { + ok &= serialize_untagged_u64(pmt_u64vector_ref(obj, i), sb); + } + return ok; + } + + if(pmt_is_s64vector(obj)) { + ok = serialize_untagged_u8(PST_UNIFORM_VECTOR, sb); + ok &= serialize_untagged_u8(UVI_S64, sb); + ok &= serialize_untagged_u32(vec_len, sb); + ok &= serialize_untagged_u8(npad, sb); + for(size_t i=0; i<npad; i++) { + ok &= serialize_untagged_u8(0, sb); + } + for(size_t i=0; i<vec_len; i++) { + ok &= serialize_untagged_u64(pmt_s64vector_ref(obj, i), sb); + } + return ok; + } + + if(pmt_is_f32vector(obj)) { + ok = serialize_untagged_u8(PST_UNIFORM_VECTOR, sb); + ok &= serialize_untagged_u8(UVI_F32, sb); + ok &= serialize_untagged_u32(vec_len, sb); + ok &= serialize_untagged_u8(npad, sb); + for(size_t i=0; i<npad; i++) { + ok &= serialize_untagged_u8(0, sb); + } + for(size_t i=0; i<vec_len; i++) { + ok &= serialize_untagged_f64(pmt_f32vector_ref(obj, i), sb); + } + return ok; + } + + if(pmt_is_f64vector(obj)) { + ok = serialize_untagged_u8(PST_UNIFORM_VECTOR, sb); + ok &= serialize_untagged_u8(UVI_F64, sb); + ok &= serialize_untagged_u32(vec_len, sb); + ok &= serialize_untagged_u8(npad, sb); + for(size_t i=0; i<npad; i++) { + ok &= serialize_untagged_u8(0, sb); + } + for(size_t i=0; i<vec_len; i++) { + ok &= serialize_untagged_f64(pmt_f64vector_ref(obj, i), sb); + } + return ok; + } + + if(pmt_is_c32vector(obj)) { + ok = serialize_untagged_u8(PST_UNIFORM_VECTOR, sb); + ok &= serialize_untagged_u8(UVI_C32, sb); + ok &= serialize_untagged_u32(vec_len, sb); + ok &= serialize_untagged_u8(npad, sb); + for(size_t i=0; i<npad; i++) { + ok &= serialize_untagged_u8(0, sb); + } + for(size_t i=0; i<vec_len; i++) { + std::complex<float> c = pmt_c32vector_ref(obj, i); + ok &= serialize_untagged_f64(c.real(), sb); + ok &= serialize_untagged_f64(c.imag(), sb); + } + return ok; + } + + if(pmt_is_c64vector(obj)) { + ok = serialize_untagged_u8(PST_UNIFORM_VECTOR, sb); + ok &= serialize_untagged_u8(UVI_C64, sb); + ok &= serialize_untagged_u32(vec_len, sb); + ok &= serialize_untagged_u8(npad, sb); + for(size_t i=0; i<npad; i++) { + ok &= serialize_untagged_u8(0, sb); + } + for(size_t i=0; i<vec_len; i++) { + std::complex<double> c = pmt_c64vector_ref(obj, i); + ok &= serialize_untagged_f64(c.real(), sb); + ok &= serialize_untagged_f64(c.imag(), sb); + } + return ok; + } + } + + if (pmt_is_dict(obj)) + throw pmt_notimplemented("pmt_serialize (dict)", obj); + + if (pmt_is_tuple(obj)){ + size_t tuple_len = pmt::pmt_length(obj); + ok = serialize_untagged_u8(PST_TUPLE, sb); + ok &= serialize_untagged_u32(tuple_len, sb); + for(size_t i=0; i<tuple_len; i++){ + ok &= pmt_serialize(pmt_tuple_ref(obj, i), sb); + } + return ok; + } + //throw pmt_notimplemented("pmt_serialize (tuple)", obj); + + throw pmt_notimplemented("pmt_serialize (?)", obj); +} + +/* + * Create obj from portable byte-serial representation + * + * Returns next obj from streambuf, or PMT_EOF at end of file. + * Throws exception on malformed input. + */ +pmt_t +pmt_deserialize(std::streambuf &sb) +{ + uint8_t tag; + uint8_t u8; + uint16_t u16; + uint32_t u32; + uint64_t u64; + double f64; + static char tmpbuf[1024]; + + if (!deserialize_untagged_u8(&tag, sb)) + return PMT_EOF; + + switch (tag){ + case PST_TRUE: + return PMT_T; + + case PST_FALSE: + return PMT_F; + + case PST_NULL: + return PMT_NIL; + + case PST_SYMBOL: + if (!deserialize_untagged_u16(&u16, sb)) + goto error; + if (u16 > sizeof(tmpbuf)) + throw pmt_notimplemented("pmt_deserialize: very long symbol", + PMT_F); + if (sb.sgetn(tmpbuf, u16) != u16) + goto error; + return pmt_intern(std::string(tmpbuf, u16)); + + case PST_INT32: + if (!deserialize_untagged_u32(&u32, sb)) + goto error; + return pmt_from_long((int32_t) u32); + + case PST_UINT64: + if(!deserialize_untagged_u64(&u64, sb)) + goto error; + return pmt_from_uint64(u64); + + case PST_PAIR: + return parse_pair(sb); + + case PST_DOUBLE: + if(!deserialize_untagged_f64(&f64, sb)) + goto error; + return pmt_from_double( f64 ); + + case PST_COMPLEX: + { + double r,i; + if(!deserialize_untagged_f64(&r, sb) && !deserialize_untagged_f64(&i, sb)) + goto error; + return pmt_make_rectangular( r,i ); + } + + case PST_TUPLE: + { + pmt_t tuple; + if(!deserialize_tuple(&tuple, sb)){ + goto error; + } + return tuple; + } + + case PST_VECTOR: + { + uint32_t nitems; + if(!deserialize_untagged_u32(&nitems, sb)) + goto error; + pmt_t vec = pmt_make_vector(nitems, PMT_NIL); + for(uint32_t i=0; i<nitems; i++) { + pmt_t item = pmt_deserialize(sb); + pmt_vector_set(vec, i, item); + } + return vec; + } + + case PST_UNIFORM_VECTOR: + { + uint8_t utag, npad; + uint32_t nitems; + + if(!deserialize_untagged_u8(&utag, sb)) + return PMT_EOF; + + if(!deserialize_untagged_u32(&nitems, sb)) + goto error; + + deserialize_untagged_u8(&npad, sb); + for(size_t i; i < npad; i++) + deserialize_untagged_u8(&u8, sb); + + switch(utag) { + case(UVI_U8): + { + pmt_t vec = pmt_make_u8vector(nitems, 0); + for(uint32_t i=0; i<nitems; i++) { + deserialize_untagged_u8(&u8, sb); + pmt_u8vector_set(vec, i, u8); + } + return vec; + } + case(UVI_S8): + { + pmt_t vec = pmt_make_s8vector(nitems, 0); + for(uint32_t i=0; i<nitems; i++) { + deserialize_untagged_u8(&u8, sb); + pmt_s8vector_set(vec, i, u8); + } + return vec; + } + case(UVI_U16): + { + pmt_t vec = pmt_make_u16vector(nitems, 0); + for(uint32_t i=0; i<nitems; i++) { + deserialize_untagged_u16(&u16, sb); + pmt_u16vector_set(vec, i, u16); + } + return vec; + } + case(UVI_S16): + { + pmt_t vec = pmt_make_s16vector(nitems, 0); + for(uint32_t i=0; i<nitems; i++) { + deserialize_untagged_u16(&u16, sb); + pmt_s16vector_set(vec, i, u16); + } + return vec; + } + case(UVI_U32): + { + pmt_t vec = pmt_make_u32vector(nitems, 0); + for(uint32_t i=0; i<nitems; i++) { + deserialize_untagged_u32(&u32, sb); + pmt_u32vector_set(vec, i, u32); + } + return vec; + } + case(UVI_S32): + { + pmt_t vec = pmt_make_s32vector(nitems, 0); + for(uint32_t i=0; i<nitems; i++) { + deserialize_untagged_u32(&u32, sb); + pmt_s32vector_set(vec, i, u32); + } + return vec; + } + case(UVI_U64): + { + pmt_t vec = pmt_make_u64vector(nitems, 0); + for(uint32_t i=0; i<nitems; i++) { + deserialize_untagged_u64(&u64, sb); + pmt_u64vector_set(vec, i, u64); + } + return vec; + } + case(UVI_S64): + { + pmt_t vec = pmt_make_s64vector(nitems, 0); + for(uint32_t i=0; i<nitems; i++) { + deserialize_untagged_u64(&u64, sb); + pmt_s64vector_set(vec, i, u64); + } + return vec; + } + case(UVI_F32): + { + pmt_t vec = pmt_make_f32vector(nitems, 0); + for(uint32_t i=0; i<nitems; i++) { + deserialize_untagged_f64(&f64, sb); + pmt_f32vector_set(vec, i, static_cast<float>(f64)); + } + return vec; + } + case(UVI_F64): + { + pmt_t vec = pmt_make_f64vector(nitems, 0); + for(uint32_t i=0; i<nitems; i++) { + deserialize_untagged_f64(&f64, sb); + pmt_f64vector_set(vec, i, f64); + } + return vec; + } + case(UVI_C32): + { + pmt_t vec = pmt_make_c32vector(nitems, 0); + for(uint32_t i=0; i<nitems; i++) { + float re, im; + deserialize_untagged_f64(&f64, sb); + re = static_cast<float>(f64); + deserialize_untagged_f64(&f64, sb); + im = static_cast<float>(f64); + pmt_c32vector_set(vec, i, std::complex<float>(re, im)); + } + return vec; + } + + case(UVI_C64): + { + pmt_t vec = pmt_make_c64vector(nitems, 0); + for(uint32_t i=0; i<nitems; i++) { + double re, im; + deserialize_untagged_f64(&f64, sb); + re = f64; + deserialize_untagged_f64(&f64, sb); + im = f64; + pmt_c64vector_set(vec, i, std::complex<double>(re, im)); + } + return vec; + } + + default: + throw pmt_exception("pmt_deserialize: malformed input stream, tag value = ", + pmt_from_long(tag)); + } + } + + case PST_DICT: + case PST_COMMENT: + throw pmt_notimplemented("pmt_deserialize: tag value = ", + pmt_from_long(tag)); + + default: + throw pmt_exception("pmt_deserialize: malformed input stream, tag value = ", + pmt_from_long(tag)); + } + + error: + throw pmt_exception("pmt_deserialize: malformed input stream", PMT_F); +} + + +/* + * provide a simple string accessor to the serialized pmt form + */ +std::string pmt_serialize_str(pmt_t obj){ + std::stringbuf sb; + pmt_serialize(obj, sb); + return sb.str(); +} + + +/* + * provide a simple string accessor to the deserialized pmt form + */ +pmt_t pmt_deserialize_str(std::string s){ + std::stringbuf sb(s); + return pmt_deserialize(sb); +} + + +/* + * This is a mostly non-recursive implementation that allows us to + * deserialize very long lists w/o exhausting the evaluation stack. + * + * On entry we've already eaten the PST_PAIR tag. + */ +pmt_t +parse_pair(std::streambuf &sb) +{ + uint8_t tag; + pmt_t val, expr, lastnptr, nptr; + + // + // Keep appending nodes until we get a non-PAIR cdr. + // + lastnptr = PMT_NIL; + while (1){ + expr = pmt_deserialize(sb); // read the car + + nptr = pmt_cons(expr, PMT_NIL); // build new cell + if (pmt_is_null(lastnptr)) + val = nptr; + else + pmt_set_cdr(lastnptr, nptr); + lastnptr = nptr; + + if (!deserialize_untagged_u8(&tag, sb)) // get tag of cdr + throw pmt_exception("pmt_deserialize: malformed input stream", PMT_F); + + if (tag == PST_PAIR) + continue; // keep on looping... + + if (tag == PST_NULL){ + expr = PMT_NIL; + break; + } + + // + // default: push tag back and use pmt_deserialize to get the cdr + // + sb.sungetc(); + expr = pmt_deserialize(sb); + break; + } + + // + // At this point, expr contains the value of the final cdr in the list. + // + pmt_set_cdr(lastnptr, expr); + return val; +} + +} /* namespace pmt */ diff --git a/gruel/src/lib/pmt/qa_pmt.cc b/gruel/src/lib/pmt/qa_pmt.cc new file mode 100644 index 000000000..27c617e74 --- /dev/null +++ b/gruel/src/lib/pmt/qa_pmt.cc @@ -0,0 +1,40 @@ +/* + * Copyright 2006 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +/* + * This class gathers together all the test cases for pmt into + * a single test suite. As you create new test cases, add them here. + */ + +#include <qa_pmt.h> +#include <qa_pmt_prims.h> +#include <qa_pmt_unv.h> + +CppUnit::TestSuite * +qa_pmt::suite () +{ + CppUnit::TestSuite *s = new CppUnit::TestSuite ("pmt"); + + s->addTest (qa_pmt_prims::suite ()); + s->addTest (qa_pmt_unv::suite ()); + + return s; +} diff --git a/gruel/src/lib/pmt/qa_pmt.h b/gruel/src/lib/pmt/qa_pmt.h new file mode 100644 index 000000000..3de5872c7 --- /dev/null +++ b/gruel/src/lib/pmt/qa_pmt.h @@ -0,0 +1,37 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef INCLUDED_QA_PMT_H +#define INCLUDED_QA_PMT_H + +#include <gruel/attributes.h> +#include <cppunit/TestSuite.h> + +//! collect all the tests for pmt + +class __GR_ATTR_EXPORT qa_pmt { + public: + //! return suite of tests for all of pmt + static CppUnit::TestSuite *suite (); +}; + +#endif /* INCLUDED_QA_PMT_H */ diff --git a/gruel/src/lib/pmt/qa_pmt_prims.cc b/gruel/src/lib/pmt/qa_pmt_prims.cc new file mode 100644 index 000000000..3ae4d70b6 --- /dev/null +++ b/gruel/src/lib/pmt/qa_pmt_prims.cc @@ -0,0 +1,603 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006,2009,2010 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#include <qa_pmt_prims.h> +#include <cppunit/TestAssert.h> +#include <gruel/msg_passing.h> +#include <boost/format.hpp> +#include <cstdio> +#include <cstring> +#include <sstream> + +using namespace pmt; + +void +qa_pmt_prims::test_symbols() +{ + CPPUNIT_ASSERT(!pmt_is_symbol(PMT_T)); + CPPUNIT_ASSERT(!pmt_is_symbol(PMT_F)); + CPPUNIT_ASSERT_THROW(pmt_symbol_to_string(PMT_F), pmt_wrong_type); + + pmt_t sym1 = mp("test"); + CPPUNIT_ASSERT(pmt_is_symbol(sym1)); + CPPUNIT_ASSERT_EQUAL(std::string("test"), pmt_symbol_to_string(sym1)); + CPPUNIT_ASSERT(pmt_is_true(sym1)); + CPPUNIT_ASSERT(!pmt_is_false(sym1)); + + pmt_t sym2 = mp("foo"); + pmt_t sym3 = mp("test"); + CPPUNIT_ASSERT_EQUAL(sym1, sym3); + CPPUNIT_ASSERT(sym1 != sym2); + CPPUNIT_ASSERT(sym1 == sym3); + + static const int N = 2048; + std::vector<pmt_t> v1(N); + std::vector<pmt_t> v2(N); + + // generate a bunch of symbols + for (int i = 0; i < N; i++){ + std::string buf = str(boost::format("test-%d") % i); + v1[i] = mp(buf.c_str()); + } + + // confirm that they are all unique + for (int i = 0; i < N; i++) + for (int j = i + 1; j < N; j++) + CPPUNIT_ASSERT(v1[i] != v1[j]); + + // generate the same symbols again + for (int i = 0; i < N; i++){ + std::string buf = str(boost::format("test-%d") % i); + v2[i] = mp(buf.c_str()); + } + + // confirm that we get the same ones back + for (int i = 0; i < N; i++) + CPPUNIT_ASSERT(v1[i] == v2[i]); +} + +void +qa_pmt_prims::test_booleans() +{ + pmt_t sym = mp("test"); + CPPUNIT_ASSERT(pmt_is_bool(PMT_T)); + CPPUNIT_ASSERT(pmt_is_bool(PMT_F)); + CPPUNIT_ASSERT(!pmt_is_bool(sym)); + CPPUNIT_ASSERT_EQUAL(pmt_from_bool(false), PMT_F); + CPPUNIT_ASSERT_EQUAL(pmt_from_bool(true), PMT_T); + CPPUNIT_ASSERT_EQUAL(false, pmt_to_bool(PMT_F)); + CPPUNIT_ASSERT_EQUAL(true, pmt_to_bool(PMT_T)); + CPPUNIT_ASSERT_THROW(pmt_to_bool(sym), pmt_wrong_type); +} + +void +qa_pmt_prims::test_integers() +{ + pmt_t p1 = pmt_from_long(1); + pmt_t m1 = pmt_from_long(-1); + CPPUNIT_ASSERT(!pmt_is_integer(PMT_T)); + CPPUNIT_ASSERT(pmt_is_integer(p1)); + CPPUNIT_ASSERT(pmt_is_integer(m1)); + CPPUNIT_ASSERT_THROW(pmt_to_long(PMT_T), pmt_wrong_type); + CPPUNIT_ASSERT_EQUAL(-1L, pmt_to_long(m1)); + CPPUNIT_ASSERT_EQUAL(1L, pmt_to_long(p1)); +} + +void +qa_pmt_prims::test_uint64s() +{ + pmt_t p1 = pmt_from_uint64((uint64_t)1); + pmt_t m1 = pmt_from_uint64((uint64_t)8589934592ULL); + CPPUNIT_ASSERT(!pmt_is_uint64(PMT_T)); + CPPUNIT_ASSERT(pmt_is_uint64(p1)); + CPPUNIT_ASSERT(pmt_is_uint64(m1)); + CPPUNIT_ASSERT_THROW(pmt_to_uint64(PMT_T), pmt_wrong_type); + CPPUNIT_ASSERT_EQUAL((uint64_t)8589934592ULL, (uint64_t)pmt_to_uint64(m1)); + CPPUNIT_ASSERT_EQUAL((uint64_t)1ULL, (uint64_t)pmt_to_uint64(p1)); +} + +void +qa_pmt_prims::test_reals() +{ + pmt_t p1 = pmt_from_double(1); + pmt_t m1 = pmt_from_double(-1); + CPPUNIT_ASSERT(!pmt_is_real(PMT_T)); + CPPUNIT_ASSERT(pmt_is_real(p1)); + CPPUNIT_ASSERT(pmt_is_real(m1)); + CPPUNIT_ASSERT_THROW(pmt_to_double(PMT_T), pmt_wrong_type); + CPPUNIT_ASSERT_EQUAL(-1.0, pmt_to_double(m1)); + CPPUNIT_ASSERT_EQUAL(1.0, pmt_to_double(p1)); + CPPUNIT_ASSERT_EQUAL(1.0, pmt_to_double(pmt_from_long(1))); +} + +void +qa_pmt_prims::test_complexes() +{ + pmt_t p1 = pmt_make_rectangular(2, -3); + pmt_t m1 = pmt_make_rectangular(-3, 2); + pmt_t p2 = pmt_from_complex(2, -3); + pmt_t m2 = pmt_from_complex(-3, 2); + pmt_t p3 = pmt_from_complex(std::complex<double>(2, -3)); + pmt_t m3 = pmt_from_complex(std::complex<double>(-3, 2)); + CPPUNIT_ASSERT(!pmt_is_complex(PMT_T)); + CPPUNIT_ASSERT(pmt_is_complex(p1)); + CPPUNIT_ASSERT(pmt_is_complex(m1)); + CPPUNIT_ASSERT(pmt_is_complex(p2)); + CPPUNIT_ASSERT(pmt_is_complex(m2)); + CPPUNIT_ASSERT(pmt_is_complex(p3)); + CPPUNIT_ASSERT(pmt_is_complex(m3)); + CPPUNIT_ASSERT_THROW(pmt_to_complex(PMT_T), pmt_wrong_type); + CPPUNIT_ASSERT_EQUAL(std::complex<double>(2, -3), pmt_to_complex(p1)); + CPPUNIT_ASSERT_EQUAL(std::complex<double>(-3, 2), pmt_to_complex(m1)); + CPPUNIT_ASSERT_EQUAL(std::complex<double>(2, -3), pmt_to_complex(p2)); + CPPUNIT_ASSERT_EQUAL(std::complex<double>(-3, 2), pmt_to_complex(m2)); + CPPUNIT_ASSERT_EQUAL(std::complex<double>(2, -3), pmt_to_complex(p3)); + CPPUNIT_ASSERT_EQUAL(std::complex<double>(-3, 2), pmt_to_complex(m3)); + CPPUNIT_ASSERT_EQUAL(std::complex<double>(1.0, 0), pmt_to_complex(pmt_from_long(1))); + CPPUNIT_ASSERT_EQUAL(std::complex<double>(1.0, 0), pmt_to_complex(pmt_from_double(1.0))); +} + +void +qa_pmt_prims::test_pairs() +{ + CPPUNIT_ASSERT(pmt_is_null(PMT_NIL)); + CPPUNIT_ASSERT(!pmt_is_pair(PMT_NIL)); + pmt_t s1 = mp("s1"); + pmt_t s2 = mp("s2"); + pmt_t s3 = mp("s3"); + + + CPPUNIT_ASSERT_EQUAL((size_t)0, pmt_length(PMT_NIL)); + CPPUNIT_ASSERT_THROW(pmt_length(s1), pmt_wrong_type); + CPPUNIT_ASSERT_THROW(pmt_length(pmt_from_double(42)), pmt_wrong_type); + + pmt_t c1 = pmt_cons(s1, PMT_NIL); + CPPUNIT_ASSERT(pmt_is_pair(c1)); + CPPUNIT_ASSERT(!pmt_is_pair(s1)); + CPPUNIT_ASSERT_EQUAL(s1, pmt_car(c1)); + CPPUNIT_ASSERT_EQUAL(PMT_NIL, pmt_cdr(c1)); + CPPUNIT_ASSERT_EQUAL((size_t) 1, pmt_length(c1)); + + pmt_t c3 = pmt_cons(s3, PMT_NIL); + pmt_t c2 = pmt_cons(s2, c3); + pmt_set_cdr(c1, c2); + CPPUNIT_ASSERT_EQUAL(c2, pmt_cdr(c1)); + pmt_set_car(c1, s3); + CPPUNIT_ASSERT_EQUAL(s3, pmt_car(c1)); + CPPUNIT_ASSERT_EQUAL((size_t)1, pmt_length(c3)); + CPPUNIT_ASSERT_EQUAL((size_t)2, pmt_length(c2)); + + CPPUNIT_ASSERT_THROW(pmt_cdr(PMT_NIL), pmt_wrong_type); + CPPUNIT_ASSERT_THROW(pmt_car(PMT_NIL), pmt_wrong_type); + CPPUNIT_ASSERT_THROW(pmt_set_car(s1, PMT_NIL), pmt_wrong_type); + CPPUNIT_ASSERT_THROW(pmt_set_cdr(s1, PMT_NIL), pmt_wrong_type); +} + +void +qa_pmt_prims::test_vectors() +{ + static const size_t N = 3; + pmt_t v1 = pmt_make_vector(N, PMT_NIL); + CPPUNIT_ASSERT_EQUAL(N, pmt_length(v1)); + pmt_t s0 = mp("s0"); + pmt_t s1 = mp("s1"); + pmt_t s2 = mp("s2"); + + pmt_vector_set(v1, 0, s0); + pmt_vector_set(v1, 1, s1); + pmt_vector_set(v1, 2, s2); + + CPPUNIT_ASSERT_EQUAL(s0, pmt_vector_ref(v1, 0)); + CPPUNIT_ASSERT_EQUAL(s1, pmt_vector_ref(v1, 1)); + CPPUNIT_ASSERT_EQUAL(s2, pmt_vector_ref(v1, 2)); + + CPPUNIT_ASSERT_THROW(pmt_vector_ref(v1, N), pmt_out_of_range); + CPPUNIT_ASSERT_THROW(pmt_vector_set(v1, N, PMT_NIL), pmt_out_of_range); + + pmt_vector_fill(v1, s0); + for (size_t i = 0; i < N; i++) + CPPUNIT_ASSERT_EQUAL(s0, pmt_vector_ref(v1, i)); +} + +static void +check_tuple(size_t len, const std::vector<pmt_t> &s, pmt_t t) +{ + CPPUNIT_ASSERT_EQUAL(true, pmt_is_tuple(t)); + CPPUNIT_ASSERT_EQUAL(len, pmt_length(t)); + + for (size_t i = 0; i < len; i++) + CPPUNIT_ASSERT_EQUAL(s[i], pmt_tuple_ref(t, i)); + +} + +void +qa_pmt_prims::test_tuples() +{ + pmt_t v = pmt_make_vector(10, PMT_NIL); + std::vector<pmt_t> s(10); + for (size_t i = 0; i < 10; i++){ + std::ostringstream os; + os << "s" << i; + s[i] = mp(os.str()); + pmt_vector_set(v, i, s[i]); + } + + + pmt_t t; + + t = pmt_make_tuple(); + check_tuple(0, s, t); + + t = pmt_make_tuple(s[0]); + check_tuple(1, s, t); + + CPPUNIT_ASSERT(pmt_is_vector(v)); + CPPUNIT_ASSERT(!pmt_is_tuple(v)); + CPPUNIT_ASSERT(pmt_is_tuple(t)); + CPPUNIT_ASSERT(!pmt_is_vector(t)); + + t = pmt_make_tuple(s[0], s[1]); + check_tuple(2, s, t); + + t = pmt_make_tuple(s[0], s[1], s[2]); + check_tuple(3, s, t); + + t = pmt_make_tuple(s[0], s[1], s[2], s[3]); + check_tuple(4, s, t); + + t = pmt_make_tuple(s[0], s[1], s[2], s[3], s[4]); + check_tuple(5, s, t); + + t = pmt_make_tuple(s[0], s[1], s[2], s[3], s[4], s[5]); + check_tuple(6, s, t); + + t = pmt_make_tuple(s[0], s[1], s[2], s[3], s[4], s[5], s[6]); + check_tuple(7, s, t); + + t = pmt_make_tuple(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7]); + check_tuple(8, s, t); + + t = pmt_make_tuple(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8]); + check_tuple(9, s, t); + + t = pmt_make_tuple(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9]); + check_tuple(10, s, t); + + t = pmt_make_tuple(s[0], s[1], s[2]); + CPPUNIT_ASSERT_THROW(pmt_tuple_ref(t, 3), pmt_out_of_range); + CPPUNIT_ASSERT_THROW(pmt_vector_ref(t, 0), pmt_wrong_type); + CPPUNIT_ASSERT_THROW(pmt_tuple_ref(v, 0), pmt_wrong_type); + + t = pmt_make_tuple(s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9]); + pmt_t t2 = pmt_to_tuple(v); + CPPUNIT_ASSERT_EQUAL(size_t(10), pmt_length(v)); + CPPUNIT_ASSERT(pmt_equal(t, t2)); + //std::cout << v << std::endl; + //std::cout << t2 << std::endl; + + + t = pmt_make_tuple(s[0], s[1], s[2]); + pmt_t list0 = pmt_list3(s[0], s[1], s[2]); + CPPUNIT_ASSERT_EQUAL(size_t(3), pmt_length(list0)); + t2 = pmt_to_tuple(list0); + CPPUNIT_ASSERT_EQUAL(size_t(3), pmt_length(t2)); + CPPUNIT_ASSERT(pmt_equal(t, t2)); +} + +void +qa_pmt_prims::test_equivalence() +{ + pmt_t s0 = mp("s0"); + pmt_t s1 = mp("s1"); + pmt_t s2 = mp("s2"); + pmt_t list0 = pmt_cons(s0, pmt_cons(s1, pmt_cons(s2, PMT_NIL))); + pmt_t list1 = pmt_cons(s0, pmt_cons(s1, pmt_cons(s2, PMT_NIL))); + pmt_t i0 = pmt_from_long(42); + pmt_t i1 = pmt_from_long(42); + pmt_t r0 = pmt_from_double(42); + pmt_t r1 = pmt_from_double(42); + pmt_t r2 = pmt_from_double(43); + + CPPUNIT_ASSERT(pmt_eq(s0, s0)); + CPPUNIT_ASSERT(!pmt_eq(s0, s1)); + CPPUNIT_ASSERT(pmt_eqv(s0, s0)); + CPPUNIT_ASSERT(!pmt_eqv(s0, s1)); + + CPPUNIT_ASSERT(pmt_eqv(i0, i1)); + CPPUNIT_ASSERT(pmt_eqv(r0, r1)); + CPPUNIT_ASSERT(!pmt_eqv(r0, r2)); + CPPUNIT_ASSERT(!pmt_eqv(i0, r0)); + + CPPUNIT_ASSERT(!pmt_eq(list0, list1)); + CPPUNIT_ASSERT(!pmt_eqv(list0, list1)); + CPPUNIT_ASSERT(pmt_equal(list0, list1)); + + pmt_t v0 = pmt_make_vector(3, s0); + pmt_t v1 = pmt_make_vector(3, s0); + pmt_t v2 = pmt_make_vector(4, s0); + CPPUNIT_ASSERT(!pmt_eqv(v0, v1)); + CPPUNIT_ASSERT(pmt_equal(v0, v1)); + CPPUNIT_ASSERT(!pmt_equal(v0, v2)); + + pmt_vector_set(v0, 0, list0); + pmt_vector_set(v0, 1, list0); + pmt_vector_set(v1, 0, list1); + pmt_vector_set(v1, 1, list1); + CPPUNIT_ASSERT(pmt_equal(v0, v1)); +} + +void +qa_pmt_prims::test_misc() +{ + pmt_t k0 = mp("k0"); + pmt_t k1 = mp("k1"); + pmt_t k2 = mp("k2"); + pmt_t k3 = mp("k3"); + pmt_t v0 = mp("v0"); + pmt_t v1 = mp("v1"); + pmt_t v2 = mp("v2"); + pmt_t p0 = pmt_cons(k0, v0); + pmt_t p1 = pmt_cons(k1, v1); + pmt_t p2 = pmt_cons(k2, v2); + + pmt_t alist = pmt_cons(p0, pmt_cons(p1, pmt_cons(p2, PMT_NIL))); + CPPUNIT_ASSERT(pmt_eq(p1, pmt_assv(k1, alist))); + CPPUNIT_ASSERT(pmt_eq(PMT_F, pmt_assv(k3, alist))); + + pmt_t keys = pmt_cons(k0, pmt_cons(k1, pmt_cons(k2, PMT_NIL))); + pmt_t vals = pmt_cons(v0, pmt_cons(v1, pmt_cons(v2, PMT_NIL))); + CPPUNIT_ASSERT(pmt_equal(keys, pmt_map(pmt_car, alist))); + CPPUNIT_ASSERT(pmt_equal(vals, pmt_map(pmt_cdr, alist))); +} + +void +qa_pmt_prims::test_dict() +{ + pmt_t dict = pmt_make_dict(); + CPPUNIT_ASSERT(pmt_is_dict(dict)); + + pmt_t k0 = mp("k0"); + pmt_t k1 = mp("k1"); + pmt_t k2 = mp("k2"); + pmt_t k3 = mp("k3"); + pmt_t v0 = mp("v0"); + pmt_t v1 = mp("v1"); + pmt_t v2 = mp("v2"); + pmt_t v3 = mp("v3"); + pmt_t not_found = pmt_cons(PMT_NIL, PMT_NIL); + + CPPUNIT_ASSERT(!pmt_dict_has_key(dict, k0)); + dict = pmt_dict_add(dict, k0, v0); + CPPUNIT_ASSERT(pmt_dict_has_key(dict, k0)); + CPPUNIT_ASSERT(pmt_eqv(pmt_dict_ref(dict, k0, not_found), v0)); + CPPUNIT_ASSERT(pmt_eqv(pmt_dict_ref(dict, k1, not_found), not_found)); + dict = pmt_dict_add(dict, k1, v1); + dict = pmt_dict_add(dict, k2, v2); + CPPUNIT_ASSERT(pmt_eqv(pmt_dict_ref(dict, k1, not_found), v1)); + dict = pmt_dict_add(dict, k1, v3); + CPPUNIT_ASSERT(pmt_eqv(pmt_dict_ref(dict, k1, not_found), v3)); + + pmt_t keys = pmt_list3(k1, k2, k0); + pmt_t vals = pmt_list3(v3, v2, v0); + //std::cout << "pmt_dict_keys: " << pmt_dict_keys(dict) << std::endl; + //std::cout << "pmt_dict_values: " << pmt_dict_values(dict) << std::endl; + CPPUNIT_ASSERT(pmt_equal(keys, pmt_dict_keys(dict))); + CPPUNIT_ASSERT(pmt_equal(vals, pmt_dict_values(dict))); +} + +void +qa_pmt_prims::test_io() +{ + pmt_t k0 = mp("k0"); + pmt_t k1 = mp("k1"); + pmt_t k2 = mp("k2"); + pmt_t k3 = mp("k3"); + + CPPUNIT_ASSERT_EQUAL(std::string("k0"), pmt_write_string(k0)); +} + +void +qa_pmt_prims::test_lists() +{ + pmt_t s0 = mp("s0"); + pmt_t s1 = mp("s1"); + pmt_t s2 = mp("s2"); + pmt_t s3 = mp("s3"); + + pmt_t l1 = pmt_list4(s0, s1, s2, s3); + pmt_t l2 = pmt_list3(s0, s1, s2); + pmt_t l3 = pmt_list_add(l2, s3); + CPPUNIT_ASSERT(pmt_equal(l1, l3)); +} + +// ------------------------------------------------------------------------ + +// class foo is used in test_any below. +// It can't be declared in the scope of test_any because of template +// namespace problems. + +class foo { +public: + double d_double; + int d_int; + foo(double d=0, int i=0) : d_double(d), d_int(i) {} +}; + +bool operator==(const foo &a, const foo &b) +{ + return a.d_double == b.d_double && a.d_int == b.d_int; +} + +std::ostream& operator<<(std::ostream &os, const foo obj) +{ + os << "<foo: " << obj.d_double << ", " << obj.d_int << ">"; + return os; +} + +void +qa_pmt_prims::test_any() +{ + boost::any a0; + boost::any a1; + boost::any a2; + + a0 = std::string("Hello!"); + a1 = 42; + a2 = foo(3.250, 21); + + pmt_t p0 = pmt_make_any(a0); + pmt_t p1 = pmt_make_any(a1); + pmt_t p2 = pmt_make_any(a2); + + CPPUNIT_ASSERT_EQUAL(std::string("Hello!"), + boost::any_cast<std::string>(pmt_any_ref(p0))); + + CPPUNIT_ASSERT_EQUAL(42, + boost::any_cast<int>(pmt_any_ref(p1))); + + CPPUNIT_ASSERT_EQUAL(foo(3.250, 21), + boost::any_cast<foo>(pmt_any_ref(p2))); +} + +// ------------------------------------------------------------------------ + +class qa_pmt_msg_accepter_nop : public gruel::msg_accepter { +public: + qa_pmt_msg_accepter_nop(){}; + ~qa_pmt_msg_accepter_nop(); + void post(pmt_t,pmt_t){}; +}; + +qa_pmt_msg_accepter_nop::~qa_pmt_msg_accepter_nop(){} + +void +qa_pmt_prims::test_msg_accepter() +{ + pmt_t sym = mp("my-symbol"); + + boost::any a0; + a0 = std::string("Hello!"); + pmt_t p0 = pmt_make_any(a0); + + gruel::msg_accepter_sptr ma0 = gruel::msg_accepter_sptr(new qa_pmt_msg_accepter_nop()); + pmt_t p1 = pmt_make_msg_accepter(ma0); + + CPPUNIT_ASSERT_EQUAL(ma0.get(), pmt_msg_accepter_ref(p1).get()); + + CPPUNIT_ASSERT_THROW(pmt_msg_accepter_ref(sym), pmt_wrong_type); + CPPUNIT_ASSERT_THROW(pmt_msg_accepter_ref(p0), pmt_wrong_type); + + // just confirm interfaces on send are OK + pmt_t port(pmt_intern("port")); + gruel::send(ma0.get(), port, sym); + gruel::send(ma0, port, sym); + gruel::send(p1, port, sym); + +} + +// ------------------------------------------------------------------------ + +void +qa_pmt_prims::test_serialize() +{ + std::stringbuf sb; // fake channel + pmt_t a = mp("a"); + pmt_t b = mp("b"); + pmt_t c = mp("c"); + + sb.str(""); // reset channel to empty + + // write stuff to channel + + pmt_serialize(PMT_NIL, sb); + pmt_serialize(mp("foobarvia"), sb); + pmt_serialize(pmt_from_long(123456789), sb); + pmt_serialize(pmt_from_long(-123456789), sb); + pmt_serialize(pmt_cons(PMT_NIL, PMT_NIL), sb); + pmt_serialize(pmt_cons(a, b), sb); + pmt_serialize(pmt_list1(a), sb); + pmt_serialize(pmt_list2(a, b), sb); + pmt_serialize(pmt_list3(a, b, c), sb); + pmt_serialize(pmt_list3(a, pmt_list3(c, b, a), c), sb); + pmt_serialize(PMT_T, sb); + pmt_serialize(PMT_F, sb); + + // read it back + + CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), PMT_NIL)); + CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), mp("foobarvia"))); + CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), pmt_from_long(123456789))); + CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), pmt_from_long(-123456789))); + CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), pmt_cons(PMT_NIL, PMT_NIL))); + CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), pmt_cons(a, b))); + CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), pmt_list1(a))); + CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), pmt_list2(a, b))); + CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), pmt_list3(a, b, c))); + CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), pmt_list3(a, pmt_list3(c, b, a), c))); + CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), PMT_T)); + CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), PMT_F)); + + CPPUNIT_ASSERT(pmt_equal(pmt_deserialize(sb), PMT_EOF)); // last item + + + // FIXME add tests for real, complex, vector, uniform-vector, dict + // FIXME add tests for malformed input too. + +} + +void +qa_pmt_prims::test_sets() +{ + pmt_t s1 = mp("s1"); + pmt_t s2 = mp("s2"); + pmt_t s3 = mp("s3"); + + pmt_t l1 = pmt_list1(s1); + pmt_t l2 = pmt_list2(s2,s3); + pmt_t l3 = pmt_list3(s1,s2,s3); + + CPPUNIT_ASSERT(pmt_is_pair(pmt_memq(s1,l1))); + CPPUNIT_ASSERT(pmt_is_false(pmt_memq(s3,l1))); + + CPPUNIT_ASSERT(pmt_subsetp(l1,l3)); + CPPUNIT_ASSERT(pmt_subsetp(l2,l3)); + CPPUNIT_ASSERT(!pmt_subsetp(l1,l2)); + CPPUNIT_ASSERT(!pmt_subsetp(l2,l1)); + CPPUNIT_ASSERT(!pmt_subsetp(l3,l2)); +} + +void +qa_pmt_prims::test_sugar() +{ + CPPUNIT_ASSERT(pmt_is_symbol(mp("my-symbol"))); + CPPUNIT_ASSERT_EQUAL((long) 10, pmt_to_long(mp(10))); + CPPUNIT_ASSERT_EQUAL((double) 1e6, pmt_to_double(mp(1e6))); + CPPUNIT_ASSERT_EQUAL(std::complex<double>(2, 3), + pmt_to_complex(mp(std::complex<double>(2, 3)))); + + int buf[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + pmt_t blob = mp(buf, sizeof(buf)); + const void *data = pmt_blob_data(blob); + size_t nbytes = pmt_blob_length(blob); + CPPUNIT_ASSERT_EQUAL(sizeof(buf), nbytes); + CPPUNIT_ASSERT(memcmp(buf, data, nbytes) == 0); +} diff --git a/gruel/src/lib/pmt/qa_pmt_prims.h b/gruel/src/lib/pmt/qa_pmt_prims.h new file mode 100644 index 000000000..a407509b2 --- /dev/null +++ b/gruel/src/lib/pmt/qa_pmt_prims.h @@ -0,0 +1,77 @@ +/* -*- c++ -*- */ +/* + * Copyright 2006 Free Software Foundation, Inc. + * + * This file is part of GNU Radio + * + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + * + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GNU Radio; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ +#ifndef INCLUDED_QA_PMT_PRIMS_H +#define INCLUDED_QA_PMT_PRIMS_H + +#include <gruel/attributes.h> +#include <gruel/api.h> //reason: suppress warnings +#include <cppunit/extensions/HelperMacros.h> +#include <cppunit/TestCase.h> + +class __GR_ATTR_EXPORT qa_pmt_prims : public CppUnit::TestCase { + + CPPUNIT_TEST_SUITE(qa_pmt_prims); + CPPUNIT_TEST(test_symbols); + CPPUNIT_TEST(test_booleans); + CPPUNIT_TEST(test_integers); + CPPUNIT_TEST(test_uint64s); + CPPUNIT_TEST(test_reals); + CPPUNIT_TEST(test_complexes); + CPPUNIT_TEST(test_pairs); + CPPUNIT_TEST(test_vectors); + CPPUNIT_TEST(test_tuples); + CPPUNIT_TEST(test_equivalence); + CPPUNIT_TEST(test_misc); + CPPUNIT_TEST(test_dict); + CPPUNIT_TEST(test_any); + CPPUNIT_TEST(test_msg_accepter); + CPPUNIT_TEST(test_io); + CPPUNIT_TEST(test_lists); + CPPUNIT_TEST(test_serialize); + CPPUNIT_TEST(test_sets); + CPPUNIT_TEST(test_sugar); + CPPUNIT_TEST_SUITE_END(); + + private: + void test_symbols(); + void test_booleans(); + void test_integers(); + void test_uint64s(); + void test_reals(); + void test_complexes(); + void test_pairs(); + void test_vectors(); + void test_tuples(); + void test_equivalence(); + void test_misc(); + void test_dict(); + void test_any(); + void test_msg_accepter(); + void test_io(); + void test_lists(); + void test_serialize(); + void test_sets(); + void test_sugar(); +}; + +#endif /* INCLUDED_QA_PMT_PRIMS_H */ + diff --git a/gruel/src/lib/pmt/unv_qa_template.cc.t b/gruel/src/lib/pmt/unv_qa_template.cc.t new file mode 100644 index 000000000..1e2c8e8eb --- /dev/null +++ b/gruel/src/lib/pmt/unv_qa_template.cc.t @@ -0,0 +1,35 @@ +void +qa_pmt_unv::test_@TAG@vector() +{ + static const size_t N = 3; + pmt_t v1 = pmt_make_@TAG@vector(N, 0); + CPPUNIT_ASSERT_EQUAL(N, pmt_length(v1)); + @TYPE@ s0 = @TYPE@(10); + @TYPE@ s1 = @TYPE@(20); + @TYPE@ s2 = @TYPE@(30); + + pmt_@TAG@vector_set(v1, 0, s0); + pmt_@TAG@vector_set(v1, 1, s1); + pmt_@TAG@vector_set(v1, 2, s2); + + CPPUNIT_ASSERT_EQUAL(s0, pmt_@TAG@vector_ref(v1, 0)); + CPPUNIT_ASSERT_EQUAL(s1, pmt_@TAG@vector_ref(v1, 1)); + CPPUNIT_ASSERT_EQUAL(s2, pmt_@TAG@vector_ref(v1, 2)); + + CPPUNIT_ASSERT_THROW(pmt_@TAG@vector_ref(v1, N), pmt_out_of_range); + CPPUNIT_ASSERT_THROW(pmt_@TAG@vector_set(v1, N, @TYPE@(0)), pmt_out_of_range); + + size_t len; + const @TYPE@ *rd = pmt_@TAG@vector_elements(v1, len); + CPPUNIT_ASSERT_EQUAL(len, N); + CPPUNIT_ASSERT_EQUAL(s0, rd[0]); + CPPUNIT_ASSERT_EQUAL(s1, rd[1]); + CPPUNIT_ASSERT_EQUAL(s2, rd[2]); + + @TYPE@ *wr = pmt_@TAG@vector_writable_elements(v1, len); + CPPUNIT_ASSERT_EQUAL(len, N); + wr[0] = @TYPE@(0); + CPPUNIT_ASSERT_EQUAL(@TYPE@(0), wr[0]); + CPPUNIT_ASSERT_EQUAL(s1, wr[1]); + CPPUNIT_ASSERT_EQUAL(s2, wr[2]); +} diff --git a/gruel/src/lib/pmt/unv_template.cc.t b/gruel/src/lib/pmt/unv_template.cc.t new file mode 100644 index 000000000..1ed505e29 --- /dev/null +++ b/gruel/src/lib/pmt/unv_template.cc.t @@ -0,0 +1,141 @@ +//////////////////////////////////////////////////////////////////////////// +// pmt_@TAG@vector +//////////////////////////////////////////////////////////////////////////// + +namespace pmt { + +static pmt_@TAG@vector * +_@TAG@vector(pmt_t x) +{ + return dynamic_cast<pmt_@TAG@vector*>(x.get()); +} + + +pmt_@TAG@vector::pmt_@TAG@vector(size_t k, @TYPE@ fill) + : d_v(k) +{ + for (size_t i = 0; i < k; i++) + d_v[i] = fill; +} + +pmt_@TAG@vector::pmt_@TAG@vector(size_t k, const @TYPE@ *data) + : d_v(k) +{ + for (size_t i = 0; i < k; i++) + d_v[i] = data[i]; +} + +@TYPE@ +pmt_@TAG@vector::ref(size_t k) const +{ + if (k >= length()) + throw pmt_out_of_range("pmt_@TAG@vector_ref", pmt_from_long(k)); + return d_v[k]; +} + +void +pmt_@TAG@vector::set(size_t k, @TYPE@ x) +{ + if (k >= length()) + throw pmt_out_of_range("pmt_@TAG@vector_set", pmt_from_long(k)); + d_v[k] = x; +} + +const @TYPE@ * +pmt_@TAG@vector::elements(size_t &len) +{ + len = length(); + return &d_v[0]; +} + +@TYPE@ * +pmt_@TAG@vector::writable_elements(size_t &len) +{ + len = length(); + return &d_v[0]; +} + +const void* +pmt_@TAG@vector::uniform_elements(size_t &len) +{ + len = length() * sizeof(@TYPE@); + return &d_v[0]; +} + +void* +pmt_@TAG@vector::uniform_writable_elements(size_t &len) +{ + len = length() * sizeof(@TYPE@); + return &d_v[0]; +} + +bool +pmt_is_@TAG@vector(pmt_t obj) +{ + return obj->is_@TAG@vector(); +} + +pmt_t +pmt_make_@TAG@vector(size_t k, @TYPE@ fill) +{ + return pmt_t(new pmt_@TAG@vector(k, fill)); +} + +pmt_t +pmt_init_@TAG@vector(size_t k, const @TYPE@ *data) +{ + return pmt_t(new pmt_@TAG@vector(k, data)); +} + +pmt_t +pmt_init_@TAG@vector(size_t k, const std::vector< @TYPE@ > &data) +{ + + return pmt_t(new pmt_@TAG@vector(k, &data[0])); +} + +@TYPE@ +pmt_@TAG@vector_ref(pmt_t vector, size_t k) +{ + if (!vector->is_@TAG@vector()) + throw pmt_wrong_type("pmt_@TAG@vector_ref", vector); + return _@TAG@vector(vector)->ref(k); +} + +void +pmt_@TAG@vector_set(pmt_t vector, size_t k, @TYPE@ obj) +{ + if (!vector->is_@TAG@vector()) + throw pmt_wrong_type("pmt_@TAG@vector_set", vector); + _@TAG@vector(vector)->set(k, obj); +} + +const @TYPE@ * +pmt_@TAG@vector_elements(pmt_t vector, size_t &len) +{ + if (!vector->is_@TAG@vector()) + throw pmt_wrong_type("pmt_@TAG@vector_elements", vector); + return _@TAG@vector(vector)->elements(len); +} + +const std::vector< @TYPE@ > +pmt_@TAG@vector_elements(pmt_t vector) +{ + if (!vector->is_@TAG@vector()) + throw pmt_wrong_type("pmt_@TAG@vector_elements", vector); + size_t len; + const @TYPE@ *array = _@TAG@vector(vector)->elements(len); + const std::vector< @TYPE@ > vec(array, array+len); + return vec; +} + + +@TYPE@ * +pmt_@TAG@vector_writable_elements(pmt_t vector, size_t &len) +{ + if (!vector->is_@TAG@vector()) + throw pmt_wrong_type("pmt_@TAG@vector_writable_elements", vector); + return _@TAG@vector(vector)->writable_elements(len); +} + +} /* namespace pmt */ diff --git a/gruel/src/lib/pmt/unv_template.h.t b/gruel/src/lib/pmt/unv_template.h.t new file mode 100644 index 000000000..83ba0be0f --- /dev/null +++ b/gruel/src/lib/pmt/unv_template.h.t @@ -0,0 +1,23 @@ + +//////////////////////////////////////////////////////////////////////////// +// pmt_@TAG@vector +//////////////////////////////////////////////////////////////////////////// + +class pmt_@TAG@vector : public pmt_uniform_vector +{ + std::vector< @TYPE@ > d_v; + +public: + pmt_@TAG@vector(size_t k, @TYPE@ fill); + pmt_@TAG@vector(size_t k, const @TYPE@ *data); + // ~pmt_@TAG@vector(); + + bool is_@TAG@vector() const { return true; } + size_t length() const { return d_v.size(); } + @TYPE@ ref(size_t k) const; + void set(size_t k, @TYPE@ x); + const @TYPE@ *elements(size_t &len); + @TYPE@ *writable_elements(size_t &len); + const void *uniform_elements(size_t &len); + void *uniform_writable_elements(size_t &len); +}; |