summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorKrzysztof Kosi??ski <tweenk.pl@gmail.com>2013-10-05 03:54:43 +0000
committerKrzysztof Kosiński <tweenk.pl@gmail.com>2013-10-05 03:54:43 +0000
commit706294ff1fa82c86089221d8ee4a0d5bd032925a (patch)
tree4f57389a922f2cb3fdcec99cb21599580e954867 /src
parentC++ (diff)
downloadinkscape-706294ff1fa82c86089221d8ee4a0d5bd032925a.tar.gz
inkscape-706294ff1fa82c86089221d8ee4a0d5bd032925a.zip
Rewrite the internals of the unit code for somewhat better performance
(bzr r12661)
Diffstat (limited to 'src')
-rw-r--r--src/display/canvas-axonomgrid.cpp10
-rw-r--r--src/display/canvas-grid.cpp12
-rw-r--r--src/svg/svg-length.cpp2
-rw-r--r--src/ui/widget/selected-style.cpp2
-rw-r--r--src/ui/widget/unit-menu.cpp8
-rw-r--r--src/ui/widget/unit-tracker.cpp8
-rw-r--r--src/util/units.cpp307
-rw-r--r--src/util/units.h81
-rw-r--r--src/util/unordered-containers.h29
9 files changed, 269 insertions, 190 deletions
diff --git a/src/display/canvas-axonomgrid.cpp b/src/display/canvas-axonomgrid.cpp
index f7a7cb39a..654144122 100644
--- a/src/display/canvas-axonomgrid.cpp
+++ b/src/display/canvas-axonomgrid.cpp
@@ -214,18 +214,18 @@ CanvasAxonomGrid::readRepr()
{
gchar const *value;
if ( (value = repr->attribute("originx")) ) {
- Inkscape::Util::Quantity q = unit_table.getQuantity(value);
+ Inkscape::Util::Quantity q = unit_table.parseQuantity(value);
gridunit = q.unit;
- origin[Geom::X] = unit_table.getQuantity(value).value("px");
+ origin[Geom::X] = q.value("px");
}
if ( (value = repr->attribute("originy")) ) {
- Inkscape::Util::Quantity q = unit_table.getQuantity(value);
+ Inkscape::Util::Quantity q = unit_table.parseQuantity(value);
gridunit = q.unit;
- origin[Geom::Y] = unit_table.getQuantity(value).value("px");
+ origin[Geom::Y] = q.value("px");
}
if ( (value = repr->attribute("spacingy")) ) {
- Inkscape::Util::Quantity q = unit_table.getQuantity(value);
+ Inkscape::Util::Quantity q = unit_table.parseQuantity(value);
gridunit = q.unit;
lengthy = q.value("px");
if (lengthy < 0.0500) lengthy = 0.0500;
diff --git a/src/display/canvas-grid.cpp b/src/display/canvas-grid.cpp
index ef32c113b..5701b91a1 100644
--- a/src/display/canvas-grid.cpp
+++ b/src/display/canvas-grid.cpp
@@ -588,20 +588,20 @@ CanvasXYGrid::readRepr()
{
gchar const *value;
if ( (value = repr->attribute("originx")) ) {
- Inkscape::Util::Quantity q = unit_table.getQuantity(value);
+ Inkscape::Util::Quantity q = unit_table.parseQuantity(value);
gridunit = q.unit;
- origin[Geom::X] = unit_table.getQuantity(value).value("px");
+ origin[Geom::X] = q.value("px");
}
if ( (value = repr->attribute("originy")) ) {
- Inkscape::Util::Quantity q = unit_table.getQuantity(value);
+ Inkscape::Util::Quantity q = unit_table.parseQuantity(value);
gridunit = q.unit;
- origin[Geom::Y] = unit_table.getQuantity(value).value("px");
+ origin[Geom::Y] = q.value("px");
}
if ( (value = repr->attribute("spacingx")) ) {
double oldVal = spacing[Geom::X];
- Inkscape::Util::Quantity q = unit_table.getQuantity(value);
+ Inkscape::Util::Quantity q = unit_table.parseQuantity(value);
gridunit = q.unit;
spacing[Geom::X] = q.quantity;
validateScalar(oldVal, &spacing[Geom::X]);
@@ -609,7 +609,7 @@ CanvasXYGrid::readRepr()
}
if ( (value = repr->attribute("spacingy")) ) {
double oldVal = spacing[Geom::Y];
- Inkscape::Util::Quantity q = unit_table.getQuantity(value);
+ Inkscape::Util::Quantity q = unit_table.parseQuantity(value);
gridunit = q.unit;
spacing[Geom::Y] = q.quantity;
validateScalar(oldVal, &spacing[Geom::Y]);
diff --git a/src/svg/svg-length.cpp b/src/svg/svg-length.cpp
index 8d26a95d2..6f1a88a58 100644
--- a/src/svg/svg-length.cpp
+++ b/src/svg/svg-length.cpp
@@ -541,6 +541,8 @@ std::string sp_svg_length_write_with_units(SVGLength const &length)
Inkscape::SVGOStringStream os;
if (length.unit == SVGLength::PERCENT) {
os << 100*length.value << sp_svg_length_get_css_units(length.unit);
+ } else if (length.unit == SVGLength::FOOT) {
+ os << 12*length.value << sp_svg_length_get_css_units(SVGLength::INCH);
} else {
os << length.value << sp_svg_length_get_css_units(length.unit);
}
diff --git a/src/ui/widget/selected-style.cpp b/src/ui/widget/selected-style.cpp
index 894700046..97581aa83 100644
--- a/src/ui/widget/selected-style.cpp
+++ b/src/ui/widget/selected-style.cpp
@@ -313,7 +313,7 @@ SelectedStyle::SelectedStyle(bool /*layout*/)
Inkscape::Util::UnitTable::UnitMap::iterator iter = m.begin();
while(iter != m.end()) {
Gtk::RadioMenuItem *mi = Gtk::manage(new Gtk::RadioMenuItem(_sw_group));
- mi->add(*(new Gtk::Label((*iter).first, 0.0, 0.5)));
+ mi->add(*(new Gtk::Label(iter->first, 0.0, 0.5)));
_unit_mis = g_slist_append(_unit_mis, mi);
Inkscape::Util::Unit const *u = new Inkscape::Util::Unit(unit_table.getUnit(iter->first));
mi->signal_activate().connect(sigc::bind<Inkscape::Util::Unit>(sigc::mem_fun(*this, &SelectedStyle::on_popup_units), *u));
diff --git a/src/ui/widget/unit-menu.cpp b/src/ui/widget/unit-menu.cpp
index 111226774..684016471 100644
--- a/src/ui/widget/unit-menu.cpp
+++ b/src/ui/widget/unit-menu.cpp
@@ -33,11 +33,9 @@ bool UnitMenu::setUnitType(UnitType unit_type)
{
// Expand the unit widget with unit entries from the unit table
UnitTable::UnitMap m = unit_table.units(unit_type);
- UnitTable::UnitMap::iterator iter = m.begin();
- while(iter != m.end()) {
- Glib::ustring text = (*iter).first;
- append(text);
- ++iter;
+
+ for (UnitTable::UnitMap::iterator i = m.begin(); i != m.end(); ++i) {
+ append(i->first);
}
_type = unit_type;
set_active_text(unit_table.primary(unit_type));
diff --git a/src/ui/widget/unit-tracker.cpp b/src/ui/widget/unit-tracker.cpp
index f9b0c3a44..155f3fafe 100644
--- a/src/ui/widget/unit-tracker.cpp
+++ b/src/ui/widget/unit-tracker.cpp
@@ -38,10 +38,10 @@ UnitTracker::UnitTracker(UnitType unit_type) :
GtkTreeIter iter;
UnitTable::UnitMap m = unit_table.units(unit_type);
- UnitTable::UnitMap::iterator m_iter = m.begin();
- while(m_iter != m.end()) {
- Glib::ustring text = (*m_iter).first;
- ++m_iter;
+
+
+ for (UnitTable::UnitMap::iterator m_iter = m.begin(); m_iter != m.end(); ++m_iter) {
+ Glib::ustring text = m_iter->first;
gtk_list_store_append(_store, &iter);
gtk_list_store_set(_store, &iter, COLUMN_STRING, text.c_str(), -1);
}
diff --git a/src/util/units.cpp b/src/util/units.cpp
index 59717d0b5..cabbc044d 100644
--- a/src/util/units.cpp
+++ b/src/util/units.cpp
@@ -33,29 +33,85 @@ using Inkscape::Util::UNIT_TYPE_FONT_HEIGHT;
namespace
{
-/**
- * A std::map that gives the data type value for the string version.
- *
- * Note that we'd normally not return a reference to an internal version, but
- * for this constant case it allows us to check against getTypeMappings().end().
- */
-/** @todo consider hiding map behind hasFoo() and getFoo() type functions.*/
-std::map<Glib::ustring, Inkscape::Util::UnitType> &getTypeMappings()
+#define MAKE_UNIT_CODE(a, b) \
+ ((((unsigned)(a) & 0xdf) << 8) | ((unsigned)(b) & 0xdf))
+
+enum UnitCode {
+ UNIT_CODE_PX = MAKE_UNIT_CODE('p','x'),
+ UNIT_CODE_PT = MAKE_UNIT_CODE('p','t'),
+ UNIT_CODE_PC = MAKE_UNIT_CODE('p','c'),
+ UNIT_CODE_MM = MAKE_UNIT_CODE('m','m'),
+ UNIT_CODE_CM = MAKE_UNIT_CODE('c','m'),
+ UNIT_CODE_IN = MAKE_UNIT_CODE('i','n'),
+ UNIT_CODE_FT = MAKE_UNIT_CODE('f','t'),
+ UNIT_CODE_EM = MAKE_UNIT_CODE('e','m'),
+ UNIT_CODE_EX = MAKE_UNIT_CODE('e','x'),
+ UNIT_CODE_PERCENT = MAKE_UNIT_CODE('%',0)
+};
+
+// TODO: convert to constexpr in C++11, so that the above constants can be eliminated
+inline unsigned make_unit_code(char a, char b) {
+ // this should work without the casts, but let's be 100% sure
+ // also ensure that the codes are in lowercase
+ return MAKE_UNIT_CODE(a,b);
+}
+inline unsigned make_unit_code(char const *str) {
+ if (!str || str[0] == 0) return 0;
+ return MAKE_UNIT_CODE(str[0], str[1]);
+}
+
+
+
+unsigned const svg_length_lookup[] = {
+ 0,
+ UNIT_CODE_PX,
+ UNIT_CODE_PT,
+ UNIT_CODE_PC,
+ UNIT_CODE_MM,
+ UNIT_CODE_CM,
+ UNIT_CODE_IN,
+ UNIT_CODE_FT,
+ UNIT_CODE_EM,
+ UNIT_CODE_EX,
+ UNIT_CODE_PERCENT
+};
+
+
+
+// maps unit codes obtained from their abbreviations to their SVGLength unit indexes
+typedef INK_UNORDERED_MAP<unsigned, SVGLength::Unit> UnitCodeLookup;
+
+UnitCodeLookup make_unit_code_lookup()
{
- static bool init = false;
- static std::map<Glib::ustring, Inkscape::Util::UnitType> typeMap;
- if (!init)
- {
- init = true;
- typeMap["DIMENSIONLESS"] = UNIT_TYPE_DIMENSIONLESS;
- typeMap["LINEAR"] = UNIT_TYPE_LINEAR;
- typeMap["RADIAL"] = UNIT_TYPE_RADIAL;
- typeMap["FONT_HEIGHT"] = UNIT_TYPE_FONT_HEIGHT;
- // Note that code was not yet handling LINEAR_SCALED, TIME, QTY and NONE
+ UnitCodeLookup umap;
+ for (unsigned i = 1; i < G_N_ELEMENTS(svg_length_lookup); ++i) {
+ umap[svg_length_lookup[i]] = static_cast<SVGLength::Unit>(i);
}
- return typeMap;
+ return umap;
+}
+
+UnitCodeLookup const unit_code_lookup = make_unit_code_lookup();
+
+
+
+typedef INK_UNORDERED_MAP<Glib::ustring, Inkscape::Util::UnitType> TypeMap;
+
+/** A std::map that gives the data type value for the string version.
+ * @todo consider hiding map behind hasFoo() and getFoo() type functions. */
+TypeMap make_type_map()
+{
+ TypeMap tmap;
+ tmap["DIMENSIONLESS"] = UNIT_TYPE_DIMENSIONLESS;
+ tmap["LINEAR"] = UNIT_TYPE_LINEAR;
+ tmap["RADIAL"] = UNIT_TYPE_RADIAL;
+ tmap["FONT_HEIGHT"] = UNIT_TYPE_FONT_HEIGHT;
+ // Note that code was not yet handling LINEAR_SCALED, TIME, QTY and NONE
+
+ return tmap;
}
+TypeMap const type_map = make_type_map();
+
} // namespace
namespace Inkscape {
@@ -106,13 +162,13 @@ Unit::Unit(UnitType type,
Glib::ustring const &name,
Glib::ustring const &name_plural,
Glib::ustring const &abbr,
- Glib::ustring const &description) :
- type(type),
- factor(factor),
- name(name),
- name_plural(name_plural),
- abbr(abbr),
- description(description)
+ Glib::ustring const &description)
+ : type(type)
+ , factor(factor)
+ , name(name)
+ , name_plural(name_plural)
+ , abbr(abbr)
+ , description(description)
{
g_return_if_fail(factor <= 0);
}
@@ -133,62 +189,48 @@ int Unit::defaultDigits() const
return factor_digits;
}
-bool Unit::compatibleWith(const Unit &u) const
+bool Unit::compatibleWith(Unit const &u) const
{
// Percentages
if (type == UNIT_TYPE_DIMENSIONLESS || u.type == UNIT_TYPE_DIMENSIONLESS) {
return true;
}
-
+
// Other units with same type
if (type == u.type) {
return true;
}
-
+
// Different, incompatible types
return false;
}
-bool Unit::compatibleWith(const Glib::ustring u) const
+bool Unit::compatibleWith(Glib::ustring const &u) const
{
static UnitTable unit_table;
return compatibleWith(unit_table.getUnit(u));
}
-bool operator== (const Unit &u1, const Unit &u2)
+bool Unit::operator==(Unit const &other) const
{
- return (u1.type == u2.type && u1.name.compare(u2.name) == 0);
-}
-
-bool operator!= (const Unit &u1, const Unit &u2)
-{
- return !(u1 == u2);
+ return (type == other.type && name.compare(other.name) == 0);
}
int Unit::svgUnit() const
{
- if (!abbr.compare("px"))
- return SVGLength::PX;
- if (!abbr.compare("pt"))
- return SVGLength::PT;
- if (!abbr.compare("pc"))
- return SVGLength::PC;
- if (!abbr.compare("mm"))
- return SVGLength::MM;
- if (!abbr.compare("cm"))
- return SVGLength::CM;
- if (!abbr.compare("in"))
- return SVGLength::INCH;
- if (!abbr.compare("ft"))
- return SVGLength::FOOT;
- if (!abbr.compare("em"))
- return SVGLength::EM;
- if (!abbr.compare("ex"))
- return SVGLength::EX;
- if (!abbr.compare("%"))
- return SVGLength::PERCENT;
+ char const *astr = abbr.c_str();
+ unsigned code = make_unit_code(astr);
+
+ UnitCodeLookup::const_iterator u = unit_code_lookup.find(code);
+ if (u != unit_code_lookup.end()) {
+ return u->second;
+ }
return 0;
}
+
+
+Unit UnitTable::_empty_unit;
+
UnitTable::UnitTable()
{
gchar *filename = g_build_filename(INKSCAPE_UIDIR, "units.xml", NULL);
@@ -198,64 +240,50 @@ UnitTable::UnitTable()
UnitTable::~UnitTable()
{
- for (UnitMap::iterator iter = _unit_map.begin(); iter != _unit_map.end(); ++iter)
+ for (UnitCodeMap::iterator iter = _unit_map.begin(); iter != _unit_map.end(); ++iter)
{
- delete (*iter).second;
+ delete iter->second;
}
}
void UnitTable::addUnit(Unit const &u, bool primary)
{
- _unit_map[u.abbr] = new Unit(u);
+ _unit_map[make_unit_code(u.abbr.c_str())] = new Unit(u);
if (primary) {
_primary_unit[u.type] = u.abbr;
}
}
-Unit UnitTable::getUnit(Glib::ustring const &unit_abbr) const
+Unit const &UnitTable::getUnit(char const *abbr) const
{
- UnitMap::const_iterator iter = _unit_map.find(unit_abbr);
- if (iter != _unit_map.end()) {
- return *((*iter).second);
- } else {
- return Unit();
+ UnitCodeMap::const_iterator f = _unit_map.find(make_unit_code(abbr));
+ if (f != _unit_map.end()) {
+ return *f->second;
}
+ return _empty_unit;
}
-Unit UnitTable::getUnit(SVGLength::Unit const u) const
-{
- Glib::ustring u_str;
- switch(u) {
- case SVGLength::PX:
- u_str = "px"; break;
- case SVGLength::PT:
- u_str = "pt"; break;
- case SVGLength::PC:
- u_str = "pc"; break;
- case SVGLength::MM:
- u_str = "mm"; break;
- case SVGLength::CM:
- u_str = "cm"; break;
- case SVGLength::INCH:
- u_str = "in"; break;
- case SVGLength::FOOT:
- u_str = "ft"; break;
- case SVGLength::EM:
- u_str = "em"; break;
- case SVGLength::EX:
- u_str = "ex"; break;
- case SVGLength::PERCENT:
- u_str = "%"; break;
- default:
- u_str = "";
+
+Unit const &UnitTable::getUnit(Glib::ustring const &unit_abbr) const
+{
+ return getUnit(unit_abbr.c_str());
+}
+Unit const &UnitTable::getUnit(SVGLength::Unit u) const
+{
+ if (u == 0 || u > SVGLength::LAST_UNIT) {
+ return _empty_unit;
}
-
- return getUnit(u_str);
+
+ UnitCodeMap::const_iterator f = _unit_map.find(svg_length_lookup[u]);
+ if (f != _unit_map.end()) {
+ return *f->second;
+ }
+ return _empty_unit;
}
-Quantity UnitTable::getQuantity(Glib::ustring const& q) const
+Quantity UnitTable::parseQuantity(Glib::ustring const &q) const
{
Glib::MatchInfo match_info;
-
+
// Extract value
double value = 0;
Glib::RefPtr<Glib::Regex> value_regex = Glib::Regex::create("[-+]*[\\d+]*[\\.,]*[\\d+]*[eE]*[-+]*\\d+");
@@ -263,15 +291,16 @@ Quantity UnitTable::getQuantity(Glib::ustring const& q) const
std::istringstream tmp_v(match_info.fetch(0));
tmp_v >> value;
}
-
+
// Extract unit abbreviation
Glib::ustring abbr;
Glib::RefPtr<Glib::Regex> unit_regex = Glib::Regex::create("[A-z%]+");
if (unit_regex->match(q, match_info)) {
abbr = match_info.fetch(0);
}
-
- return Quantity(value, abbr);
+
+ Quantity qty(value, abbr);
+ return qty;
}
bool UnitTable::deleteUnit(Unit const &u)
@@ -280,7 +309,7 @@ bool UnitTable::deleteUnit(Unit const &u)
// Cannot delete the primary unit type since it's
// used for conversions
if (u.abbr != _primary_unit[u.type]) {
- UnitMap::iterator iter = _unit_map.find(u.abbr);
+ UnitCodeMap::iterator iter = _unit_map.find(make_unit_code(u.abbr.c_str()));
if (iter != _unit_map.end()) {
delete (*iter).second;
_unit_map.erase(iter);
@@ -292,16 +321,16 @@ bool UnitTable::deleteUnit(Unit const &u)
bool UnitTable::hasUnit(Glib::ustring const &unit) const
{
- UnitMap::const_iterator iter = _unit_map.find(unit);
+ UnitCodeMap::const_iterator iter = _unit_map.find(make_unit_code(unit.c_str()));
return (iter != _unit_map.end());
}
UnitTable::UnitMap UnitTable::units(UnitType type) const
{
UnitMap submap;
- for (UnitMap::const_iterator iter = _unit_map.begin(); iter != _unit_map.end(); ++iter) {
- if (((*iter).second)->type == type) {
- submap.insert(UnitMap::value_type((*iter).first, new Unit(*((*iter).second))));
+ for (UnitCodeMap::const_iterator iter = _unit_map.begin(); iter != _unit_map.end(); ++iter) {
+ if (iter->second->type == type) {
+ submap.insert(UnitMap::value_type(iter->second->abbr, *iter->second));
}
}
@@ -351,8 +380,9 @@ void UnitParser::on_start_element(Ctx &ctx, Glib::ustring const &name, AttrMap c
AttrMap::const_iterator f;
if ((f = attrs.find("type")) != attrs.end()) {
Glib::ustring type = f->second;
- if (getTypeMappings().find(type) != getTypeMappings().end()) {
- unit.type = getTypeMappings()[type];
+ TypeMap::const_iterator tf = type_map.find(type);
+ if (tf != type_map.end()) {
+ unit.type = tf->second;
} else {
g_warning("Skipping unknown unit type '%s'.\n", type.c_str());
skip = true;
@@ -388,46 +418,59 @@ void UnitParser::on_end_element(Ctx &ctx, Glib::ustring const &name)
}
}
-Quantity::Quantity(double q, const Unit &u)
+Quantity::Quantity(double q, Unit const &u)
{
unit = new Unit(u);
quantity = q;
}
-Quantity::Quantity(double q, const Glib::ustring u)
+Quantity::Quantity(double q, Glib::ustring const &u)
+{
+ unit = new Unit(unit_table.getUnit(u.c_str()));
+ quantity = q;
+}
+Quantity::Quantity(double q, char const *u)
{
unit = new Unit(unit_table.getUnit(u));
quantity = q;
}
-bool Quantity::compatibleWith(const Unit &u) const
+bool Quantity::compatibleWith(Unit const &u) const
{
return unit->compatibleWith(u);
}
-bool Quantity::compatibleWith(const Glib::ustring u) const
+bool Quantity::compatibleWith(Glib::ustring const &u) const
+{
+ return compatibleWith(u.c_str());
+}
+bool Quantity::compatibleWith(char const *u) const
{
return compatibleWith(unit_table.getUnit(u));
}
-double Quantity::value(const Unit &u) const
+double Quantity::value(Unit const &u) const
{
return convert(quantity, *unit, u);
}
-double Quantity::value(const Glib::ustring u) const
+double Quantity::value(Glib::ustring const &u) const
+{
+ return value(u.c_str());
+}
+double Quantity::value(char const *u) const
{
return value(unit_table.getUnit(u));
}
-Glib::ustring Quantity::string(const Unit &u) const {
+Glib::ustring Quantity::string(Unit const &u) const {
return Glib::ustring::format(std::fixed, std::setprecision(2), value(u)) + " " + unit->abbr;
}
-Glib::ustring Quantity::string(const Glib::ustring u) const {
- return string(unit_table.getUnit(u));
+Glib::ustring Quantity::string(Glib::ustring const &u) const {
+ return string(unit_table.getUnit(u.c_str()));
}
Glib::ustring Quantity::string() const {
return string(*unit);
}
-double Quantity::convert(const double from_dist, const Unit &from, const Unit &to)
+double Quantity::convert(double from_dist, Unit const &from, Unit const &to)
{
// Percentage
if (to.type == UNIT_TYPE_DIMENSIONLESS) {
@@ -442,38 +485,34 @@ double Quantity::convert(const double from_dist, const Unit &from, const Unit &t
// Compatible units
return from_dist * from.factor / to.factor;
}
-double Quantity::convert(const double from_dist, const Glib::ustring from, const Unit &to)
+double Quantity::convert(double from_dist, Glib::ustring const &from, Unit const &to)
{
- return convert(from_dist, unit_table.getUnit(from), to);
+ return convert(from_dist, unit_table.getUnit(from.c_str()), to);
}
-double Quantity::convert(const double from_dist, const Unit &from, const Glib::ustring to)
+double Quantity::convert(double from_dist, Unit const &from, Glib::ustring const &to)
{
- return convert(from_dist, from, unit_table.getUnit(to));
+ return convert(from_dist, from, unit_table.getUnit(to.c_str()));
}
-double Quantity::convert(const double from_dist, const Glib::ustring from, const Glib::ustring to)
+double Quantity::convert(double from_dist, Glib::ustring const &from, Glib::ustring const &to)
{
- return convert(from_dist, unit_table.getUnit(from), unit_table.getUnit(to));
+ return convert(from_dist, unit_table.getUnit(from.c_str()), unit_table.getUnit(to.c_str()));
}
-
-bool operator< (const Quantity &ql, const Quantity &qr)
+double Quantity::convert(double from_dist, char const *from, char const *to)
{
- if (ql.unit->type != qr.unit->type) {
- g_warning("Incompatible units");
- return false;
- }
- return ql.quantity < qr.value(*ql.unit);
+ return convert(from_dist, unit_table.getUnit(from), unit_table.getUnit(to));
}
-bool operator> (const Quantity &ql, const Quantity &qr)
+
+bool Quantity::operator<(Quantity const &other) const
{
- if (ql.unit->type != qr.unit->type) {
+ if (unit->type != other.unit->type) {
g_warning("Incompatible units");
return false;
}
- return ql.quantity > qr.value(*ql.unit);
+ return quantity < other.value(*unit);
}
-bool operator!= (const Quantity &q1, const Quantity &q2)
+bool Quantity::operator==(Quantity const &other) const
{
- return (*q1.unit != *q2.unit) || (q1.quantity != q2.quantity);
+ return (*unit == *other.unit) && (quantity == other.quantity);
}
} // namespace Util
diff --git a/src/util/units.h b/src/util/units.h
index 7ba6e1e86..7566715d8 100644
--- a/src/util/units.h
+++ b/src/util/units.h
@@ -14,8 +14,10 @@
#define INKSCAPE_UTIL_UNITS_H
#include <map>
+#include <boost/operators.hpp>
#include <glibmm/ustring.h>
#include "svg/svg-length.h"
+#include "unordered-containers.h"
namespace Inkscape {
namespace Util {
@@ -33,8 +35,10 @@ enum UnitType {
const char DEG[] = "°";
-class Unit {
- public:
+class Unit
+ : boost::equality_comparable<Unit>
+{
+public:
Unit();
Unit(UnitType type,
double factor,
@@ -54,8 +58,9 @@ class Unit {
int defaultDigits() const;
/** Checks if a unit is compatible with the specified unit. */
- bool compatibleWith(const Unit &u) const;
- bool compatibleWith(const Glib::ustring) const;
+ bool compatibleWith(Unit const &u) const;
+ bool compatibleWith(Glib::ustring const &) const;
+ bool compatibleWith(char const *) const;
UnitType type;
double factor;
@@ -65,50 +70,53 @@ class Unit {
Glib::ustring description;
/** Check if units are equal. */
- friend bool operator== (const Unit &u1, const Unit &u2);
- /** Check if units are not equal. */
- friend bool operator!= (const Unit &u1, const Unit &u2);
+ bool operator==(Unit const &other) const;
- /** Get SVG unit. */
+ /** Get SVG unit code. */
int svgUnit() const;
};
-class Quantity {
+class Quantity
+ : boost::totally_ordered<Quantity>
+{
public:
- const Unit *unit;
+ Unit const *unit;
double quantity;
/** Initialize a quantity. */
- Quantity(double q, const Unit &u); // constructor
- Quantity(double q, const Glib::ustring u); // constructor
+ Quantity(double q, Unit const &u);
+ Quantity(double q, Glib::ustring const &u);
+ Quantity(double q, char const *u);
/** Checks if a quantity is compatible with the specified unit. */
- bool compatibleWith(const Unit &u) const;
- bool compatibleWith(const Glib::ustring u) const;
+ bool compatibleWith(Unit const &u) const;
+ bool compatibleWith(Glib::ustring const &u) const;
+ bool compatibleWith(char const *u) const;
/** Return the quantity's value in the specified unit. */
- double value(const Unit &u) const;
- double value(const Glib::ustring u) const;
+ double value(Unit const &u) const;
+ double value(Glib::ustring const &u) const;
+ double value(char const *u) const;
/** Return a printable string of the value in the specified unit. */
- Glib::ustring string(const Unit &u) const;
- Glib::ustring string(const Glib::ustring u) const;
+ Glib::ustring string(Unit const &u) const;
+ Glib::ustring string(Glib::ustring const &u) const;
Glib::ustring string() const;
/** Convert distances. */
- static double convert(const double from_dist, const Unit &from, const Unit &to);
- static double convert(const double from_dist, const Glib::ustring from, const Unit &to);
- static double convert(const double from_dist, const Unit &from, const Glib::ustring to);
- static double convert(const double from_dist, const Glib::ustring from, const Glib::ustring to);
-
+ static double convert(double from_dist, Unit const &from, Unit const &to);
+ static double convert(double from_dist, Glib::ustring const &from, Unit const &to);
+ static double convert(double from_dist, Unit const &from, Glib::ustring const &to);
+ static double convert(double from_dist, Glib::ustring const &from, Glib::ustring const &to);
+ static double convert(double from_dist, char const *from, char const *to);
+
/** Comparison operators. */
- friend bool operator< (const Quantity &ql, const Quantity &qr);
- friend bool operator> (const Quantity &ql, const Quantity &qr);
- friend bool operator!= (const Quantity &q1, const Quantity &q2);
+ bool operator<(Quantity const &other) const;
+ bool operator==(Quantity const &other) const;
};
class UnitTable {
- public:
+public:
/**
* Initializes the unit tables and identifies the primary unit types.
*
@@ -117,19 +125,21 @@ class UnitTable {
UnitTable();
virtual ~UnitTable();
- typedef std::map<Glib::ustring, Unit*> UnitMap;
+ typedef INK_UNORDERED_MAP<Glib::ustring, Unit> UnitMap;
+ typedef INK_UNORDERED_MAP<unsigned, Unit*> UnitCodeMap;
/** Add a new unit to the table */
void addUnit(Unit const &u, bool primary);
/** Retrieve a given unit based on its string identifier */
- Unit getUnit(Glib::ustring const &name) const;
+ Unit const &getUnit(Glib::ustring const &name) const;
+ Unit const &getUnit(char const *name) const;
/** Retrieve a given unit based on its SVGLength unit */
- Unit getUnit(SVGLength::Unit const u) const;
+ Unit const &getUnit(SVGLength::Unit u) const;
/** Retrieve a quantity based on its string identifier */
- Quantity getQuantity(Glib::ustring const &q) const;
+ Quantity parseQuantity(Glib::ustring const &q) const;
/** Remove a unit definition from the given unit type table */
bool deleteUnit(Unit const &u);
@@ -138,7 +148,7 @@ class UnitTable {
bool hasUnit(Glib::ustring const &name) const;
/** Provides an iteratable list of items in the given unit table */
- UnitTable::UnitMap units(UnitType type) const;
+ UnitMap units(UnitType type) const;
/** Returns the default unit abbr for the given type */
Glib::ustring primary(UnitType type) const;
@@ -159,13 +169,14 @@ class UnitTable {
/** Saves the current UnitTable to the given file. */
bool save(std::string const &filename);
- protected:
- UnitTable::UnitMap _unit_map;
+protected:
+ UnitCodeMap _unit_map;
Glib::ustring _primary_unit[UNIT_TYPE_QTY];
double _linear_scale;
+ static Unit _empty_unit;
- private:
+private:
UnitTable(UnitTable const &t);
UnitTable operator=(UnitTable const &t);
diff --git a/src/util/unordered-containers.h b/src/util/unordered-containers.h
index 6f738f0ce..70d36c4dc 100644
--- a/src/util/unordered-containers.h
+++ b/src/util/unordered-containers.h
@@ -16,6 +16,8 @@
# include "config.h"
#endif
+#include <glibmm/ustring.h>
+
#ifndef DOXYGEN_SHOULD_SKIP_THIS
#if defined(HAVE_TR1_UNORDERED_SET)
@@ -25,6 +27,17 @@
# define INK_UNORDERED_MAP std::tr1::unordered_map
# define INK_HASH std::tr1::hash
+namespace std {
+namespace tr1 {
+template <>
+struct hash<Glib::ustring> : public std::unary_function<Glib::ustring, std::size_t> {
+ std::size_t operator()(Glib::ustring const &s) const {
+ return hash<std::string>()(s.raw());
+ }
+};
+} // namespace tr1
+} // namespace std
+
#elif defined(HAVE_BOOST_UNORDERED_SET)
# include <boost/unordered_set.hpp>
# include <boost/unordered_map.hpp>
@@ -32,6 +45,15 @@
# define INK_UNORDERED_MAP boost::unordered_map
# define INK_HASH boost::hash
+namespace boost {
+template <>
+struct hash<Glib::ustring> : public std::unary_function<Glib::ustring, std::size_t> {
+ std::size_t operator()(Glib::ustring const &s) const {
+ return hash<std::string>()(s.raw());
+ }
+};
+} // namespace boost
+
#elif defined(HAVE_EXT_HASH_SET)
# include <functional>
@@ -54,6 +76,13 @@ struct hash<T *> : public std::unary_function<T *, std::size_t> {
return x + (x >> 3);
}
};
+
+template <>
+struct hash<Glib::ustring> : public std::unary_function<Glib::ustring, std::size_t> {
+ std::size_t operator()(Glib::ustring const &s) const {
+ return hash<std::string>()(s.raw());
+ }
+};
} // namespace __gnu_cxx
#endif