From 6b2e4ef52debaa0a61cf242b20818d161d79cc85 Mon Sep 17 00:00:00 2001
From: Josh Blum <josh@joshknows.com>
Date: Fri, 27 Apr 2012 16:19:49 -0700
Subject: convert: added prio param to get converter

We can now test generic conversion implementations against SIMD (for example)
---
 host/include/uhd/convert.hpp      |  8 ++++++--
 host/lib/convert/convert_impl.cpp | 43 +++++++++++++++++++++------------------
 host/tests/convert_test.cpp       | 28 ++++++++++++++++++-------
 3 files changed, 50 insertions(+), 29 deletions(-)

(limited to 'host')

diff --git a/host/include/uhd/convert.hpp b/host/include/uhd/convert.hpp
index f906ff0e9..c6b005867 100644
--- a/host/include/uhd/convert.hpp
+++ b/host/include/uhd/convert.hpp
@@ -1,5 +1,5 @@
 //
-// Copyright 2011 Ettus Research LLC
+// Copyright 2011-2012 Ettus Research LLC
 //
 // This program is free software: you can redistribute it and/or modify
 // it under the terms of the GNU General Public License as published by
@@ -80,9 +80,13 @@ namespace uhd{ namespace convert{
     /*!
      * Get a converter factory function.
      * \param id identify the conversion
+     * \param prio the desired prio or -1 for best
      * \return the converter factory function
      */
-    UHD_API function_type get_converter(const id_type &id);
+    UHD_API function_type get_converter(
+        const id_type &id,
+        const priority_type prio = -1
+    );
 
     /*!
      * Register the size of a particular item.
diff --git a/host/lib/convert/convert_impl.cpp b/host/lib/convert/convert_impl.cpp
index 12ad54486..dc7f8f9dc 100644
--- a/host/lib/convert/convert_impl.cpp
+++ b/host/lib/convert/convert_impl.cpp
@@ -22,6 +22,7 @@
 #include <uhd/exception.hpp>
 #include <boost/cstdint.hpp>
 #include <boost/format.hpp>
+#include <boost/foreach.hpp>
 #include <complex>
 
 using namespace uhd;
@@ -50,18 +51,10 @@ std::string convert::id_type::to_pp_string(void) const{
     );
 }
 
-/***********************************************************************
- * Define types for the function tables
- **********************************************************************/
-struct fcn_table_entry_type{
-    convert::priority_type prio;
-    convert::function_type fcn;
-};
-
 /***********************************************************************
  * Setup the table registry
  **********************************************************************/
-typedef uhd::dict<convert::id_type, fcn_table_entry_type> fcn_table_type;
+typedef uhd::dict<convert::id_type, uhd::dict<convert::priority_type, convert::function_type> > fcn_table_type;
 UHD_SINGLETON_FCN(fcn_table_type, get_table);
 
 /***********************************************************************
@@ -72,14 +65,7 @@ void uhd::convert::register_converter(
     const function_type &fcn,
     const priority_type prio
 ){
-    //get a reference to the function table
-    fcn_table_type &table = get_table();
-
-    //register the function if higher priority
-    if (not table.has_key(id) or table[id].prio < prio){
-        table[id].fcn = fcn;
-        table[id].prio = prio;
-    }
+    get_table()[id][prio] = fcn;
 
     //----------------------------------------------------------------//
     UHD_LOGV(always) << "register_converter: " << id.to_pp_string() << std::endl
@@ -92,9 +78,26 @@ void uhd::convert::register_converter(
 /***********************************************************************
  * The converter functions
  **********************************************************************/
-convert::function_type convert::get_converter(const id_type &id){
-    if (get_table().has_key(id)) return get_table()[id].fcn;
-    throw uhd::key_error("Cannot find a conversion routine for " + id.to_pp_string());
+convert::function_type convert::get_converter(
+    const id_type &id,
+    const priority_type prio
+){
+    if (not get_table().has_key(id)) throw uhd::key_error(
+        "Cannot find a conversion routine for " + id.to_pp_string());
+
+    //find a matching priority
+    priority_type best_prio = -1;
+    BOOST_FOREACH(priority_type prio_i, get_table()[id].keys()){
+        if (prio_i == prio) return get_table()[id][prio];
+        best_prio = std::max(best_prio, prio_i);
+    }
+
+    //wanted a specific prio, didnt find
+    if (prio != -1) throw uhd::key_error(
+        "Cannot find a conversion routine [with prio] for " + id.to_pp_string());
+
+    //otherwise, return best prio
+    return get_table()[id][best_prio];
 }
 
 /***********************************************************************
diff --git a/host/tests/convert_test.cpp b/host/tests/convert_test.cpp
index 6b0ae53a9..4b0226e3d 100644
--- a/host/tests/convert_test.cpp
+++ b/host/tests/convert_test.cpp
@@ -19,6 +19,7 @@
 #include <boost/test/unit_test.hpp>
 #include <boost/foreach.hpp>
 #include <boost/cstdint.hpp>
+#include <boost/assign/list_of.hpp>
 #include <complex>
 #include <vector>
 #include <cstdlib>
@@ -45,7 +46,9 @@ template <typename Range> static void loopback(
     convert::id_type &in_id,
     convert::id_type &out_id,
     const Range &input,
-    Range &output
+    Range &output,
+    const int prio_in = -1,
+    const int prio_out = -1
 ){
     //item32 is largest device type
     std::vector<boost::uint32_t> interm(nsamps);
@@ -54,12 +57,12 @@ template <typename Range> static void loopback(
     std::vector<void *> output0(1, &interm[0]), output1(1, &output[0]);
 
     //convert to intermediate type
-    convert::converter::sptr c0 = convert::get_converter(in_id)();
+    convert::converter::sptr c0 = convert::get_converter(in_id, prio_in)();
     c0->set_scalar(32767.);
     c0->conv(input0, output0, nsamps);
 
     //convert back to host type
-    convert::converter::sptr c1 = convert::get_converter(out_id)();
+    convert::converter::sptr c1 = convert::get_converter(out_id, prio_out)();
     c1->set_scalar(1/32767.);
     c1->conv(input1, output1, nsamps);
 }
@@ -133,10 +136,21 @@ static void test_convert_types_for_floats(
     convert::id_type out_id = id;
     std::swap(out_id.input_format, out_id.output_format);
     std::swap(out_id.num_inputs, out_id.num_outputs);
-    loopback(nsamps, in_id, out_id, input, output);
-    for (size_t i = 0; i < nsamps; i++){
-        MY_CHECK_CLOSE(input[i].real(), output[i].real(), value_type(1./32767));
-        MY_CHECK_CLOSE(input[i].imag(), output[i].imag(), value_type(1./32767));
+
+    //make a list of all prio: best/generic combos
+    typedef std::pair<int, int> int_pair_t;
+    std::vector<int_pair_t> prios = boost::assign::list_of
+        (int_pair_t(0, 0)) (int_pair_t(-1, 0))
+        (int_pair_t(0, -1)) (int_pair_t(-1, -1))
+    ;
+
+    //loopback foreach prio combo (generic vs best)
+    BOOST_FOREACH(const int_pair_t &prio, prios){
+        loopback(nsamps, in_id, out_id, input, output, prio.first, prio.second);
+        for (size_t i = 0; i < nsamps; i++){
+            MY_CHECK_CLOSE(input[i].real(), output[i].real(), value_type(1./32767));
+            MY_CHECK_CLOSE(input[i].imag(), output[i].imag(), value_type(1./32767));
+        }
     }
 }
 
-- 
cgit v1.2.3