@@ -597,7 +597,19 @@ namespace Sass {
597
597
denominator_units_(vector<string>()),
598
598
hash_(0 )
599
599
{
600
- if (!u.empty ()) numerator_units_.push_back (u);
600
+ size_t l = 0 , r = 0 ;
601
+ if (!u.empty ()) {
602
+ bool nominator = true ;
603
+ while (true ) {
604
+ r = u.find_first_of (" */" , l);
605
+ string unit (u.substr (l, r - l));
606
+ if (nominator) numerator_units_.push_back (unit);
607
+ else denominator_units_.push_back (unit);
608
+ if (u[r] == ' /' ) nominator = false ;
609
+ if (r == string::npos) break ;
610
+ else l = r + 1 ;
611
+ }
612
+ }
601
613
concrete_type (NUMBER);
602
614
}
603
615
@@ -619,67 +631,169 @@ namespace Sass {
619
631
bool Number::is_unitless ()
620
632
{ return numerator_units_.empty () && denominator_units_.empty (); }
621
633
622
- void Number::normalize (string to )
634
+ void Number::normalize (const string& prefered )
623
635
{
624
- // (multiple passes because I'm too tired to think up something clever)
625
- // Find a unit to convert everything to, if one isn't provided.
626
- if (to.empty ()) {
627
- for (size_t i = 0 , S = numerator_units_.size (); i < S; ++i) {
628
- string u (numerator_units_[i]);
629
- if (string_to_unit (u) == INCOMMENSURABLE) {
630
- continue ;
631
- }
632
- else {
633
- to = u;
634
- break ;
635
- }
636
+
637
+ // first make sure same units cancel each other out
638
+ // it seems that a map table will fit nicely to do this
639
+ // we basically construct exponents for each unit
640
+ // has the advantage that they will be pre-sorted
641
+ map<string, int > exponents;
642
+
643
+ // initialize by summing up occurences in unit vectors
644
+ for (size_t i = 0 , S = numerator_units_.size (); i < S; ++i) ++ exponents[numerator_units_[i]];
645
+ for (size_t i = 0 , S = denominator_units_.size (); i < S; ++i) -- exponents[denominator_units_[i]];
646
+
647
+ // the final conversion factor
648
+ double factor = 1 ;
649
+
650
+ // get the first entry of numerators
651
+ // forward it when entry is converted
652
+ vector<string>::iterator nom_it = numerator_units_.begin ();
653
+ vector<string>::iterator nom_end = numerator_units_.end ();
654
+ vector<string>::iterator denom_it = denominator_units_.begin ();
655
+ vector<string>::iterator denom_end = denominator_units_.end ();
656
+
657
+ // main normalization loop
658
+ // should be close to optimal
659
+ while (denom_it != denom_end)
660
+ {
661
+ // get and increment afterwards
662
+ const string denom = *(denom_it ++);
663
+ // skip already canceled out unit
664
+ if (exponents[denom] >= 0 ) continue ;
665
+ // skip all units we don't know how to convert
666
+ if (string_to_unit (denom) == INCOMMENSURABLE) continue ;
667
+ // now search for nominator
668
+ while (nom_it != nom_end)
669
+ {
670
+ // get and increment afterwards
671
+ const string nom = *(nom_it ++);
672
+ // skip already canceled out unit
673
+ if (exponents[nom] <= 0 ) continue ;
674
+ // skip all units we don't know how to convert
675
+ if (string_to_unit (nom) == INCOMMENSURABLE) continue ;
676
+ // we now have two convertable units
677
+ // add factor for current conversion
678
+ factor *= conversion_factor (nom, denom);
679
+ // update nominator/denominator exponent
680
+ -- exponents[nom]; ++ exponents[denom];
681
+ // inner loop done
682
+ break ;
636
683
}
637
684
}
638
- if (to.empty ()) {
639
- for (size_t i = 0 , S = denominator_units_.size (); i < S; ++i) {
640
- string u (denominator_units_[i]);
641
- if (string_to_unit (u) == INCOMMENSURABLE) {
642
- continue ;
643
- }
644
- else {
645
- to = u;
646
- break ;
647
- }
685
+
686
+ // now we can build up the new unit arrays
687
+ numerator_units_.clear ();
688
+ denominator_units_.clear ();
689
+
690
+ // build them by iterating over the exponents
691
+ for (auto exp : exponents)
692
+ {
693
+ // maybe there is more effecient way to push
694
+ // the same item multiple times to a vector?
695
+ for (size_t i = 0 , S = abs (exp.second ); i < S; ++i)
696
+ {
697
+ // opted to have these switches in the inner loop
698
+ // makes it more readable and should not cost much
699
+ if (exp.second < 0 ) denominator_units_.push_back (exp.first );
700
+ else if (exp.second > 0 ) numerator_units_.push_back (exp.first );
648
701
}
649
702
}
650
- // Now loop through again and do all the conversions.
651
- for (size_t i = 0 , S = numerator_units_.size (); i < S; ++i) {
652
- string from (numerator_units_[i]);
653
- if (string_to_unit (from) == INCOMMENSURABLE) continue ;
654
- value_ *= conversion_factor (from, to);
655
- numerator_units_[i] = to;
656
- }
657
- for (size_t i = 0 , S = denominator_units_.size (); i < S; ++i) {
658
- string from (denominator_units_[i]);
659
- if (string_to_unit (from) == INCOMMENSURABLE) continue ;
660
- value_ /= conversion_factor (from, to);
661
- denominator_units_[i] = to;
662
- }
663
- // Now divide out identical units in the numerator and denominator.
664
- vector<string> ncopy;
665
- ncopy.reserve (numerator_units_.size ());
666
- for (vector<string>::iterator n = numerator_units_.begin ();
667
- n != numerator_units_.end ();
668
- ++n) {
669
- vector<string>::iterator d = find (denominator_units_.begin (),
670
- denominator_units_.end (),
671
- *n);
672
- if (d != denominator_units_.end ()) {
673
- denominator_units_.erase (d);
674
- }
675
- else {
676
- ncopy.push_back (*n);
703
+
704
+ // apply factor to value_
705
+ // best precision this way
706
+ value_ *= factor;
707
+
708
+ // maybe convert to other unit
709
+ // easier implemented on its own
710
+ convert (prefered);
711
+
712
+ }
713
+
714
+ void Number::convert (const string& prefered)
715
+ {
716
+ // abort if unit is empty
717
+ if (prefered.empty ()) return ;
718
+
719
+ // first make sure same units cancel each other out
720
+ // it seems that a map table will fit nicely to do this
721
+ // we basically construct exponents for each unit
722
+ // has the advantage that they will be pre-sorted
723
+ map<string, int > exponents;
724
+
725
+ // initialize by summing up occurences in unit vectors
726
+ for (size_t i = 0 , S = numerator_units_.size (); i < S; ++i) ++ exponents[numerator_units_[i]];
727
+ for (size_t i = 0 , S = denominator_units_.size (); i < S; ++i) -- exponents[denominator_units_[i]];
728
+
729
+ // the final conversion factor
730
+ double factor = 1 ;
731
+
732
+ vector<string>::iterator denom_it = denominator_units_.begin ();
733
+ vector<string>::iterator denom_end = denominator_units_.end ();
734
+
735
+ // main normalization loop
736
+ // should be close to optimal
737
+ while (denom_it != denom_end)
738
+ {
739
+ // get and increment afterwards
740
+ const string denom = *(denom_it ++);
741
+ // check if conversion is needed
742
+ if (denom == prefered) continue ;
743
+ // skip already canceled out unit
744
+ if (exponents[denom] >= 0 ) continue ;
745
+ // skip all units we don't know how to convert
746
+ if (string_to_unit (denom) == INCOMMENSURABLE) continue ;
747
+ // we now have two convertable units
748
+ // add factor for current conversion
749
+ factor *= conversion_factor (denom, prefered);
750
+ // update nominator/denominator exponent
751
+ ++ exponents[denom]; -- exponents[prefered];
752
+ }
753
+
754
+ vector<string>::iterator nom_it = numerator_units_.begin ();
755
+ vector<string>::iterator nom_end = numerator_units_.end ();
756
+
757
+ // now search for nominator
758
+ while (nom_it != nom_end)
759
+ {
760
+ // get and increment afterwards
761
+ const string nom = *(nom_it ++);
762
+ // check if conversion is needed
763
+ if (nom == prefered) continue ;
764
+ // skip already canceled out unit
765
+ if (exponents[nom] <= 0 ) continue ;
766
+ // skip all units we don't know how to convert
767
+ if (string_to_unit (nom) == INCOMMENSURABLE) continue ;
768
+ // we now have two convertable units
769
+ // add factor for current conversion
770
+ factor *= conversion_factor (nom, prefered);
771
+ // update nominator/denominator exponent
772
+ -- exponents[nom]; ++ exponents[prefered];
773
+ }
774
+
775
+ // now we can build up the new unit arrays
776
+ numerator_units_.clear ();
777
+ denominator_units_.clear ();
778
+
779
+ // build them by iterating over the exponents
780
+ for (auto exp : exponents)
781
+ {
782
+ // maybe there is more effecient way to push
783
+ // the same item multiple times to a vector?
784
+ for (size_t i = 0 , S = abs (exp.second ); i < S; ++i)
785
+ {
786
+ // opted to have these switches in the inner loop
787
+ // makes it more readable and should not cost much
788
+ if (exp.second < 0 ) denominator_units_.push_back (exp.first );
789
+ else if (exp.second > 0 ) numerator_units_.push_back (exp.first );
677
790
}
678
791
}
679
- numerator_units_ = ncopy;
680
- // Sort the units to make them pretty and, well, normal.
681
- sort (numerator_units_.begin (), numerator_units_.end ());
682
- sort (denominator_units_.begin (), denominator_units_.end ());
792
+
793
+ // apply factor to value_
794
+ // best precision this way
795
+ value_ *= factor;
796
+
683
797
}
684
798
685
799
// useful for making one number compatible with another
@@ -697,6 +811,21 @@ namespace Sass {
697
811
}
698
812
699
813
814
+ bool Number::operator == (Expression* rhs) const
815
+ {
816
+ Number l (pstate_, value_, unit ());
817
+ Number& r = dynamic_cast <Number&>(*rhs);
818
+ l.normalize (find_convertible_unit ());
819
+ r.normalize (find_convertible_unit ());
820
+ return l.unit () == r.unit () &&
821
+ l.value () == r.value ();
822
+ }
823
+
824
+ bool Number::operator == (Expression& rhs) const
825
+ {
826
+ return operator ==(&rhs);
827
+ }
828
+
700
829
Expression* Hashed::at (Expression* k) const
701
830
{
702
831
if (elements_.count (k))
0 commit comments