1 /* -*- c++ -*- */
2 /*
3 * Copyright 2011,2013 Free Software Foundation, Inc.
4 *
5 * This file is part of GNU Radio
6 *
7 * GNU Radio is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3, or (at your option)
10 * any later version.
11 *
12 * GNU Radio is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Radio; see the file COPYING. If not, write to
19 * the Free Software Foundation, Inc., 51 Franklin Street,
20 * Boston, MA 02110-1301, USA.
21 */
22
23 #include "transcendental_impl.h"
24 #include <gnuradio/io_signature.h>
25 #include <cmath> //real math
26 #include <complex> //complex math
27 #include <map>
28 #include <stdexcept>
29
30 namespace gr {
31 namespace blocks {
32
33 /***********************************************************************
34 * work function creation and registration
35 **********************************************************************/
36 struct map_val_type {
37 work_fcn_type work_fcn;
38 size_t io_size;
39 };
40 typedef std::map<std::string, map_val_type> map_type;
41
42 // construct map on first use idiom
get_map(void)43 static map_type& get_map(void)
44 {
45 static map_type map;
46 return map;
47 }
48
49 // static initialization of this object registers a function
50 struct transcendental_registrant {
transcendental_registrantgr::blocks::transcendental_registrant51 transcendental_registrant(const std::string& key,
52 const work_fcn_type& work_fcn,
53 const size_t io_size)
54 {
55 map_val_type val;
56 val.work_fcn = work_fcn;
57 val.io_size = io_size;
58 get_map()[key] = val;
59 }
60 };
61
62 // macro to create a work function and register it
63 #define REGISTER_FUNCTION(__fcn__, __type__, __key__) \
64 static int __key__##_work(int noutput_items, \
65 gr_vector_const_void_star& input_items, \
66 gr_vector_void_star& output_items) \
67 { \
68 const __type__* in = (const __type__*)input_items[0]; \
69 __type__* out = (__type__*)output_items[0]; \
70 for (size_t i = 0; i < size_t(noutput_items); i++) { \
71 out[i] = std::__fcn__(in[i]); \
72 } \
73 return noutput_items; \
74 } \
75 transcendental_registrant __key__##_registrant( \
76 #__key__, &__key__##_work, sizeof(__type__));
77
78 // register work functions for real types
79 #define REGISTER_REAL_FUNCTIONS(__fcn__) \
80 REGISTER_FUNCTION(__fcn__, float, __fcn__##_float) \
81 REGISTER_FUNCTION(__fcn__, double, __fcn__##_double)
82
83 // register work functions for complex types
84 #define REGISTER_COMPLEX_FUNCTIONS(__fcn__) \
85 REGISTER_FUNCTION(__fcn__, std::complex<float>, __fcn__##_complex_float) \
86 REGISTER_FUNCTION(__fcn__, std::complex<double>, __fcn__##_complex_double)
87
88 // register both complex and real
89 #define REGISTER_FUNCTIONS(__fcn__) \
90 REGISTER_REAL_FUNCTIONS(__fcn__) \
91 REGISTER_COMPLEX_FUNCTIONS(__fcn__)
92
93 // create and register transcendental work functions
94 REGISTER_FUNCTIONS(cos)
REGISTER_FUNCTIONS(sin)95 REGISTER_FUNCTIONS(sin)
96 REGISTER_FUNCTIONS(tan)
97 REGISTER_REAL_FUNCTIONS(acos)
98 REGISTER_REAL_FUNCTIONS(asin)
99 REGISTER_REAL_FUNCTIONS(atan)
100 REGISTER_FUNCTIONS(cosh)
101 REGISTER_FUNCTIONS(sinh)
102 REGISTER_FUNCTIONS(tanh)
103 REGISTER_FUNCTIONS(exp)
104 REGISTER_FUNCTIONS(log)
105 REGISTER_FUNCTIONS(log10)
106 REGISTER_FUNCTIONS(sqrt)
107
108
109 transcendental::sptr transcendental::make(const std::string& name,
110 const std::string& type)
111 {
112 // search for an entry in the map
113 const std::string key = name + "_" + type;
114 const bool has_key = get_map().count(key) != 0;
115 if (!has_key)
116 throw std::runtime_error("could not find transcendental function for " + key);
117
118 // make a new block with found work function
119 return gnuradio::get_initial_sptr(
120 new transcendental_impl(get_map()[key].work_fcn, get_map()[key].io_size));
121 }
122
transcendental_impl(const work_fcn_type & work_fcn,const size_t io_size)123 transcendental_impl::transcendental_impl(const work_fcn_type& work_fcn,
124 const size_t io_size)
125 : sync_block("transcendental",
126 io_signature::make(1, 1, io_size),
127 io_signature::make(1, 1, io_size)),
128 _work_fcn(work_fcn)
129 {
130 // NOP
131 }
132
~transcendental_impl()133 transcendental_impl::~transcendental_impl() {}
134
work(int noutput_items,gr_vector_const_void_star & input_items,gr_vector_void_star & output_items)135 int transcendental_impl::work(int noutput_items,
136 gr_vector_const_void_star& input_items,
137 gr_vector_void_star& output_items)
138 {
139 return _work_fcn(noutput_items, input_items, output_items);
140 }
141
142 } /* namespace blocks */
143 } /* namespace gr */
144