Last active
July 16, 2023 07:47
-
-
Save warmonkey/16c98dbb15abd0a12b2ffee6112f9efe to your computer and use it in GitHub Desktop.
a simple replacement for gnuradio runtime / block class
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
#include <vector> | |
#include <stdexcept> | |
#define SDR_DICT | |
#ifdef SDR_DICT | |
#include <list> | |
#include <map> | |
#include <any> | |
#include <functional> | |
#include <iostream> | |
#endif | |
namespace sdr { | |
/* | |
///work() function usage | |
std::vector<T> x1; | |
std::vector<T> x2; | |
std::vector<T> x3; | |
x1.reserve(block_len + history_len); | |
x2.reserve(block_len + history_len); | |
x3.reserve(block_len + history_len); | |
block.init_history(x1); | |
block.init_history(x2); | |
block.init_history(x3); | |
///now x1 = {all_zero_history} | |
///now x2 = {all_zero_history} | |
///now x3 = {all_zero_history} | |
x1.push_back(in); | |
///now x1 = {all_zero_history, in} | |
block.work1(x1, x2); | |
///now x1 = {new_history_from_in} | |
///now x2 = {history, result_from_x1} | |
block.work2(x2, x3); | |
///now x2 = {new_history_from_x1} | |
///now x3 = {history, result_from_x2} | |
///work() function example: | |
void work(std::vector<T_in>& in, std::vector<T_out>& out) { | |
///verify input | |
if(!check_history(in)) return; | |
///calc parameters | |
int batches = num_batches(in.size()); | |
T_in *iptr = in.data(); | |
T_out *optr = produce(out, out.size()); | |
///do work | |
int k = 0; | |
for(int i = 0; i < batches - 100; i++) { | |
optr[i] = iptr[i]; | |
k++; | |
} | |
///adjust input and output | |
consume(in, k); | |
out.resize(out.size() ); | |
} | |
*/ | |
#ifdef SDR_DICT | |
class dict : public std::map<std::string, std::any> { | |
public: | |
std::list<std::string> keys() const { | |
std::list<std::string> k; | |
for(auto it = this->begin(); it != this->end(); ++it) { | |
k.push_back(it->first); | |
} | |
} | |
template<typename T> | |
T get(const std::string& key, T default_value) const { | |
auto it = this->find(key); | |
if(it == this->end()) return default_value; | |
return std::any_cast<T>(it->second); | |
}; | |
template<typename T> | |
void set(const std::string& key, T value) { | |
this->operator[](key) = value; | |
}; | |
}; | |
static std::ostream& operator<<(std::ostream& os, const dict& vals) { | |
os << "{"; | |
for (const auto& pair : vals) { | |
os << pair.first << ": "; | |
try { | |
if (pair.second.type() == typeid(bool)) { | |
os << std::any_cast<bool>(pair.second); | |
} else if (pair.second.type() == typeid(short)) { | |
os << std::any_cast<short>(pair.second); | |
} else if (pair.second.type() == typeid(long)) { | |
os << std::any_cast<long>(pair.second); | |
} else if (pair.second.type() == typeid(long long)) { | |
os << std::any_cast<long long>(pair.second); | |
} else if (pair.second.type() == typeid(unsigned short)) { | |
os << std::any_cast<unsigned short>(pair.second); | |
} else if (pair.second.type() == typeid(unsigned long)) { | |
os << std::any_cast<unsigned long>(pair.second); | |
} else if (pair.second.type() == typeid(unsigned long long)) { | |
os << std::any_cast<unsigned long long>(pair.second); | |
} else if (pair.second.type() == typeid(float)) { | |
os << std::any_cast<float>(pair.second); | |
} else if (pair.second.type() == typeid(double)) { | |
os << std::any_cast<double>(pair.second); | |
} else if (pair.second.type() == typeid(const char*)) { | |
os << std::any_cast<const char*>(pair.second); | |
} else if (pair.second.type() == typeid(std::string)) { | |
os << std::any_cast<std::string>(pair.second); | |
} else { | |
os << "unsupported type"; | |
} | |
} catch (const std::bad_any_cast& e) { | |
os << "type mismatch"; | |
} | |
os << ", "; | |
} | |
os << "}" << std::endl; | |
return os; | |
} | |
#endif | |
template <unsigned batch_size = 1, unsigned max_output_size = 128*1024*1024> | |
class base_block { | |
private: | |
unsigned m_history; | |
#ifdef SDR_DICT | |
std::vector<std::function<void(dict&)> > m_callbacks; | |
#endif | |
protected: | |
unsigned history() { return m_history; } | |
void set_history(unsigned history) { | |
m_history = history; | |
} | |
template <typename T> | |
void consume(std::vector<T>& in, int n) { | |
if(n == 0) return; //consume nothing | |
//calculate num of leftover samples | |
int k = in.size() - n; | |
if(k < 0) { | |
throw std::runtime_error("underflow"); | |
} | |
for(int i = 0; i < k; i++) { | |
in[i] = in[i + n]; | |
} | |
in.resize(k); | |
} | |
template <typename T> | |
T* produce(std::vector<T>& out, int n) { | |
int out_offset = out.size(); | |
out.resize(out_offset + n); | |
return out.data() + out_offset; | |
} | |
template <typename T> | |
bool check_history(std::vector<T>& in) { | |
if((int)in.size() < m_history) { | |
return false; | |
} | |
return true; | |
} | |
int num_batches(int k) { | |
int n = k - m_history + 1; | |
if(n < 0) { | |
throw std::runtime_error("in size invalid"); | |
} | |
return n / batch_size; | |
} | |
#ifdef SDR_DICT | |
void dispatch_msg(int port, dict& msg) { | |
auto cb = m_callbacks[port]; | |
if(!cb) return; | |
cb(msg); | |
} | |
#endif | |
public: | |
base_block(unsigned history=1) : | |
m_history(history), | |
if(m_batch_size <= 0) throw std::runtime_error("batch_size must >=1"); | |
if(m_history <= 0) throw std::runtime_error("history must >=1"); | |
if(m_max_output_size <= 0) throw std::runtime_error("max_output_size must >=1"); | |
} | |
virtual void reserve(int n) { (void)n; } | |
#ifdef SDR_DICT | |
void set_msg_callback(int port, std::function<void(dict&)> callback) { | |
if(port >= m_callback.size()) m_callback.resize(port + 1); | |
m_callback[port] = callback; | |
} | |
#endif | |
//function workmn(...) : m input -> n output | |
//function work(std::vector<T>& in, std::vector<T>& out) : 1 input -> 1 output | |
}; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment