Changeset 1723
- Timestamp:
- 07/04/10 21:54:33 (14 years ago)
- Files:
-
- trunk/phobos/std/typecons.d (modified) (6 diffs)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/phobos/std/typecons.d
r1676 r1723 46 46 Copyright: Copyright the respective authors, 2008- 47 47 License: $(WEB boost.org/LICENSE_1_0.txt, Boost License 1.0). 48 48 Authors: $(WEB erdani.org, Andrei Alexandrescu), 49 49 $(WEB bartoszmilewski.wordpress.com, Bartosz Milewski), 50 50 Don Clugston, 51 51 Shin Fujishiro 52 52 */ 53 53 module std.typecons; 54 54 import core.stdc.stdlib, std.algorithm, std.array, std.contracts, std.conv, 55 55 std.metastrings, std.traits, std.typetuple, core.memory; 56 version(unittest) import std.stdio; 56 57 57 58 /** 58 59 Encapsulates unique ownership of a resource. Resource of type T is 59 60 deleted at the end of the scope, unless it is transferred. The 60 61 transfer can be explicit, by calling $(D release), or implicit, when 61 62 returning Unique from a function. The resource can be a polymorphic 62 63 class object, in which case Unique behaves polymorphically too. 63 64 64 65 Example: 65 66 */ … … 321 322 } 322 323 alias field expand; 323 324 // @@@BUG 2800 324 325 //alias field this; 325 326 326 327 /** 327 328 Default constructor. 328 329 */ 329 330 this(U...)(U values) if (U.length == 0) 330 331 { 331 332 332 } 333 333 334 334 /** 335 335 Constructor taking one value for each field. Each argument must be 336 336 implicitly assignable to the respective element of the target. 337 337 */ 338 338 this(U...)(U values) if (U.length == Types.length) 339 339 { 340 340 foreach (i, Unused; Types) 341 341 { … … 359 359 360 360 /** 361 361 Comparison for equality. 362 362 */ 363 363 bool opEquals(T)(T rhs) if (is(typeof(T.field))) 364 364 { 365 365 static assert(field.length == rhs.field.length, 366 366 "Length mismatch in attempting to compare a " 367 367 ~typeof(this).stringof 368 368 ~" with a "~typeof(rhs).stringof); 369 foreach (i, f; field)370 { 371 if (f != rhs.field[i]) return false;369 foreach (i, Unused; Types) 370 { 371 if (field[i] != rhs.field[i]) return false; 372 372 } 373 373 return true; 374 374 } 375 375 376 376 /** 377 377 Comparison for ordering. 378 378 */ 379 379 int opCmp(T)(T rhs) if (is(typeof(T.field))) 380 380 { 381 381 static assert(field.length == rhs.field.length, 382 382 "Length mismatch in attempting to compare a " 383 383 ~typeof(this).stringof 384 384 ~" with a "~typeof(rhs).stringof); 385 foreach (i, f; field) 386 { 387 if (f != rhs.field[i]) return f < rhs.field[i] ? -1 : 1; 385 foreach (i, Unused; Types) 386 { 387 if (field[i] != rhs.field[i]) 388 { 389 return field[i] < rhs.field[i] ? -1 : 1; 390 } 388 391 } 389 392 return 0; 390 393 } 391 394 395 // Should really be opAssign, not assign 392 396 /** 393 397 Assignment from another tuple. Each element of the source must be 394 398 implicitly assignable to the respective element of the target. 395 399 */ 396 void opAssign(U)(U rhs) if (is(typeof(U.init.field[0])))397 { 398 foreach (i, Unused; noStrings!(T).Result)400 void assign(U)(U rhs) if (is(typeof(U.init.field[0]))) 401 { 402 foreach (i, Unused; Types) 399 403 { 400 404 field[i] = rhs.field[i]; 401 405 } 402 406 } 407 403 408 /** 404 409 Takes a slice of the tuple. 405 410 406 411 Example: 407 412 408 413 ---- 409 414 Tuple!(int, string, float, double) a; 410 415 a.field[1] = "abc"; 411 416 a.field[2] = 4.5; 412 417 auto s = a.slice!(1, 3); … … 473 478 auto c = Tuple!(int, "a", double, "b")(a); 474 479 assert(c.field[0] == 1 && c.field[1] == 2); 475 480 } 476 481 Tuple!(int, int) nosh; 477 482 nosh.field[0] = 5; 478 483 assert(nosh.field[0] == 5); 479 484 // Tuple!(int, int) nosh1; 480 485 // assert(!is(typeof(nosh) == typeof(nosh1))); 481 486 assert(nosh.toString == "Tuple!(int,int)(5, 0)", nosh.toString); 482 487 Tuple!(int, short) yessh; 483 nosh = yessh;488 nosh.assign(yessh); 484 489 485 490 Tuple!(int, "a", float, "b") x; 486 491 static assert(x.a.offsetof == x.field[0].offsetof); 487 492 static assert(x.b.offsetof == x.field[1].offsetof); 488 493 x.b = 4.5; 489 494 x.a = 5; 490 495 assert(x.field[0] == 5 && x.field[1] == 4.5); 491 496 assert(x.a == 5 && x.b == 4.5); 492 497 493 498 { … … 2024 2029 // Reference semantics 2025 2030 rc2 = 42; 2026 2031 assert(rc1 == 42); 2027 2032 // the pair will be freed when rc1 and rc2 go out of scope 2028 2033 ---- 2029 2034 */ 2030 2035 struct RefCounted(T, RefCountedAutoInitialize autoInit = 2031 2036 RefCountedAutoInitialize.yes) 2032 2037 if (!is(T == class)) 2033 2038 { 2034 private Tuple!(T, " payload_", size_t, "count_") * refCountedStore_;2039 private Tuple!(T, "_payload", size_t, "_count") * _refCountedStore; 2035 2040 2036 2041 private void refCountedInitialize(A...)(A args) 2037 2042 { 2038 const sz = (*refCountedStore_).sizeof;2043 const sz = (*_refCountedStore).sizeof; 2039 2044 auto p = malloc(sz)[0 .. sz]; 2040 2045 if (sz >= size_t.sizeof && p.ptr) 2041 2046 GC.addRange(p.ptr, sz); 2042 2047 emplace!T(p[0 .. T.sizeof], args); 2043 refCountedStore_ = cast(typeof(refCountedStore_)) p;2044 refCountedStore_.count_= 1;2048 _refCountedStore = cast(typeof(_refCountedStore)) p; 2049 _refCountedStore._count = 1; 2045 2050 } 2046 2051 2047 2052 /** 2048 2053 Returns $(D true) if and only if the underlying store has been 2049 2054 allocated and initialized. 2050 2055 */ 2051 2056 @property bool refCountedIsInitialized() const 2052 2057 { 2053 return refCountedStore_!is null;2058 return _refCountedStore !is null; 2054 2059 } 2055 2060 2056 2061 /** 2057 2062 Makes sure the payload was properly initialized. Such a call is 2058 2063 typically inserted before using the payload. 2059 2064 */ 2060 2065 void refCountedEnsureInitialized() 2061 2066 { 2062 if (refCountedIsInitialized ()) return;2067 if (refCountedIsInitialized) return; 2063 2068 refCountedInitialize(); 2064 2069 } 2065 2070 2066 2071 /** 2067 2072 Constructor that initializes the payload. 2068 2073 2069 2074 Postcondition: $(D refCountedIsInitialized) 2070 2075 */ 2071 2076 this(A...)(A args) if (A.length > 0) 2072 2077 { 2073 2078 refCountedInitialize(args); 2074 2079 } 2075 2080 2076 2081 /** 2077 2082 Constructor that tracks the reference count appropriately. If $(D 2078 2083 !refCountedIsInitialized), does nothing. 2079 2084 */ 2080 2085 this(this) 2081 2086 { 2082 2087 if (!refCountedIsInitialized) return; 2083 ++ refCountedStore_.count_;2088 ++_refCountedStore._count; 2084 2089 } 2085 2090 2086 2091 /** 2087 2092 Destructor that tracks the reference count appropriately. If $(D 2088 2093 !refCountedIsInitialized), does nothing. When the reference count goes 2089 2094 down to zero, calls $(D clear) agaist the payload and calls $(D free) 2090 2095 to deallocate the corresponding resource. 2091 2096 */ 2092 2097 ~this() 2093 2098 { 2094 if (! refCountedStore_ || --refCountedStore_.count_) return;2099 if (!_refCountedStore || --_refCountedStore._count) return; 2095 2100 // Done, deallocate 2096 clear(* refCountedStore_);2097 if ((*refCountedStore_).sizeof >= size_t.sizeof && refCountedStore_)2098 GC.removeRange(refCountedStore_);2099 free( refCountedStore_);2100 refCountedStore_= null;2101 clear(*_refCountedStore); 2102 if (hasIndirections!T && _refCountedStore) 2103 GC.removeRange(_refCountedStore); 2104 free(_refCountedStore); 2105 _refCountedStore = null; 2101 2106 } 2102 2107 2103 2108 /** 2104 2109 Assignment operators 2105 2110 */ 2106 void opAssign(RefCounted !Trhs)2107 { 2108 swap( refCountedStore_, rhs.refCountedStore_);2111 void opAssign(RefCounted rhs) 2112 { 2113 swap(_refCountedStore, rhs._refCountedStore); 2109 2114 } 2110 2115 2111 2116 /// Ditto 2112 2117 void opAssign(T rhs) 2113 2118 { 2114 2119 refCountedPayload() = move(rhs); 2115 2120 } 2116 2121 2117 2122 /** 2118 2123 Returns a reference to the payload. If (autoInit == … … 2132 2137 */ 2133 2138 @property ref T refCountedPayload() { 2134 2139 static if (autoInit == RefCountedAutoInitialize.yes) 2135 2140 { 2136 2141 refCountedEnsureInitialized(); 2137 2142 } 2138 2143 else 2139 2144 { 2140 2145 assert(refCountedIsInitialized); 2141 2146 } 2142 return refCountedStore_.payload_; 2147 return _refCountedStore._payload; 2148 } 2149 2150 // 2151 @property ref const(T) refCountedPayload() const { 2152 static if (autoInit == RefCountedAutoInitialize.yes) 2153 { 2154 // @@@ 2155 //refCountedEnsureInitialized(); 2156 assert(refCountedIsInitialized); 2157 } 2158 else 2159 { 2160 assert(refCountedIsInitialized); 2161 } 2162 return _refCountedStore._payload; 2143 2163 } 2144 2164 } 2145 2165 2146 2166 unittest 2147 2167 { 2148 2168 RefCounted!int* p; 2149 2169 { 2150 2170 auto rc1 = RefCounted!int(5); 2151 2171 p = &rc1; 2152 2172 assert(rc1 == 5); 2153 assert(rc1. refCountedStore_.count_== 1);2173 assert(rc1._refCountedStore._count == 1); 2154 2174 auto rc2 = rc1; 2155 assert(rc1. refCountedStore_.count_== 2);2175 assert(rc1._refCountedStore._count == 2); 2156 2176 // Reference semantics 2157 2177 rc2 = 42; 2158 2178 assert(rc1 == 42); 2159 2179 rc2 = rc2; 2160 assert(rc2. refCountedStore_.count_== 2);2180 assert(rc2._refCountedStore._count == 2); 2161 2181 rc1 = rc2; 2162 assert(rc1.refCountedStore_.count_ == 2); 2163 } 2164 assert(p.refCountedStore_ == null); 2165 } 2166 2182 assert(rc1._refCountedStore._count == 2); 2183 } 2184 assert(p._refCountedStore == null); 2185 2186 // RefCounted as a member 2187 struct A 2188 { 2189 RefCounted!int x; 2190 this(int y) 2191 { 2192 x.refCountedInitialize(y); 2193 } 2194 A copy() 2195 { 2196 auto another = this; 2197 return another; 2198 } 2199 } 2200 auto a = A(4); 2201 auto b = a.copy(); 2202 if (a.x._refCountedStore._count != 2) { 2203 stderr.writeln("*** BUG 4356 still unfixed"); 2204 } 2205 } 2206
