@@ -1526,7 +1526,7 @@ namespace Sass {
1526
1526
denominator_units ().size () == 0 ;
1527
1527
}
1528
1528
1529
- bool Number::is_unitless ()
1529
+ bool Number::is_unitless () const
1530
1530
{ return numerator_units_.empty () && denominator_units_.empty (); }
1531
1531
1532
1532
void Number::normalize (const std::string& prefered, bool strict)
@@ -1614,10 +1614,128 @@ namespace Sass {
1614
1614
1615
1615
}
1616
1616
1617
- void Number::convert (const std::string& prefered, bool strict)
1617
+ // this does not cover all cases (multiple prefered units)
1618
+ double Number::convert_factor (const Number& n) const
1618
1619
{
1619
- // abort if unit is empty
1620
- if (prefered.empty ()) return ;
1620
+
1621
+ // first make sure same units cancel each other out
1622
+ // it seems that a map table will fit nicely to do this
1623
+ // we basically construct exponents for each unit class
1624
+ // std::map<std::string, int> exponents;
1625
+ // initialize by summing up occurences in unit vectors
1626
+ // for (size_t i = 0, S = numerator_units_.size(); i < S; ++i) ++ exponents[unit_to_class(numerator_units_[i])];
1627
+ // for (size_t i = 0, S = denominator_units_.size(); i < S; ++i) -- exponents[unit_to_class(denominator_units_[i])];
1628
+
1629
+ std::vector<std::string> l_miss_nums (0 );
1630
+ std::vector<std::string> l_miss_dens (0 );
1631
+ // create copy since we need these for state keeping
1632
+ std::vector<std::string> r_nums = n.numerator_units_ ;
1633
+ std::vector<std::string> r_dens = n.denominator_units_ ;
1634
+
1635
+ std::vector<std::string>::const_iterator l_num_it = numerator_units_.begin ();
1636
+ std::vector<std::string>::const_iterator l_num_end = numerator_units_.end ();
1637
+
1638
+ bool l_unitless = is_unitless ();
1639
+ bool r_unitless = n.is_unitless ();
1640
+
1641
+ // overall conversion
1642
+ double factor = 1 ;
1643
+
1644
+ // process all left numerators
1645
+ while (l_num_it != l_num_end)
1646
+ {
1647
+ // get and increment afterwards
1648
+ const std::string l_num = *(l_num_it ++);
1649
+
1650
+ std::vector<std::string>::iterator r_num_it = r_nums.begin ();
1651
+ std::vector<std::string>::iterator r_num_end = r_nums.end ();
1652
+
1653
+ // search for compatible numerator
1654
+ while (r_num_it != r_num_end)
1655
+ {
1656
+ // get and increment afterwards
1657
+ const std::string r_num = *(r_num_it);
1658
+ // get possible converstion factor for units
1659
+ double conversion = conversion_factor (l_num, r_num, false );
1660
+ // skip incompatible numerator
1661
+ if (conversion == 0 ) {
1662
+ ++ r_num_it;
1663
+ continue ;
1664
+ }
1665
+ // apply to global factor
1666
+ factor *= conversion;
1667
+ // remove item from vector
1668
+ r_nums.erase (r_num_it);
1669
+ // found it
1670
+ break ;
1671
+ }
1672
+ // maybe we did not find any
1673
+ if (r_num_it == r_num_end) {
1674
+ // left numerator is leftover
1675
+ l_miss_nums.push_back (l_num);
1676
+ }
1677
+ }
1678
+
1679
+ std::vector<std::string>::const_iterator l_den_it = denominator_units_.begin ();
1680
+ std::vector<std::string>::const_iterator l_den_end = denominator_units_.end ();
1681
+
1682
+ // process all left denominators
1683
+ while (l_den_it != l_den_end)
1684
+ {
1685
+ // get and increment afterwards
1686
+ const std::string l_den = *(l_den_it ++);
1687
+
1688
+ std::vector<std::string>::iterator r_den_it = r_dens.begin ();
1689
+ std::vector<std::string>::iterator r_den_end = r_dens.end ();
1690
+
1691
+ // search for compatible denominator
1692
+ while (r_den_it != r_den_end)
1693
+ {
1694
+ // get and increment afterwards
1695
+ const std::string r_den = *(r_den_it);
1696
+ // get possible converstion factor for units
1697
+ double conversion = conversion_factor (l_den, r_den, false );
1698
+ // skip incompatible denominator
1699
+ if (conversion == 0 ) {
1700
+ ++ r_den_it;
1701
+ continue ;
1702
+ }
1703
+ // apply to global factor
1704
+ factor *= conversion;
1705
+ // remove item from vector
1706
+ r_dens.erase (r_den_it);
1707
+ // found it
1708
+ break ;
1709
+ }
1710
+ // maybe we did not find any
1711
+ if (r_den_it == r_den_end) {
1712
+ // left denominator is leftover
1713
+ l_miss_dens.push_back (l_den);
1714
+ }
1715
+ }
1716
+
1717
+ // check left-overs (ToDo: might cancel out)
1718
+ if (l_miss_nums.size () > 0 && !r_unitless) {
1719
+ throw Exception::IncompatibleUnits (n, *this );
1720
+ }
1721
+ if (l_miss_dens.size () > 0 && !r_unitless) {
1722
+ throw Exception::IncompatibleUnits (n, *this );
1723
+ }
1724
+ if (r_nums.size () > 0 && !l_unitless) {
1725
+ throw Exception::IncompatibleUnits (n, *this );
1726
+ }
1727
+ if (r_dens.size () > 0 && !l_unitless) {
1728
+ throw Exception::IncompatibleUnits (n, *this );
1729
+ }
1730
+
1731
+ return factor;
1732
+ }
1733
+
1734
+ // this does not cover all cases (multiple prefered units)
1735
+ bool Number::convert (const std::string& prefered, bool strict)
1736
+ {
1737
+ // no conversion if unit is empty
1738
+ if (prefered.empty ()) return true ;
1621
1739
1622
1740
// first make sure same units cancel each other out
1623
1741
// it seems that a map table will fit nicely to do this
@@ -1699,6 +1817,9 @@ namespace Sass {
1699
1817
// best precision this way
1700
1818
value_ *= factor;
1701
1819
1820
+ // success?
1821
+ return true ;
1822
+
1702
1823
}
1703
1824
1704
1825
// useful for making one number compatible with another
0 commit comments