]> Shamusworld >> Repos - architektonas/blob - fparser/mpfr/GmpInt.cc
Bugfixes related to removing Snapper class.
[architektonas] / fparser / mpfr / GmpInt.cc
1 #include "GmpInt.hh"
2 #include <gmp.h>
3 #include <deque>
4 #include <vector>
5 #include <cstring>
6 #include <cctype>
7
8 //===========================================================================
9 // Shared data
10 //===========================================================================
11 namespace
12 {
13     unsigned long gIntDefaultNumberOfBits = 256;
14
15     std::vector<char>& intString()
16     {
17         static std::vector<char> str;
18         return str;
19     }
20 }
21
22 //===========================================================================
23 // Auxiliary structs
24 //===========================================================================
25 struct GmpInt::GmpIntData
26 {
27     unsigned mRefCount;
28     GmpIntData* nextFreeNode;
29     mpz_t mInteger;
30
31     GmpIntData(): mRefCount(1), nextFreeNode(0) {}
32 };
33
34 class GmpInt::GmpIntDataContainer
35 {
36     std::deque<GmpInt::GmpIntData> mData;
37     GmpInt::GmpIntData* mFirstFreeNode;
38     GmpInt::GmpIntData* mConst_0;
39
40  public:
41     GmpIntDataContainer(): mFirstFreeNode(0), mConst_0(0) {}
42
43     ~GmpIntDataContainer()
44     {
45         for(size_t i = 0; i < mData.size(); ++i)
46             mpz_clear(mData[i].mInteger);
47     }
48
49     GmpInt::GmpIntData* allocateGmpIntData(unsigned long numberOfBits,
50                                            bool initToZero)
51     {
52         if(mFirstFreeNode)
53         {
54             GmpInt::GmpIntData* node = mFirstFreeNode;
55             mFirstFreeNode = node->nextFreeNode;
56             if(initToZero) mpz_set_si(node->mInteger, 0);
57             ++(node->mRefCount);
58             return node;
59         }
60
61         mData.push_back(GmpInt::GmpIntData());
62         if(numberOfBits > 0)
63             mpz_init2(mData.back().mInteger, numberOfBits);
64         else
65             mpz_init(mData.back().mInteger);
66         return &mData.back();
67     }
68
69     void releaseGmpIntData(GmpIntData* data)
70     {
71         if(--(data->mRefCount) == 0)
72         {
73             data->nextFreeNode = mFirstFreeNode;
74             mFirstFreeNode = data;
75         }
76     }
77
78     GmpInt::GmpIntData* const_0()
79     {
80         if(!mConst_0)
81             mConst_0 = allocateGmpIntData(gIntDefaultNumberOfBits, true);
82         return mConst_0;
83     }
84 };
85
86
87 GmpInt::GmpIntDataContainer& GmpInt::gmpIntDataContainer()
88 {
89     static GmpIntDataContainer container;
90     return container;
91 }
92
93 //===========================================================================
94 // Auxiliary functions
95 //===========================================================================
96 void GmpInt::setDefaultNumberOfBits(unsigned long value)
97 {
98     gIntDefaultNumberOfBits = value;
99 }
100
101 unsigned long GmpInt::getDefaultNumberOfBits()
102 {
103     return gIntDefaultNumberOfBits;
104 }
105
106 inline void GmpInt::copyIfShared()
107 {
108     if(mData->mRefCount > 1)
109     {
110         --(mData->mRefCount);
111         GmpIntData* oldData = mData;
112         mData = gmpIntDataContainer().allocateGmpIntData(0, false);
113         mpz_set(mData->mInteger, oldData->mInteger);
114     }
115 }
116
117
118 //===========================================================================
119 // Constructors, destructor, assignment
120 //===========================================================================
121 GmpInt::GmpInt(DummyType):
122     mData(gmpIntDataContainer().allocateGmpIntData(0, false))
123 {}
124
125 GmpInt::GmpInt()
126 {
127     mData = gmpIntDataContainer().const_0();
128     ++(mData->mRefCount);
129 }
130
131 GmpInt::GmpInt(long value)
132 {
133     if(value == 0)
134     {
135         mData = gmpIntDataContainer().const_0();
136         ++(mData->mRefCount);
137     }
138     else
139     {
140         mData = gmpIntDataContainer().allocateGmpIntData
141             (gIntDefaultNumberOfBits, false);
142         mpz_set_si(mData->mInteger, value);
143     }
144 }
145
146 GmpInt::GmpInt(unsigned long value)
147 {
148     if(value == 0)
149     {
150         mData = gmpIntDataContainer().const_0();
151         ++(mData->mRefCount);
152     }
153     else
154     {
155         mData = gmpIntDataContainer().allocateGmpIntData
156             (gIntDefaultNumberOfBits, false);
157         mpz_set_ui(mData->mInteger, value);
158     }
159 }
160
161 GmpInt::GmpInt(int value)
162 {
163     if(value == 0)
164     {
165         mData = gmpIntDataContainer().const_0();
166         ++(mData->mRefCount);
167     }
168     else
169     {
170         mData = gmpIntDataContainer().allocateGmpIntData
171             (gIntDefaultNumberOfBits, false);
172         mpz_set_si(mData->mInteger, value);
173     }
174 }
175
176 GmpInt::GmpInt(double value)
177 {
178     const double absValue = value >= 0.0 ? value : -value;
179     if(absValue < 1.0)
180     {
181         mData = gmpIntDataContainer().const_0();
182         ++(mData->mRefCount);
183     }
184     else
185     {
186         mData = gmpIntDataContainer().allocateGmpIntData
187             (gIntDefaultNumberOfBits, false);
188         mpz_set_d(mData->mInteger, value);
189     }
190 }
191
192 GmpInt::GmpInt(long double value)
193 {
194     const long double absValue = value >= 0.0L ? value : -value;
195     if(absValue < 1.0L)
196     {
197         mData = gmpIntDataContainer().const_0();
198         ++(mData->mRefCount);
199     }
200     else
201     {
202         mData = gmpIntDataContainer().allocateGmpIntData
203             (gIntDefaultNumberOfBits, false);
204         mpz_set_d(mData->mInteger, double(value));
205     }
206 }
207
208 GmpInt::GmpInt(const GmpInt& rhs):
209     mData(rhs.mData)
210 {
211     ++(mData->mRefCount);
212 }
213
214 GmpInt& GmpInt::operator=(const GmpInt& rhs)
215 {
216     if(mData != rhs.mData)
217     {
218         gmpIntDataContainer().releaseGmpIntData(mData);
219         mData = rhs.mData;
220         ++(mData->mRefCount);
221     }
222     return *this;
223 }
224
225 GmpInt& GmpInt::operator=(signed long value)
226 {
227     if(value == 0)
228     {
229         gmpIntDataContainer().releaseGmpIntData(mData);
230         mData = gmpIntDataContainer().const_0();
231         ++(mData->mRefCount);
232     }
233     else
234     {
235         if(mData->mRefCount > 1)
236         {
237             --(mData->mRefCount);
238             mData = gmpIntDataContainer().allocateGmpIntData
239                 (gIntDefaultNumberOfBits, false);
240         }
241         mpz_set_si(mData->mInteger, value);
242     }
243     return *this;
244 }
245
246 GmpInt::~GmpInt()
247 {
248     gmpIntDataContainer().releaseGmpIntData(mData);
249 }
250
251
252 //===========================================================================
253 // Data getters
254 //===========================================================================
255 template<>
256 void GmpInt::get_raw_mpfr_data<mpz_t>(mpz_t& dest_mpz_t)
257 {
258     std::memcpy(&dest_mpz_t, mData->mInteger, sizeof(mpz_t));
259 }
260
261 const char* GmpInt::getAsString(int base) const
262 {
263     intString().resize(mpz_sizeinbase(mData->mInteger, base) + 2);
264     return mpz_get_str(&intString()[0], base, mData->mInteger);
265 }
266
267 long GmpInt::toInt() const
268 {
269     return mpz_get_si(mData->mInteger);
270 }
271
272
273 //===========================================================================
274 // Modifying operators
275 //===========================================================================
276 GmpInt& GmpInt::operator+=(const GmpInt& rhs)
277 {
278     copyIfShared();
279     mpz_add(mData->mInteger, mData->mInteger, rhs.mData->mInteger);
280     return *this;
281 }
282
283 GmpInt& GmpInt::operator+=(long value)
284 {
285     copyIfShared();
286     if(value >= 0)
287         mpz_add_ui(mData->mInteger, mData->mInteger, value);
288     else
289         mpz_sub_ui(mData->mInteger, mData->mInteger, -value);
290     return *this;
291 }
292
293 GmpInt& GmpInt::operator-=(const GmpInt& rhs)
294 {
295     copyIfShared();
296     mpz_sub(mData->mInteger, mData->mInteger, rhs.mData->mInteger);
297     return *this;
298 }
299
300 GmpInt& GmpInt::operator-=(long value)
301 {
302     copyIfShared();
303     if(value >= 0)
304         mpz_sub_ui(mData->mInteger, mData->mInteger, value);
305     else
306         mpz_add_ui(mData->mInteger, mData->mInteger, -value);
307     return *this;
308 }
309
310 GmpInt& GmpInt::operator*=(const GmpInt& rhs)
311 {
312     copyIfShared();
313     mpz_mul(mData->mInteger, mData->mInteger, rhs.mData->mInteger);
314     return *this;
315 }
316
317 GmpInt& GmpInt::operator*=(long value)
318 {
319     copyIfShared();
320     mpz_mul_si(mData->mInteger, mData->mInteger, value);
321     return *this;
322 }
323
324 GmpInt& GmpInt::operator/=(const GmpInt& rhs)
325 {
326     copyIfShared();
327     mpz_tdiv_q(mData->mInteger, mData->mInteger, rhs.mData->mInteger);
328     return *this;
329 }
330
331 GmpInt& GmpInt::operator/=(long value)
332 {
333     copyIfShared();
334     if(value >= 0)
335         mpz_tdiv_q_ui(mData->mInteger, mData->mInteger, value);
336     else
337     {
338         mpz_neg(mData->mInteger, mData->mInteger);
339         mpz_tdiv_q_ui(mData->mInteger, mData->mInteger, -value);
340     }
341     return *this;
342 }
343
344 GmpInt& GmpInt::operator%=(const GmpInt& rhs)
345 {
346     copyIfShared();
347     if(operator<(0))
348     {
349         negate();
350         mpz_mod(mData->mInteger, mData->mInteger, rhs.mData->mInteger);
351         negate();
352     }
353     else
354     {
355         mpz_mod(mData->mInteger, mData->mInteger, rhs.mData->mInteger);
356     }
357     return *this;
358 }
359
360 GmpInt& GmpInt::operator%=(long value)
361 {
362     copyIfShared();
363     if(value < 0) value = -value;
364     if(operator<(0))
365     {
366         negate();
367         mpz_mod_ui(mData->mInteger, mData->mInteger, value);
368         negate();
369     }
370     else
371     {
372         mpz_mod_ui(mData->mInteger, mData->mInteger, value);
373     }
374     return *this;
375 }
376
377 GmpInt& GmpInt::operator<<=(unsigned long bits)
378 {
379     copyIfShared();
380     mpz_mul_2exp(mData->mInteger, mData->mInteger, bits);
381     return *this;
382 }
383
384 GmpInt& GmpInt::operator>>=(unsigned long bits)
385 {
386     copyIfShared();
387     mpz_tdiv_q_2exp(mData->mInteger, mData->mInteger, bits);
388     return *this;
389 }
390
391
392 //===========================================================================
393 // Modifying functions
394 //===========================================================================
395 void GmpInt::addProduct(const GmpInt& value1, const GmpInt& value2)
396 {
397     copyIfShared();
398     mpz_addmul(mData->mInteger, value1.mData->mInteger, value2.mData->mInteger);
399 }
400
401 void GmpInt::addProduct(const GmpInt& value1, unsigned long value2)
402 {
403     copyIfShared();
404     mpz_addmul_ui(mData->mInteger, value1.mData->mInteger, value2);
405 }
406
407 void GmpInt::subProduct(const GmpInt& value1, const GmpInt& value2)
408 {
409     copyIfShared();
410     mpz_submul(mData->mInteger, value1.mData->mInteger, value2.mData->mInteger);
411 }
412
413 void GmpInt::subProduct(const GmpInt& value1, unsigned long value2)
414 {
415     copyIfShared();
416     mpz_submul_ui(mData->mInteger, value1.mData->mInteger, value2);
417 }
418
419 void GmpInt::negate()
420 {
421     copyIfShared();
422     mpz_neg(mData->mInteger, mData->mInteger);
423 }
424
425 void GmpInt::abs()
426 {
427     copyIfShared();
428     mpz_abs(mData->mInteger, mData->mInteger);
429 }
430
431 GmpInt GmpInt::abs(const GmpInt& value)
432 {
433     GmpInt retval(kNoInitialization);
434     mpz_abs(retval.mData->mInteger, value.mData->mInteger);
435     return retval;
436 }
437
438
439 //===========================================================================
440 // Non-modifying operators
441 //===========================================================================
442 GmpInt GmpInt::operator+(const GmpInt& rhs) const
443 {
444     GmpInt retval(kNoInitialization);
445     mpz_add(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger);
446     return retval;
447 }
448
449 GmpInt GmpInt::operator+(long value) const
450 {
451     GmpInt retval(kNoInitialization);
452     if(value >= 0)
453         mpz_add_ui(retval.mData->mInteger, mData->mInteger, value);
454     else
455         mpz_sub_ui(retval.mData->mInteger, mData->mInteger, -value);
456     return retval;
457 }
458
459 GmpInt GmpInt::operator-(const GmpInt& rhs) const
460 {
461     GmpInt retval(kNoInitialization);
462     mpz_sub(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger);
463     return retval;
464 }
465
466 GmpInt GmpInt::operator-(long value) const
467 {
468     GmpInt retval(kNoInitialization);
469     if(value >= 0)
470         mpz_sub_ui(retval.mData->mInteger, mData->mInteger, value);
471     else
472         mpz_add_ui(retval.mData->mInteger, mData->mInteger, -value);
473     return retval;
474 }
475
476 GmpInt GmpInt::operator*(const GmpInt& rhs) const
477 {
478     GmpInt retval(kNoInitialization);
479     mpz_mul(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger);
480     return retval;
481 }
482
483 GmpInt GmpInt::operator*(long value) const
484 {
485     GmpInt retval(kNoInitialization);
486     mpz_mul_si(retval.mData->mInteger, mData->mInteger, value);
487     return retval;
488 }
489
490 GmpInt GmpInt::operator/(const GmpInt& rhs) const
491 {
492     GmpInt retval(kNoInitialization);
493     mpz_tdiv_q(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger);
494     return retval;
495 }
496
497 GmpInt GmpInt::operator/(long value) const
498 {
499     GmpInt retval(kNoInitialization);
500     if(value >= 0)
501         mpz_tdiv_q_ui(retval.mData->mInteger, mData->mInteger, value);
502     else
503     {
504         mpz_neg(retval.mData->mInteger, mData->mInteger);
505         mpz_tdiv_q_ui(retval.mData->mInteger, retval.mData->mInteger, -value);
506     }
507     return retval;
508 }
509
510 GmpInt GmpInt::operator%(const GmpInt& rhs) const
511 {
512     GmpInt retval(kNoInitialization);
513     if(operator<(0))
514     {
515         mpz_neg(retval.mData->mInteger, mData->mInteger);
516         mpz_mod(retval.mData->mInteger,
517                 retval.mData->mInteger, rhs.mData->mInteger);
518         retval.negate();
519     }
520     else
521     {
522         mpz_mod(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger);
523     }
524     return retval;
525 }
526
527 GmpInt GmpInt::operator%(long value) const
528 {
529     GmpInt retval(kNoInitialization);
530     if(value < 0) value = -value;
531     if(operator<(0))
532     {
533         mpz_neg(retval.mData->mInteger, mData->mInteger);
534         mpz_mod_ui(retval.mData->mInteger, retval.mData->mInteger, value);
535         retval.negate();
536     }
537     else
538     {
539         mpz_mod_ui(retval.mData->mInteger, mData->mInteger, value);
540     }
541     return retval;
542 }
543
544 GmpInt GmpInt::operator-() const
545 {
546     GmpInt retval(kNoInitialization);
547     mpz_neg(retval.mData->mInteger, mData->mInteger);
548     return retval;
549 }
550
551 GmpInt GmpInt::operator<<(unsigned long bits) const
552 {
553     GmpInt retval(kNoInitialization);
554     mpz_mul_2exp(retval.mData->mInteger, mData->mInteger, bits);
555     return retval;
556 }
557
558 GmpInt GmpInt::operator>>(unsigned long bits) const
559 {
560     GmpInt retval(kNoInitialization);
561     mpz_tdiv_q_2exp(retval.mData->mInteger, mData->mInteger, bits);
562     return retval;
563 }
564
565
566 //===========================================================================
567 // Comparison operators
568 //===========================================================================
569 bool GmpInt::operator<(const GmpInt& rhs) const
570 {
571     return mpz_cmp(mData->mInteger, rhs.mData->mInteger) < 0;
572 }
573
574 bool GmpInt::operator<(long value) const
575 {
576     return mpz_cmp_si(mData->mInteger, value) < 0;
577 }
578
579 bool GmpInt::operator<=(const GmpInt& rhs) const
580 {
581     return mpz_cmp(mData->mInteger, rhs.mData->mInteger) <= 0;
582 }
583
584 bool GmpInt::operator<=(long value) const
585 {
586     return mpz_cmp_si(mData->mInteger, value) <= 0;
587 }
588
589 bool GmpInt::operator>(const GmpInt& rhs) const
590 {
591     return mpz_cmp(mData->mInteger, rhs.mData->mInteger) > 0;
592 }
593
594 bool GmpInt::operator>(long value) const
595 {
596     return mpz_cmp_si(mData->mInteger, value) > 0;
597 }
598
599 bool GmpInt::operator>=(const GmpInt& rhs) const
600 {
601     return mpz_cmp(mData->mInteger, rhs.mData->mInteger) >= 0;
602 }
603
604 bool GmpInt::operator>=(long value) const
605 {
606     return mpz_cmp_si(mData->mInteger, value) >= 0;
607 }
608
609 bool GmpInt::operator==(const GmpInt& rhs) const
610 {
611     return mpz_cmp(mData->mInteger, rhs.mData->mInteger) == 0;
612 }
613
614 bool GmpInt::operator==(long value) const
615 {
616     return mpz_cmp_si(mData->mInteger, value) == 0;
617 }
618
619 bool GmpInt::operator!=(const GmpInt& rhs) const
620 {
621     return mpz_cmp(mData->mInteger, rhs.mData->mInteger) != 0;
622 }
623
624 bool GmpInt::operator!=(long value) const
625 {
626     return mpz_cmp_si(mData->mInteger, value) != 0;
627 }
628
629 void GmpInt::parseValue(const char* value)
630 {
631     mpz_set_str(mData->mInteger, value, 10);
632 }
633
634 void GmpInt::parseValue(const char* value, char** endptr)
635 {
636     static std::vector<char> str;
637
638     unsigned startIndex = 0;
639     while(value[startIndex] && std::isspace(value[startIndex])) ++startIndex;
640     if(!value[startIndex]) { *endptr = const_cast<char*>(value); return; }
641
642     unsigned endIndex = startIndex;
643     if(value[endIndex] == '-') ++endIndex;
644     if(!std::isdigit(value[endIndex]))
645     { *endptr = const_cast<char*>(value); return; }
646     if(value[endIndex] == '0' && value[endIndex+1] == 'x')
647     {
648         endIndex += 1;
649         while(std::isxdigit(value[++endIndex])) {}
650     }
651     else
652     {
653         while(std::isdigit(value[++endIndex])) {}
654     }
655
656     str.reserve(endIndex - startIndex + 1);
657     str.assign(value + startIndex, value + endIndex);
658     str.push_back(0);
659
660     mpz_set_str(mData->mInteger, &str[0], 0);
661     *endptr = const_cast<char*>(value + endIndex);
662 }
663
664 GmpInt GmpInt::parseString(const char* str, char** endptr)
665 {
666     GmpInt retval(kNoInitialization);
667     retval.parseValue(str, endptr);
668     return retval;
669 }
670
671 //===========================================================================
672 // Operator functions
673 //===========================================================================
674 GmpInt operator+(long lhs, const GmpInt& rhs)
675 {
676     GmpInt retval(GmpInt::kNoInitialization);
677     if(lhs >= 0)
678         mpz_add_ui(retval.mData->mInteger, rhs.mData->mInteger, lhs);
679     else
680         mpz_sub_ui(retval.mData->mInteger, rhs.mData->mInteger, -lhs);
681     return retval;
682 }
683
684 GmpInt operator-(long lhs, const GmpInt& rhs)
685 {
686     GmpInt retval(GmpInt::kNoInitialization);
687     if(lhs >= 0)
688         mpz_ui_sub(retval.mData->mInteger, lhs, rhs.mData->mInteger);
689     else
690     {
691         mpz_add_ui(retval.mData->mInteger, rhs.mData->mInteger, -lhs);
692         mpz_neg(retval.mData->mInteger, retval.mData->mInteger);
693     }
694     return retval;
695 }
696
697 GmpInt operator*(long lhs, const GmpInt& rhs)
698 {
699     return rhs * lhs;
700 }
701
702 GmpInt operator/(long lhs, const GmpInt& rhs)
703 {
704     return GmpInt(lhs) / rhs;
705 }
706
707 GmpInt operator%(long lhs, const GmpInt& rhs)
708 {
709     return GmpInt(lhs) % rhs;
710 }