Skip to content

Instantly share code, notes, and snippets.

@warmonkey
Last active July 16, 2023 07:47
Show Gist options
  • Save warmonkey/16c98dbb15abd0a12b2ffee6112f9efe to your computer and use it in GitHub Desktop.
Save warmonkey/16c98dbb15abd0a12b2ffee6112f9efe to your computer and use it in GitHub Desktop.
a simple replacement for gnuradio runtime / block class
#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