esphome/components/nimble_distance/framework.h
2023-12-02 12:01:23 +03:00

231 lines
6.6 KiB
C++

/**
* @file framework.h
* %Filter framework.
*
* @author Haimo Zhang <zh.hammer.dev@gmail.com>
*/
#ifndef FRAMEWORK_H
#define FRAMEWORK_H
#include "FilterList.h"
#include "Tree.h"
/**
* The %Filter interface without type checking at compile time.
*
* @note
* It is the client code's responsibility to ensure
* that the correct pointers are passed to the filter.
*/
class Filter
{
// Composite filter classes need to access protected and private members
// of Filter instances, and are thus marked as friends.
friend class FilterChain;
friend class FilterTree;
public:
/**
* Push a new data through the filter.
*
* A filter is not required to always output a data in response
* to a new input data.
* For example, a delay filter might wait for several input data
* before outputing.
* This behavior is supported through the boolean return value.
*
* @note
* The input and output memory is managed by the client code,
* i.e., the client code is responsible for
* the lifetime of the input and output memory
* and the validity of the two pointers.
*
* @param[in] input
* A read-only pointer to the input data.
* When the input pointer is NULL, this function returns false.
*
* @param[out] output
* A pointer to the memory (managed by the client code)
* where the output data is to be written.
*
* @returns
* True if there is output data; false otherwise.
* @note
* The output memory is not guaranteed to remain the same even if
* the return value is false.
*
* @note
* Derived classes should not overload this member function.
* For composite filters that combine several filters
* (e.g., FilterChain and FilterTree),
* it is recommended to derive from this class
* and override its protected member functions.
* For filters that perform actual computation,
* it is recommended to derive from the BaseFilter class
* and only override its BaseFilter::update member function,
* since the BaseFilter class already takes care of
* the other protected member functions for the internal workings.
*/
bool push(void const * const input, void * const output)
{
if (input != NULL && update(input)) {
copy_to_client(output);
return true;
}
return false;
}
protected:
/**
* Read-only access to the internal output memory.
*
* This member function is mainly used by derived composite filters,
* which needs to point the output of the previous filter stage
* to the input of the next fitler stage.
* See for example the implementation of FilterChain.
*
* @returns
* A read-only pointer to the memory where the output value is stored internally
* by the filter.
*/
virtual void const * const get_output_val_ptr() = 0;
/**
* Internally update the filter output based on the given input.
* This method behaves similarly to the public Filter::push method,
* but without copying the output to the client memory.
* This method is for internal workings of the filter framework.
*/
virtual bool update(void const * const input) = 0;
/**
* Copy the output to client memory.
*/
virtual void copy_to_client(void * const output) = 0;
};
/**
* The typed filter base class.
*
* @tparam IN_T type of input data
* @tparam OUT_T type of output data
*
* @see Filter
*/
template <typename IN_T, typename OUT_T>
class BaseFilter : public Filter
{
public:
//// OBSOLETE NOTE ////////////////////////////////////////////////////////////
//// The typed `push` method was originally designed to be beginner-friendly
//// by passing by references to avoid the need to familiarize with pointers.
//// Due to requirement of some filter classes (composite filters such as
//// FilterChain, FilterTree, and PassThroughFilter), the input and output
//// need to be passed by pointers. To provide a unified use case, I have
//// decided to remove the typed `push` method.
////
//// Haimo Zhang, 9 Jun 2019
////
//
// /*
// * Push a new data through the filter.
// * This function is essentially a proxy call to the Filter::push function
// * that does away the pointer parameter, which is supposed to be
// * beginner-friendly.
// *
// * @param[in] input A read-only reference to the input data.
// * @param[out] output The reference to the output data to be written to.
// *
// * @returns True if there is output data; false otherwise.
// * @note The output variable is not guaranteed to remain the same even if
// * the return value is false.
// */
// bool push(IN_T const &input, OUT_T &output)
// {
// return Filter::push(&input, &output);
// }
///////////////////////////////////////////////////////////////////////////////
protected:
virtual void const * const get_output_val_ptr() final { return &out_val; }
virtual void copy_to_client(void * const output) final
{
if (output != NULL) {
*(OUT_T * const) output = out_val;
}
}
/**
* Internally managed storage of the output value.
*/
OUT_T out_val;
};
/**
* A pass-through filter does nothing and is useful for derived classes
* to perform monitoring functionalities, such as the FlowRateFilter.
*
* @tparam T The type of the data that is passing through.
*/
template <typename T>
class PassThroughFilter : public Filter
{
public:
PassThroughFilter() : ptr(NULL) { }
protected:
virtual void const * const get_output_val_ptr() override { return ptr; }
virtual bool update(void const * const input) override
{
ptr = (T const * const) input;
return true;
}
virtual void copy_to_client(void * const output) override
{
if (output != NULL) {
*(T * const) output = *ptr;
}
}
T const *ptr; ///< Pointer to the latest data that passed through.
};
/**
* A chain of filters.
*/
class FilterChain : public FilterList<Filter *>, public Filter
{
protected:
virtual void const * const get_output_val_ptr() final
{
return (*last())->get_output_val_ptr();
}
virtual bool update(void const * const input) final
{
for (it = begin(); it != last(); ++it) {
if (!(*it)->update(it != begin() ? (*prev)->get_output_val_ptr() : input)) {
return false;
}
prev = it;
}
return (*it)->update((*prev)->get_output_val_ptr());
}
virtual void copy_to_client(void * const output) final
{
if (output != NULL && !isEmpty()) {
(*last())->copy_to_client(output);
}
}
private:
FilterList<Filter *>::iterator it;
FilterList<Filter *>::iterator prev;
};
/**
* A tree of interconnected filters.
* While a filter has only one input, it can output to multiple other filters.
* Therefore, we can construct a tree of filters to simplify the interaction
* with complex filter graph in the client code.
*
* @todo Implement the filter tree when this use case is needed.
*/
class FilterTree : public Tree<Filter *>
{
};
#endif