Merged branch 'msg-passing' from http://gnuradio.org/git/eb.git
authorJohnathan Corgan <jcorgan@corganenterprises.com>
Sat, 15 Aug 2009 16:28:54 +0000 (09:28 -0700)
committerJohnathan Corgan <jcorgan@corganenterprises.com>
Sat, 15 Aug 2009 16:28:54 +0000 (09:28 -0700)
This is work in progress on the message passing implementation.

Passes distcheck.

Signed-off-by: Johnathan Corgan <jcorgan@corganenterprises.com>
20 files changed:
gnuradio-core/src/lib/runtime/Makefile.am
gnuradio-core/src/lib/runtime/gr_basic_block.cc
gnuradio-core/src/lib/runtime/gr_basic_block.h
gnuradio-core/src/lib/runtime/gr_block_detail.cc
gnuradio-core/src/lib/runtime/gr_block_detail.h
gnuradio-core/src/lib/runtime/gr_msg_accepter.cc [new file with mode: 0644]
gnuradio-core/src/lib/runtime/gr_msg_accepter.h [new file with mode: 0644]
gnuradio-core/src/lib/runtime/gr_tpb_detail.cc
gnuradio-core/src/lib/runtime/gr_tpb_detail.h
gnuradio-core/src/lib/runtime/gr_tpb_thread_body.cc
gruel/src/include/gruel/Makefile.am
gruel/src/include/gruel/msg_accepter.h
gruel/src/include/gruel/msg_accepter_msgq.h
gruel/src/include/gruel/pmt.h
gruel/src/include/gruel/send.h [new file with mode: 0644]
gruel/src/lib/pmt/pmt.cc
gruel/src/lib/pmt/pmt_int.h
gruel/src/lib/pmt/pmt_io.cc
gruel/src/lib/pmt/qa_pmt_prims.cc
gruel/src/lib/pmt/qa_pmt_prims.h

index 14ab464ad257835cdc579cf896386b004dd04b1d..b0e80427700c649efbb25bf0e674a96be839e775 100644 (file)
@@ -44,6 +44,7 @@ libruntime_la_SOURCES =                       \
        gr_io_signature.cc                      \
        gr_local_sighandler.cc                  \
        gr_message.cc                           \
+       gr_msg_accepter.cc                      \
        gr_msg_handler.cc                       \
        gr_msg_queue.cc                         \
        gr_pagesize.cc                          \
@@ -96,6 +97,7 @@ grinclude_HEADERS =                           \
        gr_io_signature.h                       \
        gr_local_sighandler.h                   \
        gr_message.h                            \
+       gr_msg_accepter.h                       \
        gr_msg_handler.h                        \
        gr_msg_queue.h                          \
        gr_pagesize.h                           \
index 71ccc02454c591d21eb31efd094c7da063de5725..2fa1066cb9b99f5045d48d5de7dbd4a059d0f582 100644 (file)
@@ -41,8 +41,7 @@ gr_basic_block_ncurrently_allocated()
 gr_basic_block::gr_basic_block(const std::string &name,
                                gr_io_signature_sptr input_signature,
                                gr_io_signature_sptr output_signature) 
-  : gruel::msg_accepter_msgq(gruel::make_msg_queue(0)),
-    d_name(name),
+  : d_name(name),
     d_input_signature(input_signature),
     d_output_signature(output_signature),
     d_unique_id(s_next_id++),
index 27ec0fd89b1d44ed39745fd835956cb92122b307..b8797fdc678038d49075b0faf94cce8176ca5267 100644 (file)
@@ -26,7 +26,7 @@
 #include <gr_runtime_types.h>
 #include <gr_sptr_magic.h>
 #include <boost/enable_shared_from_this.hpp>
-#include <gruel/msg_accepter_msgq.h>
+#include <gr_msg_accepter.h>
 #include <string>
 
 /*!
@@ -40,7 +40,7 @@
  * signal processing functions.
  */
 
