/usr/include/mathic/NameFactory.h is in libmathic-dev 1.0~git20170606-1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | #ifndef MATHIC_NAME_FACTORY_GUARD
#define MATHIC_NAME_FACTORY_GUARD
#include "stdinc.h"
#include "error.h"
#include <vector>
#include <string>
#include <algorithm>
#include <memory>
namespace mathic {
/** A NameFactory takes a name and then creates an instance of a class
that has been previously registered under that name. This is done
in a general way using templates.
None of this is very efficient currently. However, the interface can be
implemented much more efficiently if that becomes necessary.
*/
template<class AbstractProduct>
class NameFactory {
public:
/** @param abstractName The name for those things that are being
generated in general. Used for error messages. */
NameFactory(const char* abstractName): _abstractName(abstractName) {}
typedef std::unique_ptr<AbstractProduct> (*FactoryFunction)();
void registerProduct(const std::string& name, FactoryFunction function);
/** Calls the function registered to the parameter name and returns
the result. Returns null if name has not been registered. */
std::unique_ptr<AbstractProduct>
createNullOnUnknown(const std::string& name) const;
/** Calls the function registered to the parameter name and returns
the result. Throws an exception if name has not been registered. */
std::unique_ptr<AbstractProduct> create(const std::string& name) const;
/** Inserts into names all registered names that have the indicated
prefix in lexicographic increasing order. */
void namesWithPrefix
(const std::string& prefix, std::vector<std::string>& names) const;
/** Returns the name of the kinds of things being created. */
std::string abstractProductName() const;
/** Returns true if no names have been registered. */
bool empty() const;
private:
typedef std::pair<std::string, FactoryFunction> Pair;
typedef typename std::vector<Pair>::const_iterator const_iterator;
std::vector<Pair> _pairs;
const std::string _abstractName;
};
/** Registers the given name to a function that
default-constructs a ConcreteProduct. */
template<class ConcreteProduct, class AbstractProduct>
void nameFactoryRegister
(NameFactory<AbstractProduct>& factory, const std::string& name);
/** Registers the name ConcreteProduct::staticName() to a function that
default-constructs a ConcreteProduct. */
template<class ConcreteProduct, class AbstractProduct>
void nameFactoryRegister
(NameFactory<AbstractProduct>& factory);
/** Registers the string returned by ConcreteProduct::staticName()
to a function that default-constructs a ConcreteProduct. */
template<class ConcreteProduct, class AbstractProduct>
void nameFactoryRegister(NameFactory<AbstractProduct>& factory);
/** Creates the unique product that has the indicated prefix, or
creates the actual product that has name equal to the indicated
prefix. Exceptions thrown are as for uniqueNamesWithPrefix(). */
template<class AbstractProduct>
std::unique_ptr<AbstractProduct> createWithPrefix
(const NameFactory<AbstractProduct>& factory, const std::string& prefix);
/** Returns the unique product name that has the indicated prefix, or
return prefix itself if it is the actual name of a product.
@exception UnknownNameException If no product has the indicated
prefix.
@exception AmbiguousNameException If more than one product has the
indicated prefix and the prefix is not the actual name of any
product. */
template<class AbstractProduct>
std::string uniqueNameWithPrefix
(const NameFactory<AbstractProduct>& factory, const std::string& prefix);
// **************************************************************
// These implementations have to be included here due
// to being templates.
template<class AbstractProduct>
std::unique_ptr<AbstractProduct> NameFactory<AbstractProduct>::
createNullOnUnknown(const std::string& name) const {
for (const_iterator it = _pairs.begin(); it != _pairs.end(); ++it)
if (it->first == name)
return it->second();
return std::unique_ptr<AbstractProduct>();
}
template<class AbstractProduct>
std::unique_ptr<AbstractProduct> NameFactory<AbstractProduct>::
create(const std::string& name) const {
std::unique_ptr<AbstractProduct> product = createNullOnUnknown(name);
if (product.get() == 0)
throwError<UnknownNameException>(
"Unknown " + abstractProductName() + " \"" + name + "\".");
return product;
}
template<class AbstractProduct>
void NameFactory<AbstractProduct>::
registerProduct(const std::string& name, FactoryFunction function) {
MATHIC_ASSERT(createNullOnUnknown(name).get() == 0); // no duplicate names
_pairs.push_back(Pair(name, function));
}
template<class AbstractProduct>
void NameFactory<AbstractProduct>::namesWithPrefix(
const std::string& prefix,
std::vector<std::string>& names
) const {
for (const_iterator it = _pairs.begin(); it != _pairs.end(); ++it)
if (it->first.compare(0, prefix.size(), prefix) == 0)
names.push_back(it->first);
std::sort(names.begin(), names.end());
}
template<class AbstractProduct>
bool NameFactory<AbstractProduct>::empty() const {
return _pairs.empty();
}
template<class AbstractProduct>
std::string NameFactory<AbstractProduct>::abstractProductName() const {
return _abstractName;
}
template<class ConcreteProduct, class AbstractProduct>
void nameFactoryRegister(NameFactory<AbstractProduct>& factory) {
nameFactoryRegister<ConcreteProduct, AbstractProduct>
(factory, ConcreteProduct::staticName());
}
template<class ConcreteProduct, class AbstractProduct>
void nameFactoryRegister
(NameFactory<AbstractProduct>& factory, const std::string& name) {
// work-around for no local functions in old C++
struct HoldsFunction {
static std::unique_ptr<AbstractProduct> createConcreteProduct() {
return std::unique_ptr<AbstractProduct>(new ConcreteProduct());
}
};
factory.registerProduct(name, HoldsFunction::createConcreteProduct);
}
template<class AbstractProduct>
std::unique_ptr<AbstractProduct> createWithPrefix
(const NameFactory<AbstractProduct>& factory, const std::string& prefix) {
return factory.createNullOnUnknown(uniqueNameWithPrefix(factory, prefix));
}
template<class AbstractProduct>
std::string uniqueNameWithPrefix
(const NameFactory<AbstractProduct>& factory, const std::string& prefix) {
std::vector<std::string> names;
factory.namesWithPrefix(prefix, names);
// if exact string found, then use that one even if there are other
// prefix matches.
if (std::find(names.begin(), names.end(), prefix) != names.end()) {
names.clear();
names.push_back(prefix);
}
if (names.empty()) {
throwError<UnknownNameException>
("No " + factory.abstractProductName() +
" has the prefix \"" + prefix + "\".");
}
if (names.size() >= 2) {
std::string errorMsg = "More than one " + factory.abstractProductName() +
" has prefix \"" + prefix + "\":\n ";
for (size_t name = 0; name < names.size(); ++name)
errorMsg += ' ' + names[name];
throwError<AmbiguousNameException>(errorMsg);
}
MATHIC_ASSERT(names.size() == 1);
return names.back();
}
}
#endif
|