]> git.saurik.com Git - wxWidgets.git/blame - src/common/longlong.cpp
Don't complain under MicroWindows if a wxDC's HDC is NULL - it happens
[wxWidgets.git] / src / common / longlong.cpp
CommitLineData
8b81872f
VZ
1/////////////////////////////////////////////////////////////////////////////
2// Name: wx/longlong.cpp
3// Purpose: implementation of wxLongLongNative
4// Author: Jeffrey C. Ollie <jeff@ollie.clive.ia.us>, Vadim Zeitlin
5// Remarks: this class is not public in wxWindows 2.0! It is intentionally
6// not documented and is for private use only.
7// Modified by:
8// Created: 10.02.99
9// RCS-ID: $Id$
10// Copyright: (c) 1998 Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>
11// Licence: wxWindows license
12/////////////////////////////////////////////////////////////////////////////
13
14// ============================================================================
15// headers
16// ============================================================================
17
18#ifdef __GNUG__
19 #pragma implementation "longlong.h"
20#endif
21
22#include "wx/wxprec.h"
23
24#ifdef __BORLANDC__
25 #pragma hdrstop
26#endif
27
4e57b0d4 28#if wxUSE_LONGLONG
8b81872f
VZ
29#include "wx/longlong.h"
30
31#include <memory.h> // for memset()
41acf5c0 32#include <math.h> // for fabs()
8b81872f
VZ
33
34// ============================================================================
35// implementation
36// ============================================================================
37
38#if wxUSE_LONGLONG_NATIVE
39
40// ----------------------------------------------------------------------------
41// misc
42// ----------------------------------------------------------------------------
43
2a310492 44void *wxLongLongNative::asArray() const
8b81872f
VZ
45{
46 static unsigned char temp[8];
47
48 temp[0] = (m_ll >> 56) & 0xFF;
49 temp[1] = (m_ll >> 48) & 0xFF;
50 temp[2] = (m_ll >> 40) & 0xFF;
51 temp[3] = (m_ll >> 32) & 0xFF;
52 temp[4] = (m_ll >> 24) & 0xFF;
53 temp[5] = (m_ll >> 16) & 0xFF;
54 temp[6] = (m_ll >> 8) & 0xFF;
55 temp[7] = (m_ll >> 0) & 0xFF;
56
57 return temp;
58}
59
fcc3d7cb
VZ
60#if wxUSE_STD_IOSTREAM
61
8b81872f 62// input/output
dd107c50 63wxSTD ostream& operator<< (wxSTD ostream& o, const wxLongLongNative& ll)
8b81872f
VZ
64{
65 char result[65];
66
dd107c50 67 wxSTD memset(result, 'A', 64);
8b81872f
VZ
68
69 result[64] = '\0';
70
71 for (int i = 0; i < 64; i++)
72 {
ea968ccd 73 result[63 - i] = '0' + (char) ((ll.GetValue() >> i) & 1);
8b81872f
VZ
74 }
75
76 return o << result;
77}
78
fcc3d7cb
VZ
79#endif // wxUSE_STD_IOSTREAM
80
8b81872f
VZ
81#endif // wxUSE_LONGLONG_NATIVE
82
41acf5c0
VZ
83// ============================================================================
84// wxLongLongWx: emulation of 'long long' using 2 longs
85// ============================================================================
86
8b81872f
VZ
87#if wxUSE_LONGLONG_WX
88
41acf5c0
VZ
89// assignment
90wxLongLongWx& wxLongLongWx::Assign(double d)
91{
2a310492
VZ
92 bool positive = d >= 0;
93 d = fabs(d);
617ec456 94 if ( d <= ULONG_MAX )
41acf5c0 95 {
2a310492 96 m_hi = 0;
41acf5c0
VZ
97 m_lo = (long)d;
98 }
99 else
100 {
617ec456
VZ
101 m_hi = (unsigned long)(d / (1.0 + (double)ULONG_MAX));
102 m_lo = (unsigned long)(d - ((double)m_hi * (1.0 + (double)ULONG_MAX)));
41acf5c0
VZ
103 }
104
2a310492
VZ
105#ifdef wxLONGLONG_TEST_MODE
106 m_ll = (wxLongLong_t)d;
107
108 Check();
109#endif // wxLONGLONG_TEST_MODE
110
617ec456
VZ
111 if ( !positive )
112 Negate();
113
41acf5c0
VZ
114 return *this;
115}
116
8b81872f
VZ
117wxLongLongWx wxLongLongWx::operator<<(int shift) const
118{
2a310492
VZ
119 wxLongLongWx ll(*this);
120 ll <<= shift;
8b81872f 121
2a310492 122 return ll;
8b81872f
VZ
123}
124
125wxLongLongWx& wxLongLongWx::operator<<=(int shift)
126{
2a310492 127 if (shift != 0)
8b81872f 128 {
2a310492
VZ
129 if (shift < 32)
130 {
131 m_hi <<= shift;
132 m_hi |= m_lo >> (32 - shift);
133 m_lo <<= shift;
134 }
135 else
136 {
137 m_hi = m_lo << (shift - 32);
138 m_lo = 0;
139 }
8b81872f
VZ
140 }
141
2a310492
VZ
142#ifdef wxLONGLONG_TEST_MODE
143 m_ll <<= shift;
144
145 Check();
146#endif // wxLONGLONG_TEST_MODE
147
8b81872f
VZ
148 return *this;
149}
150
151wxLongLongWx wxLongLongWx::operator>>(int shift) const
152{
2a310492
VZ
153 wxLongLongWx ll(*this);
154 ll >>= shift;
8b81872f 155
2a310492 156 return ll;
8b81872f
VZ
157}
158
159wxLongLongWx& wxLongLongWx::operator>>=(int shift)
160{
2a310492 161 if (shift != 0)
8b81872f 162 {
2a310492
VZ
163 if (shift < 32)
164 {
165 m_lo >>= shift;
166 m_lo |= m_hi << (32 - shift);
167 m_hi >>= shift;
168 }
169 else
170 {
171 m_lo = m_hi >> (shift - 32);
172 m_hi = (m_hi < 0 ? -1L : 0);
173 }
8b81872f
VZ
174 }
175
2a310492
VZ
176#ifdef wxLONGLONG_TEST_MODE
177 m_ll >>= shift;
178
179 Check();
180#endif // wxLONGLONG_TEST_MODE
181
8b81872f
VZ
182 return *this;
183}
184
185wxLongLongWx wxLongLongWx::operator+(const wxLongLongWx& ll) const
186{
2a310492
VZ
187 wxLongLongWx res(*this);
188 res += ll;
8b81872f 189
2a310492 190 return res;
8b81872f
VZ
191}
192
193wxLongLongWx wxLongLongWx::operator+(long l) const
194{
2a310492
VZ
195 wxLongLongWx res(*this);
196 res += l;
8b81872f 197
2a310492 198 return res;
8b81872f
VZ
199}
200
201wxLongLongWx& wxLongLongWx::operator+=(const wxLongLongWx& ll)
202{
203 unsigned long previous = m_lo;
204
205 m_lo += ll.m_lo;
206 m_hi += ll.m_hi;
207
208 if ((m_lo < previous) || (m_lo < ll.m_lo))
209 m_hi++;
210
2a310492
VZ
211#ifdef wxLONGLONG_TEST_MODE
212 m_ll += ll.m_ll;
213
214 Check();
215#endif // wxLONGLONG_TEST_MODE
216
8b81872f
VZ
217 return *this;
218}
219
220wxLongLongWx& wxLongLongWx::operator+=(long l)
221{
222 unsigned long previous = m_lo;
223
224 m_lo += l;
225 if (l < 0)
226 m_hi += -1l;
227
228 if ((m_lo < previous) || (m_lo < (unsigned long)l))
229 m_hi++;
230
2a310492
VZ
231#ifdef wxLONGLONG_TEST_MODE
232 m_ll += l;
233
234 Check();
235#endif // wxLONGLONG_TEST_MODE
236
8b81872f
VZ
237 return *this;
238}
239
240// pre increment
241wxLongLongWx& wxLongLongWx::operator++()
242{
243 m_lo++;
244 if (m_lo == 0)
245 m_hi++;
246
2a310492
VZ
247#ifdef wxLONGLONG_TEST_MODE
248 m_ll++;
8b81872f 249
2a310492
VZ
250 Check();
251#endif // wxLONGLONG_TEST_MODE
8b81872f
VZ
252
253 return *this;
254}
255
256// negation
257wxLongLongWx wxLongLongWx::operator-() const
258{
2a310492
VZ
259 wxLongLongWx res(*this);
260 res.Negate();
261
262 return res;
263}
264
265wxLongLongWx& wxLongLongWx::Negate()
266{
267 m_hi = ~m_hi;
268 m_lo = ~m_lo;
269
270 m_lo++;
271 if ( m_lo == 0 )
272 m_hi++;
8b81872f 273
2a310492
VZ
274#ifdef wxLONGLONG_TEST_MODE
275 m_ll = -m_ll;
8b81872f 276
2a310492
VZ
277 Check();
278#endif // wxLONGLONG_TEST_MODE
279
280 return *this;
8b81872f
VZ
281}
282
283// subtraction
284
285wxLongLongWx wxLongLongWx::operator-(const wxLongLongWx& ll) const
286{
2a310492
VZ
287 wxLongLongWx res(*this);
288 res -= ll;
8b81872f 289
2a310492 290 return res;
8b81872f
VZ
291}
292
293wxLongLongWx& wxLongLongWx::operator-=(const wxLongLongWx& ll)
294{
295 unsigned long previous = m_lo;
296
297 m_lo -= ll.m_lo;
298 m_hi -= ll.m_hi;
299
300 if (previous < ll.m_lo)
301 m_hi--;
302
2a310492
VZ
303#ifdef wxLONGLONG_TEST_MODE
304 m_ll -= ll.m_ll;
305
306 Check();
307#endif // wxLONGLONG_TEST_MODE
308
13111b2a 309 return *this;
8b81872f
VZ
310}
311
312// pre decrement
313wxLongLongWx& wxLongLongWx::operator--()
314{
315 m_lo--;
316 if (m_lo == 0xFFFFFFFF)
317 m_hi--;
318
2a310492
VZ
319#ifdef wxLONGLONG_TEST_MODE
320 m_ll--;
8b81872f 321
2a310492
VZ
322 Check();
323#endif // wxLONGLONG_TEST_MODE
8b81872f
VZ
324
325 return *this;
326}
327
328// comparison operators
329
330bool wxLongLongWx::operator<(const wxLongLongWx& ll) const
331{
2ea24d9f
VZ
332 if ( m_hi < ll.m_hi )
333 return TRUE;
334 else if ( m_hi == ll.m_hi )
335 return m_lo < ll.m_lo;
336 else
337 return FALSE;
8b81872f
VZ
338}
339
340bool wxLongLongWx::operator>(const wxLongLongWx& ll) const
341{
2ea24d9f
VZ
342 if ( m_hi > ll.m_hi )
343 return TRUE;
344 else if ( m_hi == ll.m_hi )
345 return m_lo > ll.m_lo;
346 else
347 return FALSE;
8b81872f
VZ
348}
349
350// bitwise operators
351
352wxLongLongWx wxLongLongWx::operator&(const wxLongLongWx& ll) const
353{
354 return wxLongLongWx(m_hi & ll.m_hi, m_lo & ll.m_lo);
355}
356
357wxLongLongWx wxLongLongWx::operator|(const wxLongLongWx& ll) const
358{
359 return wxLongLongWx(m_hi | ll.m_hi, m_lo | ll.m_lo);
360}
361
362wxLongLongWx wxLongLongWx::operator^(const wxLongLongWx& ll) const
363{
364 return wxLongLongWx(m_hi ^ ll.m_hi, m_lo ^ ll.m_lo);
365}
366
367wxLongLongWx& wxLongLongWx::operator&=(const wxLongLongWx& ll)
368{
369 m_lo &= ll.m_lo;
370 m_hi &= ll.m_hi;
371
2a310492
VZ
372#ifdef wxLONGLONG_TEST_MODE
373 m_ll &= ll.m_ll;
374
375 Check();
376#endif // wxLONGLONG_TEST_MODE
377
8b81872f
VZ
378 return *this;
379}
380
381wxLongLongWx& wxLongLongWx::operator|=(const wxLongLongWx& ll)
382{
383 m_lo |= ll.m_lo;
384 m_hi |= ll.m_hi;
385
2a310492
VZ
386#ifdef wxLONGLONG_TEST_MODE
387 m_ll |= ll.m_ll;
388
389 Check();
390#endif // wxLONGLONG_TEST_MODE
391
8b81872f
VZ
392 return *this;
393}
394
395wxLongLongWx& wxLongLongWx::operator^=(const wxLongLongWx& ll)
396{
397 m_lo ^= ll.m_lo;
398 m_hi ^= ll.m_hi;
399
2a310492
VZ
400#ifdef wxLONGLONG_TEST_MODE
401 m_ll ^= ll.m_ll;
402
403 Check();
404#endif // wxLONGLONG_TEST_MODE
405
8b81872f
VZ
406 return *this;
407}
408
409wxLongLongWx wxLongLongWx::operator~() const
410{
411 return wxLongLongWx(~m_hi, ~m_lo);
412}
413
414// multiplication
415
416wxLongLongWx wxLongLongWx::operator*(const wxLongLongWx& ll) const
417{
2a310492
VZ
418 wxLongLongWx res(*this);
419 res *= ll;
8b81872f 420
2a310492 421 return res;
8b81872f
VZ
422}
423
424wxLongLongWx& wxLongLongWx::operator*=(const wxLongLongWx& ll)
425{
426 wxLongLongWx t(m_hi, m_lo);
427 wxLongLongWx q(ll.m_hi, ll.m_lo);
8b81872f 428
2a310492
VZ
429 m_hi = m_lo = 0;
430
431#ifdef wxLONGLONG_TEST_MODE
432 wxLongLong_t llOld = m_ll;
433 m_ll = 0;
434#endif // wxLONGLONG_TEST_MODE
435
436 int counter = 0;
8b81872f
VZ
437 do
438 {
439 if ((q.m_lo & 1) != 0)
2a310492 440 *this += t;
8b81872f
VZ
441 q >>= 1;
442 t <<= 1;
443 counter++;
2a310492
VZ
444 }
445 while ((counter < 64) && ((q.m_hi != 0) || (q.m_lo != 0)));
446
447#ifdef wxLONGLONG_TEST_MODE
448 m_ll = llOld * ll.m_ll;
449
450 Check();
451#endif // wxLONGLONG_TEST_MODE
452
8b81872f
VZ
453 return *this;
454}
455
456// division
457
5e6a0e83 458void wxLongLongWx::Divide(const wxLongLongWx& divisorIn,
cd0b1709
VZ
459 wxLongLongWx& quotient,
460 wxLongLongWx& remainder) const
8b81872f 461{
5e6a0e83 462 if ((divisorIn.m_lo == 0) && (divisorIn.m_hi == 0))
8b81872f
VZ
463 {
464 // provoke division by zero error and silence the compilers warnings
465 // about an expression without effect and unused variable
5e6a0e83 466 long dummy = divisorIn.m_lo/divisorIn.m_hi;
8b81872f
VZ
467 dummy += 0;
468 }
469
2ea24d9f
VZ
470 // VZ: I'm writing this in a hurry and it's surely not the fastest way to
471 // do this - any improvements are more than welcome
5e6a0e83
VZ
472 //
473 // code inspired by the snippet at
474 // http://www.bearcave.com/software/divide.htm
475 //
476 // Copyright notice:
477 //
478 // Use of this program, for any purpose, is granted the author, Ian
479 // Kaplan, as long as this copyright notice is included in the source
480 // code or any source code derived from this program. The user assumes
481 // all responsibility for using this code.
482
483 // init everything
484 wxLongLongWx dividend = *this,
485 divisor = divisorIn;
486
487 quotient = 0l;
488 remainder = 0l;
489
5e6a0e83
VZ
490 // always do unsigned division and adjust the signs later: in C integer
491 // division, the sign of the remainder is the same as the sign of the
492 // dividend, while the sign of the quotient is the product of the signs of
493 // the dividend and divisor. Of course, we also always have
494 //
495 // dividend = quotient*divisor + remainder
496 //
497 // with 0 <= abs(remainder) < abs(divisor)
498 bool negRemainder = dividend.m_hi < 0;
499 bool negQuotient = FALSE; // assume positive
500 if ( dividend.m_hi < 0 )
501 {
502 negQuotient = !negQuotient;
503 dividend = -dividend;
504 }
505 if ( divisor.m_hi < 0 )
506 {
507 negQuotient = !negQuotient;
508 divisor = -divisor;
509 }
2ea24d9f 510
2a310492
VZ
511 // check for some particular cases
512 if ( divisor > dividend )
2ea24d9f 513 {
2a310492
VZ
514 remainder = dividend;
515 }
516 else if ( divisor == dividend )
517 {
518 quotient = 1l;
5e6a0e83 519 }
2a310492
VZ
520 else
521 {
522 // here: dividend > divisor and both are positibe: do unsigned division
523 size_t nBits = 64u;
524 wxLongLongWx d;
5e6a0e83 525
2a310492 526 #define IS_MSB_SET(ll) ((ll.m_hi) & (1 << (8*sizeof(long) - 1)))
2ea24d9f 527
2a310492 528 while ( remainder < divisor )
2ea24d9f 529 {
2a310492
VZ
530 remainder <<= 1;
531 if ( IS_MSB_SET(dividend) )
532 {
533 remainder |= 1;
534 }
535
536 d = dividend;
537 dividend <<= 1;
538
539 nBits--;
2ea24d9f
VZ
540 }
541
2a310492
VZ
542 // undo the last loop iteration
543 dividend = d;
544 remainder >>= 1;
545 nBits++;
5e6a0e83 546
2a310492
VZ
547 for ( size_t i = 0; i < nBits; i++ )
548 {
549 remainder <<= 1;
550 if ( IS_MSB_SET(dividend) )
551 {
552 remainder |= 1;
553 }
554
555 wxLongLongWx t = remainder - divisor;
556 dividend <<= 1;
557 quotient <<= 1;
558 if ( !IS_MSB_SET(t) )
559 {
560 quotient |= 1;
561
562 remainder = t;
563 }
5e6a0e83 564 }
2ea24d9f
VZ
565 }
566
5e6a0e83
VZ
567 // adjust signs
568 if ( negRemainder )
2ea24d9f 569 {
5e6a0e83 570 remainder = -remainder;
2ea24d9f
VZ
571 }
572
5e6a0e83
VZ
573 if ( negQuotient )
574 {
575 quotient = -quotient;
576 }
2ea24d9f
VZ
577}
578
579wxLongLongWx wxLongLongWx::operator/(const wxLongLongWx& ll) const
580{
581 wxLongLongWx quotient, remainder;
582
583 Divide(ll, quotient, remainder);
584
585 return quotient;
586}
587
588wxLongLongWx& wxLongLongWx::operator/=(const wxLongLongWx& ll)
589{
590 wxLongLongWx quotient, remainder;
591
592 Divide(ll, quotient, remainder);
593
55dfa8d3
RR
594 *this = quotient;
595
596 return *this;
8b81872f
VZ
597}
598
2ea24d9f
VZ
599wxLongLongWx wxLongLongWx::operator%(const wxLongLongWx& ll) const
600{
601 wxLongLongWx quotient, remainder;
602
603 Divide(ll, quotient, remainder);
604
605 return remainder;
606}
607
608// ----------------------------------------------------------------------------
609// misc
610// ----------------------------------------------------------------------------
611
8b81872f
VZ
612// temporary - just for testing
613void *wxLongLongWx::asArray(void) const
614{
615 static unsigned char temp[8];
616
13111b2a
VZ
617 temp[0] = (char)((m_hi >> 24) & 0xFF);
618 temp[1] = (char)((m_hi >> 16) & 0xFF);
619 temp[2] = (char)((m_hi >> 8) & 0xFF);
620 temp[3] = (char)((m_hi >> 0) & 0xFF);
621 temp[4] = (char)((m_lo >> 24) & 0xFF);
622 temp[5] = (char)((m_lo >> 16) & 0xFF);
623 temp[6] = (char)((m_lo >> 8) & 0xFF);
624 temp[7] = (char)((m_lo >> 0) & 0xFF);
8b81872f
VZ
625
626 return temp;
627}
628
fcc3d7cb 629#if wxUSE_STD_IOSTREAM
8b81872f 630
fcc3d7cb 631// input/output
dd107c50 632wxSTD ostream& operator<< (wxSTD ostream& o, const wxLongLongWx& ll)
8b81872f
VZ
633{
634 char result[65];
635
636 memset(result, 'A', 64);
637
638 result[64] = '\0';
639
640 for (int i = 0; i < 32; i++)
641 {
642 result[31 - i] = (char) ('0' + (int) ((ll.m_hi >> i) & 1));
643 result[63 - i] = (char) ('0' + (int) ((ll.m_lo >> i) & 1));
644 }
645
646 return o << result;
647}
fcc3d7cb
VZ
648#endif // wxUSE_STD_IOSTREAM
649
650#endif // wxUSE_LONGLONG_NATIVE
8b81872f 651
4e57b0d4 652#endif // wxUSE_LONGLONG