Merge r6160:6168 from jcorgan/fg into trunk.
authorjcorgan <jcorgan@221aa14e-8319-0410-a670-987f0aec2ac5>
Thu, 23 Aug 2007 18:46:20 +0000 (18:46 +0000)
committerjcorgan <jcorgan@221aa14e-8319-0410-a670-987f0aec2ac5>
Thu, 23 Aug 2007 18:46:20 +0000 (18:46 +0000)
Refactors gr_simple_flowgraph into gr_flowgraph and gr_flat_flowgraph.

Adds cppunit-based QA.

Trial fix for ticket:164 included for free.

git-svn-id: http://gnuradio.org/svn/gnuradio/trunk@6169 221aa14e-8319-0410-a670-987f0aec2ac5

23 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.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_flat_flowgraph.cc [new file with mode: 0644]
gnuradio-core/src/lib/runtime/gr_flat_flowgraph.h [new file with mode: 0644]
gnuradio-core/src/lib/runtime/gr_flowgraph.cc [new file with mode: 0644]
gnuradio-core/src/lib/runtime/gr_flowgraph.h [new file with mode: 0644]
gnuradio-core/src/lib/runtime/gr_hier_block2_detail.cc
gnuradio-core/src/lib/runtime/gr_hier_block2_detail.h
gnuradio-core/src/lib/runtime/gr_runtime_impl.cc
gnuradio-core/src/lib/runtime/gr_runtime_impl.h
gnuradio-core/src/lib/runtime/gr_runtime_types.h
gnuradio-core/src/lib/runtime/gr_simple_flowgraph.cc [deleted file]
gnuradio-core/src/lib/runtime/gr_simple_flowgraph.h [deleted file]
gnuradio-core/src/lib/runtime/gr_simple_flowgraph_detail.cc [deleted file]
gnuradio-core/src/lib/runtime/gr_simple_flowgraph_detail.h [deleted file]
gnuradio-core/src/lib/runtime/qa_gr_flowgraph.cc [new file with mode: 0644]
gnuradio-core/src/lib/runtime/qa_gr_flowgraph.h [new file with mode: 0644]
gnuradio-core/src/lib/runtime/qa_runtime.cc
gnuradio-core/src/python/gnuradio/gr/qa_hier_block2.py

index b15e651dd484c5b56e522be4030d129207dbd02b..346f23b6a3e19725538c49a8f312b1fab277bd9e 100644 (file)
@@ -31,8 +31,8 @@ libruntime_la_LIBADD =                \
 
 libruntime_la_SOURCES =                        \
        gr_basic_block.cc                       \
-       gr_simple_flowgraph.cc                  \
-       gr_simple_flowgraph_detail.cc           \
+       gr_flowgraph.cc                         \
+       gr_flat_flowgraph.cc                    \
        gr_block.cc                             \
        gr_block_detail.cc                      \
        gr_hier_block2.cc                       \
@@ -66,14 +66,15 @@ libruntime_qa_la_SOURCES =                  \
        qa_gr_block.cc                          \
        qa_gr_hier_block2.cc                    \
        qa_gr_buffer.cc                         \
+       qa_gr_flowgraph.cc                      \
        qa_gr_io_signature.cc                   \
        qa_gr_vmcircbuf.cc                      \
        qa_runtime.cc                           
 
 grinclude_HEADERS =                            \
        gr_basic_block.h                        \
-       gr_simple_flowgraph.h                   \
-       gr_simple_flowgraph_detail.h            \
+       gr_flowgraph.h                          \
+       gr_flat_flowgraph.h                     \
        gr_block.h                              \
        gr_block_detail.h                       \
        gr_hier_block2.h                        \
@@ -109,6 +110,7 @@ noinst_HEADERS =                            \
        gr_vmcircbuf_sysv_shm.h                 \
        gr_vmcircbuf_createfilemapping.h        \
        qa_gr_block.h                           \
+       qa_gr_flowgraph.h                       \
        qa_gr_hier_block2.h                     \
        qa_gr_buffer.h                          \
        qa_gr_io_signature.h                    \
@@ -135,3 +137,5 @@ swiginclude_HEADERS =                       \
        gr_sync_interpolator.i          \
        gr_swig_block_magic.i           \
        runtime.i
