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();
}

Reply via email to