Angus Leeming wrote:
> Lars Gullik Bjønnes wrote:
>> note the member function boost::any:type
>
> Bingo! No need for exceptions after all.
> Many thanks, Lars.
Next iteration. I think that this is ready to convert into InsetExternal
code. However, I think that I'll also use it in the documentation.
--
Angus
#include <boost/any.hpp>
#include <boost/function.hpp>
#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include <vector>
using std::string;
// ExternalTransforms.h
struct RotationData {
RotationData(int a = 0) : angle(a) {}
int angle;
};
struct ResizeData {
ResizeData(double w = 0) : width(w) {}
double width;
};
struct TransformCommand {
typedef std::auto_ptr<TransformCommand const> ptr_type;
virtual ~TransformCommand(){}
virtual string const front() const = 0;
virtual string const back() const = 0;
};
struct TransformOption {
typedef std::auto_ptr<TransformOption const> ptr_type;
virtual ~TransformOption(){}
virtual string const option() const = 0;
};
struct RotateLatexCommand : public TransformCommand {
static ptr_type factory(RotationData const & data);
private:
RotateLatexCommand(RotationData const & data_) : data(data_) {}
virtual string const front() const;
virtual string const back() const { return "}"; }
RotationData data;
};
struct ResizeLatexCommand : public TransformCommand {
static ptr_type factory(ResizeData const & data);
private:
ResizeLatexCommand(ResizeData const & data_) : data(data_) {}
virtual string const front() const;
virtual string const back() const { return "}"; }
ResizeData data;
};
struct RotateLatexOption : public TransformOption {
static ptr_type factory(RotationData const & data);
private:
RotateLatexOption(RotationData const & data_) : data(data_) {}
virtual string const option() const;
RotationData data;
};
struct ResizeLatexOption : public TransformOption {
static ptr_type factory(ResizeData const & data);
private:
ResizeLatexOption(ResizeData const & data_) : data(data_) {}
virtual string const option() const;
ResizeData data;
};
struct TransformStore
{
TransformStore() {}
template <typename Data, typename Factory>
TransformStore(Data const & data, Factory const & factory)
: any_factory(boost::any(factory)),
any_data(boost::any(data))
{}
template<typename Factory, typename Data, typename Transformer>
void getTransformer(Data const & data, Transformer & transformer) const
{
if (any_factory.type() != typeid(Factory) ||
any_data.type() != typeid(Data))
return;
Factory factory = boost::any_cast<Factory>(any_factory);
// Generate the transformer
if (!factory.empty())
transformer = factory(data);
}
private:
boost::any any_factory;
boost::any any_data;
};
typedef boost::function1<TransformCommand::ptr_type, RotationData>
RotationCommandFactory;
typedef boost::function1<TransformCommand::ptr_type, ResizeData>
ResizeCommandFactory;
typedef boost::function1<TransformOption::ptr_type, RotationData>
RotationOptionFactory;
typedef boost::function1<TransformOption::ptr_type, ResizeData>
ResizeOptionFactory;
// Hidden away inside ExternalTemplates.C
void build_command_transformers(std::vector<TransformStore> & store)
{
RotationCommandFactory rotation_factory = RotateLatexCommand::factory;
ResizeCommandFactory resize_factory = ResizeLatexCommand::factory;
store.push_back(TransformStore(RotationData(), rotation_factory));
store.push_back(TransformStore(ResizeData(), resize_factory));
}
void build_option_transformers(std::vector<TransformStore> & store)
{
RotationOptionFactory rotation_factory = RotateLatexOption::factory;
ResizeOptionFactory resize_factory = ResizeLatexOption::factory;
store.push_back(TransformStore(RotationData(), rotation_factory));
store.push_back(TransformStore(ResizeData(), resize_factory));
}
TransformCommand::ptr_type
getCommandTransformer(TransformStore const & store,
RotationData const & rotationdata,
ResizeData const & resizedata)
{
TransformCommand::ptr_type ptr;
store.getTransformer<RotationCommandFactory>(rotationdata, ptr);
if (!ptr.get())
store.getTransformer<ResizeCommandFactory>(resizedata, ptr);
return ptr;
}
TransformOption::ptr_type
getOptionTransformer(TransformStore const & store,
RotationData const & rotationdata,
ResizeData const & resizedata)
{
TransformOption::ptr_type ptr;
store.getTransformer<RotationOptionFactory>(rotationdata, ptr);
if (!ptr.get())
store.getTransformer<ResizeOptionFactory>(resizedata, ptr);
return ptr;
}
// This loop is all that needs go in insetexternal.C
int main()
{
RotationData rotationdata(30);
ResizeData resizedata(2);
// Transform the data using command-style transformers.
string command = "\\input{foo}";
std::vector<TransformStore> command_transformers;
build_command_transformers(command_transformers);
typedef std::vector<TransformStore> Transformers;
Transformers::const_iterator cit = command_transformers.begin();
Transformers::const_iterator cend = command_transformers.end();
for (; cit != cend; ++cit) {
TransformCommand::ptr_type ptr =
getCommandTransformer(*cit, rotationdata, resizedata);
if (!ptr.get())
continue;
std::ostringstream os;
os << ptr->front() << command << ptr->back();
command = os.str();
}
std::cout << command << std::endl;
// Transform the data using option-style transformers.
command = "\\includegraphics[";
std::vector<TransformStore> option_transformers;
build_option_transformers(option_transformers);
typedef std::vector<TransformStore> Transformers;
Transformers::const_iterator obegin = option_transformers.begin();
Transformers::const_iterator oend = option_transformers.end();
Transformers::const_iterator oit = obegin;
for (; oit != oend; ++oit) {
TransformOption::ptr_type ptr =
getOptionTransformer(*cit, rotationdata, resizedata);
if (!ptr.get())
continue;
std::ostringstream os;
os << command;
if (oit != obegin)
os << ',';
os << ptr->option();
command = os.str();
}
std::cout << command << "]{foo}" << std::endl;
}
TransformCommand::ptr_type
RotateLatexCommand::factory(RotationData const & data)
{
return ptr_type(new RotateLatexCommand(data));
}
TransformCommand::ptr_type
ResizeLatexCommand::factory(ResizeData const & data)
{
return ptr_type(new ResizeLatexCommand(data));
}
TransformOption::ptr_type
RotateLatexOption::factory(RotationData const & data)
{
return ptr_type(new RotateLatexOption(data));
}
TransformOption::ptr_type
ResizeLatexOption::factory(ResizeData const & data)
{
return ptr_type(new ResizeLatexOption(data));
}
string const RotateLatexCommand::front() const
{
std::ostringstream os;
os << "\\rotatebox{" << data.angle << "}{";
return os.str();
}
string const ResizeLatexCommand::front() const
{
std::ostringstream os;
os << "\\resizebox{" << data.width << "cm}{!}{";
return os.str();
}
string const RotateLatexOption::option() const
{
std::ostringstream os;
os << "angle=" << data.angle;
return os.str();
}
string const ResizeLatexOption::option() const
{
std::ostringstream os;
os << "width=" << data.width;
return os.str();
}