+
+MOSTLYCLEANFILES = *~ *.loT
index 33cc3c2e9f103013e8ab7e6469d1b2387b5c1aad..e94e089e2fcdd7d49981c5cd0954974f2a086b92 100644 (file)
@@ -42,7 +42,8 @@ gr_basic_block::gr_basic_block(const std::string &name,
   : d_name(name),
     d_input_signature(input_signature),
     d_output_signature(output_signature),
-    d_unique_id(s_next_id++)
+    d_unique_id(s_next_id++),
+    d_color(WHITE)
 {
     s_ncurrently_allocated++;
 }
index c47430e12517018d55093773205e2f9b7cb0b522..b2b8b42a369f7d46fb810d87e8bd52bf6a8a48e5 100644 (file)
 class gr_basic_block : public boost::enable_shared_from_this<gr_basic_block>
 {
 protected:
+    friend class gr_flowgraph;
+    friend class gr_flat_flowgraph; // TODO: will be redundant
+
+    enum vcolor { WHITE, GREY, BLACK };
+
     std::string          d_name;
     gr_io_signature_sptr d_input_signature;
     gr_io_signature_sptr d_output_signature;
     long                 d_unique_id;
+    vcolor               d_color;
 
     //! Protected constructor prevents instantiation by non-derived classes
     gr_basic_block(const std::string &name,
@@ -61,6 +67,12 @@ protected:
         d_output_signature = iosig;
     }
 
+    /*!
+     * \brief Allow the flowgraph to set for sorting and partitioning
+     */
+    void set_color(vcolor color) { d_color = color; }
+    vcolor color() const { return d_color; }
+
 public:
     virtual ~gr_basic_block();
     long unique_id() const { return d_unique_id; }
index aa2b0bde98636deff78a1afc8789ab6bc06dfd14..ce58ca9ac774471bc8e76a05e517cb41e359c22f 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- c++ -*- */
 /*
- * Copyright 2004 Free Software Foundation, Inc.
+ * Copyright 2004,2007 Free Software Foundation, Inc.
  * 
  * This file is part of GNU Radio
  * 
@@ -214,4 +214,9 @@ class gr_block : public gr_basic_block {
 typedef std::vector<gr_block_sptr> gr_block_vector_t;
 typedef std::vector<gr_block_sptr>::iterator gr_block_viter_t;
 
+inline gr_block_sptr make_gr_block_sptr(gr_basic_block_sptr p)
+{
+  return boost::dynamic_pointer_cast<gr_block, gr_basic_block>(p);
+}
+
 #endif /* INCLUDED_GR_BLOCK_H */
index e545d833d498db7e0b2a53df8c9a52d50720da29..ae1ea25628d63631df41dcd4924fa85cdfa1a8ed 100644 (file)
@@ -38,8 +38,7 @@ gr_block_detail_ncurrently_allocated ()
 gr_block_detail::gr_block_detail (unsigned int ninputs, unsigned int noutputs)
   : d_ninputs (ninputs), d_noutputs (noutputs),
     d_input (ninputs), d_output (noutputs),
-    d_done (false),
-    d_color (gr_block_detail::WHITE)
+    d_done (false)
 {
   s_ncurrently_allocated++;
 }
index 78b1019ebf641851716daef5167329007283f1b2..a3b7731c01728712860dc8c180abc0e088d238ba 100644 (file)
@@ -75,13 +75,6 @@ class gr_block_detail {
 
   void produce_each (int how_many_items);
 
-  /*!
-   * \brief Allow the flowgraph to set for sorting and partitioning
-   */
-  enum vcolor { WHITE, GREY, BLACK };
-  void set_color(vcolor color) { d_color = color; }
-  vcolor color() const { return d_color; }
-
   // ----------------------------------------------------------------------------
 
  private:
@@ -90,7 +83,6 @@ class gr_block_detail {
   std::vector<gr_buffer_reader_sptr> d_input;
   std::vector<gr_buffer_sptr>       d_output;
   bool                               d_done;
-  vcolor                             d_color;
 
   gr_block_detail (unsigned int ninputs, unsigned int noutputs);
 
diff --git a/gnuradio-core/src/lib/runtime/gr_flat_flowgraph.cc b/gnuradio-core/src/lib/runtime/gr_flat_flowgraph.cc
new file mode 100644 (file)
index 0000000..d7f3ffb
--- /dev/null
@@ -0,0 +1,223 @@
+/* -*- c++ -*- */
+/*
+ * 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 (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 <gr_flat_flowgraph.h>
+#include <gr_block_detail.h>
+#include <gr_io_signature.h>
+#include <gr_buffer.h>
+#include <iostream>
+#include <map>
+
+#define GR_FLAT_FLOWGRAPH_DEBUG 0
+
+gr_flat_flowgraph_sptr
+gr_make_flat_flowgraph()
+{
+  return gr_flat_flowgraph_sptr(new gr_flat_flowgraph());
+}
+
+gr_flat_flowgraph::gr_flat_flowgraph()
+{
+}
+
+gr_flat_flowgraph::~gr_flat_flowgraph()
+{
+}
+
+void
+gr_flat_flowgraph::setup_connections()
+{
+  gr_basic_block_vector_t blocks = calc_used_blocks();
+
+  // Assign block details to blocks
+  for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++)
+    make_gr_block_sptr(*p)->set_detail(allocate_block_detail(*p));
+
+  // Connect inputs to outputs for each block
+  for(gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++)
+    connect_block_inputs(*p);
+}
+
+gr_block_detail_sptr
+gr_flat_flowgraph::allocate_block_detail(gr_basic_block_sptr block, gr_block_detail_sptr old_detail)
+{
+  int ninputs = calc_used_ports(block, true).size();
+  int noutputs = calc_used_ports(block, false).size();
+  gr_block_detail_sptr detail = gr_make_block_detail(ninputs, noutputs);
+
+  if (GR_FLAT_FLOWGRAPH_DEBUG)
+    std::cout << "Creating block detail for " << block << std::endl;
+
+  // Re-use or allocate output buffers
+  for (int i = 0; i < noutputs; i++) {
+    gr_buffer_sptr buffer;
+
+    if (!old_detail || i >= old_detail->noutputs()) {
+      if (GR_FLAT_FLOWGRAPH_DEBUG)
+       std::cout << "Allocating new buffer for output " << i << std::endl;
+      buffer = allocate_buffer(block, i);
+    }
+    else {
+      if (GR_FLAT_FLOWGRAPH_DEBUG)
+       std::cout << "Reusing old buffer for output " << i << std::endl;
+      buffer = old_detail->output(i);
+    }
+
+    detail->set_output(i, buffer);
+  }
+
+  return detail;
+}
+
+gr_buffer_sptr
+gr_flat_flowgraph::allocate_buffer(gr_basic_block_sptr block, int port)
+{
+  gr_block_sptr grblock = make_gr_block_sptr(block);
+  if (!grblock)
+    throw std::runtime_error("allocate_buffer found non-gr_block");
+  int item_size = block->output_signature()->sizeof_stream_item(port);
+  int nitems = s_fixed_buffer_size/item_size;
+
+  // Make sure there are at least twice the output_multiple no. of items
+  if (nitems < 2*grblock->output_multiple())   // Note: this means output_multiple()
+    nitems = 2*grblock->output_multiple();     // can't be changed by block dynamically
+
+  // If any downstream blocks are decimators and/or have a large output_multiple,
+  // ensure we have a buffer at least twice their decimation factor*output_multiple
+  gr_basic_block_vector_t blocks = calc_downstream_blocks(block, port);
+
+  for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) {
+    gr_block_sptr dgrblock = make_gr_block_sptr(*p);
+    if (!dgrblock)
+      throw std::runtime_error("allocate_buffer found non-gr_block");
+
+    double decimation = (1.0/dgrblock->relative_rate());
+    int multiple      = dgrblock->output_multiple();
+    int history       = dgrblock->history();
+    nitems = std::max(nitems, static_cast<int>(2*(decimation*multiple+history)));
+  }
+
+  return gr_make_buffer(nitems, item_size);
+}
+
+void
+gr_flat_flowgraph::connect_block_inputs(gr_basic_block_sptr block)
+{
+  gr_block_sptr grblock = make_gr_block_sptr(block);
+  if (!grblock)
+    throw std::runtime_error("found non-gr_block");
+  
+  // Get its detail and edges that feed into it
+  gr_block_detail_sptr detail = grblock->detail();
+  gr_edge_vector_t in_edges = calc_upstream_edges(block);
+  
+  // For each edge that feeds into it
+  for (gr_edge_viter_t e = in_edges.begin(); e != in_edges.end(); e++) {
+    // Set the buffer reader on the destination port to the output
+    // buffer on the source port
+    int dst_port = e->dst().port();
+    int src_port = e->src().port();
+    gr_basic_block_sptr src_block = e->src().block();
+    gr_block_sptr src_grblock = make_gr_block_sptr(src_block);
+    if (!src_grblock)
+      throw std::runtime_error("found non-gr_block");
+    gr_buffer_sptr src_buffer = src_grblock->detail()->output(src_port);
+    
+    if (GR_FLAT_FLOWGRAPH_DEBUG)
+      std::cout << "Setting input " << dst_port << " from edge " << (*e) << std::endl;
+
+    detail->set_input(dst_port, gr_buffer_add_reader(src_buffer, grblock->history()-1));
+  }
+}
+
+void
+gr_flat_flowgraph::merge_connections(gr_flat_flowgraph_sptr old_ffg)
+{
+  std::map<gr_block_sptr, gr_block_detail_sptr> old_details;
+
+  // Allocate or reuse output buffers
+  for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) {
+    gr_block_sptr block = make_gr_block_sptr(*p);
+
+    gr_block_detail_sptr old_detail = block->detail();
+    block->set_detail(allocate_block_detail(block, old_detail));
+
+    // Save old detail for use in next step
+    old_details[block] = old_detail;
+  }
+
+  for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) {
+    gr_block_sptr block = make_gr_block_sptr(*p);
+
+    if (GR_FLAT_FLOWGRAPH_DEBUG)
+      std::cout << "merge: testing " << (*p) << "...";
+    
+    if (old_ffg->has_block_p(*p)) {
+      // Block exists in old flow graph
+      if (GR_FLAT_FLOWGRAPH_DEBUG)
+       std::cout << "used in old flow graph" << std::endl;
+      gr_block_detail_sptr detail = block->detail();
+
+      // Iterate through the inputs and see what needs to be done
+      for (int i = 0; i < detail->ninputs(); i++) {
+       if (GR_FLAT_FLOWGRAPH_DEBUG)
+         std::cout << "Checking input " << i << "...";
+       gr_edge edge = calc_upstream_edge(*p, i);
+
+       // Fish out old buffer reader and see if it matches correct buffer from edge list
+       gr_block_sptr src_block = make_gr_block_sptr(edge.src().block());
+       gr_block_detail_sptr src_detail = src_block->detail();
+       gr_buffer_sptr src_buffer = src_detail->output(edge.src().port());
+       gr_buffer_reader_sptr old_reader;
+       gr_block_detail_sptr old_detail = old_details[block];
+       if (old_detail && i < old_detail->ninputs())
+         old_reader = old_detail->input(i);
+       
+       // If there's a match, use it
+       if (old_reader && (src_buffer == old_reader->buffer())) {
+         if (GR_FLAT_FLOWGRAPH_DEBUG)
+           std::cout << "matched" << std::endl;
+         detail->set_input(i, old_reader);
+
+       }
+       else {
+         if (GR_FLAT_FLOWGRAPH_DEBUG)
+           std::cout << "needs a new reader" << std::endl;
+
+         // Create new buffer reader and assign
+         detail->set_input(i, gr_buffer_add_reader(src_buffer, block->history()-1));
+       }
+      }
+    }
+    else {
+      // Block is new, it just needs buffer readers at this point
+      if (GR_FLAT_FLOWGRAPH_DEBUG)
+       std::cout << "new block" << std::endl;
+      connect_block_inputs(block);
+    }
+  }  
+}
+
diff --git a/gnuradio-core/src/lib/runtime/gr_flat_flowgraph.h b/gnuradio-core/src/lib/runtime/gr_flat_flowgraph.h
new file mode 100644 (file)
index 0000000..0f49280
--- /dev/null
@@ -0,0 +1,65 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006,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 (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_GR_FLAT_FLOWGRAPH_H
+#define INCLUDED_GR_FLAT_FLOWGRAPH_H
+
+#include <gr_flowgraph.h>
+#include <gr_block.h>
+
+// 32Kbyte buffer size between blocks
+#define GR_FIXED_BUFFER_SIZE (32*(1L<<10))
+
+// Create a shared pointer to a heap allocated gr_flat_flowgraph
+// (types defined in gr_runtime_types.h)
+gr_flat_flowgraph_sptr gr_make_flat_flowgraph();
+
+/*!
+ *\brief Class specializing gr_flat_flowgraph that has all nodes
+ * as gr_blocks, with no hierarchy
+ *
+ */
+class gr_flat_flowgraph : public gr_flowgraph
+{
+public:
+  friend gr_flat_flowgraph_sptr gr_make_flat_flowgraph();
+
+  // Destruct an arbitrary gr_flat_flowgraph
+  ~gr_flat_flowgraph();
+
+  // Wire gr_blocks together in new flat_flowgraph
+  void setup_connections();
+
+  // Merge applicable connections from existing flat flowgraph
+  void merge_connections(gr_flat_flowgraph_sptr sfg);
+
+private:
+  gr_flat_flowgraph();
+
+  static const unsigned int s_fixed_buffer_size = GR_FIXED_BUFFER_SIZE;
+  gr_block_detail_sptr allocate_block_detail(gr_basic_block_sptr block, 
+                                            gr_block_detail_sptr old_detail=gr_block_detail_sptr());
+  gr_buffer_sptr allocate_buffer(gr_basic_block_sptr block, int port);
+  void connect_block_inputs(gr_basic_block_sptr block);
+};
+
+#endif /* INCLUDED_GR_FLAT_FLOWGRAPH_H */
diff --git a/gnuradio-core/src/lib/runtime/gr_flowgraph.cc b/gnuradio-core/src/lib/runtime/gr_flowgraph.cc
new file mode 100644 (file)
index 0000000..8e96dba
--- /dev/null
@@ -0,0 +1,436 @@
+/* -*- c++ -*- */
+/*
+ * 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 (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 <gr_flowgraph.h>
+#include <gr_io_signature.h>
+#include <stdexcept>
+#include <iostream>
+
+#define GR_FLOWGRAPH_DEBUG 0
+
+gr_edge::~gr_edge()
+{
+}
+
+gr_flowgraph_sptr gr_make_flowgraph()
+{
+  return gr_flowgraph_sptr(new gr_flowgraph());
+}
+
+gr_flowgraph::gr_flowgraph()
+{
+}
+  
+gr_flowgraph::~gr_flowgraph()
+{
+}
+
+void
+gr_flowgraph::connect(const gr_endpoint &src, const gr_endpoint &dst)
+{
+  check_valid_port(src.block()->output_signature(), src.port());
+  check_valid_port(dst.block()->input_signature(), dst.port());
+  check_dst_not_used(dst);
+  check_type_match(src, dst);
+
+  // All ist klar, Herr Kommisar
+  d_edges.push_back(gr_edge(src,dst));
+}
+
+void
+gr_flowgraph::disconnect(const gr_endpoint &src, const gr_endpoint &dst)
+{
+  for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) {
+    if (src == p->src() && dst == p->dst()) {
+      d_edges.erase(p);
+      return;
+    }
+  }
+
+  throw std::invalid_argument("edge to disconnect not found");
+}
+
+void
+gr_flowgraph::validate()
+{
+  d_blocks = calc_used_blocks();
+
+  for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) {
+    std::vector<int> used_ports;
+    int ninputs, noutputs;
+
+    if (GR_FLOWGRAPH_DEBUG)
+      std::cout << "Validating block: " << (*p) << std::endl;
+
+    used_ports = calc_used_ports(*p, true); // inputs
+    ninputs = used_ports.size();
+    check_contiguity(*p, used_ports, true); // inputs
+
+    used_ports = calc_used_ports(*p, false); // outputs
+    noutputs = used_ports.size();
+    check_contiguity(*p, used_ports, false); // outputs
+
+    if (!((*p)->check_topology(ninputs, noutputs)))
+      throw std::runtime_error("check topology failed");
+  }
+}
+
+void
+gr_flowgraph::clear()
+{
+  // Boost shared pointers will deallocate as needed
+  d_blocks.clear();
+  d_edges.clear();
+}
+
+void
+gr_flowgraph::check_valid_port(gr_io_signature_sptr sig, int port)
+{
+  if (port < 0)
+    throw std::invalid_argument("negative port number");
+  if (sig->max_streams() >= 0 && port >= sig->max_streams())
+    throw std::invalid_argument("port number exceeds max");
+}
+
+void
+gr_flowgraph::check_dst_not_used(const gr_endpoint &dst)
+{
+  // A destination is in use if it is already on the edge list
+  for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++)
+    if (p->dst() == dst)
+      throw std::invalid_argument("dst already in use");
+}
+
+void
+gr_flowgraph::check_type_match(const gr_endpoint &src, const gr_endpoint &dst)
+{
+  int src_size = src.block()->output_signature()->sizeof_stream_item(src.port());
+  int dst_size = dst.block()->input_signature()->sizeof_stream_item(dst.port());
+
+  if (src_size != dst_size)
+    throw std::invalid_argument("itemsize mismatch between src and dst");
+}
+
+gr_basic_block_vector_t
+gr_flowgraph::calc_used_blocks()
+{
+  gr_basic_block_vector_t tmp, result;
+  std::insert_iterator<gr_basic_block_vector_t> inserter(result, result.begin());
+
+  // Collect all blocks in the edge list
+  for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) {
+    tmp.push_back(p->src().block());
+    tmp.push_back(p->dst().block());
+  }
+
+  // Return vector of unique blocks
+  sort(tmp.begin(), tmp.end());
+  unique_copy(tmp.begin(), tmp.end(), inserter);
+  return result;
+}
+
+std::vector<int>
+gr_flowgraph::calc_used_ports(gr_basic_block_sptr block, bool check_inputs)
+{
+  std::vector<int> tmp, result;
+  std::insert_iterator<std::vector<int> > inserter(result, result.begin());
+
+  // Collect all seen ports 
+  gr_edge_vector_t edges = calc_connections(block, check_inputs);
+  for (gr_edge_viter_t p = edges.begin(); p != edges.end(); p++) {
+    if (check_inputs == true)
+      tmp.push_back(p->dst().port());
+    else
+      tmp.push_back(p->src().port());
+  }
+
+  // Return vector of unique values
+  std::sort(tmp.begin(), tmp.end());
+  std::unique_copy(tmp.begin(), tmp.end(), inserter);
+  return result;
+}
+
+gr_edge_vector_t
+gr_flowgraph::calc_connections(gr_basic_block_sptr block, bool check_inputs)
+{
+  gr_edge_vector_t result;
+
+  for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) {
+    if (check_inputs) {
+      if (p->dst().block() == block)
+       result.push_back(*p);
+    }
+    else {
+      if (p->src().block() == block)
+       result.push_back(*p);
+    }
+  }
+
+  return result; // assumes no duplicates
+}
+
+void
+gr_flowgraph::check_contiguity(gr_basic_block_sptr block,
+                              const std::vector<int> &used_ports,
+                              bool check_inputs)
+{
+  gr_io_signature_sptr sig =
+    check_inputs ? block->input_signature() : block->output_signature();
+
+  int nports = used_ports.size();
+  int min_ports = sig->min_streams();
+
+  if (nports == 0) {
+    if (min_ports == 0)
+      return;
+    else
+      throw std::runtime_error("insufficient ports");
+  }
+
+  if (used_ports[nports-1]+1 != nports) {
+    for (int i = 0; i < nports; i++)
+      if (used_ports[i] != i)
+       throw std::runtime_error("missing input assignment");
+  }
+}
+
+gr_basic_block_vector_t
+gr_flowgraph::calc_downstream_blocks(gr_basic_block_sptr block, int port)
+{
+  gr_basic_block_vector_t tmp, result;
+  std::insert_iterator<gr_basic_block_vector_t> inserter(result, result.begin());
+
+  for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++)
+    if (p->src() == gr_endpoint(block, port))
+      tmp.push_back(p->dst().block());
+
+  // Remove duplicates
+  sort(tmp.begin(), tmp.end());
+  unique_copy(tmp.begin(), tmp.end(), inserter);
+  return result;
+}
+
+gr_basic_block_vector_t
+gr_flowgraph::calc_downstream_blocks(gr_basic_block_sptr block)
+{
+  gr_basic_block_vector_t tmp, result;
+  std::insert_iterator<gr_basic_block_vector_t> inserter(result, result.begin());
+
+  for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++)
+    if (p->src().block() == block)
+      tmp.push_back(p->dst().block());
+
+  // Remove duplicates
+  sort(tmp.begin(), tmp.end());
+  unique_copy(tmp.begin(), tmp.end(), inserter);
+  return result;
+}
+
+gr_edge_vector_t
+gr_flowgraph::calc_upstream_edges(gr_basic_block_sptr block)
+{
+  gr_edge_vector_t result;
+
+  for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++)
+    if (p->dst().block() == block)
+      result.push_back(*p);
+
+  return result; // Assume no duplicates
+}
+
+bool
+gr_flowgraph::has_block_p(gr_basic_block_sptr block)
+{
+  gr_basic_block_viter_t result;
+  result = std::find(d_blocks.begin(), d_blocks.end(), block);
+  return (result != d_blocks.end());
+}
+
+gr_edge
+gr_flowgraph::calc_upstream_edge(gr_basic_block_sptr block, int port)
+{
+  gr_edge result;
+
+  for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) {
+    if (p->dst() == gr_endpoint(block, port)) {
+      result = (*p);
+      break;
+    }
+  }
+
+  return result;
+}
+
+std::vector<gr_basic_block_vector_t>
+gr_flowgraph::partition()
+{
+  std::vector<gr_basic_block_vector_t> result;
+  gr_basic_block_vector_t blocks = calc_used_blocks();
+  gr_basic_block_vector_t graph;
+
+  while (blocks.size() > 0) {
+    graph = calc_reachable_blocks(blocks[0], blocks);
+    assert(graph.size());
+    result.push_back(topological_sort(graph));
+
+    for (gr_basic_block_viter_t p = graph.begin(); p != graph.end(); p++)
+      blocks.erase(find(blocks.begin(), blocks.end(), *p));
+  }
+
+  return result;
+}
+
+gr_basic_block_vector_t
+gr_flowgraph::calc_reachable_blocks(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks)
+{
+  gr_basic_block_vector_t result;
+
+  // Mark all blocks as unvisited
+  for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++)
+    (*p)->set_color(gr_basic_block::WHITE);
+
+  // Recursively mark all reachable blocks
+  reachable_dfs_visit(block, blocks);
+
+  // Collect all the blocks that have been visited
+  for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++)
+    if ((*p)->color() == gr_basic_block::BLACK)
+      result.push_back(*p);
+
+  return result;
+}
+
+// Recursively mark all reachable blocks from given block and block list
+void 
+gr_flowgraph::reachable_dfs_visit(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks)
+{
+  // Mark the current one as visited
+  block->set_color(gr_basic_block::BLACK);
+
+  // Recurse into adjacent vertices
+  gr_basic_block_vector_t adjacent = calc_adjacent_blocks(block, blocks);
+
+  for (gr_basic_block_viter_t p = adjacent.begin(); p != adjacent.end(); p++)
+    if ((*p)->color() == gr_basic_block::WHITE)
+      reachable_dfs_visit(*p, blocks);
+}
+
+// Return a list of block adjacent to a given block along any edge
+gr_basic_block_vector_t 
+gr_flowgraph::calc_adjacent_blocks(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks)
+{
+  gr_basic_block_vector_t tmp, result;
+  std::insert_iterator<gr_basic_block_vector_t> inserter(result, result.begin());
+    
+  // Find any blocks that are inputs or outputs
+  for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) {
+
+    if (p->src().block() == block)
+      tmp.push_back(p->dst().block());
+    if (p->dst().block() == block)
+      tmp.push_back(p->src().block());
+  }    
+
+  // Remove duplicates
+  sort(tmp.begin(), tmp.end());
+  unique_copy(tmp.begin(), tmp.end(), inserter);
+  return result;
+}
+
+gr_basic_block_vector_t
+gr_flowgraph::topological_sort(gr_basic_block_vector_t &blocks)
+{
+  gr_basic_block_vector_t tmp;
+  gr_basic_block_vector_t result;
+  tmp = sort_sources_first(blocks);
+
+  // Start 'em all white
+  for (gr_basic_block_viter_t p = tmp.begin(); p != tmp.end(); p++)
+    (*p)->set_color(gr_basic_block::WHITE);
+
+  for (gr_basic_block_viter_t p = tmp.begin(); p != tmp.end(); p++) {
+    if ((*p)->color() == gr_basic_block::WHITE)
+      topological_dfs_visit(*p, result);
+  }    
+
+  reverse(result.begin(), result.end());
+  return result;
+}
+
+gr_basic_block_vector_t
+gr_flowgraph::sort_sources_first(gr_basic_block_vector_t &blocks)
+{
+  gr_basic_block_vector_t sources, nonsources, result;
+
+  for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) {
+    if (source_p(*p))
+      sources.push_back(*p);
+    else
+      nonsources.push_back(*p);
+  }
+
+  for (gr_basic_block_viter_t p = sources.begin(); p != sources.end(); p++)
+    result.push_back(*p);
+
+  for (gr_basic_block_viter_t p = nonsources.begin(); p != nonsources.end(); p++)
+    result.push_back(*p);
+
+  return result;
+}
+
+bool
+gr_flowgraph::source_p(gr_basic_block_sptr block)
+{
+  return (calc_upstream_edges(block).size() == 0);
+}
+
+void
+gr_flowgraph::topological_dfs_visit(gr_basic_block_sptr block, gr_basic_block_vector_t &output)
+{
+  block->set_color(gr_basic_block::GREY);
+  gr_basic_block_vector_t blocks(calc_downstream_blocks(block));
+
+  for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) {
+    switch ((*p)->color()) {
+    case gr_basic_block::WHITE:           
+      topological_dfs_visit(*p, output);
+      break;
+
+    case gr_basic_block::GREY:            
+      throw std::runtime_error("flow graph has loops!");
+
+    case gr_basic_block::BLACK:
+      continue;
+
+    default:
+      throw std::runtime_error("invalid color on block!");
+    }
+  }
+
+  block->set_color(gr_basic_block::BLACK);
+  output.push_back(block);
+}
+
diff --git a/gnuradio-core/src/lib/runtime/gr_flowgraph.h b/gnuradio-core/src/lib/runtime/gr_flowgraph.h
new file mode 100644 (file)
index 0000000..131e41b
--- /dev/null
@@ -0,0 +1,188 @@
+/* -*- c++ -*- */
+/*
+ * Copyright 2006,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 (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_GR_FLOWGRAPH_H
+#define INCLUDED_GR_FLOWGRAPH_H
+
+#include <gr_basic_block.h>
+#include <iostream>
+
+/*!
+ *\brief Class representing a specific input or output graph endpoint
+ *
+ */
+class gr_endpoint
+{
+private:
+  gr_basic_block_sptr d_basic_block;
+  int d_port;
+
+public:
+  gr_endpoint() : d_basic_block(), d_port(0) { }
+  gr_endpoint(gr_basic_block_sptr block, int port) { d_basic_block = block; d_port = port; }
+  gr_basic_block_sptr block() const { return d_basic_block; }
+  int port() const { return d_port; }
+
+  bool operator==(const gr_endpoint &other) const;
+};    
+
+inline bool gr_endpoint::operator==(const gr_endpoint &other) const
+{
+  return (d_basic_block == other.d_basic_block && 
+         d_port == other.d_port);
+}
+
+// Hold vectors of gr_endpoint objects
+typedef std::vector<gr_endpoint> gr_endpoint_vector_t;
+typedef std::vector<gr_endpoint>::iterator gr_endpoint_viter_t;
+
+/*!
+ *\brief Class representing a connection between to graph endpoints
+ *
+ */
+class gr_edge
+{
+public:
+  gr_edge() : d_src(), d_dst() { };
+  gr_edge(const gr_endpoint &src, const gr_endpoint &dst) : d_src(src), d_dst(dst) { }
+  ~gr_edge();
+
+  const gr_endpoint &src() const { return d_src; }
+  const gr_endpoint &dst() const { return d_dst; }
+
+private:
+  gr_endpoint d_src;
+  gr_endpoint d_dst;
+};
+
+// Hold vectors of gr_edge objects
+typedef std::vector<gr_edge> gr_edge_vector_t;
+typedef std::vector<gr_edge>::iterator gr_edge_viter_t;
+
+
+// Create a shared pointer to a heap allocated flowgraph
+// (types defined in gr_runtime_types.h)
+gr_flowgraph_sptr gr_make_flowgraph();
+
+/*!
+ *\brief Class representing a directed, acyclic graph of basic blocks
+ *
+ */
+class gr_flowgraph
+{
+public:
+  friend gr_flowgraph_sptr gr_make_flowgraph();
+
+  // Destruct an arbitrary flowgraph
+  ~gr_flowgraph();
+
+  // Connect two endpoints
+  void connect(const gr_endpoint &src, const gr_endpoint &dst);
+
+  // Disconnect two endpoints
+  void disconnect(const gr_endpoint &src, const gr_endpoint &dst);
+
+  // Connect an output port to an input port (convenience)
+  void connect(gr_basic_block_sptr src_block, int src_port,
+              gr_basic_block_sptr dst_block, int dst_port);
+
+  // Disconnect an input port from an output port (convenience)
+  void disconnect(gr_basic_block_sptr src_block, int src_port,
+                 gr_basic_block_sptr dst_block, int dst_port);
+
+  // Validate connectivity, raise exception if invalid
+  void validate();
+
+  // Clear existing flowgraph
+  void clear();
+
+  // Return vector of edges
+  const gr_edge_vector_t &edges() const { return d_edges; }
+
+  // Return vector of connected blocks
+  gr_basic_block_vector_t calc_used_blocks();
+
+  // Return vector of vectors of disjointly connected blocks, topologically
+  // sorted.
+  std::vector<gr_basic_block_vector_t> partition();
+
+protected:
+  gr_basic_block_vector_t d_blocks;
+  gr_edge_vector_t d_edges;
+
+  gr_flowgraph();
+  std::vector<int> calc_used_ports(gr_basic_block_sptr block, bool check_inputs); 
+  gr_basic_block_vector_t calc_downstream_blocks(gr_basic_block_sptr block, int port);
+  gr_edge_vector_t calc_upstream_edges(gr_basic_block_sptr block);
+  bool has_block_p(gr_basic_block_sptr block);
+  gr_edge calc_upstream_edge(gr_basic_block_sptr block, int port);
+
+private:
+
+  void check_valid_port(gr_io_signature_sptr sig, int port);
+  void check_dst_not_used(const gr_endpoint &dst);
+  void check_type_match(const gr_endpoint &src, const gr_endpoint &dst);
+  gr_edge_vector_t calc_connections(gr_basic_block_sptr block, bool check_inputs); // false=use outputs
+  void check_contiguity(gr_basic_block_sptr block, const std::vector<int> &used_ports, bool check_inputs);
+
+  gr_basic_block_vector_t calc_downstream_blocks(gr_basic_block_sptr block);
+  gr_basic_block_vector_t calc_reachable_blocks(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks);
+  void reachable_dfs_visit(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks);
+  gr_basic_block_vector_t calc_adjacent_blocks(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks);
+  gr_basic_block_vector_t topological_sort(gr_basic_block_vector_t &blocks);
+  gr_basic_block_vector_t sort_sources_first(gr_basic_block_vector_t &blocks);
+  bool source_p(gr_basic_block_sptr block);
+  void topological_dfs_visit(gr_basic_block_sptr block, gr_basic_block_vector_t &output);
+};
+
+// Convenience functions
+inline
+void gr_flowgraph::connect(gr_basic_block_sptr src_block, int src_port,
+                     gr_basic_block_sptr dst_block, int dst_port)
+{
+  connect(gr_endpoint(src_block, src_port),
+         gr_endpoint(dst_block, dst_port));
+}
+
+inline
+void gr_flowgraph::disconnect(gr_basic_block_sptr src_block, int src_port,
+                        gr_basic_block_sptr dst_block, int dst_port)
+{
+  disconnect(gr_endpoint(src_block, src_port),
+            gr_endpoint(dst_block, dst_port));
+}
+
+inline std::ostream&
+operator <<(std::ostream &os, const gr_endpoint endp)
+{
+  os << endp.block() << ":" << endp.port();
+  return os;
+}
+
+inline std::ostream&
+operator <<(std::ostream &os, const gr_edge edge)
+{
+  os << edge.src() << "->" << edge.dst();
+  return os;
+}
+
+#endif /* INCLUDED_GR_FLOWGRAPH_H */
index 46656360e09a5ff646f1c194bb102ffbb7f92173..99131afb64acfd72f508857dafecab0e00f6bf0c 100644 (file)
@@ -24,7 +24,6 @@
 #endif
 
 #include <gr_hier_block2_detail.h>
-#include <gr_simple_flowgraph.h>
 #include <gr_io_signature.h>
 #include <gr_runtime.h>
 #include <stdexcept>
@@ -35,7 +34,7 @@
 gr_hier_block2_detail::gr_hier_block2_detail(gr_hier_block2 *owner) :
   d_owner(owner), 
   d_parent_detail(0),
-  d_fg(gr_make_simple_flowgraph()),
+  d_fg(gr_make_flowgraph()),
   d_inputs(owner->input_signature()->max_streams()),
   d_outputs(owner->output_signature()->max_streams()),
   d_runtime()
@@ -228,22 +227,24 @@ gr_hier_block2_detail::resolve_endpoint(const gr_endpoint &endp, bool is_input)
 }
 
 void
-gr_hier_block2_detail::flatten(gr_simple_flowgraph_sptr sfg)
+gr_hier_block2_detail::flatten(gr_flat_flowgraph_sptr sfg)
 {
   if (GR_HIER_BLOCK2_DETAIL_DEBUG)
     std::cout << "flattening " << d_owner->name() << std::endl;
 
   // Add my edges to the flow graph, resolving references to actual endpoints
-  for (gr_edge_viter_t p = d_fg->d_detail->d_edges.begin(); p != d_fg->d_detail->d_edges.end(); p++) {
+  gr_edge_vector_t edges = d_fg->edges();
+
+  for (gr_edge_viter_t p = edges.begin(); p != edges.end(); p++) {
     if (GR_HIER_BLOCK2_DETAIL_DEBUG)
       std::cout << "Flattening edge " << (*p) << std::endl;
 
-    gr_endpoint src_endp = resolve_endpoint((*p)->src(), false);
-    gr_endpoint dst_endp = resolve_endpoint((*p)->dst(), true);
+    gr_endpoint src_endp = resolve_endpoint(p->src(), false);
+    gr_endpoint dst_endp = resolve_endpoint(p->dst(), true);
     sfg->connect(src_endp, dst_endp);
   }
 
-  gr_basic_block_vector_t blocks = d_fg->d_detail->calc_used_blocks();
+  gr_basic_block_vector_t blocks = d_fg->calc_used_blocks();
 
   // Recurse hierarchical children
   for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) {
index 9002dde1ddf13bda8a15213eed0003cc02268df6..b315061bec5e5b38c5b544b6783c7b2b9f55e806 100644 (file)
@@ -22,7 +22,7 @@
 #define INCLUDED_GR_HIER_BLOCK2_DETAIL_H
 
 #include <gr_hier_block2.h>
-#include <gr_simple_flowgraph_detail.h>
+#include <gr_flat_flowgraph.h>
 #include <boost/utility.hpp>
 
 class gr_hier_block2_detail : boost::noncopyable
@@ -37,7 +37,7 @@ private:
     // Private implementation data
     gr_hier_block2 *d_owner;
     gr_hier_block2_detail *d_parent_detail;
-    gr_simple_flowgraph_sptr d_fg;
+    gr_flowgraph_sptr d_fg;
     gr_endpoint_vector_t d_inputs;
     gr_endpoint_vector_t d_outputs;
     gr_runtime *d_runtime;
@@ -51,7 +51,7 @@ private:
     void connect_output(int my_port, int port, gr_basic_block_sptr block);
     void disconnect_input(int my_port, int port, gr_basic_block_sptr block);
     void disconnect_output(int my_port, int port, gr_basic_block_sptr block);
-    void flatten(gr_simple_flowgraph_sptr sfg);
+    void flatten(gr_flat_flowgraph_sptr sfg);
     gr_endpoint resolve_port(int port, bool is_input);
     gr_endpoint resolve_endpoint(const gr_endpoint &endp, bool is_input);
     void set_runtime(gr_runtime *runtime) { d_runtime = runtime; }
index 134690a1ae5bfc1bcae5c9426b453496e570ef3a..30a39f1d80c0dce03327c908561fc518641558a0 100644 (file)
@@ -26,7 +26,7 @@
 
 #include <gr_runtime.h>
 #include <gr_runtime_impl.h>
-#include <gr_simple_flowgraph.h>
+#include <gr_flat_flowgraph.h>
 #include <gr_hier_block2.h>
 #include <gr_hier_block2_detail.h>
 #include <gr_local_sighandler.h>
 
 static gr_runtime_impl *s_runtime = 0;
 
+// Make a vector of gr_block from a vector of gr_basic_block
+static
+gr_block_vector_t
+make_gr_block_vector(gr_basic_block_vector_t &blocks)
+{
+  gr_block_vector_t result;
+  for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) {
+    result.push_back(make_gr_block_sptr(*p));
+  }
+
+  return result;
+}
+
 // FIXME: This prevents using more than one gr_runtime instance
 void 
 runtime_sigint_handler(int signum)
@@ -56,7 +69,7 @@ runtime_sigint_handler(int signum)
 gr_runtime_impl::gr_runtime_impl(gr_hier_block2_sptr top_block, gr_runtime *owner) 
   : d_running(false),
     d_top_block(top_block),
-    d_sfg(gr_make_simple_flowgraph()),
+    d_ffg(gr_make_flat_flowgraph()),
     d_owner(owner)
 {
   s_runtime = this;
@@ -79,12 +92,12 @@ gr_runtime_impl::start()
     throw std::runtime_error("already running");
 
   // Create new simple flow graph by flattening hierarchical block
-  d_sfg->d_detail->reset();
-  d_top_block->d_detail->flatten(d_sfg);
+  d_ffg->clear();
+  d_top_block->d_detail->flatten(d_ffg);
 
   // Validate new simple flow graph and wire it up
-  d_sfg->d_detail->validate();
-  d_sfg->d_detail->setup_connections();
+  d_ffg->validate();
+  d_ffg->setup_connections();
 
   // Execute scheduler threads
   start_threads();
@@ -96,10 +109,10 @@ gr_runtime_impl::start_threads()
   if (GR_RUNTIME_IMPL_DEBUG)
     std::cout << "start_threads: entered" << std::endl;
 
-  d_graphs = d_sfg->d_detail->partition();
-  for (std::vector<gr_block_vector_t>::iterator p = d_graphs.begin();
+  d_graphs = d_ffg->partition();
+  for (std::vector<gr_basic_block_vector_t>::iterator p = d_graphs.begin();
        p != d_graphs.end(); p++) {
-    gr_scheduler_thread *thread = new gr_scheduler_thread(*p);
+    gr_scheduler_thread *thread = new gr_scheduler_thread(make_gr_block_vector(*p));
     d_threads.push_back(thread);
     if (GR_RUNTIME_IMPL_DEBUG)
       std::cout << "start_threads: starting " << thread << std::endl;
@@ -188,14 +201,14 @@ gr_runtime_impl::restart()
     std::cout << "restart: threads stopped" << std::endl;
 
   // Create new simple flow graph 
-  gr_simple_flowgraph_sptr new_sfg = gr_make_simple_flowgraph();
-  d_top_block->d_detail->flatten(new_sfg);
-  new_sfg->validate();
-  new_sfg->d_detail->merge_connections(d_sfg);
+  gr_flat_flowgraph_sptr new_ffg = gr_make_flat_flowgraph();
+  d_top_block->d_detail->flatten(new_ffg);
+  new_ffg->validate();
+  new_ffg->merge_connections(d_ffg);
 
   if (GR_RUNTIME_IMPL_DEBUG)
     std::cout << "restart: replacing old flow graph with new" << std::endl;
-  d_sfg = new_sfg;
+  d_ffg = new_ffg;
 
   start_threads();
 }
index 17a8a985c5ac5c3ca96e703cb371bf32cc0b9eb1..f6230018a0e37990a155926c46358e0f8c1bcf13 100644 (file)
@@ -72,8 +72,8 @@ private:
     
   bool                           d_running;
   gr_hier_block2_sptr            d_top_block;
-  gr_simple_flowgraph_sptr       d_sfg;
-  std::vector<gr_block_vector_t> d_graphs;
+  gr_flat_flowgraph_sptr         d_ffg;
+  std::vector<gr_basic_block_vector_t> d_graphs;
   gr_scheduler_thread_vector_t   d_threads;
   gr_runtime                    *d_owner;
   int                            d_lock_count;
index 6ab1ac8f7849c9df6e27f9ebd47903e027927091..8af663cdfc271805ca594b62108a31f54cb80bee 100644 (file)
@@ -1,6 +1,6 @@
 /* -*- c++ -*- */
 /*
- * Copyright 2004 Free Software Foundation, Inc.
+ * Copyright 2004,2007 Free Software Foundation, Inc.
  * 
  * This file is part of GNU Radio
  * 
@@ -36,17 +36,19 @@ class gr_hier_block2;
 class gr_io_signature;
 class gr_buffer;
 class gr_buffer_reader;
-class gr_simple_flowgraph;
+class gr_flowgraph;
+class gr_flat_flowgraph;
 class gr_runtime;
 
 typedef boost::shared_ptr<gr_basic_block>       gr_basic_block_sptr;
 typedef boost::shared_ptr<gr_block>             gr_block_sptr;
-typedef boost::shared_ptr<gr_block_detail>         gr_block_detail_sptr;
-typedef boost::shared_ptr<gr_hier_block2>          gr_hier_block2_sptr;
+typedef boost::shared_ptr<gr_block_detail>     gr_block_detail_sptr;
+typedef boost::shared_ptr<gr_hier_block2>      gr_hier_block2_sptr;
 typedef boost::shared_ptr<gr_io_signature>      gr_io_signature_sptr;
-typedef boost::shared_ptr<gr_buffer>               gr_buffer_sptr;
-typedef boost::shared_ptr<gr_buffer_reader>        gr_buffer_reader_sptr;
-typedef boost::shared_ptr<gr_runtime>              gr_runtime_sptr;
-typedef boost::shared_ptr<gr_simple_flowgraph>  gr_simple_flowgraph_sptr;
+typedef boost::shared_ptr<gr_buffer>           gr_buffer_sptr;
+typedef boost::shared_ptr<gr_buffer_reader>    gr_buffer_reader_sptr;
+typedef boost::shared_ptr<gr_runtime>          gr_runtime_sptr;
+typedef boost::shared_ptr<gr_flowgraph>         gr_flowgraph_sptr;
+typedef boost::shared_ptr<gr_flat_flowgraph>    gr_flat_flowgraph_sptr;
 
 #endif /* INCLUDED_GR_RUNTIME_TYPES_H */
diff --git a/gnuradio-core/src/lib/runtime/gr_simple_flowgraph.cc b/gnuradio-core/src/lib/runtime/gr_simple_flowgraph.cc
deleted file mode 100644 (file)
index be74cec..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/* -*- 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.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <gr_simple_flowgraph.h>
-#include <gr_simple_flowgraph_detail.h>
-#include <iostream>
-
-gr_simple_flowgraph_sptr gr_make_simple_flowgraph()
-{
-  return gr_simple_flowgraph_sptr(new gr_simple_flowgraph());
-}
-
-gr_simple_flowgraph::gr_simple_flowgraph() :
-d_detail(new gr_simple_flowgraph_detail())
-{
-}
-  
-gr_simple_flowgraph::~gr_simple_flowgraph()
-{
-  delete d_detail;
-}
-
-void
-gr_simple_flowgraph::connect(gr_basic_block_sptr src_block, int src_port,
-                            gr_basic_block_sptr dst_block, int dst_port)
-{
-  d_detail->connect(gr_endpoint(src_block, src_port), gr_endpoint(dst_block, dst_port));
-}
-
-void
-gr_simple_flowgraph::connect(const gr_endpoint &src, const gr_endpoint &dst)
-{
-  d_detail->connect(src, dst);
-}
-
-void
-gr_simple_flowgraph::disconnect(gr_basic_block_sptr src_block, int src_port,
-                               gr_basic_block_sptr dst_block, int dst_port)
-{
-  d_detail->disconnect(gr_endpoint(src_block, src_port), gr_endpoint(dst_block, dst_port));
-}
-
-void
-gr_simple_flowgraph::validate()
-{
-  d_detail->validate();
-}
diff --git a/gnuradio-core/src/lib/runtime/gr_simple_flowgraph.h b/gnuradio-core/src/lib/runtime/gr_simple_flowgraph.h
deleted file mode 100644 (file)
index 998bcb6..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2006,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 (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_GR_SIMPLE_FLOWGRAPH_H
-#define INCLUDED_GR_SIMPLE_FLOWGRAPH_H
-
-#include <gr_block.h>
-#include <boost/shared_ptr.hpp>
-#include <string>
-
-gr_simple_flowgraph_sptr gr_make_simple_flowgraph();
-
-class gr_simple_flowgraph_detail;
-
-class gr_endpoint
-{
-private:
-  friend class gr_hier_block2_detail;
-  gr_basic_block_sptr d_block;
-  int d_port;
-
-public:
-  gr_endpoint() : d_block(), d_port(0) { } // Internal use only
-  gr_endpoint(gr_basic_block_sptr block, int port) { d_block = block; d_port = port; }
-  gr_basic_block_sptr block() const { return d_block; }
-  int port() const { return d_port; }
-};    
-
-typedef std::vector<gr_endpoint> gr_endpoint_vector_t;
-
-/*!
- *\brief Class representing a low-level, "flattened" flow graph
- *
- * This class holds the results of the call to gr.hier_block2.flatten(),
- * which is a graph that has only the connected blocks and edges of
- * the original hier_block2, with all the hierarchy removed.
- *
- * While this class is exported to Python via SWIG for ease of QA
- * testing, it is not used by application developers, and there is
- * no way to feed this to a gr.runtime() instance.
- */
-class gr_simple_flowgraph
-{
-private:
-  friend class gr_runtime_impl;
-  friend class gr_simple_flowgraph_detail;
-  friend class gr_hier_block2_detail;
-  friend gr_simple_flowgraph_sptr gr_make_simple_flowgraph();
-  gr_simple_flowgraph();
-
-  gr_simple_flowgraph_detail *d_detail;
-            
-public:
-  ~gr_simple_flowgraph();
-
-  void connect(gr_basic_block_sptr src_block, int src_port,
-              gr_basic_block_sptr dst_block, int dst_port);
-  void connect(const gr_endpoint &src, const gr_endpoint &dst);
-  void disconnect(gr_basic_block_sptr src_block, int src_port,
-                 gr_basic_block_sptr dst_block, int dst_port);
-  void validate();
-};
-
-#endif /* INCLUDED_GR_SIMPLE_FLOWGRAPH_H */
diff --git a/gnuradio-core/src/lib/runtime/gr_simple_flowgraph_detail.cc b/gnuradio-core/src/lib/runtime/gr_simple_flowgraph_detail.cc
deleted file mode 100644 (file)
index 2da2dad..0000000
+++ /dev/null
@@ -1,609 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2006,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 (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 <gr_simple_flowgraph.h>
-#include <gr_simple_flowgraph_detail.h>
-#include <gr_io_signature.h>
-#include <gr_block_detail.h>
-#include <gr_buffer.h>
-#include <iostream>
-#include <stdexcept>
-#include <map>
-
-#define GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG 0
-
-gr_edge_sptr
-gr_make_edge(const gr_endpoint &src, const gr_endpoint &dst)
-{
-  return gr_edge_sptr(new gr_edge(src, dst));
-}
-
-gr_edge::~gr_edge()
-{
-}
-
-gr_simple_flowgraph_detail::~gr_simple_flowgraph_detail()
-{
-}
-
-void
-gr_simple_flowgraph_detail::reset()
-{
-  // Boost shared pointers will deallocate as needed
-  d_edges.clear();
-  d_blocks.clear();
-}
-
-void
-gr_simple_flowgraph_detail::connect(const gr_endpoint &src, const gr_endpoint &dst)
-{
-  check_valid_port(src.block()->output_signature(), src.port());
-  check_valid_port(dst.block()->input_signature(), dst.port());
-  check_dst_not_used(dst);
-  check_type_match(src, dst);
-  d_edges.push_back(gr_make_edge(src,dst));
-}
-
-void
-gr_simple_flowgraph_detail::disconnect(const gr_endpoint &src, const gr_endpoint &dst)
-{
-  for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) {
-    if (src.block() == (*p)->src().block() && src.port() == (*p)->src().port() && 
-       dst.block() == (*p)->dst().block() && dst.port() == (*p)->dst().port()) {
-      d_edges.erase(p);
-      return;
-    }
-  }
-
-  throw std::invalid_argument("edge to disconnect not found");
-}
-
-void
-gr_simple_flowgraph_detail::check_valid_port(gr_io_signature_sptr sig, int port)
-{
-  if (port < 0)
-    throw std::invalid_argument("negative port number");
-  if (sig->max_streams() >= 0 && port >= sig->max_streams())
-    throw std::invalid_argument("port number exceeds max");
-}
-
-void
-gr_simple_flowgraph_detail::check_dst_not_used(const gr_endpoint &dst)
-{
-  for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++)
-    if ((*p)->dst().block() == dst.block() &&
-        (*p)->dst().port() == dst.port())
-      throw std::invalid_argument("dst already in use");
-}
-
-void
-gr_simple_flowgraph_detail::check_type_match(const gr_endpoint &src, const gr_endpoint &dst)
-{
-  int src_size = src.block()->output_signature()->sizeof_stream_item(src.port());
-  int dst_size = dst.block()->input_signature()->sizeof_stream_item(dst.port());
-
-  if (src_size != dst_size)
-    throw std::invalid_argument("type size mismatch while attempting to connect");
-}
-
-void
-gr_simple_flowgraph_detail::validate()
-{
-  d_blocks = calc_used_blocks();
-
-  for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) {
-    std::vector<int> used_ports;
-    int ninputs, noutputs;
-
-    if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
-      std::cout << "Validating block: " << (*p) << std::endl;
-
-    used_ports = calc_used_ports(*p, true); // inputs
-    ninputs = used_ports.size();
-    check_contiguity(*p, used_ports, true); // inputs
-
-    used_ports = calc_used_ports(*p, false); // outputs
-    noutputs = used_ports.size();
-    check_contiguity(*p, used_ports, false); // outputs
-
-    if (!((*p)->check_topology(ninputs, noutputs)))
-      throw std::runtime_error("check topology failed");
-  }
-}
-
-std::vector<int>
-gr_simple_flowgraph_detail::calc_used_ports(gr_basic_block_sptr block, bool check_inputs)
-{
-  std::vector<int> tmp, result;
-  std::insert_iterator<std::vector<int> > inserter(result, result.begin());
-
-  gr_edge_vector_t edges = calc_connections(block, check_inputs);
-  for (gr_edge_viter_t p = edges.begin(); p != edges.end(); p++) {
-    if (check_inputs == true)
-      tmp.push_back((*p)->dst().port());
-    else
-      tmp.push_back((*p)->src().port());
-  }
-
-  // remove duplicates
-  std::sort(tmp.begin(), tmp.end());
-  std::unique_copy(tmp.begin(), tmp.end(), inserter);
-  return result;
-}
-
-gr_edge_vector_t
-gr_simple_flowgraph_detail::calc_connections(gr_basic_block_sptr block, bool check_inputs)
-{
-  gr_edge_vector_t result;
-
-  for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) {
-    if (check_inputs) {
-      if ((*p)->dst().block() == block)
-       result.push_back(*p);
-    }
-    else {
-      if ((*p)->src().block() == block)
-       result.push_back(*p);
-    }
-  }
-
-  return result;    // assumes no duplicates
-}
-
-void
-gr_simple_flowgraph_detail::check_contiguity(gr_basic_block_sptr block,
-                                             const std::vector<int> &used_ports,
-                                             bool check_inputs)
-{
-  gr_io_signature_sptr sig =
-    check_inputs ? block->input_signature() : block->output_signature();
-
-  int nports = used_ports.size();
-  int min_ports = sig->min_streams();
-
-  if (nports == 0) {
-    if (min_ports == 0)
-      return;
-    else
-      throw std::runtime_error("insufficient ports");
-  }
-
-  if (used_ports[nports-1]+1 != nports) {
-    for (int i = 0; i < nports; i++)
-      if (used_ports[i] != i)
-       throw std::runtime_error("missing input assignment");
-  }
-}
-
-gr_basic_block_vector_t
-gr_simple_flowgraph_detail::calc_downstream_blocks(gr_basic_block_sptr block, int port)
-{
-  gr_basic_block_vector_t tmp, result;
-  std::insert_iterator<gr_basic_block_vector_t> inserter(result, result.begin());
-
-  for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++)
-    if ((*p)->src().block() == block && (*p)->src().port() == port)
-      tmp.push_back((*p)->dst().block());
-
-  // Remove duplicates
-  sort(tmp.begin(), tmp.end());
-  unique_copy(tmp.begin(), tmp.end(), inserter);
-  return result;
-}
-
-gr_basic_block_vector_t
-gr_simple_flowgraph_detail::calc_downstream_blocks(gr_basic_block_sptr block)
-{
-  gr_basic_block_vector_t tmp, result;
-  std::insert_iterator<gr_basic_block_vector_t> inserter(result, result.begin());
-
-  for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++)
-    if ((*p)->src().block() == block)
-      tmp.push_back((*p)->dst().block());
-
-  // Remove duplicates
-  sort(tmp.begin(), tmp.end());
-  unique_copy(tmp.begin(), tmp.end(), inserter);
-  return result;
-}
-
-gr_edge_vector_t
-gr_simple_flowgraph_detail::calc_upstream_edges(gr_basic_block_sptr block)
-{
-  gr_edge_vector_t result;
-
-  for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++)
-    if ((*p)->dst().block() == block)
-      result.push_back(*p);
-
-  return result; // Assume no duplicates
-}
-
-gr_basic_block_vector_t
-gr_simple_flowgraph_detail::calc_used_blocks()
-{
-  gr_basic_block_vector_t tmp, result;
-  std::insert_iterator<gr_basic_block_vector_t> inserter(result, result.begin());
-
-  for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) {
-    tmp.push_back((*p)->src().block());
-    tmp.push_back((*p)->dst().block());
-  }
-
-  sort(tmp.begin(), tmp.end());
-  unique_copy(tmp.begin(), tmp.end(), inserter);
-  return result;
-}
-
-std::vector<gr_block_vector_t>
-gr_simple_flowgraph_detail::partition()
-{
-  std::vector<gr_block_vector_t> result;
-  gr_basic_block_vector_t blocks = calc_used_blocks();
-  gr_basic_block_vector_t graph;
-
-  while (blocks.size() > 0) {
-    graph = calc_reachable_blocks(blocks[0], blocks);
-    assert(graph.size());
-    result.push_back(topological_sort(graph));
-
-    for (gr_basic_block_viter_t p = graph.begin(); p != graph.end(); p++)
-      blocks.erase(find(blocks.begin(), blocks.end(), *p));
-  }
-
-  return result;
-}
-
-gr_basic_block_vector_t
-gr_simple_flowgraph_detail::calc_reachable_blocks(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks)
-{
-  gr_basic_block_vector_t result;
-
-  // Mark all blocks as unvisited
-  for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++)
-    boost::dynamic_pointer_cast<gr_block, gr_basic_block>(*p)->detail()->set_color(gr_block_detail::WHITE);
-
-  // Recursively mark all reachable blocks
-  reachable_dfs_visit(block, blocks);
-
-  // Collect all the blocks that have been visited
-  for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++)
-    if ((boost::dynamic_pointer_cast<gr_block, gr_basic_block>(*p))->detail()->color() == gr_block_detail::BLACK)
-      result.push_back(*p);
-
-  return result;
-}
-
-// Recursively mark all reachable blocks from given block and block list
-void 
-gr_simple_flowgraph_detail::reachable_dfs_visit(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks)
-{
-  // Mark the current one as visited
-  boost::dynamic_pointer_cast<gr_block, gr_basic_block>(block)->detail()->set_color(gr_block_detail::BLACK);
-
-  // Recurse into adjacent vertices
-  gr_basic_block_vector_t adjacent = calc_adjacent_blocks(block, blocks);
-
-  for (gr_basic_block_viter_t p = adjacent.begin(); p != adjacent.end(); p++)
-    if (boost::dynamic_pointer_cast<gr_block, gr_basic_block>(*p)->detail()->color() == gr_block_detail::WHITE)
-      reachable_dfs_visit(*p, blocks);
-}
-
-// Return a list of block adjacent to a given block along any edge
-gr_basic_block_vector_t 
-gr_simple_flowgraph_detail::calc_adjacent_blocks(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks)
-{
-  gr_basic_block_vector_t tmp, result;
-  std::insert_iterator<gr_basic_block_vector_t> inserter(result, result.begin());
-    
-  // Find any blocks that are inputs or outputs
-  for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) {
-
-    if ((*p)->src().block() == block)
-      tmp.push_back((*p)->dst().block());
-    if ((*p)->dst().block() == block)
-      tmp.push_back((*p)->src().block());
-  }    
-
-  // Remove duplicates
-  sort(tmp.begin(), tmp.end());
-  unique_copy(tmp.begin(), tmp.end(), inserter);
-  return result;
-}
-
-gr_block_vector_t
-gr_simple_flowgraph_detail::topological_sort(gr_basic_block_vector_t &blocks)
-{
-  gr_basic_block_vector_t tmp;
-  gr_block_vector_t result;
-  tmp = sort_sources_first(blocks);
-
-  // Start 'em all white
-  for (gr_basic_block_viter_t p = tmp.begin(); p != tmp.end(); p++)
-    boost::dynamic_pointer_cast<gr_block, gr_basic_block>(*p)->detail()->set_color(gr_block_detail::WHITE);
-
-  for (gr_basic_block_viter_t p = tmp.begin(); p != tmp.end(); p++) {
-    if (boost::dynamic_pointer_cast<gr_block, gr_basic_block>(*p)->detail()->color() == gr_block_detail::WHITE)
-      topological_dfs_visit(*p, result);
-  }    
-
-  reverse(result.begin(), result.end());
-
-  return result;
-}
-
-bool
-gr_simple_flowgraph_detail::source_p(gr_basic_block_sptr block)
-{
-  return (calc_upstream_edges(block).size() == 0);
-}
-
-gr_basic_block_vector_t
-gr_simple_flowgraph_detail::sort_sources_first(gr_basic_block_vector_t &blocks)
-{
-  gr_basic_block_vector_t sources, nonsources, result;
-
-  for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) {
-    if (source_p(*p))
-      sources.push_back(*p);
-    else
-      nonsources.push_back(*p);
-  }
-
-  for (gr_basic_block_viter_t p = sources.begin(); p != sources.end(); p++)
-    result.push_back(*p);
-
-  for (gr_basic_block_viter_t p = nonsources.begin(); p != nonsources.end(); p++)
-    result.push_back(*p);
-
-  return result;
-}
-
-void
-gr_simple_flowgraph_detail::topological_dfs_visit(gr_basic_block_sptr block, gr_block_vector_t &output)
-{
-  boost::dynamic_pointer_cast<gr_block, gr_basic_block>(block)->detail()->set_color(gr_block_detail::GREY);
-
-  gr_basic_block_vector_t blocks(calc_downstream_blocks(block));
-
-  for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) {
-    switch (boost::dynamic_pointer_cast<gr_block, gr_basic_block>(*p)->detail()->color()) {
-    case gr_block_detail::WHITE:           
-      topological_dfs_visit(*p, output);
-      break;
-
-    case gr_block_detail::GREY:            
-      throw std::runtime_error("flow graph has loops!");
-
-    case gr_block_detail::BLACK:
-      continue;
-
-    default:
-      throw std::runtime_error("invalid color on block!");
-    }
-  }
-
-  gr_block_sptr result_block(boost::dynamic_pointer_cast<gr_block, gr_basic_block>(block));
-
-  result_block->detail()->set_color(gr_block_detail::BLACK);
-  output.push_back(result_block);
-}
-
-bool
-gr_simple_flowgraph_detail::has_block_p(gr_basic_block_sptr block)
-{
-  gr_basic_block_viter_t result;
-  result = std::find(d_blocks.begin(), d_blocks.end(), block);
-  return (result != d_blocks.end());
-}
-
-gr_edge_sptr
-gr_simple_flowgraph_detail::calc_upstream_edge(gr_basic_block_sptr block, int port)
-{
-  gr_edge_sptr result;
-
-  for (gr_edge_viter_t p = d_edges.begin(); p != d_edges.end(); p++) {
-    if ((*p)->dst().block() == block && (*p)->dst().port() == port) {
-      result = (*p);
-      break;
-    }
-  }
-
-  return result;
-}
-
-gr_block_detail_sptr
-gr_simple_flowgraph_detail::allocate_block_detail(gr_basic_block_sptr block, gr_block_detail_sptr old_detail)
-{
-  int ninputs = calc_used_ports(block, true).size();
-  int noutputs = calc_used_ports(block, false).size();
-  gr_block_detail_sptr detail = gr_make_block_detail(ninputs, noutputs);
-
-  if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
-    std::cout << "Creating block detail for " << block << std::endl;
-
-  // Re-use or allocate output buffers
-  for (int i = 0; i < noutputs; i++) {
-    gr_buffer_sptr buffer;
-
-    if (!old_detail || i >= old_detail->noutputs()) {
-      if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
-       std::cout << "Allocating new buffer for output " << i << std::endl;
-      buffer = allocate_buffer(block, i);
-    }
-    else {
-      if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
-       std::cout << "Reusing old buffer for output " << i << std::endl;
-      buffer = old_detail->output(i);
-    }
-
-    detail->set_output(i, buffer);
-  }
-
-  return detail;
-}
-
-void
-gr_simple_flowgraph_detail::connect_block_inputs(gr_basic_block_sptr block)
-{
-  gr_block_sptr grblock(boost::dynamic_pointer_cast<gr_block, gr_basic_block>(block));
-  if (!grblock)
-    throw std::runtime_error("found non-gr_block");
-  
-  // Get its detail and edges that feed into it
-  gr_block_detail_sptr detail = grblock->detail();
-  gr_edge_vector_t in_edges = calc_upstream_edges(block);
-  
-  // For each edge that feeds into it
-  for (gr_edge_viter_t e = in_edges.begin(); e != in_edges.end(); e++) {
-    // Set the buffer reader on the destination port to the output
-    // buffer on the source port
-    int dst_port = (*e)->dst().port();
-    int src_port = (*e)->src().port();
-    gr_basic_block_sptr src_block = (*e)->src().block();
-    gr_block_sptr src_grblock(boost::dynamic_pointer_cast<gr_block, gr_basic_block>(src_block));
-    if (!grblock)
-      throw std::runtime_error("found non-gr_block");
-    gr_buffer_sptr src_buffer = src_grblock->detail()->output(src_port);
-    
-    if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
-      std::cout << "Setting input " << dst_port << " from edge " << (*e) << std::endl;
-
-    detail->set_input(dst_port, gr_buffer_add_reader(src_buffer, grblock->history()-1));
-  }
-}
-
-gr_buffer_sptr
-gr_simple_flowgraph_detail::allocate_buffer(gr_basic_block_sptr block, int port)
-{
-  gr_block_sptr grblock(boost::dynamic_pointer_cast<gr_block, gr_basic_block>(block));
-  if (!grblock)
-    throw std::runtime_error("allocate_buffer found non-gr_block");
-  int item_size = block->output_signature()->sizeof_stream_item(port);
-  int nitems = s_fixed_buffer_size/item_size;
-
-  // Make sure there are at least twice the output_multiple no. of items
-  if (nitems < 2*grblock->output_multiple())   // Note: this means output_multiple()
-    nitems = 2*grblock->output_multiple();     // can't be changed by block dynamically
-
-  // If any downstream blocks are decimators and/or have a large output_multiple,
-  // ensure we have a buffer at least twice their decimation factor*output_multiple
-  gr_basic_block_vector_t blocks = calc_downstream_blocks(block, port);
-  for (gr_basic_block_viter_t p = blocks.begin(); p != blocks.end(); p++) {
-    gr_block_sptr dgrblock(boost::dynamic_pointer_cast<gr_block, gr_basic_block>(*p));
-      if (!dgrblock)
-       throw std::runtime_error("allocate_buffer found non-gr_block");
-    int decimation = (int)(1.0/dgrblock->relative_rate());
-    int multiple   = dgrblock->output_multiple();
-    int history    = dgrblock->history();
-    nitems = std::max(nitems, 2*(decimation*multiple+history));
-  }
-
-  return gr_make_buffer(nitems, item_size);
-}
-
-void
-gr_simple_flowgraph_detail::setup_connections()
-{
-  // Assign block details to blocks
-  for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++)
-    boost::dynamic_pointer_cast<gr_block, gr_basic_block>(*p)->set_detail(allocate_block_detail(*p));
-
-  // Connect inputs to outputs for each block
-  for(gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++)
-    connect_block_inputs(*p);
-}
-
-void
-gr_simple_flowgraph_detail::merge_connections(gr_simple_flowgraph_sptr old_sfg)
-{
-  std::map<gr_block_sptr, gr_block_detail_sptr> old_details;
-
-  // Allocate or reuse output buffers
-  for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) {
-    gr_block_sptr block(boost::dynamic_pointer_cast<gr_block, gr_basic_block>(*p));
-
-    gr_block_detail_sptr old_detail = block->detail();
-    block->set_detail(allocate_block_detail(block, old_detail));
-
-    // Save old detail for use in next step
-    old_details[block] = old_detail;
-  }
-
-  for (gr_basic_block_viter_t p = d_blocks.begin(); p != d_blocks.end(); p++) {
-    gr_block_sptr block(boost::dynamic_pointer_cast<gr_block, gr_basic_block>(*p));
-
-    if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
-      std::cout << "merge: testing " << (*p) << "...";
-    
-    if (old_sfg->d_detail->has_block_p(*p)) {
-      // Block exists in old flow graph
-      if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
-       std::cout << "used in old flow graph" << std::endl;
-      gr_block_detail_sptr detail = block->detail();
-
-      // Iterate through the inputs and see what needs to be done
-      for (int i = 0; i < detail->ninputs(); i++) {
-       if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
-         std::cout << "Checking input " << i << "...";
-
-       gr_edge_sptr edge = calc_upstream_edge(*p, i);
-       if (!edge)
-         throw std::runtime_error("merge: missing input edge");
-
-       // Fish out old buffer reader and see if it matches correct buffer from edge list
-       gr_block_sptr src_block(boost::dynamic_pointer_cast<gr_block, gr_basic_block>(edge->src().block()));
-       gr_block_detail_sptr src_detail = src_block->detail();
-       gr_buffer_sptr src_buffer = src_detail->output(edge->src().port());
-       gr_buffer_reader_sptr old_reader;
-       gr_block_detail_sptr old_detail = old_details[block];
-       if (old_detail && i < old_detail->ninputs())
-         old_reader = old_detail->input(i);
-       
-       // If there's a match, use it
-       if (old_reader && (src_buffer == old_reader->buffer())) {
-         if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
-           std::cout << "matched" << std::endl;
-         detail->set_input(i, old_reader);
-
-       }
-       else {
-         if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
-           std::cout << "needs a new reader" << std::endl;
-
-         // Create new buffer reader and assign
-         detail->set_input(i, gr_buffer_add_reader(src_buffer, block->history()-1));
-       }
-      }
-    }
-    else {
-      // Block is new, it just needs buffer readers at this point
-      if (GR_SIMPLE_FLOWGRAPH_DETAIL_DEBUG)
-       std::cout << "new block" << std::endl;
-      connect_block_inputs(block);
-    }
-  }  
-}
diff --git a/gnuradio-core/src/lib/runtime/gr_simple_flowgraph_detail.h b/gnuradio-core/src/lib/runtime/gr_simple_flowgraph_detail.h
deleted file mode 100644 (file)
index 53b6203..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/* -*- c++ -*- */
-/*
- * Copyright 2006,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 (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_GR_SIMPLE_FLOWGRAPH_DETAIL_H
-#define INCLUDED_GR_SIMPLE_FLOWGRAPH_DETAIL_H
-
-#include <gr_basic_block.h>
-#include <gr_simple_flowgraph.h>
-#include <iostream>
-
-#define GR_FIXED_BUFFER_SIZE (32*(1L<<10))
-
-class gr_edge;
-typedef boost::shared_ptr<gr_edge> gr_edge_sptr;
-gr_edge_sptr gr_make_edge(const gr_endpoint &src, const gr_endpoint &dst);
-
-class gr_edge
-{
-private:
-  friend gr_edge_sptr gr_make_edge(const gr_endpoint &src, const gr_endpoint &dst);
-  gr_edge(const gr_endpoint &src, const gr_endpoint &dst) : d_src(src), d_dst(dst) { }
-
-  gr_endpoint d_src;
-  gr_endpoint d_dst;
-
-public:
-  ~gr_edge();
-
-  const gr_endpoint &src() const { return d_src; }
-  const gr_endpoint &dst() const { return d_dst; }
-};
-
-typedef std::vector<gr_edge_sptr> gr_edge_vector_t;
-typedef std::vector<gr_edge_sptr>::iterator gr_edge_viter_t;
-
-class gr_simple_flowgraph_detail
-{
-private:
-  friend class gr_simple_flowgraph;
-  friend class gr_runtime_impl;
-  friend class gr_hier_block2_detail;
-  friend class topo_block_cmp;
-    
-  gr_simple_flowgraph_detail() : d_blocks(), d_edges() { }
-
-  gr_basic_block_vector_t d_blocks;
-  gr_edge_vector_t  d_edges;
-  static const unsigned int s_fixed_buffer_size = GR_FIXED_BUFFER_SIZE;
-    
-  void reset();
-  void connect(const gr_endpoint &src, const gr_endpoint &dst);
-  void disconnect(const gr_endpoint &src, const gr_endpoint &dst);
-  void check_valid_port(gr_io_signature_sptr sig, int port);
-  void check_dst_not_used(const gr_endpoint &dst);
-  void check_type_match(const gr_endpoint &src, const gr_endpoint &dst);
-  void validate();
-  gr_edge_vector_t calc_connections(gr_basic_block_sptr block, bool check_inputs); // false=use outputs
-  std::vector<int> calc_used_ports(gr_basic_block_sptr block, bool check_inputs); 
-  void check_contiguity(gr_basic_block_sptr block, const std::vector<int> &used_ports, bool check_inputs);
-  void setup_connections();
-  void merge_connections(gr_simple_flowgraph_sptr sfg);
-
-  void connect_block_inputs(gr_basic_block_sptr block);
-  gr_block_detail_sptr allocate_block_detail(gr_basic_block_sptr block, 
-                                            gr_block_detail_sptr old_detail=gr_block_detail_sptr());
-  gr_buffer_sptr allocate_buffer(gr_basic_block_sptr block, int port);
-  gr_basic_block_vector_t calc_downstream_blocks(gr_basic_block_sptr block, int port);
-  gr_basic_block_vector_t calc_downstream_blocks(gr_basic_block_sptr block);
-  gr_edge_sptr calc_upstream_edge(gr_basic_block_sptr block, int port);
-  gr_edge_vector_t calc_upstream_edges(gr_basic_block_sptr block);
-  gr_basic_block_vector_t calc_used_blocks();
-  std::vector<gr_block_vector_t> partition();
-  gr_basic_block_vector_t calc_reachable_blocks(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks);
-  gr_block_vector_t topological_sort(gr_basic_block_vector_t &blocks);
-  void reachable_dfs_visit(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks);
-  gr_basic_block_vector_t calc_adjacent_blocks(gr_basic_block_sptr block, gr_basic_block_vector_t &blocks);
-  bool source_p(gr_basic_block_sptr block);
-  gr_basic_block_vector_t sort_sources_first(gr_basic_block_vector_t &blocks);
-  void topological_dfs_visit(gr_basic_block_sptr block, gr_block_vector_t &output);
-  bool has_block_p(gr_basic_block_sptr block);
-
-public:
-  ~gr_simple_flowgraph_detail();
-};
-
-inline std::ostream&
-operator <<(std::ostream &os, const gr_endpoint endp)
-{
-  os << endp.block() << ":" << endp.port();
-  return os;
-}
-
-inline std::ostream&
-operator <<(std::ostream &os, const gr_edge_sptr edge)
-{
-  os << edge->src() << "->" << edge->dst();
-  return os;
-}
-
-inline void
-enumerate_edges(gr_edge_vector_t &edges)
-{
-  std::cout << "Edge list has " << edges.size() << " elements" << std::endl;
-  for(gr_edge_viter_t p = edges.begin(); p != edges.end(); p++)
-    std::cout << *p << std::endl;
-}
-
-#endif /* INCLUDED_GR_SIMPLE_FLOWGRAPH_H */
diff --git a/gnuradio-core/src/lib/runtime/qa_gr_flowgraph.cc b/gnuradio-core/src/lib/runtime/qa_gr_flowgraph.cc
new file mode 100644 (file)
index 0000000..c883c16
--- /dev/null
@@ -0,0 +1,245 @@
+/* -*- c++ -*- */
+/*
+ * 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 (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 <qa_gr_flowgraph.h>
+#include <gr_flowgraph.h>
+#include <gr_nop.h>
+#include <gr_null_source.h>
+#include <gr_null_sink.h>
+
+void qa_gr_flowgraph::t0()
+{
+  gr_flowgraph_sptr fg = gr_make_flowgraph();
+
+  CPPUNIT_ASSERT(fg);
+}
+
+void qa_gr_flowgraph::t1_connect()
+{
+  gr_flowgraph_sptr fg = gr_make_flowgraph();
+
+  gr_block_sptr nop1 = gr_make_nop(sizeof(int));
+  gr_block_sptr nop2 = gr_make_nop(sizeof(int));
+
+  fg->connect(nop1, 0, nop2, 0);
+}
+
+void qa_gr_flowgraph::t2_connect_invalid_src_port_neg()
+{
+  gr_flowgraph_sptr fg = gr_make_flowgraph();
+
+  gr_block_sptr nop1 = gr_make_nop(sizeof(int));
+  gr_block_sptr nop2 = gr_make_nop(sizeof(int));
+
+  CPPUNIT_ASSERT_THROW(fg->connect(nop1, -1, nop2, 0), std::invalid_argument);
+}
+
+void qa_gr_flowgraph::t3_connect_src_port_exceeds()
+{
+  gr_flowgraph_sptr fg = gr_make_flowgraph();
+
+  gr_block_sptr src = gr_make_null_source(sizeof(int));
+  gr_block_sptr dst = gr_make_null_sink(sizeof(int));
+
+  CPPUNIT_ASSERT_THROW(fg->connect(src, 1, dst, 0), std::invalid_argument);
+}
+
+void qa_gr_flowgraph::t4_connect_invalid_dst_port_neg()
+{
+  gr_flowgraph_sptr fg = gr_make_flowgraph();
+
+  gr_block_sptr nop1 = gr_make_nop(sizeof(int));
+  gr_block_sptr nop2 = gr_make_nop(sizeof(int));
+
+  CPPUNIT_ASSERT_THROW(fg->connect(nop1, 0, nop2, -1), std::invalid_argument);
+}
+
+void qa_gr_flowgraph::t5_connect_dst_port_exceeds()
+{
+  gr_flowgraph_sptr fg = gr_make_flowgraph();
+
+  gr_block_sptr src = gr_make_null_source(sizeof(int));
+  gr_block_sptr dst = gr_make_null_sink(sizeof(int));
+
+  CPPUNIT_ASSERT_THROW(fg->connect(src, 0, dst, 1), std::invalid_argument);
+}
+
+void qa_gr_flowgraph::t6_connect_dst_in_use()
+{
+  gr_flowgraph_sptr fg = gr_make_flowgraph();
+
+  gr_block_sptr src1 = gr_make_null_source(sizeof(int));
+  gr_block_sptr src2 = gr_make_null_source(sizeof(int));
+  gr_block_sptr dst = gr_make_null_sink(sizeof(int));
+
+  fg->connect(src1, 0, dst, 0);
+  CPPUNIT_ASSERT_THROW(fg->connect(src2, 0, dst, 0), std::invalid_argument);
+}
+
+void qa_gr_flowgraph::t7_connect_one_src_two_dst()
+{
+  gr_flowgraph_sptr fg = gr_make_flowgraph();
+
+  gr_block_sptr src = gr_make_null_source(sizeof(int));
+  gr_block_sptr dst1 = gr_make_null_sink(sizeof(int));
+  gr_block_sptr dst2 = gr_make_null_sink(sizeof(int));
+
+  fg->connect(src, 0, dst1, 0);
+  fg->connect(src, 0, dst2, 0);
+}
+
+void qa_gr_flowgraph::t8_connect_type_mismatch()
+{
+  gr_flowgraph_sptr fg = gr_make_flowgraph();
+
+  gr_block_sptr nop1 = gr_make_nop(sizeof(char));
+  gr_block_sptr nop2 = gr_make_nop(sizeof(int));
+
+  CPPUNIT_ASSERT_THROW(fg->connect(nop1, 0, nop2, 0), std::invalid_argument);
+}
+
+void qa_gr_flowgraph::t9_disconnect()
+{
+  gr_flowgraph_sptr fg = gr_make_flowgraph();
+
+  gr_block_sptr nop1 = gr_make_nop(sizeof(int));
+  gr_block_sptr nop2 = gr_make_nop(sizeof(int));
+
+  fg->connect(nop1, 0, nop2, 0);
+  fg->disconnect(nop1, 0, nop2, 0);
+}
+
+void qa_gr_flowgraph::t10_disconnect_unconnected_block()
+{
+  gr_flowgraph_sptr fg = gr_make_flowgraph();
+
+  gr_block_sptr nop1 = gr_make_nop(sizeof(int));
+  gr_block_sptr nop2 = gr_make_nop(sizeof(int));
+  gr_block_sptr nop3 = gr_make_nop(sizeof(int));
+
+  fg->connect(nop1, 0, nop2, 0);
+  CPPUNIT_ASSERT_THROW(fg->disconnect(nop1, 0, nop3, 0), std::invalid_argument);
+}
+
+void qa_gr_flowgraph::t11_disconnect_unconnected_port()
+{
+  gr_flowgraph_sptr fg = gr_make_flowgraph();
+
+  gr_block_sptr nop1 = gr_make_nop(sizeof(int));
+  gr_block_sptr nop2 = gr_make_nop(sizeof(int));
+
+  fg->connect(nop1, 0, nop2, 0);
+  CPPUNIT_ASSERT_THROW(fg->disconnect(nop1, 0, nop2, 1), std::invalid_argument);
+}
+
+void qa_gr_flowgraph::t12_validate()
+{
+  gr_flowgraph_sptr fg = gr_make_flowgraph();
+
+  gr_block_sptr nop1 = gr_make_nop(sizeof(int));
+  gr_block_sptr nop2 = gr_make_nop(sizeof(int));
+
+  fg->connect(nop1, 0, nop2, 0);
+  fg->validate();
+}
+
+void qa_gr_flowgraph::t13_validate_missing_input_assignment()
+{
+  gr_flowgraph_sptr fg = gr_make_flowgraph();
+
+  gr_block_sptr nop1 = gr_make_nop(sizeof(int));
+  gr_block_sptr nop2 = gr_make_nop(sizeof(int));
+
+  fg->connect(nop1, 0, nop2, 0);
+  fg->connect(nop1, 0, nop2, 2);
+  CPPUNIT_ASSERT_THROW(fg->validate(), std::runtime_error);
+}
+
+void qa_gr_flowgraph::t14_validate_missing_output_assignment()
+{
+  gr_flowgraph_sptr fg = gr_make_flowgraph();
+
+  gr_block_sptr nop1 = gr_make_nop(sizeof(int));
+  gr_block_sptr nop2 = gr_make_nop(sizeof(int));
+
+  fg->connect(nop1, 0, nop2, 0);
+  fg->connect(nop1, 2, nop2, 1);
+  CPPUNIT_ASSERT_THROW(fg->validate(), std::runtime_error);
+}
+
+void qa_gr_flowgraph::t15_clear()
+{
+  gr_flowgraph_sptr fg = gr_make_flowgraph();
+
+  gr_block_sptr nop1 = gr_make_nop(sizeof(int));
+  gr_block_sptr nop2 = gr_make_nop(sizeof(int));
+
+  fg->connect(nop1, 0, nop2, 0);
+
+  CPPUNIT_ASSERT(fg->edges().size() == 1);
+  CPPUNIT_ASSERT(fg->calc_used_blocks().size() == 2);
+
+  fg->clear();
+
+  CPPUNIT_ASSERT(fg->edges().size() == 0);
+  CPPUNIT_ASSERT(fg->calc_used_blocks().size() == 0);
+}
+
+void qa_gr_flowgraph::t16_partition()
+{
+  gr_flowgraph_sptr fg = gr_make_flowgraph();
+
+  gr_block_sptr nop11 = gr_make_nop(sizeof(int));
+  gr_block_sptr nop12 = gr_make_nop(sizeof(int));
+  gr_block_sptr nop13 = gr_make_nop(sizeof(int));
+  gr_block_sptr nop14 = gr_make_nop(sizeof(int));
+
+  gr_block_sptr nop21 = gr_make_nop(sizeof(int));
+  gr_block_sptr nop22 = gr_make_nop(sizeof(int));
+  gr_block_sptr nop23 = gr_make_nop(sizeof(int));
+
+  gr_block_sptr nop31 = gr_make_nop(sizeof(int));
+  gr_block_sptr nop32 = gr_make_nop(sizeof(int));
+  
+  // Build disjoint graph #1
+  fg->connect(nop11, 0, nop12, 0);
+  fg->connect(nop12, 0, nop13, 0);
+  fg->connect(nop13, 0, nop14, 0);
+
+  // Build disjoint graph #2
+  fg->connect(nop21, 0, nop22, 0);
+  fg->connect(nop22, 0, nop23, 0);
+
+  // Build disjoint graph #3
+  fg->connect(nop31, 0, nop32, 0);
+
+  std::vector<gr_basic_block_vector_t> graphs = fg->partition();
+
+  CPPUNIT_ASSERT(graphs.size() == 3);
+  CPPUNIT_ASSERT(graphs[0].size() == 4);
+  CPPUNIT_ASSERT(graphs[1].size() == 3);
+  CPPUNIT_ASSERT(graphs[2].size() == 2);
+}
diff --git a/gnuradio-core/src/lib/runtime/qa_gr_flowgraph.h b/gnuradio-core/src/lib/runtime/qa_gr_flowgraph.h
new file mode 100644 (file)
index 0000000..2253afc
--- /dev/null
@@ -0,0 +1,75 @@
+/* -*- c++ -*- */
+/*
+ * 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 (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_GR_FLOWGRAPH_H
+#define INCLUDED_QA_GR_FLOWGRAPH_H
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <cppunit/TestCase.h>
+#include <stdexcept>
+
+class qa_gr_flowgraph : public CppUnit::TestCase 
+{
+  CPPUNIT_TEST_SUITE(qa_gr_flowgraph);
+  
+  CPPUNIT_TEST(t0);
+  CPPUNIT_TEST(t1_connect);
+  CPPUNIT_TEST(t2_connect_invalid_src_port_neg);
+  CPPUNIT_TEST(t3_connect_src_port_exceeds);
+  CPPUNIT_TEST(t4_connect_invalid_dst_port_neg);
+  CPPUNIT_TEST(t5_connect_dst_port_exceeds);
+  CPPUNIT_TEST(t6_connect_dst_in_use);
+  CPPUNIT_TEST(t7_connect_one_src_two_dst);
+  CPPUNIT_TEST(t8_connect_type_mismatch);
+  CPPUNIT_TEST(t9_disconnect);
+  CPPUNIT_TEST(t10_disconnect_unconnected_block);
+  CPPUNIT_TEST(t11_disconnect_unconnected_port);
+  CPPUNIT_TEST(t12_validate);
+  CPPUNIT_TEST(t13_validate_missing_input_assignment);
+  CPPUNIT_TEST(t14_validate_missing_output_assignment);
+  CPPUNIT_TEST(t15_clear);
+  CPPUNIT_TEST(t16_partition);
+
+  CPPUNIT_TEST_SUITE_END();
+
+private:
+
+  void t0();
+  void t1_connect();
+  void t2_connect_invalid_src_port_neg();
+  void t3_connect_src_port_exceeds();
+  void t4_connect_invalid_dst_port_neg();
+  void t5_connect_dst_port_exceeds();
+  void t6_connect_dst_in_use();
+  void t7_connect_one_src_two_dst();
+  void t8_connect_type_mismatch();
+  void t9_disconnect();
+  void t10_disconnect_unconnected_block();
+  void t11_disconnect_unconnected_port();
+  void t12_validate();
+  void t13_validate_missing_input_assignment();
+  void t14_validate_missing_output_assignment();
+  void t15_clear();
+  void t16_partition();
+};
+
+#endif /* INCLUDED_QA_GR_FLOWGRAPH_H */
index 2abdc36b3a879ff80eaa19227b30be467232e486..5c00a4fbe1234f4ac4ed56590f61f74c0f7b2aa7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2002 Free Software Foundation, Inc.
+ * Copyright 2002,2007 Free Software Foundation, Inc.
  * 
  * This file is part of GNU Radio
  * 
