summaryrefslogtreecommitdiff
path: root/src/input-parser.cpp
diff options
context:
space:
mode:
authorVasile Vilvoiu <vasi.vilvoiu@gmail.com>2020-12-29 19:33:03 +0200
committerVasile Vilvoiu <vasi.vilvoiu@gmail.com>2020-12-29 19:33:03 +0200
commit26293db40f8ac62f3971e0e9dbbc0bf3439e61c0 (patch)
tree218c93aba851c3c3123e9e72d25c974aa65cfd52 /src/input-parser.cpp
Initial commit
Diffstat (limited to 'src/input-parser.cpp')
-rw-r--r--src/input-parser.cpp153
1 files changed, 153 insertions, 0 deletions
diff --git a/src/input-parser.cpp b/src/input-parser.cpp
new file mode 100644
index 0000000..d55661b
--- /dev/null
+++ b/src/input-parser.cpp
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2020-2021 Vasile Vilvoiu <vasi.vilvoiu@gmail.com>
+ *
+ * specgram is free software; you can redistribute it and/or modify
+ * it under the terms of the MIT license. See LICENSE for details.
+ */
+#include "input-parser.hpp"
+
+#include <cassert>
+
+InputParser::InputParser(double prescale, bool is_complex) : prescale_factor_(prescale), is_complex_(is_complex)
+{
+}
+
+std::size_t
+InputParser::GetBufferedValueCount() const
+{
+ return values_.size();
+}
+
+std::vector<Complex>
+InputParser::PeekValues(std::size_t count) const
+{
+ count = std::min<std::size_t>(count, this->values_.size());
+ if (count == 0) {
+ return std::vector<Complex>();
+ }
+ return std::vector<Complex> (this->values_.begin(), this->values_.begin() + count);
+}
+
+void
+InputParser::RemoveValues(std::size_t count)
+{
+ count = std::min<std::size_t>(count, this->values_.size());
+ if (count > 0) {
+ this->values_.erase(this->values_.begin(), this->values_.begin() + count);
+ }
+}
+
+std::unique_ptr<InputParser>
+InputParser::FromDataType(DataType dtype, double prescale, bool is_complex)
+{
+ if (dtype == DataType::kSignedInt8) {
+ return std::make_unique<IntegerInputParser<char>>(prescale, is_complex);
+ } else if (dtype == DataType::kSignedInt16) {
+ return std::make_unique<IntegerInputParser<short>>(prescale, is_complex);
+ } else if (dtype == DataType::kSignedInt32) {
+ return std::make_unique<IntegerInputParser<int>>(prescale, is_complex);
+ } else if (dtype == DataType::kSignedInt64) {
+ return std::make_unique<IntegerInputParser<long long>>(prescale, is_complex);
+ } else if (dtype == DataType::kUnsignedInt8) {
+ return std::make_unique<IntegerInputParser<unsigned char>>(prescale, is_complex);
+ } else if (dtype == DataType::kUnsignedInt16) {
+ return std::make_unique<IntegerInputParser<unsigned short>>(prescale, is_complex);
+ } else if (dtype == DataType::kUnsignedInt32) {
+ return std::make_unique<IntegerInputParser<unsigned int>>(prescale, is_complex);
+ } else if (dtype == DataType::kUnsignedInt64) {
+ return std::make_unique<IntegerInputParser<unsigned long long>>(prescale, is_complex);
+ } else if (dtype == DataType::kFloat32) {
+ return std::make_unique<FloatInputParser<float>>(prescale, is_complex);
+ } else if (dtype == DataType::kFloat64) {
+ return std::make_unique<FloatInputParser<double>>(prescale, is_complex);
+ } else {
+ throw std::runtime_error("unknown datatype");
+ }
+}
+
+template <class T>
+IntegerInputParser<T>::IntegerInputParser(double prescale, bool is_complex) : InputParser(prescale, is_complex)
+{
+}
+
+template <class T>
+std::size_t
+IntegerInputParser<T>::GetDataTypeSize() const
+{
+ return sizeof(T) * (this->is_complex_ ? 2 : 1);
+}
+
+template <class T>
+std::size_t
+IntegerInputParser<T>::ParseBlock(const std::vector<char> &block)
+{
+ /* this function assumes well structured blocks */
+ std::size_t item_size = (this->is_complex_ ? 2 : 1) * sizeof(T);
+ if (block.size() % item_size != 0) {
+ throw std::runtime_error("block size must be a multiple of sizeof(datatype)");
+ }
+
+ std::size_t count = block.size() / item_size;
+ const T *start = reinterpret_cast<const T *>(block.data());
+
+ /* parse one value at a time into complex target */
+ for (std::size_t i = 0; i < count; i ++) {
+ Complex value;
+ if (this->is_complex_) {
+ value = Complex(start[i * 2], start[i * 2 + 1]);
+ } else {
+ value = Complex(start[i], 0.0f);
+ }
+
+ /* normalize to domain limit */
+ value /= (double)std::numeric_limits<T>::max();
+ value *= this->prescale_factor_;
+ this->values_.emplace_back(value);
+ }
+
+ return count;
+}
+
+template <class T>
+FloatInputParser<T>::FloatInputParser(double prescale, bool is_complex) : InputParser(prescale, is_complex)
+{
+}
+
+template <class T>
+std::size_t
+FloatInputParser<T>::GetDataTypeSize() const
+{
+ return sizeof(T) * (this->is_complex_ ? 2 : 1);
+}
+
+template <class T>
+std::size_t
+FloatInputParser<T>::ParseBlock(const std::vector<char> &block)
+{
+ /* this function assumes well structured blocks */
+ std::size_t item_size = (this->is_complex_ ? 2 : 1) * sizeof(T);
+ if (block.size() % item_size != 0) {
+ throw std::runtime_error("block size must be a multiple of sizeof(datatype)");
+ }
+
+ std::size_t count = block.size() / item_size;
+ const T *start = reinterpret_cast<const T *>(block.data());
+
+ /* parse one value at a time into complex target */
+ for (std::size_t i = 0; i < count; i ++) {
+ Complex value;
+ /* remove NaNs */
+ if (this->is_complex_) {
+ value = Complex(std::isnan(start[i * 2]) ? 0.0f : start[i * 2],
+ std::isnan(start[i * 2 + 1]) ? 0.0f : start[i * 2 + 1]);
+ } else {
+ value = Complex(std::isnan(start[i]) ? 0.0f : start[i], 0.0f);
+ }
+
+ /* prescale */
+ value *= this->prescale_factor_;
+ this->values_.emplace_back(value);
+ }
+
+ return count;
+} \ No newline at end of file