-class gr_basic_block : gruel::msg_accepter_msgq, public boost::enable_shared_from_this<gr_basic_block>
+class gr_basic_block : public gr_msg_accepter, public boost::enable_shared_from_this<gr_basic_block>
 {
 protected:
     friend class gr_flowgraph;
index ae1ea25628d63631df41dcd4924fa85cdfa1a8ed..d33dfed8461da2903be450d20b8de9fd4316de53 100644 (file)
@@ -106,3 +106,10 @@ gr_block_detail::produce_each (int how_many_items)
     for (int i = 0; i < noutputs (); i++)
       d_output[i]->update_write_pointer (how_many_items);
 }
+
+
+void
+gr_block_detail::_post(pmt::pmt_t msg)
+{
+  d_tpb.insert_tail(msg);
+}
index 2856c402c7a7925a5d8f762adc9d2eb7f5861633..9d63586024fd57030557951a2286476b4c1a2687 100644 (file)
@@ -79,6 +79,12 @@ class gr_block_detail {
   void produce_each (int how_many_items);
 
 
+  /*!
+   * Accept msg, place in queue, arrange for thread to be awakened if it's not already.
+   */
+  void _post(pmt::pmt_t msg);
+
+
   gr_tpb_detail                             d_tpb;     // used by thread-per-block scheduler
 
   // ----------------------------------------------------------------------------
diff --git a/gnuradio-core/src/lib/runtime/gr_msg_accepter.cc b/gnuradio-core/src/lib/runtime/gr_msg_accepter.cc
new file mode 100644 (file)
index 0000000..89876ae
--- /dev/null
@@ -0,0 +1,59 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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.
+ */
+
+#if HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <gr_msg_accepter.h>
+#include <gr_block.h>
+#include <gr_block_detail.h>
+#include <gr_hier_block2.h>
+#include <stdexcept>
+
+using namespace pmt;
+
+gr_msg_accepter::gr_msg_accepter()
+{
+}
+
+gr_msg_accepter::~gr_msg_accepter()
+{
+  // NOP, required as virtual destructor
+}
+
+void
+gr_msg_accepter::post(pmt_t msg)
+{
+  // Notify derived class, handled case by case
+  gr_block *p = dynamic_cast<gr_block *>(this);
+  if (p) { 
+    p->detail()->_post(msg);
+    return;
+  }
+  gr_hier_block2 *p2 = dynamic_cast<gr_hier_block2 *>(this);
+  if (p2){
+    // FIXME do the right thing
+    return;
+  }
+
+  throw std::runtime_error("unknown derived class");
+}
diff --git a/gnuradio-core/src/lib/runtime/gr_msg_accepter.h b/gnuradio-core/src/lib/runtime/gr_msg_accepter.h
new file mode 100644 (file)
index 0000000..79a631f
--- /dev/null
@@ -0,0 +1,42 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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.
+ */
+
+#ifndef INCLUDED_GR_MSG_ACCEPTER_H
+#define INCLUDED_GR_MSG_ACCEPTER_H
+
+#include <gruel/msg_accepter.h>
+#include <gruel/pmt.h>
+
+/*!
+ * \brief Accepts messages and inserts them into a message queue, then notifies
+ * subclass gr_basic_block there is a message pending.
+ */
+class gr_msg_accepter : public gruel::msg_accepter
+{
+public:
+  gr_msg_accepter();
+  ~gr_msg_accepter();
+
+  void post(pmt::pmt_t msg);
+
+};
+
+#endif /* INCLUDED_GR_MSG_ACCEPTER_H */
index 02e8deed88b90a8fda7326977ab6279c918995fe..c6311ccaa3efefd9ef62342231b0ad73aadab789 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- c++ -*- */
 /*
- * Copyright 2008 Free Software Foundation, Inc.
+ * Copyright 2008,2009 Free Software Foundation, Inc.
  * 
  * This file is part of GNU Radio
  * 
@@ -27,6 +27,8 @@
 #include <gr_block_detail.h>
 #include <gr_buffer.h>
 
+using namespace pmt;
+
 /*
  * We assume that no worker threads are ever running when the
  * graph structure is being manipulated, thus it's safe for us to poke
@@ -65,3 +67,44 @@ gr_tpb_detail::notify_neighbors(gr_block_detail *d)
   notify_downstream(d);
   notify_upstream(d);
 }
+
+void
+gr_tpb_detail::insert_tail(pmt::pmt_t msg)
+{
+  gruel::scoped_lock guard(mutex);
+
+  msg_queue.push_back(msg);
+
+  // wake up thread if BLKD_IN or BLKD_OUT
+  input_cond.notify_one();
+  output_cond.notify_one();
+}
+
+pmt_t 
+gr_tpb_detail::delete_head_nowait()
+{
+  gruel::scoped_lock guard(mutex);
+
+  if (empty_p())
+    return pmt_t();
+
+  pmt_t m(msg_queue.front());
+  msg_queue.pop_front();
+
+  return m;
+}
+
+/*
+ * Caller must already be holding the mutex
+ */
+pmt_t 
+gr_tpb_detail::delete_head_nowait_already_holding_mutex()
+{
+  if (empty_p())
+    return pmt_t();
+
+  pmt_t m(msg_queue.front());
+  msg_queue.pop_front();
+
+  return m;
+}
index ab955240b3ad0daaad399ed12cccd1080c41b57f..acfa264c7c412d02a39ce3f6d1c7e32dd48f92dc 100644 (file)
@@ -22,6 +22,8 @@
 #define INCLUDED_GR_TPB_DETAIL_H
 
 #include <gruel/thread.h>
+#include <deque>
+#include <gruel/pmt.h>
 
 class gr_block_detail;
 
@@ -36,9 +38,12 @@ struct gr_tpb_detail {
   bool                         output_changed;
   gruel::condition_variable    output_cond;
 
-  gr_tpb_detail()
-    : input_changed(false), output_changed(false) {}
+private:
+  std::deque<pmt::pmt_t>       msg_queue;
 
+public:
+  gr_tpb_detail()
+    : input_changed(false), output_changed(false) { }
 
   //! Called by us to tell all our upstream blocks that their output may have changed.
   void notify_upstream(gr_block_detail *d);
@@ -56,6 +61,23 @@ struct gr_tpb_detail {
     input_changed = false;
     output_changed = false;
   }
+  
+  //! is the queue empty?
+  bool empty_p() const { return msg_queue.empty(); }
+
+  //| Acquires and release the mutex   
+  void insert_tail(pmt::pmt_t msg);
+
+  /*!
+   * \returns returns pmt at head of queue or pmt_t() if empty.
+   */
+  pmt::pmt_t delete_head_nowait();
+
+  /*!
+   * \returns returns pmt at head of queue or pmt_t() if empty.
+   * Caller must already be holding the mutex
+   */
+  pmt::pmt_t delete_head_nowait_already_holding_mutex();
 
 private:
 
index 458b16d64cd436ee38f052f68aa8fa1071523d79..03eef17d937f63927f4723bc623b0474af17357c 100644 (file)
 #include <gr_tpb_thread_body.h>
 #include <iostream>
 #include <boost/thread.hpp>
+#include <gruel/pmt.h>
+
+using namespace pmt;
 
 gr_tpb_thread_body::gr_tpb_thread_body(gr_block_sptr block)
   : d_exec(block)
 {
   // std::cerr << "gr_tpb_thread_body: " << block << std::endl;
 
-  gr_block_detail      *d = block->detail().get();
+  gr_block_detail *d = block->detail().get();
   gr_block_executor::state s;
+  pmt_t msg;
+
 
   while (1){
     boost::this_thread::interruption_point();
+    // handle any queued up messages
+    while ((msg = d->d_tpb.delete_head_nowait()))
+      block->handle_msg(msg);
 
     d->d_tpb.clear_changed();
     s = d_exec.run_one_iteration();
@@ -55,16 +64,39 @@ gr_tpb_thread_body::gr_tpb_thread_body(gr_block_sptr block)
     case gr_block_executor::BLKD_IN:           // Wait for input.
       {
        gruel::scoped_lock guard(d->d_tpb.mutex);
-       while(!d->d_tpb.input_changed)
-         d->d_tpb.input_cond.wait(guard);
+       while (!d->d_tpb.input_changed){
+         
+         // wait for input or message
+         while(!d->d_tpb.input_changed && d->d_tpb.empty_p())
+           d->d_tpb.input_cond.wait(guard);
+
+         // handle all pending messages
+         while ((msg = d->d_tpb.delete_head_nowait_already_holding_mutex())){
+           guard.unlock();                     // release lock while processing msg
+           block->handle_msg(msg);
+           guard.lock();
+         }
+       }
       }
       break;
+
       
     case gr_block_executor::BLKD_OUT:          // Wait for output buffer space.
       {
        gruel::scoped_lock guard(d->d_tpb.mutex);
-       while(!d->d_tpb.output_changed)
-         d->d_tpb.output_cond.wait(guard);
+       while (!d->d_tpb.output_changed){
+         
+         // wait for output room or message
+         while(!d->d_tpb.output_changed && d->d_tpb.empty_p())
+           d->d_tpb.output_cond.wait(guard);
+
+         // handle all pending messages
+         while ((msg = d->d_tpb.delete_head_nowait_already_holding_mutex())){
+           guard.unlock();                     // release lock while processing msg
+           block->handle_msg(msg);
+           guard.lock();
+         }
+       }
       }
       break;
 
index c38c7fa3833d842a75e423446867ea6155492a90..9f50cb619f3e391cfa406d8a1611c4a2ae3d5790 100644 (file)
@@ -35,6 +35,7 @@ gruelinclude_HEADERS = \
        pmt_pool.h \
        pmt_serial_tags.h \
        realtime.h \
+       send.h \
        sys_pri.h \
        thread_body_wrapper.h \
        thread_group.h \
index bc287afae7c825fd84b0c5f7d2b4be7ccaa3c624..3afd6dde08fb4616354c6af017fc8968e8246277 100644 (file)
@@ -18,8 +18,8 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
-#ifndef INCLUDED_MSG_ACCEPTER_H
-#define INCLUDED_MSG_ACCEPTER_H
+#ifndef INCLUDED_GRUEL_MSG_ACCEPTER_H
+#define INCLUDED_GRUEL_MSG_ACCEPTER_H
 
 #include <gruel/pmt.h>
 
@@ -34,9 +34,16 @@ namespace gruel {
     msg_accepter() {};
     virtual ~msg_accepter();
 
+    /*!
+     * \brief send \p msg to \p msg_accepter
+     *
+     * Sending a message is an asynchronous operation.  The \p post
+     * call will not wait for the message either to arrive at the
+     * destination or to be received.
+     */
     virtual void post(pmt::pmt_t msg) = 0;
   };
 
 } /* namespace gruel */
 
-#endif /* INCLUDED_MSG_ACCEPTER_H */
+#endif /* INCLUDED_GRUEL_MSG_ACCEPTER_H */
index b14049d54f8ff134839ec10b3342a29e2676ba98..bf1762e925e5ab2e09f219d5a2b16794f83737f3 100644 (file)
@@ -32,13 +32,14 @@ namespace gruel {
    */
   class msg_accepter_msgq : public msg_accepter 
   {
+  protected:
     msg_queue_sptr d_msg_queue;
     
   public:
     msg_accepter_msgq(msg_queue_sptr msgq);
     ~msg_accepter_msgq();
 
-    void post(pmt::pmt_t msg);
+    virtual void post(pmt::pmt_t msg);
 
     msg_queue_sptr msg_queue() const { return d_msg_queue; }
   };
index caa12209d56da8500176d0df915e3bd5298109e5..2403593017f52ea79265e6a632f935d932465a28 100644 (file)
@@ -237,6 +237,42 @@ pmt_t pmt_cddr(pmt_t pair);
 pmt_t pmt_caddr(pmt_t pair);
 pmt_t pmt_cadddr(pmt_t pair);
 
+/*
+ * ------------------------------------------------------------------------
+ *                               Tuples
+ *
+ * Store a fixed number of objects.  Tuples are not modifiable, and thus
+ * are excellent for use as messages.  Indexing is zero based.
+ * Access time to an element is O(1).
+ * ------------------------------------------------------------------------
+ */
+
+//! Return true if \p x is a tuple, othewise false.
+bool pmt_is_tuple(pmt_t x);
+
+pmt_t pmt_make_tuple();
+pmt_t pmt_make_tuple(const pmt_t &e0);
+pmt_t pmt_make_tuple(const pmt_t &e0, const pmt_t &e1);
+pmt_t pmt_make_tuple(const pmt_t &e0, const pmt_t &e1, const pmt_t &e2);
+pmt_t pmt_make_tuple(const pmt_t &e0, const pmt_t &e1, const pmt_t &e2, const pmt_t &e3);
+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_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_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_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_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_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);
+
+/*!
+ * If \p x is a vector or proper list, return a tuple containing the elements of x
+ */
+pmt_t pmt_to_tuple(const pmt_t &x);
+
+/*!
+ * Return the contents of position \p k of \p tuple.
+ * \p k must be a valid index of \p tuple.
+ */
+pmt_t pmt_tuple_ref(const pmt_t &tuple, size_t k);
+
 /*
  * ------------------------------------------------------------------------
  *                            Vectors
diff --git a/gruel/src/include/gruel/send.h b/gruel/src/include/gruel/send.h
new file mode 100644 (file)
index 0000000..292017d
--- /dev/null
@@ -0,0 +1,49 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 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.
+ */
+#ifndef INCLUDED_GRUEL_SEND_H
+#define INCLUDED_GRUEL_SEND_H
+
+#include <gruel/msg_accepter.h>
+
+namespace gruel {
+
+
+  /*!
+   * \brief send \p msg to \p msg_accepter
+   *
+   * Sending a message is an asynchronous operation.  The \p send
+   * call will not wait for the message either to arrive at the
+   * destination or to be received.
+   *
+   * \returns msg
+   */
+  static inline pmt::pmt_t
+  send(msg_accepter &acc, pmt::pmt_t msg)
+  {
+    return acc.post(msg);
+  }
+
+
+
+} /* namespace gruel */
+
+
+#endif /* INCLUDED_SEND_H */
index fd4035f75f8687e8029a25cdf69ac2546c4c7452..f0e3c30a266f630a78252e0c4a2a35f2cfb7a918 100644 (file)
@@ -128,6 +128,12 @@ _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)
 {
@@ -496,6 +502,201 @@ pmt_vector_fill(pmt_t vector, pmt_t obj)
   _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
 ////////////////////////////////////////////////////////////////////////////
@@ -730,6 +931,19 @@ pmt_equal(const pmt_t& x, const pmt_t& y)
     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);
@@ -759,11 +973,15 @@ pmt_length(const pmt_t& x)
   if (x->is_uniform_vector())
     return _uniform_vector(x)->length();
 
-  if (x->is_null()) return 0;
+  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);
+    pmt_t it = pmt_cdr(x);
     while (pmt_is_pair(it)){
       length++;
       it = pmt_cdr(it);
index ba865b418979f51968e3280649d71433a15438f9..7581845f825df373a65951c7d8241e8b60e1f5f9 100644 (file)
@@ -51,6 +51,7 @@ public:
   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; }
@@ -186,6 +187,22 @@ public:
   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_dict : public pmt_base
 {
   pmt_t                d_alist;        // list of (key . value) pairs
index f5a82de0e020e07cea3bbba01b6e6a4cb317756f..179e6b72cb4f0450bfde2ced2e9711e38d717b79 100644 (file)
@@ -80,16 +80,31 @@ pmt_write(pmt_t obj, std::ostream &port)
     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_vector(obj)){
-    // FIXME
-    // port << "#<vector " << obj << ">";
-    port << "#<vector>";
-  }
   else if (pmt_is_uniform_vector(obj)){
     // FIXME
     // port << "#<uniform-vector " << obj << ">";
index b81354721dbad1b664fad64936991aecdf3ab14f..899674bbb18b4d2deaaff8cb60902c927b7a2f33 100644 (file)
@@ -193,6 +193,91 @@ qa_pmt_prims::test_vectors()
     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] = pmt_string_to_symbol(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()
 {
@@ -436,3 +521,4 @@ qa_pmt_prims::test_sets()
   CPPUNIT_ASSERT(!pmt_subsetp(l2,l1));
   CPPUNIT_ASSERT(!pmt_subsetp(l3,l2));
 }
+
index effb3a097a635fad976257a0d1d11436defd7f52..2fe473c43b5c81888f7124916c7ad6adc3401c7d 100644 (file)
@@ -35,6 +35,7 @@ class qa_pmt_prims : public CppUnit::TestCase {
   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);
@@ -53,6 +54,7 @@ class qa_pmt_prims : public CppUnit::TestCase {
   void test_complexes();
   void test_pairs();
   void test_vectors();
+  void test_tuples();
   void test_equivalence();
   void test_misc();
   void test_dict();