Note: This website is archived. For up-to-date information about D projects and development, please visit wiki.dlang.org.

Changeset 1716

Show
Ignore:
Timestamp:
07/04/10 21:16:47 (14 years ago)
Author:
andrei
Message:

Scheduled for deprecation in favor of std.exception

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/phobos/std/contracts.d

    r1707 r1716  
    11// Written in the D programming language. 
    22 
    33/** 
    4  * This module defines tools for effecting contracts and enforcing 
    5  * predicates (a la $(D_PARAM assert)). 
    6  * 
    7  * Macros: 
    8  *      WIKI = Phobos/StdContracts 
    9  * 
    10  * Synopsis: 
    11  * 
    12  * ---- 
    13  * string synopsis() 
    14  * { 
    15  *     FILE* f = enforce(fopen("some/file")); 
    16  *     // f is not null from here on 
    17  *     FILE* g = enforceEx!(WriteException)(fopen("some/other/file", "w")); 
    18  *     // g is not null from here on 
    19  *     Exception e = collectException(write(g, readln(f))); 
    20  *     if (e) 
    21  *     { 
    22  *         ... an exception occurred... 
    23  *     } 
    24  *     char[] line; 
    25  *     enforce(readln(f, line)); 
    26  *     return assumeUnique(line); 
    27  * } 
    28  * ---- 
    29  * 
    30  * Copyright: Copyright Andrei Alexandrescu 2008 - 2009. 
    31  * License:   <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>. 
    32  * Authors:   $(WEB erdani.org, Andrei Alexandrescu) 
    33  * Credits:   Brad Roberts came up with the name $(D_PARAM contracts). 
    34  * 
    35  *          Copyright Andrei Alexandrescu 2008 - 2009. 
    36  * Distributed under the Boost Software License, Version 1.0. 
    37  *    (See accompanying file LICENSE_1_0.txt or copy at 
    38  *          http://www.boost.org/LICENSE_1_0.txt) 
     4   This module has been scheduled for deprecation. Use $(D 
     5   std.exception) instead. 
    396 */ 
    407module std.contracts; 
    418 
    42 import std.array, std.c.string, std.conv, std.range, std.string, std.traits; 
    43 import core.stdc.errno; 
    44 version(unittest) 
    45 
    46     import std.stdio; 
    47 
     9pragma(msg, "std.contracts has been scheduled for deprecation." 
     10        " Please use std.exception instead."); 
    4811 
    49 /* 
    50  *  Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com 
    51  *  Written by Andrei Alexandrescu, www.erdani.org 
    52  * 
    53  *  This software is provided 'as-is', without any express or implied 
    54  *  warranty. In no event will the authors be held liable for any damages 
    55  *  arising from the use of this software. 
    56  * 
    57  *  Permission is granted to anyone to use this software for any purpose, 
    58  *  including commercial applications, and to alter it and redistribute it 
    59  *  freely, subject to the following restrictions: 
    60  * 
    61  *  o  The origin of this software must not be misrepresented; you must not 
    62  *     claim that you wrote the original software. If you use this software 
    63  *     in a product, an acknowledgment in the product documentation would be 
    64  *     appreciated but is not required. 
    65  *  o  Altered source versions must be plainly marked as such, and must not 
    66  *     be misrepresented as being the original software. 
    67  *  o  This notice may not be removed or altered from any source 
    68  *     distribution. 
    69  */ 
    70  
    71 /** 
    72  * If $(D_PARAM value) is nonzero, returns it. Otherwise, throws 
    73  * $(D_PARAM new Exception(msg)). 
    74  * Example: 
    75  * ---- 
    76  * auto f = enforce(fopen("data.txt")); 
    77  * auto line = readln(f); 
    78  * enforce(line.length); // expect a non-empty line 
    79  * ---- 
    80  */ 
    81  
    82 T enforce(T, string file = __FILE__, int line = __LINE__) 
    83     (T value, lazy const(char)[] msg = null) 
    84 
    85     if (!value) bailOut(file, line, msg); 
    86     return value; 
    87 
    88  
    89 T enforce(T, string file = __FILE__, int line = __LINE__) 
    90 (T value, scope void delegate() dg) 
    91 
    92     if (!value) dg(); 
    93     return value; 
    94 
    95  
    96 private void bailOut(string file, int line, in char[] msg) 
    97 
    98     throw new Exception(msg ? msg.idup : "Enforcement failed", file, line); 
    99 
    100  
    101 unittest 
    102 
    103     assert (enforce(123) == 123); 
    104  
    105     try 
    106     { 
    107         enforce(false, "error"); 
    108         assert (false); 
    109     } 
    110     catch (Exception e) 
    111     { 
    112         assert (e.msg == "error"); 
    113         assert (e.file == __FILE__); 
    114         assert (e.line == __LINE__-7); 
    115     } 
    116 
    117  
    118 /** 
    119  * If $(D_PARAM value) is nonzero, returns it. Otherwise, throws 
    120  * $(D_PARAM ex). 
    121  * Example: 
    122  * ---- 
    123  * auto f = enforce(fopen("data.txt")); 
    124  * auto line = readln(f); 
    125  * enforce(line.length, new IOException); // expect a non-empty line 
    126  * ---- 
    127  */ 
    128  
    129 T enforce(T)(T value, lazy Exception ex) 
    130 
    131     if (!value) throw ex(); 
    132     return value; 
    133 
    134  
    135 unittest 
    136 
    137     enforce(true, new Exception("this should not be thrown")); 
    138     try 
    139     { 
    140         enforce(false, new Exception("this should be thrown")); 
    141         assert(false); 
    142     } 
    143     catch (Exception e) 
    144     { 
    145     } 
    146 
    147  
    148 /** 
    149 If $(D value) is nonzero, returns it. Otherwise, throws $(D new 
    150 ErrnoException(msg)). The $(D ErrnoException) class assumes that the 
    151 last operation has set $(D errno) to an error code. 
    152  * 
    153  * Example: 
    154  * 
    155  * ---- 
    156  * auto f = errnoEnforce(fopen("data.txt")); 
    157  * auto line = readln(f); 
    158  * enforce(line.length); // expect a non-empty line 
    159  * ---- 
    160  */ 
    161  
    162 T errnoEnforce(T, string file = __FILE__, int line = __LINE__) 
    163     (T value, lazy string msg = null) 
    164 
    165     if (!value) throw new ErrnoException(msg, file, line); 
    166     return value; 
    167 
    168  
    169 /** 
    170  * If $(D_PARAM value) is nonzero, returns it. Otherwise, throws 
    171  * $(D_PARAM new E(msg)). 
    172  * Example: 
    173  * ---- 
    174  * auto f = enforceEx!(FileMissingException)(fopen("data.txt")); 
    175  * auto line = readln(f); 
    176  * enforceEx!(DataCorruptionException)(line.length); 
    177  * ---- 
    178  */ 
    179  
    180 template enforceEx(E) 
    181 
    182     T enforceEx(T)(T value, lazy string msg = "") 
    183     { 
    184         if (!value) throw new E(msg); 
    185         return value; 
    186     } 
    187 
    188  
    189 unittest 
    190 
    191     enforce(true); 
    192     enforce(true, "blah"); 
    193     typedef Exception MyException; 
    194     try 
    195     { 
    196         enforceEx!(MyException)(false); 
    197         assert(false); 
    198     } 
    199     catch (MyException e) 
    200     { 
    201     } 
    202 
    203  
    204 /** 
    205  * Evaluates $(D_PARAM expression). If evaluation throws an exception, 
    206  * return that exception. Otherwise, deposit the resulting value in 
    207  * $(D_PARAM target) and return $(D_PARAM null). 
    208  * Example: 
    209  * ---- 
    210  * int[] a = new int[3]; 
    211  * int b; 
    212  * assert(collectException(a[4], b)); 
    213  * ---- 
    214  */ 
    215  
    216 Exception collectException(T)(lazy T expression, ref T target) 
    217 
    218     try 
    219     { 
    220         target = expression(); 
    221     } 
    222     catch (Exception e) 
    223     { 
    224         return e; 
    225     } 
    226     return null; 
    227 
    228  
    229 unittest 
    230 
    231     int[] a = new int[3]; 
    232     int b; 
    233     int foo() { throw new Exception("blah"); } 
    234     assert(collectException(foo(), b)); 
    235 
    236  
    237 /** Evaluates $(D_PARAM expression). If evaluation throws an 
    238  * exception, return that exception. Otherwise, return $(D_PARAM 
    239  * null). $(D_PARAM T) can be $(D_PARAM void). 
    240  */ 
    241  
    242 Exception collectException(T)(lazy T expression) 
    243 
    244     try 
    245     { 
    246         expression(); 
    247     } 
    248     catch (Exception e) 
    249     { 
    250         return e; 
    251     } 
    252     return null; 
    253 
    254  
    255 unittest 
    256 
    257     int foo() { throw new Exception("blah"); } 
    258     assert(collectException(foo())); 
    259 
    260  
    261 /** 
    262  * Casts a mutable array to an immutable array in an idiomatic 
    263  * manner. Technically, $(D_PARAM assumeUnique) just inserts a cast, 
    264  * but its name documents assumptions on the part of the 
    265  * caller. $(D_PARAM assumeUnique(arr)) should only be called when 
    266  * there are no more active mutable aliases to elements of $(D_PARAM 
    267  * arr). To strenghten this assumption, $(D_PARAM assumeUnique(arr)) 
    268  * also clears $(D_PARAM arr) before returning. Essentially $(D_PARAM 
    269  * assumeUnique(arr)) indicates commitment from the caller that there 
    270  * is no more mutable access to any of $(D_PARAM arr)'s elements 
    271  * (transitively), and that all future accesses will be done through 
    272  * the immutable array returned by $(D_PARAM assumeUnique). 
    273  * 
    274  * Typically, $(D_PARAM assumeUnique) is used to return arrays from 
    275  * functions that have allocated and built them. 
    276  * 
    277  * Example: 
    278  * 
    279  * ---- 
    280  * string letters() 
    281  * { 
    282  *   char[] result = new char['z' - 'a' + 1]; 
    283  *   foreach (i, ref e; result) 
    284  *   { 
    285  *     e = 'a' + i; 
    286  *   } 
    287  *   return assumeUnique(result); 
    288  * } 
    289  * ---- 
    290  * 
    291  * The use in the example above is correct because $(D_PARAM result) 
    292  * was private to $(D_PARAM letters) and is unaccessible in writing 
    293  * after the function returns. The following example shows an 
    294  * incorrect use of $(D_PARAM assumeUnique). 
    295  * 
    296  * Bad: 
    297  * 
    298  * ---- 
    299  * private char[] buffer; 
    300  * string letters(char first, char last) 
    301  * { 
    302  *   if (first >= last) return null; // fine 
    303  *   auto sneaky = buffer; 
    304  *   sneaky.length = last - first + 1; 
    305  *   foreach (i, ref e; sneaky) 
    306  *   { 
    307  *     e = 'a' + i; 
    308  *   } 
    309  *   return assumeUnique(sneaky); // BAD 
    310  * } 
    311  * ---- 
    312  * 
    313  * The example above wreaks havoc on client code because it is 
    314  * modifying arrays that callers considered immutable. To obtain an 
    315  * immutable array from the writable array $(D_PARAM buffer), replace 
    316  * the last line with: 
    317  * ---- 
    318  * return to!(string)(sneaky); // not that sneaky anymore 
    319  * ---- 
    320  * 
    321  * The call will duplicate the array appropriately. 
    322  * 
    323  * Checking for uniqueness during compilation is possible in certain 
    324  * cases (see the $(D_PARAM unique) and $(D_PARAM lent) keywords in 
    325  * the $(WEB archjava.fluid.cs.cmu.edu/papers/oopsla02.pdf, ArchJava) 
    326  * language), but complicates the language considerably. The downside 
    327  * of $(D_PARAM assumeUnique)'s convention-based usage is that at this 
    328  * time there is no formal checking of the correctness of the 
    329  * assumption; on the upside, the idiomatic use of $(D_PARAM 
    330  * assumeUnique) is simple and rare enough to be tolerable. 
    331  * 
    332  */ 
    333  
    334 immutable(T)[] assumeUnique(T)(ref T[] array) 
    335 
    336     auto result = cast(immutable(T)[]) array; 
    337     array = null; 
    338     return result; 
    339 
    340  
    341 unittest 
    342 
    343     int[] arr = new int[1]; 
    344     auto arr1 = assumeUnique(arr); 
    345     assert(is(typeof(arr1) == immutable(int)[]) && arr == null); 
    346 
    347  
    348 immutable(T[U]) assumeUnique(T, U)(ref T[U] array) 
    349 
    350     auto result = cast(immutable(T[U])) array; 
    351     array = null; 
    352     return result; 
    353 
    354  
    355 // @@@BUG@@@ 
    356 version(none) unittest 
    357 
    358     int[string] arr = ["a":1]; 
    359     auto arr1 = assumeUnique(arr); 
    360     assert(is(typeof(arr1) == immutable(int[string])) && arr == null); 
    361 
    362  
    363 /** 
    364 Passes the type system the information that $(D range) is already 
    365 sorted by predicate $(D pred). No checking is performed; debug builds 
    366 may insert checks randomly. To insert a check, see $(XREF algorithm, 
    367 isSorted). 
    368  */ 
    369 struct AssumeSorted(Range, alias pred = "a < b") 
    370 
    371     /// Alias for $(D Range). 
    372     alias Range AssumeSorted; 
    373     /// The passed-in range. 
    374     Range assumeSorted; 
    375     /// The sorting predicate. 
    376     alias pred assumeSortedBy; 
    377 
    378  
    379 /// Ditto 
    380 AssumeSorted!(Range, pred) assumeSorted(alias pred = "a < b", Range) 
    381 (Range r) 
    382 
    383     AssumeSorted!(Range, pred) result; 
    384     result.assumeSorted = r; 
    385     return result; 
    386 
    387  
    388 unittest 
    389 
    390     static assert(is(AssumeSorted!(int[]).AssumeSorted == int[])); 
    391     int[] a = [ 1, 2 ]; 
    392     auto b = assumeSorted(a); 
    393     assert(b.assumeSorted == a); 
    394 
    395  
    396 /** 
    397 Returns $(D true) if $(D source)'s representation embeds a pointer 
    398 that points to $(D target)'s representation or somewhere inside 
    399 it. Note that evaluating $(D pointsTo(x, x)) checks whether $(D x) has 
    400 internal pointers. 
    401 */ 
    402 bool pointsTo(S, T)(ref S source, ref T target) 
    403 
    404     static if (is(S P : U*, U)) 
    405     { 
    406         const void * m = source, b = &target, e = b + target.sizeof; 
    407         return b <= m && m < e; 
    408     } 
    409     else static if (is(S == struct)) 
    410     { 
    411         foreach (i, subobj; source.tupleof) 
    412         { 
    413             static if (!isStaticArray!(typeof(subobj))) 
    414                 if (pointsTo(subobj, target)) return true; 
    415         } 
    416         return false; 
    417     } 
    418     else static if (isDynamicArray!(S)) 
    419     { 
    420         const void* p1 = source.ptr, p2 = p1 + source.length, 
    421             b = &target, e = b + target.sizeof; 
    422         return overlap(p1[0 .. p2 - p1], b[0 .. e - b]).length != 0; 
    423     } 
    424     else 
    425     { 
    426         return false; 
    427     } 
    428 
    429  
    430 unittest 
    431 
    432     struct S1 { int a; S1 * b; } 
    433     S1 a1; 
    434     S1 * p = &a1; 
    435     assert(pointsTo(p, a1)); 
    436  
    437     S1 a2; 
    438     a2.b = &a1; 
    439     assert(pointsTo(a2, a1)); 
    440  
    441     struct S3 { int[10] a; } 
    442     S3 a3; 
    443     auto a4 = a3.a[2 .. 3]; 
    444     assert(pointsTo(a4, a3)); 
    445  
    446     auto a5 = new double[4]; 
    447     auto a6 = a5[1 .. 2]; 
    448     assert(!pointsTo(a5, a6)); 
    449  
    450     auto a7 = new double[3]; 
    451     auto a8 = new double[][1]; 
    452     a8[0] = a7; 
    453     assert(!pointsTo(a8[0], a8[0])); 
    454 
    455  
    456 /********************* 
    457  * Thrown if errors that set $(D errno) happen. 
    458  */ 
    459 class ErrnoException : Exception 
    460 
    461     uint errno;                 // operating system error code 
    462     this(string msg, string file = null, uint line = 0) 
    463     { 
    464         errno = getErrno; 
    465         version (linux) 
    466         { 
    467             char[1024] buf = void; 
    468             auto s = std.c.string.strerror_r(errno, buf.ptr, buf.length); 
    469         } 
    470         else 
    471         { 
    472             auto s = std.c.string.strerror(errno); 
    473         } 
    474         super(msg~" ("~to!string(s)~")", file, line); 
    475     } 
    476 
    477  
    478 // structuralCast 
    479 // class-to-class structural cast 
    480 Target structuralCast(Target, Source)(Source obj) 
    481     if (is(Source == class) || is(Target == class)) 
    482 
    483     // For the structural cast to work, the source and the target must 
    484     // have the same base class, and the target must add no data or 
    485     // methods 
    486     static assert(0, "Not implemented"); 
    487 
    488  
    489 // interface-to-interface structural cast 
    490 Target structuralCast(Target, Source)(Source obj) 
    491     if (is(Source == interface) || is(Target == interface)) 
    492 
    493 
    494  
    495 unittest 
    496 
    497     interface I1 { void f1(); } 
    498     interface I2 { void f2(); } 
    499     interface I12 : I1, I2 { } 
    500     //pragma(msg, TransitiveBaseTypeTuple!I12.stringof); 
    501     //static assert(is(TransitiveBaseTypeTuple!I12 == TypeTuple!(I2, I1))); 
    502 
    503  
    504 // Target structuralCast(Target, Source)(Source obj) 
    505 //     if (is(Source == interface) || is(Target == interface)) 
    506 // { 
    507 //     static assert(is(BaseTypeTuple!(Source)[0] == 
    508 //                     BaseTypeTuple!(Target)[0])); 
    509 //     alias BaseTypeTuple!(Source)[1 .. $] SBases; 
    510 //     alias BaseTypeTuple!(Target)[1 .. $] TBases; 
    511 //         else 
    512 //         { 
    513 //             // interface-to-class 
    514 //             static assert(0); 
    515 //         } 
    516 //     } 
    517 //     else 
    518 //     { 
    519 //         static if (is(Source == class)) 
    520 //         { 
    521 //             // class-to-interface structural cast 
    522 //             alias BaseTypeTuple!(Source)[1 .. $] SBases; 
    523 //             alias BaseTypeTuple!(Target) TBases; 
    524 //         } 
    525 //         else 
    526 //         { 
    527 //             // interface-to-interface structural cast 
    528 //             alias BaseTypeTuple!(Source) SBases; 
    529 //             alias BaseTypeTuple!(Target) TBases; 
    530 //         } 
    531 //     } 
    532 //     static assert(SBases.length >= TBases.length, 
    533 //             "Cannot structurally cast to a target with" 
    534 //             " more interfaces implemented"); 
    535 //     static assert( 
    536 //         is(typeof(Target.tupleof) == typeof(Source.tupleof)), 
    537 //             "Cannot structurally cast to a target with more fields"); 
    538 //     // Target bases must be a prefix of the source bases 
    539 //     foreach (i, B; TBases) 
    540 //     { 
    541 //         static assert(is(SBases[i] == B) 
    542 //                 || is(SBases[i] == interface) && is(SBases[i] : B), 
    543 //                 SBases[i].stringof ~ " does not inherit " 
    544 //                 ~ B.stringof); 
    545 //     } 
    546 //     union Result 
    547 //     { 
    548 //         Source src; 
    549 //         Target tgt; 
    550 //     } 
    551 //     Result result = { obj }; 
    552 //     return result.tgt; 
    553 // } 
    554  
    555 template structurallyCompatible(S, T) if (!isArray!S || !isArray!T) 
    556 
    557     enum structurallyCompatible = 
    558         FieldTypeTuple!S.length >= FieldTypeTuple!T.length 
    559         && is(FieldTypeTuple!S[0 .. FieldTypeTuple!T.length] 
    560                 == FieldTypeTuple!T); 
    561 
    562  
    563 template structurallyCompatible(S, T) if (isArray!S && isArray!T) 
    564 
    565     enum structurallyCompatible = 
    566         .structurallyCompatible!(ElementType!S, ElementType!T) && 
    567         .structurallyCompatible!(ElementType!T, ElementType!S); 
    568 
    569  
    570 unittest 
    571 
    572     // struct X { uint a; } 
    573     // static assert(structurallyCompatible!(uint[], X[])); 
    574     // struct Y { uint a, b; } 
    575     // static assert(!structurallyCompatible!(uint[], Y[])); 
    576     // static assert(!structurallyCompatible!(Y[], uint[])); 
    577     // static assert(!structurallyCompatible!(Y[], X[])); 
    578 
    579  
    580 /* 
    581 Structural cast. Allows casting among class types that logically have 
    582 a common base, but that base is not made explicit. 
    583  
    584 Example: 
    585 ---- 
    586 interface Document { ... } 
    587 interface Storable { ... } 
    588 interface StorableDocument : Storable, Document { ... } 
    589 class Doc : Storable, Document { ... } 
    590 void process(StorableDocument d); 
    591 ... 
    592  
    593 auto c = new Doc; 
    594 process(c); // does not work 
    595 process(structuralCast!StorableDocument(c)); // works 
    596  */ 
    597  
    598 // template structuralCast(Target) 
    599 // { 
    600 //     Target structuralCast(Source)(Source obj) 
    601 //     { 
    602 //         static if (is(Source : Object) || is(Source == interface)) 
    603 //         { 
    604 //             return .structuralCastImpl!(Target)(obj); 
    605 //         } 
    606 //         else 
    607 //         { 
    608 //             static if (structurallyCompatible!(Source, Target)) 
    609 //                 return *(cast(Target*) &obj); 
    610 //             else 
    611 //                 static assert(false); 
    612 //         } 
    613 //     } 
    614 // } 
    615  
    616 unittest 
    617 
    618     // interface I1 {} 
    619     // interface I2 {} 
    620     // class Base : I1 { int x; } 
    621     // class A : I1 {} 
    622     // class B : I1, I2 {} 
    623  
    624     // auto b = new B; 
    625     // auto a = structuralCast!(A)(b); 
    626     // assert(a); 
    627  
    628     // struct X { int a; } 
    629     // int[] arr = [ 1 ]; 
    630     // auto x = structuralCast!(X[])(arr); 
    631     // assert(x[0].a == 1); 
    632 
    633  
    634 unittest 
    635 
    636     // interface Document { int fun(); } 
    637     // interface Storable { int gun(); } 
    638     // interface StorableDocument : Storable, Document {  } 
    639     // class Doc : Storable, Document { 
    640     //     int fun() { return 42; } 
    641     //     int gun() { return 43; } 
    642     // } 
    643     // void process(StorableDocument d) { 
    644     //     assert(d.fun + d.gun == 85, text(d.fun + d.gun)); 
    645     // } 
    646  
    647     // auto c = new Doc; 
    648     // Document d = c; 
    649     // //process(c); // does not work 
    650     // union A 
    651     // { 
    652     //     Storable s; 
    653     //     StorableDocument sd; 
    654     // } 
    655     // A a = { c }; 
    656     //process(a.sd); // works 
    657     //process(structuralCast!StorableDocument(d)); // works 
    658 
     12public import std.exception;