Libpressio supports adding custom compressor plugins.
To create a compressor plugin, simply create a subclass of libpressio_compressor_plugin
that implements the compressor functions that you are interested in, and register the plugin with libpressio.
For example, let's create a compressor plugin that preforms a log transform as a preprocessing step to compression, and does a exponential transformation as a post processing step to decompression. Some scientific data compresses much better in the log domain than in the normal domain.
First you will need to include several headers.
#include <cmath>
an extension header for adding compressor plugins to libpressio
C++ pressio_data interface.
C++ interface to the compressor loader.
C++ pressio_options and pressio_option interfaces.
First we are going to delegate most of the methods to the underlying compressor. To do so, we are going to do this in one of the most naive was possible and accept the compressor as a constructor argument. Then we are going to provide overrides that pass each of the methods to the underlying compressor.
Notice the function check_error
. Since we are using composition rather than inheritance, we need to propagate error messages to our wrapper. The check_error
function simply check for the error condition in the underlying function and propagates the error if these is one.
Also notice that we are using the _impl
versions of the various methods. This is because the base class is doing some work to provide metrics functionality and basic error checking that we want to use.
public:
set_meta(options,
"log:compressor", compressor_id, compressor);
return options;
}
return rc;
}
return compressor.plugin->get_configuration();
}
return check_error(compressor.plugin->check_options(options));
}
const char*
prefix()
const override {
return "log";
}
const char*
version()
const override {
return "0.1.0";
}
return 0;
}
return 1;
}
return 0;
}
std::shared_ptr<libpressio_compressor_plugin>
clone()
override {
return compat::make_unique<log_transform>(*this);
}
private:
compressor->set_name(new_name + "/" + compressor->prefix());
}
int check_error(int rc) {
if(rc) {
set_error(compressor->error_code(), compressor->error_msg());
}
return rc;
}
std::string compressor_id = "noop";
}
Definition: compressor.h:22
virtual int set_options_impl(struct pressio_options const &options)=0
virtual int check_options_impl(struct pressio_options const &)
virtual struct pressio_options get_configuration_impl() const =0
virtual struct pressio_options get_options_impl() const =0
virtual std::shared_ptr< libpressio_compressor_plugin > clone()=0
void set_meta(pressio_options &options, StringType &&key, std::string const ¤t_id, Wrapper const ¤t_value, Args &&... args) const
Definition: configurable.h:143
virtual const char * prefix() const =0
virtual void set_name_impl(std::string const &new_name)
Definition: configurable.h:46
pressio_options_key_status get_meta(pressio_options const &options, StringType &&key, Registry const ®istry, std::string ¤t_id, Wrapper ¤t_value)
Definition: configurable.h:257
int set_error(int code, std::string const &msg)
virtual const char * version() const =0
virtual int patch_version() const
virtual int minor_version() const
virtual int major_version() const
pressio_registry< std::shared_ptr< libpressio_compressor_plugin > > & compressor_plugins()
Definition: compressor.h:307
Definition: options.h:352
Now to the harder part, writing compress and decompress.
First we can write our log and exponential transform functions.
namespace {
struct log_fn{
template <class T>
auto output_it =
reinterpret_cast<T*
>(log_data.
data());
std::transform(begin, end, output_it, [](T i){ return std::log(i); });
return log_data;
}
};
struct exp_fn{
template <class T>
auto output_it =
reinterpret_cast<T*
>(log_data.
data());
std::transform(begin, end, output_it, [](T i){ return std::exp(i); });
return log_data;
}
};
}
void * data() const
Definition: data.h:327
static pressio_data clone(pressio_data const &src)
Definition: data.h:209
We will use these methods using the pressio_data_for_each
API to preform the transform Now, we can write compress and decompress:
pressio_data log_input = pressio_data_for_each<pressio_data>(*input, log_fn{input});
return check_error(compressor.
plugin->compress(&log_input, output));
}
int rc = compressor.
plugin->decompress(input, output);
*output = pressio_data_for_each<pressio_data>(*output, exp_fn{output});
return check_error(rc);
}
std::shared_ptr< libpressio_compressor_plugin > plugin
Definition: compressor.h:356
We finally register the library with libpressio:
Definition: pressio.h:105
High quality compressor modules may be accepted into libpressio. Contributed modules should be placed in to the src/plugins/compressors/
directory and added to the main CMakeLists.txt. If the compressor plugin requires an external dependency, it should be hidden behind a configuration option.