@@ -589,6 +589,270 @@ namespace Sass {
589
589
return result;
590
590
}*/
591
591
592
+ Number::Number (ParserState pstate, double val, string u, bool zero)
593
+ : Expression(pstate),
594
+ value_ (val),
595
+ zero_(zero),
596
+ numerator_units_(vector<string>()),
597
+ denominator_units_(vector<string>()),
598
+ hash_(0 )
599
+ {
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
+ }
613
+ concrete_type (NUMBER);
614
+ }
615
+
616
+ string Number::unit () const
617
+ {
618
+ stringstream u;
619
+ for (size_t i = 0 , S = numerator_units_.size (); i < S; ++i) {
620
+ if (i) u << ' *' ;
621
+ u << numerator_units_[i];
622
+ }
623
+ if (!denominator_units_.empty ()) u << ' /' ;
624
+ for (size_t i = 0 , S = denominator_units_.size (); i < S; ++i) {
625
+ if (i) u << ' *' ;
626
+ u << denominator_units_[i];
627
+ }
628
+ return u.str ();
629
+ }
630
+
631
+ bool Number::is_unitless ()
632
+ { return numerator_units_.empty () && denominator_units_.empty (); }
633
+
634
+ void Number::normalize (const string& prefered)
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 ;
683
+ }
684
+ }
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 );
701
+ }
702
+ }
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 );
790
+ }
791
+ }
792
+
793
+ // apply factor to value_
794
+ // best precision this way
795
+ value_ *= factor;
796
+
797
+ }
798
+
799
+ // useful for making one number compatible with another
800
+ string Number::find_convertible_unit () const
801
+ {
802
+ for (size_t i = 0 , S = numerator_units_.size (); i < S; ++i) {
803
+ string u (numerator_units_[i]);
804
+ if (string_to_unit (u) != INCOMMENSURABLE) return u;
805
+ }
806
+ for (size_t i = 0 , S = denominator_units_.size (); i < S; ++i) {
807
+ string u (denominator_units_[i]);
808
+ if (string_to_unit (u) != INCOMMENSURABLE) return u;
809
+ }
810
+ return string ();
811
+ }
812
+
813
+
814
+ bool Number::operator == (Expression* rhs) const
815
+ {
816
+ try
817
+ {
818
+ Number l (pstate_, value_, unit ());
819
+ Number& r = dynamic_cast <Number&>(*rhs);
820
+ l.normalize (find_convertible_unit ());
821
+ r.normalize (find_convertible_unit ());
822
+ return l.unit () == r.unit () &&
823
+ l.value () == r.value ();
824
+ }
825
+ catch (std::bad_cast&) {}
826
+ catch (...) { throw ; }
827
+ return false ;
828
+ }
829
+
830
+ bool Number::operator == (Expression& rhs) const
831
+ {
832
+ return operator ==(&rhs);
833
+ }
834
+
835
+ bool List::operator ==(Expression* rhs) const
836
+ {
837
+ try
838
+ {
839
+ List* r = dynamic_cast <List*>(rhs);
840
+ if (!r || length () != r->length ()) return false ;
841
+ if (separator () != r->separator ()) return false ;
842
+ for (size_t i = 0 , L = r->length (); i < L; ++i)
843
+ if (*elements ()[i] != *(*r)[i]) return false ;
844
+ return true ;
845
+ }
846
+ catch (std::bad_cast&) {}
847
+ catch (...) { throw ; }
848
+ return false ;
849
+ }
850
+
851
+ bool List::operator == (Expression& rhs) const
852
+ {
853
+ return operator ==(&rhs);
854
+ }
855
+
592
856
Expression* Hashed::at (Expression* k) const
593
857
{
594
858
if (elements_.count (k))
0 commit comments