@@ -33,6 +33,7 @@
 #include <qa_gr_vmcircbuf.h>
 #include <qa_gr_io_signature.h>
 #include <qa_gr_block.h>
+#include <qa_gr_flowgraph.h>
 #include <qa_gr_hier_block2.h>
 #include <qa_gr_buffer.h>
 
@@ -44,6 +45,7 @@ qa_runtime::suite ()
   s->addTest (qa_gr_vmcircbuf::suite ());
   s->addTest (qa_gr_io_signature::suite ());
   s->addTest (qa_gr_block::suite ());
+  s->addTest (qa_gr_flowgraph::suite ());
   s->addTest (qa_gr_hier_block2::suite ());
   s->addTest (qa_gr_buffer::suite ());
   
index 1e12a5d736463a1e44f688ddbff94b438d2713df..9fa002501ab96157a68fc0bcfce0336c7e0ae41b 100755 (executable)
@@ -20,14 +20,6 @@ class test_hier_block2(gr_unittest.TestCase):
        self.assertEqual(1, hblock.output_signature().max_streams())
        self.assertEqual(gr.sizeof_int, hblock.output_signature().sizeof_stream_item(0))
 
-    def test_001_connect_internal(self):
-       hblock = gr.hier_block2("test_block", 
-                               gr.io_signature(1,1,gr.sizeof_int), 
-                               gr.io_signature(1,1,gr.sizeof_int))
-       nop1 = gr.nop(gr.sizeof_int)
-       nop2 = gr.nop(gr.sizeof_int)
-       hblock.connect(nop1, nop2)
-
     def test_002_connect_input(self):
        hblock = gr.hier_block2("test_block", 
                                gr.io_signature(1,1,gr.sizeof_int), 
@@ -35,7 +27,7 @@ class test_hier_block2(gr_unittest.TestCase):
        nop1 = gr.nop(gr.sizeof_int)
        hblock.connect(hblock, nop1)
 
-    def test_002a_connect_input_in_use(self):
+    def test_003_connect_input_in_use(self):
        hblock = gr.hier_block2("test_block", 
                                gr.io_signature(1,1,gr.sizeof_int), 
                                gr.io_signature(1,1,gr.sizeof_int))
@@ -45,14 +37,14 @@ class test_hier_block2(gr_unittest.TestCase):
        self.assertRaises(ValueError,
            lambda: hblock.connect(hblock, nop2))
 
-    def test_003_connect_output(self):
+    def test_004_connect_output(self):
        hblock = gr.hier_block2("test_block", 
                                gr.io_signature(1,1,gr.sizeof_int), 
                                gr.io_signature(1,1,gr.sizeof_int))
        nop1 = gr.nop(gr.sizeof_int)
        hblock.connect(nop1, hblock)
 
-    def test_003a_connect_output_in_use(self):
+    def test_005_connect_output_in_use(self):
        hblock = gr.hier_block2("test_block", 
                                gr.io_signature(1,1,gr.sizeof_int), 
                                gr.io_signature(1,1,gr.sizeof_int))
@@ -62,7 +54,7 @@ class test_hier_block2(gr_unittest.TestCase):
        self.assertRaises(ValueError,
            lambda: hblock.connect(nop2, hblock))
 
-    def test_004_connect_invalid_src_port_neg(self):
+    def test_006_connect_invalid_src_port_neg(self):
        hblock = gr.hier_block2("test_block", 
                                gr.io_signature(1,1,gr.sizeof_int), 
                                gr.io_signature(1,1,gr.sizeof_int))
@@ -78,7 +70,7 @@ class test_hier_block2(gr_unittest.TestCase):
        self.assertRaises(ValueError, 
            lambda: hblock.connect((hblock, 1), nop1))
 
-    def test_006_connect_invalid_dst_port_neg(self):
+    def test_007_connect_invalid_dst_port_neg(self):
        hblock = gr.hier_block2("test_block", 
                                gr.io_signature(1,1,gr.sizeof_int), 
                                gr.io_signature(1,1,gr.sizeof_int))
@@ -87,7 +79,7 @@ class test_hier_block2(gr_unittest.TestCase):
        self.assertRaises(ValueError, 
            lambda: hblock.connect(nop1, (nop2, -1)))
 
-    def test_007_connect_invalid_dst_port_exceeds(self):
+    def test_008_connect_invalid_dst_port_exceeds(self):
        hblock = gr.hier_block2("test_block", 
                                gr.io_signature(1,1,gr.sizeof_int), 
                                gr.io_signature(1,1,gr.sizeof_int))
@@ -96,54 +88,11 @@ class test_hier_block2(gr_unittest.TestCase):
        self.assertRaises(ValueError, 
            lambda: hblock.connect(nop1, (nop2, 1)))
 
-    def test_008_connect_dst_port_in_use(self):
-       hblock = gr.hier_block2("test_block", 
-                               gr.io_signature(1,1,gr.sizeof_int), 
-                               gr.io_signature(1,1,gr.sizeof_int))
-       nop1 = gr.nop(gr.sizeof_int)
-       nop2 = gr.nop(gr.sizeof_int)
-       hblock.connect(nop1, nop2);
-       self.assertRaises(ValueError, 
-           lambda: hblock.connect(nop1, nop2))
-
-    def test_009_connect_one_src_two_dst(self):
-       hblock = gr.top_block("test_block")
-       src = gr.null_source(gr.sizeof_int)
-       dst1 = gr.null_sink(gr.sizeof_int)
-       dst2 = gr.null_sink(gr.sizeof_int)
-       hblock.connect(src, dst1)
-       hblock.connect(src, dst2)
-
-    def test_010_connect_type_mismatch(self):
-       hblock = gr.top_block("test_block")
-       nop1 = gr.nop(gr.sizeof_char)
-       nop2 = gr.nop(gr.sizeof_int)
-       self.assertRaises(ValueError, 
-           lambda: hblock.connect(nop1, nop2))
-
-    def test_011_check_topology(self):
+    def test_009_check_topology(self):
        hblock = gr.top_block("test_block")
        hblock.check_topology(0, 0)
 
-    def test_012_disconnect(self):
-       hblock = gr.top_block("test_block") 
-       nop1 = gr.nop(gr.sizeof_int)
-       nop2 = gr.nop(gr.sizeof_int)
-       hblock.connect(nop1, nop2)
-        hblock.disconnect(nop1, nop2)
-
-    def test_013_disconnect_not_connected(self):
-       hblock = gr.hier_block2("test_block", 
-                               gr.io_signature(1,1,gr.sizeof_int), 
-                               gr.io_signature(1,1,gr.sizeof_int))
-       nop1 = gr.nop(gr.sizeof_int)
-       nop2 = gr.nop(gr.sizeof_int)
-       nop3 = gr.nop(gr.sizeof_int)
-       hblock.connect(nop1, nop2)
-       self.assertRaises(ValueError, 
-           lambda: hblock.disconnect(nop1, nop3))
-
-    def test_014_run(self):
+    def test_010_run(self):
         expected = (1.0, 2.0, 3.0, 4.0)
         hblock = gr.top_block("test_block")
         src = gr.vector_source_f(expected, False)
@@ -158,7 +107,7 @@ class test_hier_block2(gr_unittest.TestCase):
         self.assertEquals(expected, actual1)
         self.assertEquals(expected, actual2)
 
-    def test_015_disconnect_input(self):
+    def test_012_disconnect_input(self):
        hblock = gr.hier_block2("test_block", 
                                gr.io_signature(1,1,gr.sizeof_int), 
                                gr.io_signature(1,1,gr.sizeof_int))
@@ -166,7 +115,7 @@ class test_hier_block2(gr_unittest.TestCase):
        hblock.connect(hblock, nop1)
         hblock.disconnect(hblock, nop1)
    
-    def test_016_disconnect_input_not_connected(self):
+    def test_013_disconnect_input_not_connected(self):
        hblock = gr.hier_block2("test_block", 
                                gr.io_signature(1,1,gr.sizeof_int), 
                                gr.io_signature(1,1,gr.sizeof_int))
@@ -176,7 +125,7 @@ class test_hier_block2(gr_unittest.TestCase):
         self.assertRaises(ValueError,
             lambda: hblock.disconnect(hblock, nop2))
    
-    def test_017_disconnect_input_neg(self):
+    def test_014_disconnect_input_neg(self):
        hblock = gr.hier_block2("test_block", 
                                gr.io_signature(1,1,gr.sizeof_int), 
                                gr.io_signature(1,1,gr.sizeof_int))
@@ -185,7 +134,7 @@ class test_hier_block2(gr_unittest.TestCase):
         self.assertRaises(ValueError,
             lambda: hblock.disconnect((hblock, -1), nop1))
 
-    def test_018_disconnect_input_exceeds(self):
+    def test_015_disconnect_input_exceeds(self):
        hblock = gr.hier_block2("test_block", 
                                gr.io_signature(1,1,gr.sizeof_int), 
                                gr.io_signature(1,1,gr.sizeof_int))
@@ -194,7 +143,7 @@ class test_hier_block2(gr_unittest.TestCase):
         self.assertRaises(ValueError,
             lambda: hblock.disconnect((hblock, 1), nop1))
 
-    def test_019_disconnect_output(self):
+    def test_016_disconnect_output(self):
        hblock = gr.hier_block2("test_block", 
                                gr.io_signature(1,1,gr.sizeof_int), 
                                gr.io_signature(1,1,gr.sizeof_int))
@@ -202,7 +151,7 @@ class test_hier_block2(gr_unittest.TestCase):
        hblock.connect(nop1, hblock)
         hblock.disconnect(nop1, hblock)
    
-    def test_020_disconnect_output_not_connected(self):
+    def test_017_disconnect_output_not_connected(self):
        hblock = gr.hier_block2("test_block", 
                                gr.io_signature(1,1,gr.sizeof_int), 
                                gr.io_signature(1,1,gr.sizeof_int))
@@ -212,7 +161,7 @@ class test_hier_block2(gr_unittest.TestCase):
         self.assertRaises(ValueError,
             lambda: hblock.disconnect(nop2, hblock))
    
-    def test_021_disconnect_output_neg(self):
+    def test_018_disconnect_output_neg(self):
        hblock = gr.hier_block2("test_block", 
                                gr.io_signature(1,1,gr.sizeof_int), 
                                gr.io_signature(1,1,gr.sizeof_int))
@@ -221,7 +170,7 @@ class test_hier_block2(gr_unittest.TestCase):
         self.assertRaises(ValueError,
             lambda: hblock.disconnect(nop1, (hblock, -1)))
 
-    def test_022_disconnect_output_exceeds(self):
+    def test_019_disconnect_output_exceeds(self):
        hblock = gr.hier_block2("test_block", 
                                gr.io_signature(1,1,gr.sizeof_int), 
                                gr.io_signature(1,1,gr.sizeof_int))
@@ -230,7 +179,7 @@ class test_hier_block2(gr_unittest.TestCase):
         self.assertRaises(ValueError,
             lambda: hblock.disconnect(nop1, (hblock, 1)))
 
-    def test_023_run(self):
+    def test_020_run(self):
        hblock = gr.top_block("test_block")
        data = (1.0, 2.0, 3.0, 4.0)
        src = gr.vector_source_f(data, False)