annotate runtime/internal/adi.d @ 855:e78e1d559a76

Apply fix for #151.
author Christian Kamm <kamm incasoftware de>
date Mon, 15 Dec 2008 21:09:33 +0100
parents a26b0c5d5942
children
rev   line source
tomas@443 1 //_ adi.d
tomas@443 2
tomas@443 3 /**
tomas@443 4 * Part of the D programming language runtime library.
tomas@443 5 * Dynamic array property support routines
tomas@443 6 */
tomas@443 7
tomas@443 8 /*
tomas@443 9 * Copyright (C) 2000-2006 by Digital Mars, www.digitalmars.com
tomas@443 10 * Written by Walter Bright
tomas@443 11 *
tomas@443 12 * This software is provided 'as-is', without any express or implied
tomas@443 13 * warranty. In no event will the authors be held liable for any damages
tomas@443 14 * arising from the use of this software.
tomas@443 15 *
tomas@443 16 * Permission is granted to anyone to use this software for any purpose,
tomas@443 17 * including commercial applications, and to alter it and redistribute it
tomas@443 18 * freely, in both source and binary form, subject to the following
tomas@443 19 * restrictions:
tomas@443 20 *
tomas@443 21 * o The origin of this software must not be misrepresented; you must not
tomas@443 22 * claim that you wrote the original software. If you use this software
tomas@443 23 * in a product, an acknowledgment in the product documentation would be
tomas@443 24 * appreciated but is not required.
tomas@443 25 * o Altered source versions must be plainly marked as such, and must not
tomas@443 26 * be misrepresented as being the original software.
tomas@443 27 * o This notice may not be removed or altered from any source
tomas@443 28 * distribution.
tomas@443 29 */
tomas@443 30
tomas@443 31 /*
tomas@443 32 * Modified by Sean Kelly <sean@f4.ca> for use with Tango.
tomas@443 33 */
tomas@443 34
tomas@443 35
tomas@443 36 //debug=adi; // uncomment to turn on debugging printf's
tomas@443 37
tomas@443 38 private
tomas@443 39 {
tomas@443 40 import tango.stdc.string;
tomas@443 41 import tango.stdc.stdlib;
tomas@443 42 import util.utf;
tomas@443 43
tomas@443 44 enum BlkAttr : uint
tomas@443 45 {
tomas@443 46 FINALIZE = 0b0000_0001,
tomas@443 47 NO_SCAN = 0b0000_0010,
tomas@443 48 NO_MOVE = 0b0000_0100,
tomas@443 49 ALL_BITS = 0b1111_1111
tomas@443 50 }
tomas@443 51
tomas@443 52 extern (C) void* gc_malloc( size_t sz, uint ba = 0 );
tomas@443 53 extern (C) void* gc_calloc( size_t sz, uint ba = 0 );
tomas@443 54 extern (C) void gc_free( void* p );
tomas@443 55 }
tomas@443 56
tomas@443 57
tomas@443 58 /**********************************************
tomas@443 59 * Reverse array of chars.
tomas@443 60 * Handled separately because embedded multibyte encodings should not be
tomas@443 61 * reversed.
tomas@443 62 */
tomas@443 63
tomas@486 64 extern (C) char[] _adReverseChar(char[] a)
tomas@443 65 {
kamm@855 66 bool hadErrors = false;
tomas@443 67 if (a.length > 1)
tomas@443 68 {
tomas@443 69 char[6] tmp;
tomas@443 70 char[6] tmplo;
tomas@443 71 char* lo = a.ptr;
tomas@443 72 char* hi = &a[length - 1];
tomas@443 73
tomas@443 74 while (lo < hi)
tomas@443 75 { auto clo = *lo;
tomas@443 76 auto chi = *hi;
tomas@443 77
tomas@443 78 debug(adi) printf("lo = %d, hi = %d\n", lo, hi);
tomas@443 79 if (clo <= 0x7F && chi <= 0x7F)
tomas@443 80 {
tomas@443 81 debug(adi) printf("\tascii\n");
tomas@443 82 *lo = chi;
tomas@443 83 *hi = clo;
tomas@443 84 lo++;
tomas@443 85 hi--;
tomas@443 86 continue;
tomas@443 87 }
tomas@443 88
tomas@443 89 uint stridelo = UTF8stride[clo];
kamm@855 90 if (stridelo > 6) { // invalid UTF-8 0xFF
kamm@855 91 stridelo = 1;
kamm@855 92 hadErrors=true;
kamm@855 93 }
tomas@443 94
tomas@443 95 uint stridehi = 1;
kamm@855 96 while ((chi & 0xC0) == 0x80 && hi >= lo)
tomas@443 97 {
tomas@443 98 chi = *--hi;
tomas@443 99 stridehi++;
tomas@443 100 }
kamm@855 101 if (lo >= hi) {
kamm@855 102 if (lo > hi) {
kamm@855 103 hadErrors = true;
kamm@855 104 }
tomas@443 105 break;
kamm@855 106 }
kamm@855 107 if (stridehi > 6) {
kamm@855 108 hadErrors = true;
kamm@855 109 stridehi = 6;
kamm@855 110 }
tomas@443 111
tomas@443 112 debug(adi) printf("\tstridelo = %d, stridehi = %d\n", stridelo, stridehi);
tomas@443 113 if (stridelo == stridehi)
tomas@443 114 {
tomas@443 115 memcpy(tmp.ptr, lo, stridelo);
tomas@443 116 memcpy(lo, hi, stridelo);
tomas@443 117 memcpy(hi, tmp.ptr, stridelo);
tomas@443 118 lo += stridelo;
tomas@443 119 hi--;
tomas@443 120 continue;
tomas@443 121 }
tomas@443 122
tomas@443 123 /* Shift the whole array. This is woefully inefficient
tomas@443 124 */
tomas@443 125 memcpy(tmp.ptr, hi, stridehi);
tomas@443 126 memcpy(tmplo.ptr, lo, stridelo);
tomas@443 127 memmove(lo + stridehi, lo + stridelo , cast(size_t)(hi - lo) - stridelo);
tomas@443 128 memcpy(lo, tmp.ptr, stridehi);
tomas@443 129 memcpy(hi + stridehi - stridelo, tmplo.ptr, stridelo);
tomas@443 130
tomas@443 131 lo += stridehi;
tomas@443 132 hi = hi - 1 + (stridehi - stridelo);
tomas@443 133 }
tomas@443 134 }
kamm@855 135 if (hadErrors)
kamm@855 136 throw new Exception("invalid UTF-8 sequence",__FILE__,__LINE__);
tomas@486 137 return a;
tomas@443 138 }
tomas@443 139
tomas@443 140 unittest
tomas@443 141 {
tomas@486 142 char[] a = "abcd"c;
tomas@443 143
tomas@486 144 char[] r = a.dup.reverse;
tomas@443 145 //writefln(r);
tomas@443 146 assert(r == "dcba");
tomas@443 147
tomas@443 148 a = "a\u1235\u1234c";
tomas@443 149 //writefln(a);
tomas@443 150 r = a.dup.reverse;
tomas@443 151 //writefln(r);
tomas@443 152 assert(r == "c\u1234\u1235a");
tomas@443 153
tomas@443 154 a = "ab\u1234c";
tomas@443 155 //writefln(a);
tomas@443 156 r = a.dup.reverse;
tomas@443 157 //writefln(r);
tomas@443 158 assert(r == "c\u1234ba");
tomas@443 159
tomas@443 160 a = "\u3026\u2021\u3061\n";
tomas@443 161 r = a.dup.reverse;
tomas@443 162 assert(r == "\n\u3061\u2021\u3026");
tomas@443 163 }
tomas@443 164
tomas@443 165
tomas@443 166 /**********************************************
tomas@443 167 * Reverse array of wchars.
tomas@443 168 * Handled separately because embedded multiword encodings should not be
tomas@443 169 * reversed.
tomas@443 170 */
tomas@443 171
tomas@486 172 extern (C) wchar[] _adReverseWchar(wchar[] a)
tomas@443 173 {
kamm@855 174 bool hadErrors = false;
tomas@443 175 if (a.length > 1)
tomas@443 176 {
tomas@443 177 wchar[2] tmp;
tomas@443 178 wchar* lo = a.ptr;
tomas@443 179 wchar* hi = &a[length - 1];
tomas@443 180
tomas@443 181 while (lo < hi)
tomas@443 182 { auto clo = *lo;
tomas@443 183 auto chi = *hi;
tomas@443 184
tomas@443 185 if ((clo < 0xD800 || clo > 0xDFFF) &&
tomas@443 186 (chi < 0xD800 || chi > 0xDFFF))
tomas@443 187 {
tomas@443 188 *lo = chi;
tomas@443 189 *hi = clo;
tomas@443 190 lo++;
tomas@443 191 hi--;
tomas@443 192 continue;
tomas@443 193 }
tomas@443 194
tomas@443 195 int stridelo = 1 + (clo >= 0xD800 && clo <= 0xDBFF);
tomas@443 196
tomas@443 197 int stridehi = 1;
tomas@443 198 if (chi >= 0xDC00 && chi <= 0xDFFF)
tomas@443 199 {
tomas@443 200 chi = *--hi;
tomas@443 201 stridehi++;
tomas@443 202 }
kamm@855 203 if (lo >= hi) {
kamm@855 204 if (lo > hi) {
kamm@855 205 hadErrors = true;
kamm@855 206 }
tomas@443 207 break;
kamm@855 208 }
tomas@443 209
tomas@443 210 if (stridelo == stridehi)
tomas@443 211 { int stmp;
tomas@443 212
tomas@443 213 assert(stridelo == 2);
tomas@443 214 assert(stmp.sizeof == 2 * (*lo).sizeof);
tomas@443 215 stmp = *cast(int*)lo;
tomas@443 216 *cast(int*)lo = *cast(int*)hi;
tomas@443 217 *cast(int*)hi = stmp;
tomas@443 218 lo += stridelo;
tomas@443 219 hi--;
tomas@443 220 continue;
tomas@443 221 }
tomas@443 222
tomas@443 223 /* Shift the whole array. This is woefully inefficient
tomas@443 224 */
tomas@443 225 memcpy(tmp.ptr, hi, stridehi * wchar.sizeof);
tomas@443 226 memcpy(hi + stridehi - stridelo, lo, stridelo * wchar.sizeof);
tomas@443 227 memmove(lo + stridehi, lo + stridelo , (hi - (lo + stridelo)) * wchar.sizeof);
tomas@443 228 memcpy(lo, tmp.ptr, stridehi * wchar.sizeof);
tomas@443 229
tomas@443 230 lo += stridehi;
tomas@443 231 hi = hi - 1 + (stridehi - stridelo);
tomas@443 232 }
tomas@443 233 }
kamm@855 234 if (hadErrors)
kamm@855 235 throw new Exception("invalid UTF-8 sequence",__FILE__,__LINE__);
tomas@486 236 return a;
tomas@443 237 }
tomas@443 238
tomas@443 239 unittest
tomas@443 240 {
tomas@486 241 wchar[] a = "abcd";
tomas@486 242 wchar[] r;
tomas@443 243
tomas@443 244 r = a.dup.reverse;
tomas@443 245 assert(r == "dcba");
tomas@443 246
tomas@443 247 a = "a\U00012356\U00012346c";
tomas@443 248 r = a.dup.reverse;
tomas@443 249 assert(r == "c\U00012346\U00012356a");
tomas@443 250
tomas@443 251 a = "ab\U00012345c";
tomas@443 252 r = a.dup.reverse;
tomas@443 253 assert(r == "c\U00012345ba");
tomas@443 254 }
tomas@443 255
tomas@443 256
tomas@443 257 /**********************************************
tomas@443 258 * Support for array.reverse property.
tomas@717 259 * The actual type is painted on the return value by the frontend
tomas@717 260 * Given and returned length are number of elements
tomas@443 261 */
tomas@443 262
tomas@715 263 extern (C) void[] _adReverse(void[] a, size_t szelem)
tomas@443 264 out (result)
tomas@443 265 {
tomas@443 266 assert(result.ptr is a.ptr);
tomas@443 267 }
tomas@443 268 body
tomas@443 269 {
tomas@443 270 if (a.length >= 2)
tomas@443 271 {
tomas@443 272 byte* tmp;
tomas@443 273 byte[16] buffer;
tomas@443 274
tomas@443 275 void* lo = a.ptr;
tomas@443 276 void* hi = a.ptr + (a.length - 1) * szelem;
tomas@443 277
tomas@443 278 tmp = buffer.ptr;
tomas@443 279 if (szelem > 16)
tomas@443 280 {
tomas@443 281 //version (Win32)
tomas@443 282 //tmp = cast(byte*) alloca(szelem);
tomas@443 283 //else
tomas@443 284 tmp = cast(byte*) gc_malloc(szelem);
tomas@443 285 }
tomas@443 286
tomas@443 287 for (; lo < hi; lo += szelem, hi -= szelem)
tomas@443 288 {
tomas@443 289 memcpy(tmp, lo, szelem);
tomas@443 290 memcpy(lo, hi, szelem);
tomas@443 291 memcpy(hi, tmp, szelem);
tomas@443 292 }
tomas@443 293
tomas@443 294 version (Win32)
tomas@443 295 {
tomas@443 296 }
tomas@443 297 else
tomas@443 298 {
tomas@443 299 //if (szelem > 16)
tomas@443 300 // BUG: bad code is generate for delete pointer, tries
tomas@443 301 // to call delclass.
tomas@443 302 //gc_free(tmp);
tomas@443 303 }
tomas@443 304 }
tomas@715 305 return a.ptr[0 .. a.length];
tomas@443 306 }
tomas@443 307
tomas@443 308 unittest
tomas@443 309 {
tomas@443 310 debug(adi) printf("array.reverse.unittest\n");
tomas@443 311
tomas@443 312 int[] a = new int[5];
tomas@443 313 int[] b;
tomas@443 314 size_t i;
tomas@443 315
tomas@443 316 for (i = 0; i < 5; i++)
tomas@443 317 a[i] = i;
tomas@443 318 b = a.reverse;
tomas@443 319 assert(b is a);
tomas@443 320 for (i = 0; i < 5; i++)
tomas@443 321 assert(a[i] == 4 - i);
tomas@443 322
tomas@443 323 struct X20
tomas@443 324 { // More than 16 bytes in size
tomas@443 325 int a;
tomas@443 326 int b, c, d, e;
tomas@443 327 }
tomas@443 328
tomas@443 329 X20[] c = new X20[5];
tomas@443 330 X20[] d;
tomas@443 331
tomas@443 332 for (i = 0; i < 5; i++)
tomas@443 333 { c[i].a = i;
tomas@443 334 c[i].e = 10;
tomas@443 335 }
tomas@443 336 d = c.reverse;
tomas@443 337 assert(d is c);
tomas@443 338 for (i = 0; i < 5; i++)
tomas@443 339 {
tomas@443 340 assert(c[i].a == 4 - i);
tomas@443 341 assert(c[i].e == 10);
tomas@443 342 }
tomas@443 343 }
tomas@443 344
tomas@443 345 /**********************************************
tomas@443 346 * Sort array of chars.
tomas@443 347 */
tomas@443 348
tomas@486 349 extern (C) char[] _adSortChar(char[] a)
tomas@443 350 {
tomas@443 351 if (a.length > 1)
tomas@443 352 {
tomas@443 353 dchar[] da = toUTF32(a);
tomas@443 354 da.sort;
tomas@443 355 size_t i = 0;
tomas@443 356 foreach (dchar d; da)
tomas@443 357 { char[4] buf;
tomas@443 358 auto t = toUTF8(buf, d);
tomas@443 359 a[i .. i + t.length] = t[];
tomas@443 360 i += t.length;
tomas@443 361 }
tomas@443 362 delete da;
tomas@443 363 }
tomas@486 364 return a;
tomas@443 365 }
tomas@443 366
tomas@443 367 /**********************************************
tomas@443 368 * Sort array of wchars.
tomas@443 369 */
tomas@443 370
tomas@486 371 extern (C) wchar[] _adSortWchar(wchar[] a)
tomas@443 372 {
tomas@443 373 if (a.length > 1)
tomas@443 374 {
tomas@443 375 dchar[] da = toUTF32(a);
tomas@443 376 da.sort;
tomas@443 377 size_t i = 0;
tomas@443 378 foreach (dchar d; da)
tomas@443 379 { wchar[2] buf;
tomas@443 380 auto t = toUTF16(buf, d);
tomas@443 381 a[i .. i + t.length] = t[];
tomas@443 382 i += t.length;
tomas@443 383 }
tomas@443 384 delete da;
tomas@443 385 }
tomas@486 386 return a;
tomas@443 387 }
tomas@443 388
tomas@443 389 /***************************************
tomas@443 390 * Support for array equality test.
tomas@717 391 * The actual type is painted on the return value by the frontend
tomas@717 392 * Given lengths are number of elements
tomas@443 393 */
tomas@443 394
tomas@715 395 extern (C) int _adEq(void[] a1, void[] a2, TypeInfo ti)
tomas@443 396 {
tomas@443 397 debug(adi) printf("_adEq(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
tomas@443 398
tomas@443 399 if (a1.length != a2.length)
tomas@443 400 return 0; // not equal
tomas@443 401 else if (a1.ptr == a2.ptr)
tomas@443 402 return 1; // equal
tomas@443 403
tomas@443 404 // let typeinfo decide
tomas@443 405 return ti.equals(&a1, &a2);
tomas@443 406 }
tomas@443 407
tomas@443 408 unittest
tomas@443 409 {
tomas@443 410 debug(adi) printf("array.Eq unittest\n");
tomas@443 411
tomas@486 412 char[] a = "hello"c;
tomas@443 413
tomas@443 414 assert(a != "hel");
tomas@443 415 assert(a != "helloo");
tomas@443 416 assert(a != "betty");
tomas@443 417 assert(a == "hello");
tomas@443 418 assert(a != "hxxxx");
tomas@443 419 }
tomas@443 420
tomas@443 421 /***************************************
tomas@443 422 * Support for array compare test.
tomas@717 423 * The actual type is painted on the return value by the frontend
tomas@717 424 * Given lengths are number of elements
tomas@443 425 */
tomas@443 426
tomas@715 427 extern (C) int _adCmp(void[] a1, void[] a2, TypeInfo ti)
tomas@443 428 {
tomas@443 429 debug(adi) printf("adCmp()\n");
tomas@443 430
tomas@443 431 if (a1.ptr == a2.ptr &&
tomas@443 432 a1.length == a2.length)
tomas@443 433 return 0;
tomas@443 434
tomas@443 435 auto len = a1.length;
tomas@443 436 if (a2.length < len)
tomas@443 437 len = a2.length;
tomas@443 438
tomas@443 439 // let typeinfo decide
tomas@443 440 return ti.compare(&a1, &a2);
tomas@443 441 }
tomas@443 442
tomas@443 443 unittest
tomas@443 444 {
tomas@443 445 debug(adi) printf("array.Cmp unittest\n");
tomas@443 446
tomas@486 447 char[] a = "hello"c;
tomas@443 448
tomas@443 449 assert(a > "hel");
tomas@443 450 assert(a >= "hel");
tomas@443 451 assert(a < "helloo");
tomas@443 452 assert(a <= "helloo");
tomas@443 453 assert(a > "betty");
tomas@443 454 assert(a >= "betty");
tomas@443 455 assert(a == "hello");
tomas@443 456 assert(a <= "hello");
tomas@443 457 assert(a >= "hello");
tomas@443 458 }
tomas@443 459
tomas@443 460 /***************************************
tomas@443 461 * Support for array compare test.
tomas@717 462 * The actual type is painted on the return value by the frontend
tomas@717 463 * Given lengths are number of elements
tomas@443 464 */
tomas@443 465
tomas@715 466 extern (C) int _adCmpChar(void[] a1, void[] a2)
tomas@443 467 {
tomas@443 468 version(D_InlineAsm_X86)
tomas@443 469 {
tomas@443 470 //version = Asm86;
tomas@443 471 }
tomas@443 472 version (Asm86)
tomas@443 473 {
tomas@443 474 asm
tomas@443 475 { naked ;
tomas@443 476
tomas@443 477 push EDI ;
tomas@443 478 push ESI ;
tomas@443 479
tomas@443 480 mov ESI,a1+4[4+ESP] ;
tomas@443 481 mov EDI,a2+4[4+ESP] ;
tomas@443 482
tomas@443 483 mov ECX,a1[4+ESP] ;
tomas@443 484 mov EDX,a2[4+ESP] ;
tomas@443 485
tomas@443 486 cmp ECX,EDX ;
tomas@443 487 jb GotLength ;
tomas@443 488
tomas@443 489 mov ECX,EDX ;
tomas@443 490
tomas@443 491 GotLength:
tomas@443 492 cmp ECX,4 ;
tomas@443 493 jb DoBytes ;
tomas@443 494
tomas@443 495 // Do alignment if neither is dword aligned
tomas@443 496 test ESI,3 ;
tomas@443 497 jz Aligned ;
tomas@443 498
tomas@443 499 test EDI,3 ;
tomas@443 500 jz Aligned ;
tomas@443 501 DoAlign:
tomas@443 502 mov AL,[ESI] ; //align ESI to dword bounds
tomas@443 503 mov DL,[EDI] ;
tomas@443 504
tomas@443 505 cmp AL,DL ;
tomas@443 506 jnz Unequal ;
tomas@443 507
tomas@443 508 inc ESI ;
tomas@443 509 inc EDI ;
tomas@443 510
tomas@443 511 test ESI,3 ;
tomas@443 512
tomas@443 513 lea ECX,[ECX-1] ;
tomas@443 514 jnz DoAlign ;
tomas@443 515 Aligned:
tomas@443 516 mov EAX,ECX ;
tomas@443 517
tomas@443 518 // do multiple of 4 bytes at a time
tomas@443 519
tomas@443 520 shr ECX,2 ;
tomas@443 521 jz TryOdd ;
tomas@443 522
tomas@443 523 repe ;
tomas@443 524 cmpsd ;
tomas@443 525
tomas@443 526 jnz UnequalQuad ;
tomas@443 527
tomas@443 528 TryOdd:
tomas@443 529 mov ECX,EAX ;
tomas@443 530 DoBytes:
tomas@443 531 // if still equal and not end of string, do up to 3 bytes slightly
tomas@443 532 // slower.
tomas@443 533
tomas@443 534 and ECX,3 ;
tomas@443 535 jz Equal ;
tomas@443 536
tomas@443 537 repe ;
tomas@443 538 cmpsb ;
tomas@443 539
tomas@443 540 jnz Unequal ;
tomas@443 541 Equal:
tomas@443 542 mov EAX,a1[4+ESP] ;
tomas@443 543 mov EDX,a2[4+ESP] ;
tomas@443 544
tomas@443 545 sub EAX,EDX ;
tomas@443 546 pop ESI ;
tomas@443 547
tomas@443 548 pop EDI ;
tomas@443 549 ret ;
tomas@443 550
tomas@443 551 UnequalQuad:
tomas@443 552 mov EDX,[EDI-4] ;
tomas@443 553 mov EAX,[ESI-4] ;
tomas@443 554
tomas@443 555 cmp AL,DL ;
tomas@443 556 jnz Unequal ;
tomas@443 557
tomas@443 558 cmp AH,DH ;
tomas@443 559 jnz Unequal ;
tomas@443 560
tomas@443 561 shr EAX,16 ;
tomas@443 562
tomas@443 563 shr EDX,16 ;
tomas@443 564
tomas@443 565 cmp AL,DL ;
tomas@443 566 jnz Unequal ;
tomas@443 567
tomas@443 568 cmp AH,DH ;
tomas@443 569 Unequal:
tomas@443 570 sbb EAX,EAX ;
tomas@443 571 pop ESI ;
tomas@443 572
tomas@443 573 or EAX,1 ;
tomas@443 574 pop EDI ;
tomas@443 575
tomas@443 576 ret ;
tomas@443 577 }
tomas@443 578 }
tomas@443 579 else
tomas@443 580 {
tomas@443 581 int len;
tomas@443 582 int c;
tomas@443 583
tomas@443 584 debug(adi) printf("adCmpChar()\n");
tomas@443 585 len = cast(int)a1.length;
tomas@443 586 if (a2.length < len)
tomas@443 587 len = cast(int)a2.length;
tomas@443 588 c = memcmp(cast(char *)a1.ptr, cast(char *)a2.ptr, len);
tomas@443 589 if (!c)
tomas@443 590 c = cast(int)a1.length - cast(int)a2.length;
tomas@443 591 return c;
tomas@443 592 }
tomas@443 593 }
tomas@443 594
tomas@443 595 unittest
tomas@443 596 {
tomas@443 597 debug(adi) printf("array.CmpChar unittest\n");
tomas@443 598
tomas@486 599 char[] a = "hello"c;
tomas@443 600
tomas@443 601 assert(a > "hel");
tomas@443 602 assert(a >= "hel");
tomas@443 603 assert(a < "helloo");
tomas@443 604 assert(a <= "helloo");
tomas@443 605 assert(a > "betty");
tomas@443 606 assert(a >= "betty");
tomas@443 607 assert(a == "hello");
tomas@443 608 assert(a <= "hello");
tomas@443 609 assert(a >= "hello");
tomas@443 610 }