mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-08-05 22:10:04 +02:00
[svn r136] MAJOR UNSTABLE UPDATE!!!
Initial commit after moving to Tango instead of Phobos. Lots of bugfixes... This build is not suitable for most things.
This commit is contained in:
24
tango/LICENSE
Normal file
24
tango/LICENSE
Normal file
@@ -0,0 +1,24 @@
|
||||
Tango is Open Source software, distributed by a group of developers which has been set up for the purpose of providing a vendor-neutral owner of Tango intellectual property. The goals of all Tango licensing decisions are to:
|
||||
|
||||
* Encourage adoption
|
||||
* Discourage political contention
|
||||
* Encourage collaboration and integration with other projects
|
||||
* Be transparent
|
||||
|
||||
Tango is dual-licensed:
|
||||
* Academic Free License v2.1 (http://opensource.org/licenses/afl-2.1.php)
|
||||
* BSD License (http://opensource.org/licenses/bsd-license.php) [1]
|
||||
|
||||
The preferred license is the Academic Free License v2.1. All Tango projects release their code under the terms of this license. Both licenses:
|
||||
|
||||
* Allow commercial use without encumbrance
|
||||
* Provide broad rights to make new products and derivative works
|
||||
* Place no requirement on users to contribute back (although we appreciate it if you do)
|
||||
|
||||
Users who wish to include Tango with software licensed under the (L)GPL will want to use Tango under the terms of the BSD License. [1] Tango projects may request a variance from the developers to release their projects under additional licenses in conjunction with the AFL.
|
||||
|
||||
If you have further questions regarding Tango licensing, please do not hesitate to contact us (http://dsource.org/projects/tango/wiki/Contact).
|
||||
|
||||
|
||||
[1] The advertising clause has not been a part of the BSD License since July 22, 1999. (ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change)
|
||||
|
||||
7
tango/README.txt
Normal file
7
tango/README.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
For a guide to install Tango see the online installation reference:
|
||||
|
||||
http://dsource.org/projects/tango/wiki/TopicInstallTango
|
||||
|
||||
The license can be found at
|
||||
|
||||
http://dsource.org/projects/tango/wiki/LibraryLicense
|
||||
10
tango/README_LLVMDC.txt
Normal file
10
tango/README_LLVMDC.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
This version of Tango is modified to work with LLVMDC
|
||||
by Tomas Lindquist Olsen, 2008
|
||||
|
||||
Much has been removed as this is not intended to work with other compilers.
|
||||
Hopefully in time, this will go away and the required changes merged into the
|
||||
mainline Tango repository.
|
||||
|
||||
For more information on LLVMDC, check the site at:
|
||||
|
||||
http://www.dsource.org/projects/llvmdc
|
||||
83
tango/dsss.conf
Normal file
83
tango/dsss.conf
Normal file
@@ -0,0 +1,83 @@
|
||||
name = tango
|
||||
|
||||
[tango/core]
|
||||
postinstall=install tango/core/BitManip.di $INCLUDE_PREFIX/tango/core ; \
|
||||
install tango/core/Exception.di $INCLUDE_PREFIX/tango/core ; \
|
||||
install tango/core/Memory.di $INCLUDE_PREFIX/tango/core ; \
|
||||
install tango/core/Runtime.di $INCLUDE_PREFIX/tango/core ; \
|
||||
install tango/core/Thread.di $INCLUDE_PREFIX/tango/core
|
||||
version (GNU) {
|
||||
prebuild = $DSSS_BUILD -obj -explicit lib/common/tango/core/BitManip.d -fintfc-file=tango/core/BitManip.di ; \
|
||||
$DSSS_BUILD -obj -explicit lib/common/tango/core/Exception.d -fintfc-file=tango/core/Exception.di ; \
|
||||
$DSSS_BUILD -obj -explicit lib/common/tango/core/Memory.d -fintfc-file=tango/core/Memory.di ; \
|
||||
$DSSS_BUILD -obj -explicit lib/common/tango/core/Runtime.d -fintfc-file=tango/core/Runtime.di ; \
|
||||
$DSSS_BUILD -obj -explicit lib/common/tango/core/Thread.d -fintfc-file=tango/core/Thread.di ;
|
||||
} else version (DigitalMars) {
|
||||
prebuild = $DSSS_BUILD -obj -explicit lib/common/tango/core/BitManip.d -Hftango/core/BitManip.di ; \
|
||||
$DSSS_BUILD -obj -explicit lib/common/tango/core/Exception.d -Hftango/core/Exception.di ; \
|
||||
$DSSS_BUILD -obj -explicit lib/common/tango/core/Memory.d -Hftango/core/Memory.di ; \
|
||||
$DSSS_BUILD -obj -explicit lib/common/tango/core/Runtime.d -Hftango/core/Runtime.di ; \
|
||||
$DSSS_BUILD -obj -explicit lib/common/tango/core/Thread.d -Hftango/core/Thread.di ;
|
||||
}
|
||||
else version (LLVMDC) {
|
||||
prebuild = $DSSS_BUILD -obj -explicit lib/common/tango/core/BitManip.d -Hftango/core/BitManip.di ; \
|
||||
$DSSS_BUILD -obj -explicit lib/common/tango/core/Exception.d -Hftango/core/Exception.di ; \
|
||||
$DSSS_BUILD -obj -explicit lib/common/tango/core/Memory.d -Hftango/core/Memory.di ; \
|
||||
$DSSS_BUILD -obj -explicit lib/common/tango/core/Runtime.d -Hftango/core/Runtime.di ; \
|
||||
$DSSS_BUILD -obj -explicit lib/common/tango/core/Thread.d -Hftango/core/Thread.di ;
|
||||
}
|
||||
|
||||
version(LLVMDC) {
|
||||
[tango/stdc]
|
||||
} else {
|
||||
|
||||
[tango/io]
|
||||
|
||||
[tango/math]
|
||||
|
||||
[tango/net]
|
||||
|
||||
[tango/stdc]
|
||||
version (Windows) {
|
||||
exclude = tango/stdc/posix
|
||||
}
|
||||
|
||||
[tango/sys]
|
||||
exclude = tango/sys/linux/* tango/sys/darwin/* tango/sys/win32/*
|
||||
exclude += tango/sys/TimeConverter.d
|
||||
|
||||
version (linux) {
|
||||
[tango/sys/linux]
|
||||
}
|
||||
|
||||
version (darwin) {
|
||||
[tango/sys/darwin]
|
||||
}
|
||||
|
||||
version (Windows) {
|
||||
[+tango/sys/win32]
|
||||
preinstall = install tango/sys/win32/Macros.di $INCLUDE_PREFIX/tango/sys/win32 ; \
|
||||
install tango/sys/win32/Process.di $INCLUDE_PREFIX/tango/sys/win32 ; \
|
||||
install tango/sys/win32/Types.di $INCLUDE_PREFIX/tango/sys/win32 ; \
|
||||
install tango/sys/win32/UserGdi.di $INCLUDE_PREFIX/tango/sys/win32
|
||||
}
|
||||
|
||||
[tango/text]
|
||||
|
||||
[tango/text/locale]
|
||||
version (!linux) {
|
||||
exclude += tango/text/locale/Linux.d
|
||||
}
|
||||
version (!Windows) {
|
||||
exclude += tango/text/locale/Win32.d
|
||||
}
|
||||
|
||||
[tango/util]
|
||||
|
||||
[tango/time]
|
||||
|
||||
[tango/group]
|
||||
|
||||
[+std]
|
||||
preinstall = installdir std $INCLUDE_PREFIX/std
|
||||
}
|
||||
60
tango/example/cluster/Add.d
Normal file
60
tango/example/cluster/Add.d
Normal file
@@ -0,0 +1,60 @@
|
||||
/*******************************************************************************
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
public import tango.net.cluster.NetworkCall;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
a Task function
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
real add (real x, real y)
|
||||
{
|
||||
return x + y;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
a Task function
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
int divide (int x, int y)
|
||||
{
|
||||
return x / y;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
a verbose Task message
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
class Subtract : NetworkCall
|
||||
{
|
||||
double a,
|
||||
b,
|
||||
result;
|
||||
|
||||
double opCall (double a, double b, IChannel channel = null)
|
||||
{
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
send (channel);
|
||||
return result;
|
||||
}
|
||||
|
||||
override void execute ()
|
||||
{
|
||||
result = a - b;
|
||||
}
|
||||
|
||||
override void read (IReader input) {input (a)(b)(result);}
|
||||
|
||||
override void write (IWriter output) {output (a)(b)(result);}
|
||||
}
|
||||
36
tango/example/cluster/alert.d
Normal file
36
tango/example/cluster/alert.d
Normal file
@@ -0,0 +1,36 @@
|
||||
private import tango.core.Thread;
|
||||
|
||||
private import tango.util.log.Configurator;
|
||||
|
||||
private import tango.net.cluster.NetworkAlert;
|
||||
|
||||
private import tango.net.cluster.tina.Cluster;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
How to send and recieve Alert messages using tango.net.cluster
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main()
|
||||
{
|
||||
// hook into the cluster
|
||||
auto cluster = (new Cluster).join;
|
||||
|
||||
// hook into the Alert layer
|
||||
auto alert = new NetworkAlert (cluster, "my.kind.of.alert");
|
||||
|
||||
// listen for the broadcast (on this channel)
|
||||
alert.createConsumer (delegate void (IEvent event)
|
||||
{event.log.info ("Recieved alert on channel " ~ event.channel.name);}
|
||||
);
|
||||
|
||||
// say what's going on
|
||||
alert.log.info ("broadcasting alert");
|
||||
|
||||
// and send everyone an empty alert (on this channel)
|
||||
alert.broadcast;
|
||||
|
||||
// wait for it to arrive ...
|
||||
Thread.sleep(1);
|
||||
}
|
||||
48
tango/example/cluster/cclient.d
Normal file
48
tango/example/cluster/cclient.d
Normal file
@@ -0,0 +1,48 @@
|
||||
/*******************************************************************************
|
||||
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
import tango.io.Stdout;
|
||||
|
||||
import tango.time.StopWatch;
|
||||
|
||||
import tango.util.log.Configurator;
|
||||
|
||||
import tango.net.cluster.NetworkCache;
|
||||
|
||||
import tango.net.cluster.tina.Cluster;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main (char[][] args)
|
||||
{
|
||||
StopWatch w;
|
||||
|
||||
if (args.length > 1)
|
||||
{
|
||||
auto cluster = (new Cluster).join (args[1..$]);
|
||||
auto cache = new NetworkCache (cluster, "my.cache.channel");
|
||||
|
||||
while (true)
|
||||
{
|
||||
w.start;
|
||||
for (int i=10000; i--;)
|
||||
cache.put ("key", cache.EmptyMessage);
|
||||
|
||||
Stdout.formatln ("{} put/s", 10000/w.stop);
|
||||
|
||||
w.start;
|
||||
for (int i=10000; i--;)
|
||||
cache.get ("key");
|
||||
|
||||
Stdout.formatln ("{} get/s", 10000/w.stop);
|
||||
}
|
||||
}
|
||||
else
|
||||
Stdout.formatln ("usage: cache cachehost:port ...");
|
||||
}
|
||||
|
||||
30
tango/example/cluster/cserver.d
Normal file
30
tango/example/cluster/cserver.d
Normal file
@@ -0,0 +1,30 @@
|
||||
/*******************************************************************************
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
import tango.io.Console;
|
||||
|
||||
import tango.net.InternetAddress;
|
||||
|
||||
import tango.net.cluster.tina.CmdParser,
|
||||
tango.net.cluster.tina.CacheServer;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main (char[][] args)
|
||||
{
|
||||
auto arg = new CmdParser ("cache.server");
|
||||
|
||||
// default number of cache entries
|
||||
arg.size = 8192;
|
||||
|
||||
if (args.length > 1)
|
||||
arg.parse (args[1..$]);
|
||||
|
||||
if (arg.help)
|
||||
Cout ("usage: cacheserver -port=number -size=cachesize -log[=trace, info, warn, error, fatal, none]").newline;
|
||||
else
|
||||
(new CacheServer(new InternetAddress(arg.port), arg.log, arg.size)).start;
|
||||
}
|
||||
38
tango/example/cluster/invalidate.d
Normal file
38
tango/example/cluster/invalidate.d
Normal file
@@ -0,0 +1,38 @@
|
||||
private import tango.core.Thread;
|
||||
|
||||
private import tango.util.log.Configurator;
|
||||
|
||||
private import tango.net.cluster.tina.Cluster;
|
||||
|
||||
private import tango.net.cluster.QueuedCache,
|
||||
tango.net.cluster.CacheInvalidatee,
|
||||
tango.net.cluster.CacheInvalidator;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Demonstrates how to invalidate cache entries across a cluster
|
||||
via a channel
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main()
|
||||
{
|
||||
// access the cluster
|
||||
auto cluster = (new Cluster).join;
|
||||
|
||||
// wrap a cache instance with a network listener
|
||||
auto dst = new CacheInvalidatee (cluster, "my.cache.channel", new QueuedCache!(char[], IMessage)(101));
|
||||
|
||||
// connect an invalidator to that cache channel
|
||||
auto src = new CacheInvalidator (cluster, "my.cache.channel");
|
||||
|
||||
// stuff something in the local cache
|
||||
dst.cache.put ("key", dst.EmptyMessage);
|
||||
|
||||
// get it removed via a network broadcast
|
||||
src.log.info ("invalidating 'key' across the cluster");
|
||||
src.invalidate ("key");
|
||||
|
||||
// wait for it to arrive ...
|
||||
Thread.sleep (1);
|
||||
}
|
||||
44
tango/example/cluster/qclient.d
Normal file
44
tango/example/cluster/qclient.d
Normal file
@@ -0,0 +1,44 @@
|
||||
/*******************************************************************************
|
||||
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
import tango.io.Stdout;
|
||||
|
||||
import tango.time.StopWatch;
|
||||
|
||||
import tango.util.log.Configurator;
|
||||
|
||||
import tango.net.cluster.NetworkQueue;
|
||||
|
||||
import tango.net.cluster.tina.Cluster;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main (char[][] args)
|
||||
{
|
||||
StopWatch w;
|
||||
|
||||
auto cluster = (new Cluster).join;
|
||||
auto queue = new NetworkQueue (cluster, "my.queue.channel");
|
||||
|
||||
while (true)
|
||||
{
|
||||
w.start;
|
||||
for (int i=10000; i--;)
|
||||
queue.put (queue.EmptyMessage);
|
||||
|
||||
Stdout.formatln ("{} put/s", 10000/w.stop);
|
||||
|
||||
uint count;
|
||||
w.start;
|
||||
while (queue.get !is null)
|
||||
++count;
|
||||
|
||||
Stdout.formatln ("{} get/s", count/w.stop);
|
||||
}
|
||||
}
|
||||
|
||||
41
tango/example/cluster/qlisten.d
Normal file
41
tango/example/cluster/qlisten.d
Normal file
@@ -0,0 +1,41 @@
|
||||
private import tango.core.Thread;
|
||||
|
||||
private import tango.util.log.Configurator;
|
||||
|
||||
private import tango.net.cluster.NetworkQueue;
|
||||
|
||||
private import tango.net.cluster.tina.Cluster;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Illustrates how to setup and use a Queue in asynchronous mode
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main ()
|
||||
{
|
||||
void listen (IEvent event)
|
||||
{
|
||||
while (event.get)
|
||||
event.log.info ("received asynch msg on channel " ~ event.channel.name);
|
||||
}
|
||||
|
||||
|
||||
// join the cluster
|
||||
auto cluster = (new Cluster).join;
|
||||
|
||||
// access a queue of the specified name
|
||||
auto queue = new NetworkQueue (cluster, "my.queue.channel");
|
||||
|
||||
// listen for messages placed in my queue, via a delegate
|
||||
queue.createConsumer (&listen);
|
||||
|
||||
// stuff something into the queue
|
||||
queue.log.info ("sending three messages to the queue");
|
||||
queue.put (queue.EmptyMessage);
|
||||
queue.put (queue.EmptyMessage);
|
||||
queue.put (queue.EmptyMessage);
|
||||
|
||||
// wait for asynchronous msgs to arrive ...
|
||||
Thread.sleep (1);
|
||||
}
|
||||
30
tango/example/cluster/qrequest.d
Normal file
30
tango/example/cluster/qrequest.d
Normal file
@@ -0,0 +1,30 @@
|
||||
private import tango.util.log.Configurator;
|
||||
|
||||
private import tango.net.cluster.NetworkQueue;
|
||||
|
||||
private import tango.net.cluster.tina.Cluster;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Illustrates how to setup and use a Queue in synchronous mode
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main ()
|
||||
{
|
||||
// join the cluster
|
||||
auto cluster = (new Cluster).join;
|
||||
|
||||
// access a queue of the specified name
|
||||
auto queue = new NetworkQueue (cluster, "my.queue.channel");
|
||||
|
||||
// stuff something into the queue
|
||||
queue.log.info ("sending three messages to the queue");
|
||||
queue.put (queue.EmptyMessage);
|
||||
queue.put (queue.EmptyMessage);
|
||||
queue.put (queue.EmptyMessage);
|
||||
|
||||
// retreive synchronously
|
||||
while (queue.get)
|
||||
queue.log.info ("retrieved msg");
|
||||
}
|
||||
27
tango/example/cluster/qserver.d
Normal file
27
tango/example/cluster/qserver.d
Normal file
@@ -0,0 +1,27 @@
|
||||
/*******************************************************************************
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
import tango.io.Console;
|
||||
|
||||
import tango.net.InternetAddress;
|
||||
|
||||
import tango.net.cluster.tina.CmdParser,
|
||||
tango.net.cluster.tina.QueueServer;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main (char[][] args)
|
||||
{
|
||||
auto arg = new CmdParser ("queue.server");
|
||||
|
||||
if (args.length > 1)
|
||||
arg.parse (args[1..$]);
|
||||
|
||||
if (arg.help)
|
||||
Cout ("usage: queueserver -port=number -log[=trace, info, warn, error, fatal, none]").newline;
|
||||
else
|
||||
(new QueueServer(new InternetAddress(arg.port), arg.log)).start;
|
||||
}
|
||||
38
tango/example/cluster/reply.d
Normal file
38
tango/example/cluster/reply.d
Normal file
@@ -0,0 +1,38 @@
|
||||
private import tango.core.Thread;
|
||||
|
||||
private import tango.util.log.Configurator;
|
||||
|
||||
private import tango.net.cluster.tina.Cluster;
|
||||
|
||||
private import tango.net.cluster.NetworkQueue;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main()
|
||||
{
|
||||
// open the cluster and a queue channel. Note that the queue has
|
||||
// been configured with a reply listener ...
|
||||
auto cluster = (new Cluster).join;
|
||||
auto queue = new NetworkQueue (cluster, "message.channel",
|
||||
(IEvent event){event.log.info ("Received reply");}
|
||||
);
|
||||
|
||||
void recipient (IEvent event)
|
||||
{
|
||||
auto msg = event.get;
|
||||
|
||||
event.log.info ("Replying to message on channel "~msg.reply);
|
||||
event.reply (event.replyChannel(msg), queue.EmptyMessage);
|
||||
}
|
||||
|
||||
// setup a listener to recieve and reply
|
||||
queue.createConsumer (&recipient);
|
||||
|
||||
// toss a message out to the cluster
|
||||
queue.put (queue.EmptyMessage);
|
||||
|
||||
// wait for completion ...
|
||||
Thread.sleep (1);
|
||||
}
|
||||
15
tango/example/cluster/task.d
Normal file
15
tango/example/cluster/task.d
Normal file
@@ -0,0 +1,15 @@
|
||||
/*******************************************************************************
|
||||
|
||||
Illustrates usage of cluster tasks
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
import Add, tango.io.Stdout, tango.net.cluster.tina.ClusterTask;
|
||||
|
||||
void main (char[][] args)
|
||||
{
|
||||
scope add = new NetCall!(add);
|
||||
|
||||
Stdout.formatln ("cluster expression of 3.0 + 4.0 = {}", add(3, 4));
|
||||
}
|
||||
|
||||
42
tango/example/cluster/tclient.d
Normal file
42
tango/example/cluster/tclient.d
Normal file
@@ -0,0 +1,42 @@
|
||||
/*******************************************************************************
|
||||
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
import Add;
|
||||
|
||||
import tango.io.Stdout;
|
||||
|
||||
import tango.time.StopWatch;
|
||||
|
||||
import tango.util.log.Configurator;
|
||||
|
||||
import tango.net.cluster.tina.ClusterTask;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main (char[][] args)
|
||||
{
|
||||
// an implicit task instance
|
||||
auto add = new NetCall!(add);
|
||||
|
||||
// an explicit task instance
|
||||
auto sub = new Subtract;
|
||||
|
||||
StopWatch w;
|
||||
while (true)
|
||||
{
|
||||
w.start;
|
||||
for (int i=10000; i--;)
|
||||
{
|
||||
// both task types are used in the same manner
|
||||
add (1, 2);
|
||||
sub (3, 4);
|
||||
}
|
||||
Stdout.formatln ("{} calls/s", 20000/w.stop);
|
||||
}
|
||||
}
|
||||
|
||||
34
tango/example/cluster/tserver.d
Normal file
34
tango/example/cluster/tserver.d
Normal file
@@ -0,0 +1,34 @@
|
||||
/*******************************************************************************
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
import tango.io.Console;
|
||||
|
||||
import tango.net.InternetAddress;
|
||||
|
||||
import tango.net.cluster.tina.CmdParser,
|
||||
tango.net.cluster.tina.TaskServer;
|
||||
|
||||
import Add;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main (char[][] args)
|
||||
{
|
||||
auto arg = new CmdParser ("task.server");
|
||||
|
||||
if (args.length > 1)
|
||||
arg.parse (args[1..$]);
|
||||
|
||||
if (arg.help)
|
||||
Cout ("usage: taskserver -port=number -log[=trace, info, warn, error, fatal, none]").newline;
|
||||
else
|
||||
{
|
||||
auto server = new TaskServer (new InternetAddress(arg.port), arg.log);
|
||||
server.enroll (new NetCall!(add));
|
||||
server.enroll (new Subtract);
|
||||
server.start;
|
||||
}
|
||||
}
|
||||
806
tango/example/concurrency/fiber_test.d
Normal file
806
tango/example/concurrency/fiber_test.d
Normal file
@@ -0,0 +1,806 @@
|
||||
import tango.core.Thread;
|
||||
|
||||
extern (C) int printf(char * str, ...);
|
||||
|
||||
void main()
|
||||
{
|
||||
printf("Compile with -unittest");
|
||||
}
|
||||
|
||||
|
||||
unittest
|
||||
{
|
||||
printf("Testing context creation/deletion\n");
|
||||
int s0 = 0;
|
||||
static int s1 = 0;
|
||||
|
||||
Fiber a = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
s0++;
|
||||
});
|
||||
|
||||
static void fb() { s1++; }
|
||||
|
||||
Fiber b = new Fiber(&fb);
|
||||
|
||||
Fiber c = new Fiber(
|
||||
delegate void() { assert(false); });
|
||||
|
||||
assert(a);
|
||||
assert(b);
|
||||
assert(c);
|
||||
|
||||
assert(s0 == 0);
|
||||
assert(s1 == 0);
|
||||
assert(a.state == Fiber.State.HOLD);
|
||||
assert(b.state == Fiber.State.HOLD);
|
||||
assert(c.state == Fiber.State.HOLD);
|
||||
|
||||
delete c;
|
||||
|
||||
assert(s0 == 0);
|
||||
assert(s1 == 0);
|
||||
assert(a.state == Fiber.State.HOLD);
|
||||
assert(b.state == Fiber.State.HOLD);
|
||||
|
||||
printf("running a\n");
|
||||
a.call();
|
||||
printf("done a\n");
|
||||
|
||||
assert(a);
|
||||
|
||||
assert(s0 == 1);
|
||||
assert(s1 == 0);
|
||||
assert(a.state == Fiber.State.TERM);
|
||||
assert(b.state == Fiber.State.HOLD);
|
||||
|
||||
assert(b.state == Fiber.State.HOLD);
|
||||
|
||||
printf("Running b\n");
|
||||
b.call();
|
||||
printf("Done b\n");
|
||||
|
||||
assert(s0 == 1);
|
||||
assert(s1 == 1);
|
||||
assert(b.state == Fiber.State.TERM);
|
||||
|
||||
delete a;
|
||||
delete b;
|
||||
|
||||
printf("Context creation passed\n");
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
printf("Testing context switching\n");
|
||||
int s0 = 0;
|
||||
int s1 = 0;
|
||||
int s2 = 0;
|
||||
|
||||
Fiber a = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
debug printf(" ---A---\n");
|
||||
s0++;
|
||||
Fiber.yield();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Fiber b = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
debug printf(" ---B---\n");
|
||||
s1++;
|
||||
Fiber.yield();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Fiber c = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
debug printf(" ---C---\n");
|
||||
s2++;
|
||||
Fiber.yield();
|
||||
}
|
||||
});
|
||||
|
||||
assert(a);
|
||||
assert(b);
|
||||
assert(c);
|
||||
assert(s0 == 0);
|
||||
assert(s1 == 0);
|
||||
assert(s2 == 0);
|
||||
|
||||
a.call();
|
||||
b.call();
|
||||
|
||||
assert(a);
|
||||
assert(b);
|
||||
assert(c);
|
||||
assert(s0 == 1);
|
||||
assert(s1 == 1);
|
||||
assert(s2 == 0);
|
||||
|
||||
for(int i=0; i<20; i++)
|
||||
{
|
||||
c.call();
|
||||
a.call();
|
||||
}
|
||||
|
||||
assert(a);
|
||||
assert(b);
|
||||
assert(c);
|
||||
assert(s0 == 21);
|
||||
assert(s1 == 1);
|
||||
assert(s2 == 20);
|
||||
|
||||
delete a;
|
||||
delete b;
|
||||
delete c;
|
||||
|
||||
printf("Context switching passed\n");
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
printf("Testing nested contexts\n");
|
||||
Fiber a, b, c;
|
||||
|
||||
int t0 = 0;
|
||||
int t1 = 0;
|
||||
int t2 = 0;
|
||||
|
||||
a = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
|
||||
t0++;
|
||||
b.call();
|
||||
|
||||
});
|
||||
|
||||
b = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
assert(t0 == 1);
|
||||
assert(t1 == 0);
|
||||
assert(t2 == 0);
|
||||
|
||||
t1++;
|
||||
c.call();
|
||||
|
||||
});
|
||||
|
||||
c = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
assert(t0 == 1);
|
||||
assert(t1 == 1);
|
||||
assert(t2 == 0);
|
||||
|
||||
t2++;
|
||||
});
|
||||
|
||||
assert(a);
|
||||
assert(b);
|
||||
assert(c);
|
||||
assert(t0 == 0);
|
||||
assert(t1 == 0);
|
||||
assert(t2 == 0);
|
||||
|
||||
a.call();
|
||||
|
||||
assert(t0 == 1);
|
||||
assert(t1 == 1);
|
||||
assert(t2 == 1);
|
||||
|
||||
assert(a);
|
||||
assert(b);
|
||||
assert(c);
|
||||
|
||||
delete a;
|
||||
delete b;
|
||||
delete c;
|
||||
|
||||
printf("Nesting contexts passed\n");
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
printf("Testing basic exceptions\n");
|
||||
|
||||
|
||||
int t0 = 0;
|
||||
int t1 = 0;
|
||||
int t2 = 0;
|
||||
|
||||
assert(t0 == 0);
|
||||
assert(t1 == 0);
|
||||
assert(t2 == 0);
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
throw new Exception("Testing\n");
|
||||
t2++;
|
||||
}
|
||||
catch(Exception fx)
|
||||
{
|
||||
t1++;
|
||||
throw fx;
|
||||
}
|
||||
|
||||
t2++;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
t0++;
|
||||
printf("%.*s\n", ex.toString);
|
||||
}
|
||||
|
||||
assert(t0 == 1);
|
||||
assert(t1 == 1);
|
||||
assert(t2 == 0);
|
||||
|
||||
printf("Basic exceptions are supported\n");
|
||||
}
|
||||
|
||||
|
||||
unittest
|
||||
{
|
||||
printf("Testing exceptions\n");
|
||||
Fiber a, b, c;
|
||||
|
||||
int t0 = 0;
|
||||
int t1 = 0;
|
||||
int t2 = 0;
|
||||
|
||||
printf("t0 = %d\nt1 = %d\nt2 = %d\n", t0, t1, t2);
|
||||
|
||||
a = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
t0++;
|
||||
throw new Exception("A exception\n");
|
||||
t0++;
|
||||
});
|
||||
|
||||
b = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
t1++;
|
||||
c.call();
|
||||
t1++;
|
||||
});
|
||||
|
||||
c = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
t2++;
|
||||
throw new Exception("C exception\n");
|
||||
t2++;
|
||||
});
|
||||
|
||||
assert(a);
|
||||
assert(b);
|
||||
assert(c);
|
||||
assert(t0 == 0);
|
||||
assert(t1 == 0);
|
||||
assert(t2 == 0);
|
||||
|
||||
try
|
||||
{
|
||||
a.call();
|
||||
assert(false);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
printf("%.*s\n", e.toString);
|
||||
}
|
||||
|
||||
assert(a);
|
||||
assert(a.state == Fiber.State.TERM);
|
||||
assert(b);
|
||||
assert(c);
|
||||
assert(t0 == 1);
|
||||
assert(t1 == 0);
|
||||
assert(t2 == 0);
|
||||
|
||||
try
|
||||
{
|
||||
b.call();
|
||||
assert(false);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
printf("%.*s\n", e.toString);
|
||||
}
|
||||
|
||||
printf("blah2\n");
|
||||
|
||||
assert(a);
|
||||
assert(b);
|
||||
assert(b.state == Fiber.State.TERM);
|
||||
assert(c);
|
||||
assert(c.state == Fiber.State.TERM);
|
||||
assert(t0 == 1);
|
||||
assert(t1 == 1);
|
||||
assert(t2 == 1);
|
||||
|
||||
delete a;
|
||||
delete b;
|
||||
delete c;
|
||||
|
||||
|
||||
Fiber t;
|
||||
int q0 = 0;
|
||||
int q1 = 0;
|
||||
|
||||
t = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
try
|
||||
{
|
||||
q0++;
|
||||
throw new Exception("T exception\n");
|
||||
q0++;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
q1++;
|
||||
printf("!!!!!!!!GOT EXCEPTION!!!!!!!!\n");
|
||||
printf("%.*s\n", ex.toString);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
assert(t);
|
||||
assert(q0 == 0);
|
||||
assert(q1 == 0);
|
||||
t.call();
|
||||
assert(t);
|
||||
assert(t.state == Fiber.State.TERM);
|
||||
assert(q0 == 1);
|
||||
assert(q1 == 1);
|
||||
|
||||
delete t;
|
||||
|
||||
Fiber d, e;
|
||||
int s0 = 0;
|
||||
int s1 = 0;
|
||||
|
||||
d = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
try
|
||||
{
|
||||
s0++;
|
||||
e.call();
|
||||
Fiber.yield();
|
||||
s0++;
|
||||
e.call();
|
||||
s0++;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
printf("%.*s\n", ex.toString);
|
||||
}
|
||||
});
|
||||
|
||||
e = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
s1++;
|
||||
Fiber.yield();
|
||||
throw new Exception("E exception\n");
|
||||
s1++;
|
||||
});
|
||||
|
||||
assert(d);
|
||||
assert(e);
|
||||
assert(s0 == 0);
|
||||
assert(s1 == 0);
|
||||
|
||||
d.call();
|
||||
|
||||
assert(d);
|
||||
assert(e);
|
||||
assert(s0 == 1);
|
||||
assert(s1 == 1);
|
||||
|
||||
d.call();
|
||||
|
||||
assert(d);
|
||||
assert(e);
|
||||
assert(s0 == 2);
|
||||
assert(s1 == 1);
|
||||
|
||||
assert(d.state == Fiber.State.TERM);
|
||||
assert(e.state == Fiber.State.TERM);
|
||||
|
||||
delete d;
|
||||
delete e;
|
||||
|
||||
printf("Exceptions passed\n");
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
printf("Testing standard exceptions\n");
|
||||
int t = 0;
|
||||
|
||||
Fiber a = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
throw new Exception("BLAHAHA");
|
||||
});
|
||||
|
||||
assert(a);
|
||||
assert(t == 0);
|
||||
|
||||
try
|
||||
{
|
||||
a.call();
|
||||
assert(false);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
printf("%.*s\n", e.toString);
|
||||
}
|
||||
|
||||
assert(a);
|
||||
assert(a.state == Fiber.State.TERM);
|
||||
assert(t == 0);
|
||||
|
||||
delete a;
|
||||
|
||||
|
||||
printf("Standard exceptions passed\n");
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
printf("Memory stress test\n");
|
||||
|
||||
const uint STRESS_SIZE = 5000;
|
||||
|
||||
Fiber ctx[];
|
||||
ctx.length = STRESS_SIZE;
|
||||
|
||||
int cnt0 = 0;
|
||||
int cnt1 = 0;
|
||||
|
||||
void threadFunc()
|
||||
{
|
||||
cnt0++;
|
||||
Fiber.yield;
|
||||
cnt1++;
|
||||
}
|
||||
|
||||
foreach(inout Fiber c; ctx)
|
||||
{
|
||||
c = new Fiber(&threadFunc, 1024);
|
||||
}
|
||||
|
||||
assert(cnt0 == 0);
|
||||
assert(cnt1 == 0);
|
||||
|
||||
foreach(inout Fiber c; ctx)
|
||||
{
|
||||
c.call;
|
||||
}
|
||||
|
||||
assert(cnt0 == STRESS_SIZE);
|
||||
assert(cnt1 == 0);
|
||||
|
||||
foreach(inout Fiber c; ctx)
|
||||
{
|
||||
c.call;
|
||||
}
|
||||
|
||||
assert(cnt0 == STRESS_SIZE);
|
||||
assert(cnt1 == STRESS_SIZE);
|
||||
|
||||
foreach(inout Fiber c; ctx)
|
||||
{
|
||||
delete c;
|
||||
}
|
||||
|
||||
assert(cnt0 == STRESS_SIZE);
|
||||
assert(cnt1 == STRESS_SIZE);
|
||||
|
||||
printf("Memory stress test passed\n");
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
printf("Testing floating point\n");
|
||||
|
||||
float f0 = 1.0;
|
||||
float f1 = 0.0;
|
||||
|
||||
double d0 = 2.0;
|
||||
double d1 = 0.0;
|
||||
|
||||
real r0 = 3.0;
|
||||
real r1 = 0.0;
|
||||
|
||||
assert(f0 == 1.0);
|
||||
assert(f1 == 0.0);
|
||||
assert(d0 == 2.0);
|
||||
assert(d1 == 0.0);
|
||||
assert(r0 == 3.0);
|
||||
assert(r1 == 0.0);
|
||||
|
||||
Fiber a, b, c;
|
||||
|
||||
a = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
f0 ++;
|
||||
d0 ++;
|
||||
r0 ++;
|
||||
|
||||
Fiber.yield();
|
||||
}
|
||||
});
|
||||
|
||||
b = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
f1 = d0 + r0;
|
||||
d1 = f0 + r0;
|
||||
r1 = f0 + d0;
|
||||
|
||||
Fiber.yield();
|
||||
}
|
||||
});
|
||||
|
||||
c = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
f0 *= d1;
|
||||
d0 *= r1;
|
||||
r0 *= f1;
|
||||
|
||||
Fiber.yield();
|
||||
}
|
||||
});
|
||||
|
||||
a.call();
|
||||
assert(f0 == 2.0);
|
||||
assert(f1 == 0.0);
|
||||
assert(d0 == 3.0);
|
||||
assert(d1 == 0.0);
|
||||
assert(r0 == 4.0);
|
||||
assert(r1 == 0.0);
|
||||
|
||||
b.call();
|
||||
assert(f0 == 2.0);
|
||||
assert(f1 == 7.0);
|
||||
assert(d0 == 3.0);
|
||||
assert(d1 == 6.0);
|
||||
assert(r0 == 4.0);
|
||||
assert(r1 == 5.0);
|
||||
|
||||
c.call();
|
||||
assert(f0 == 12.0);
|
||||
assert(f1 == 7.0);
|
||||
assert(d0 == 15.0);
|
||||
assert(d1 == 6.0);
|
||||
assert(r0 == 28.0);
|
||||
assert(r1 == 5.0);
|
||||
|
||||
a.call();
|
||||
assert(f0 == 13.0);
|
||||
assert(f1 == 7.0);
|
||||
assert(d0 == 16.0);
|
||||
assert(d1 == 6.0);
|
||||
assert(r0 == 29.0);
|
||||
assert(r1 == 5.0);
|
||||
|
||||
printf("Floating point passed\n");
|
||||
}
|
||||
|
||||
|
||||
version(x86) unittest
|
||||
{
|
||||
printf("Testing registers\n");
|
||||
|
||||
struct registers
|
||||
{
|
||||
int eax, ebx, ecx, edx;
|
||||
int esi, edi;
|
||||
int ebp, esp;
|
||||
|
||||
//TODO: Add fpu stuff
|
||||
}
|
||||
|
||||
static registers old;
|
||||
static registers next;
|
||||
static registers g_old;
|
||||
static registers g_next;
|
||||
|
||||
//I believe that D calling convention requires that
|
||||
//EBX, ESI and EDI be saved. In order to validate
|
||||
//this, we write to those registers and call the
|
||||
//stack thread.
|
||||
static StackThread reg_test = new StackThread(
|
||||
delegate void()
|
||||
{
|
||||
asm
|
||||
{
|
||||
naked;
|
||||
|
||||
pushad;
|
||||
|
||||
mov EBX, 1;
|
||||
mov ESI, 2;
|
||||
mov EDI, 3;
|
||||
|
||||
mov [old.ebx], EBX;
|
||||
mov [old.esi], ESI;
|
||||
mov [old.edi], EDI;
|
||||
mov [old.ebp], EBP;
|
||||
mov [old.esp], ESP;
|
||||
|
||||
call StackThread.yield;
|
||||
|
||||
mov [next.ebx], EBX;
|
||||
mov [next.esi], ESI;
|
||||
mov [next.edi], EDI;
|
||||
mov [next.ebp], EBP;
|
||||
mov [next.esp], ESP;
|
||||
|
||||
popad;
|
||||
}
|
||||
});
|
||||
|
||||
//Run the stack context
|
||||
asm
|
||||
{
|
||||
naked;
|
||||
|
||||
pushad;
|
||||
|
||||
mov EBX, 10;
|
||||
mov ESI, 11;
|
||||
mov EDI, 12;
|
||||
|
||||
mov [g_old.ebx], EBX;
|
||||
mov [g_old.esi], ESI;
|
||||
mov [g_old.edi], EDI;
|
||||
mov [g_old.ebp], EBP;
|
||||
mov [g_old.esp], ESP;
|
||||
|
||||
mov EAX, [reg_test];
|
||||
call StackThread.call;
|
||||
|
||||
mov [g_next.ebx], EBX;
|
||||
mov [g_next.esi], ESI;
|
||||
mov [g_next.edi], EDI;
|
||||
mov [g_next.ebp], EBP;
|
||||
mov [g_next.esp], ESP;
|
||||
|
||||
popad;
|
||||
}
|
||||
|
||||
|
||||
//Make sure the registers are byte for byte equal.
|
||||
assert(old.ebx = 1);
|
||||
assert(old.esi = 2);
|
||||
assert(old.edi = 3);
|
||||
assert(old == next);
|
||||
|
||||
assert(g_old.ebx = 10);
|
||||
assert(g_old.esi = 11);
|
||||
assert(g_old.edi = 12);
|
||||
assert(g_old == g_next);
|
||||
|
||||
printf("Registers passed!\n");
|
||||
}
|
||||
|
||||
|
||||
unittest
|
||||
{
|
||||
printf("Testing throwYield\n");
|
||||
|
||||
int q0 = 0;
|
||||
|
||||
Fiber st0 = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
q0++;
|
||||
Fiber.yieldAndThrow(new Exception("testing throw yield\n"));
|
||||
q0++;
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
st0.call();
|
||||
assert(false);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
printf("%.*s\n", e.toString);
|
||||
}
|
||||
|
||||
assert(q0 == 1);
|
||||
assert(st0.state == Fiber.State.HOLD);
|
||||
|
||||
st0.call();
|
||||
assert(q0 == 2);
|
||||
assert(st0.state == Fiber.State.TERM);
|
||||
|
||||
printf("throwYield passed!\n");
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
printf("Testing thread safety\n");
|
||||
|
||||
int x = 0, y = 0;
|
||||
|
||||
Fiber sc0 = new Fiber(
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
x++;
|
||||
Fiber.yield;
|
||||
}
|
||||
});
|
||||
|
||||
Fiber sc1 = new Fiber(
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
y++;
|
||||
Fiber.yield;
|
||||
}
|
||||
});
|
||||
|
||||
Thread t0 = new Thread(
|
||||
{
|
||||
for(int i=0; i<10000; i++)
|
||||
sc0.call();
|
||||
});
|
||||
|
||||
Thread t1 = new Thread(
|
||||
{
|
||||
for(int i=0; i<10000; i++)
|
||||
sc1.call();
|
||||
});
|
||||
|
||||
assert(sc0);
|
||||
assert(sc1);
|
||||
assert(t0);
|
||||
assert(t1);
|
||||
|
||||
t0.start;
|
||||
t1.start;
|
||||
t0.join;
|
||||
t1.join;
|
||||
|
||||
assert(x == 10000);
|
||||
assert(y == 10000);
|
||||
|
||||
printf("Thread safety passed!\n");
|
||||
}
|
||||
|
||||
319
tango/example/conduits/FileBucket.d
Normal file
319
tango/example/conduits/FileBucket.d
Normal file
@@ -0,0 +1,319 @@
|
||||
module FileBucket;
|
||||
|
||||
private import tango.io.FilePath,
|
||||
tango.io.FileConduit;
|
||||
|
||||
private import tango.core.Exception;
|
||||
|
||||
/******************************************************************************
|
||||
|
||||
FileBucket implements a simple mechanism to store and recover a
|
||||
large quantity of data for the duration of the hosting process.
|
||||
It is intended to act as a local-cache for a remote data-source,
|
||||
or as a spillover area for large in-memory cache instances.
|
||||
|
||||
Note that any and all stored data is rendered invalid the moment
|
||||
a FileBucket object is garbage-collected.
|
||||
|
||||
The implementation follows a fixed-capacity record scheme, where
|
||||
content can be rewritten in-place until said capacity is reached.
|
||||
At such time, the altered content is moved to a larger capacity
|
||||
record at end-of-file, and a hole remains at the prior location.
|
||||
These holes are not collected, since the lifespan of a FileBucket
|
||||
is limited to that of the host process.
|
||||
|
||||
All index keys must be unique. Writing to the FileBucket with an
|
||||
existing key will overwrite any previous content. What follows
|
||||
is a contrived example:
|
||||
|
||||
---
|
||||
char[] text = "this is a test";
|
||||
|
||||
auto bucket = new FileBucket (new FilePath("bucket.bin"), FileBucket.HalfK);
|
||||
|
||||
// insert some data, and retrieve it again
|
||||
bucket.put ("a key", text);
|
||||
char[] b = cast(char[]) bucket.get ("a key");
|
||||
|
||||
assert (b == text);
|
||||
bucket.close;
|
||||
---
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
class FileBucket
|
||||
{
|
||||
/**********************************************************************
|
||||
|
||||
Define the capacity (block-size) of each record
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
struct BlockSize
|
||||
{
|
||||
int capacity;
|
||||
}
|
||||
|
||||
// basic capacity for each record
|
||||
private FilePath path;
|
||||
|
||||
// basic capacity for each record
|
||||
private BlockSize block;
|
||||
|
||||
// where content is stored
|
||||
private FileConduit file;
|
||||
|
||||
// pointers to file records
|
||||
private Record[char[]] map;
|
||||
|
||||
// current file size
|
||||
private long fileSize;
|
||||
|
||||
// current file usage
|
||||
private long waterLine;
|
||||
|
||||
// supported block sizes
|
||||
public static const BlockSize EighthK = {128-1},
|
||||
HalfK = {512-1},
|
||||
OneK = {1024*1-1},
|
||||
TwoK = {1024*2-1},
|
||||
FourK = {1024*4-1},
|
||||
EightK = {1024*8-1},
|
||||
SixteenK = {1024*16-1},
|
||||
ThirtyTwoK = {1024*32-1},
|
||||
SixtyFourK = {1024*64-1};
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
|
||||
Construct a FileBucket with the provided path and record-
|
||||
size. Selecting a record size that roughly matches the
|
||||
serialized content will limit 'thrashing'.
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
this (char[] path, BlockSize block)
|
||||
{
|
||||
this (new FilePath(path), block);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
|
||||
Construct a FileBucket with the provided path, record-size,
|
||||
and inital record count. The latter causes records to be
|
||||
pre-allocated, saving a certain amount of growth activity.
|
||||
Selecting a record size that roughly matches the serialized
|
||||
content will limit 'thrashing'.
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
this (FilePath path, BlockSize block, uint initialRecords = 100)
|
||||
{
|
||||
this.path = path;
|
||||
this.block = block;
|
||||
|
||||
// open a storage file
|
||||
file = new FileConduit (path, FileConduit.ReadWriteCreate);
|
||||
|
||||
// set initial file size (can be zero)
|
||||
fileSize = initialRecords * block.capacity;
|
||||
file.seek (fileSize);
|
||||
file.truncate ();
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
|
||||
Return the block-size in use for this FileBucket
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
int getBufferSize ()
|
||||
{
|
||||
return block.capacity+1;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
|
||||
Return where the FileBucket is located
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
FilePath getFilePath ()
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
|
||||
Return the currently populated size of this FileBucket
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
synchronized long length ()
|
||||
{
|
||||
return waterLine;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
|
||||
Return the serialized data for the provided key. Returns
|
||||
null if the key was not found.
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
synchronized void[] get (char[] key)
|
||||
{
|
||||
Record r = null;
|
||||
|
||||
if (key in map)
|
||||
{
|
||||
r = map [key];
|
||||
return r.read (this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
|
||||
Remove the provided key from this FileBucket.
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
synchronized void remove (char[] key)
|
||||
{
|
||||
map.remove(key);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
|
||||
Write a serialized block of data, and associate it with
|
||||
the provided key. All keys must be unique, and it is the
|
||||
responsibility of the programmer to ensure this. Reusing
|
||||
an existing key will overwrite previous data.
|
||||
|
||||
Note that data is allowed to grow within the occupied
|
||||
bucket until it becomes larger than the allocated space.
|
||||
When this happens, the data is moved to a larger bucket
|
||||
at the file tail.
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
synchronized void put (char[] key, void[] data)
|
||||
{
|
||||
Record* r = key in map;
|
||||
|
||||
if (r is null)
|
||||
{
|
||||
auto rr = new Record;
|
||||
map [key] = rr;
|
||||
r = &rr;
|
||||
}
|
||||
r.write (this, data, block);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
|
||||
Close this FileBucket -- all content is lost.
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
synchronized void close ()
|
||||
{
|
||||
if (file)
|
||||
{
|
||||
file.detach;
|
||||
file = null;
|
||||
map = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
|
||||
Each Record takes up a number of 'pages' within the file.
|
||||
The size of these pages is determined by the BlockSize
|
||||
provided during FileBucket construction. Additional space
|
||||
at the end of each block is potentially wasted, but enables
|
||||
content to grow in size without creating a myriad of holes.
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
private static class Record
|
||||
{
|
||||
private long offset;
|
||||
private int length,
|
||||
capacity = -1;
|
||||
|
||||
/**************************************************************
|
||||
|
||||
**************************************************************/
|
||||
|
||||
private static void eof (FileBucket bucket)
|
||||
{
|
||||
throw new IOException ("Unexpected EOF in FileBucket '"~bucket.path.toString()~"'");
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
|
||||
This should be protected from thread-contention at
|
||||
a higher level.
|
||||
|
||||
**************************************************************/
|
||||
|
||||
void[] read (FileBucket bucket)
|
||||
{
|
||||
void[] data = new ubyte [length];
|
||||
|
||||
bucket.file.seek (offset);
|
||||
if (bucket.file.read (data) != length)
|
||||
eof (bucket);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
|
||||
This should be protected from thread-contention at
|
||||
a higher level.
|
||||
|
||||
**************************************************************/
|
||||
|
||||
void write (FileBucket bucket, void[] data, BlockSize block)
|
||||
{
|
||||
length = data.length;
|
||||
|
||||
// create new slot if we exceed capacity
|
||||
if (length > capacity)
|
||||
createBucket (bucket, length, block);
|
||||
|
||||
// locate to start of content
|
||||
bucket.file.seek (offset);
|
||||
|
||||
// write content
|
||||
if (bucket.file.write (data) != length)
|
||||
eof (bucket);
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
|
||||
**************************************************************/
|
||||
|
||||
void createBucket (FileBucket bucket, int bytes, BlockSize block)
|
||||
{
|
||||
offset = bucket.waterLine;
|
||||
capacity = (bytes + block.capacity) & ~block.capacity;
|
||||
|
||||
bucket.waterLine += capacity;
|
||||
if (bucket.waterLine > bucket.fileSize)
|
||||
{
|
||||
// grow the filesize
|
||||
bucket.fileSize = bucket.waterLine * 2;
|
||||
|
||||
// expand the physical file size
|
||||
bucket.file.seek (bucket.fileSize);
|
||||
bucket.file.truncate ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
85
tango/example/conduits/composite.d
Normal file
85
tango/example/conduits/composite.d
Normal file
@@ -0,0 +1,85 @@
|
||||
|
||||
private import tango.io.protocol.Reader,
|
||||
tango.io.protocol.Writer,
|
||||
tango.io.FileConduit;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Use cascading reads & writes to handle a composite class. There is
|
||||
just one primary call for output, and just one for input, but the
|
||||
classes propogate the request as appropriate.
|
||||
|
||||
Note that the class instances don't know how their content will be
|
||||
represented; that is dictated by the caller (via the reader/writer
|
||||
implementation).
|
||||
|
||||
Note also that this only serializes the content. To serialize the
|
||||
classes too, take a look at the Pickle.d example.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main()
|
||||
{
|
||||
// define a serializable class (via interfaces)
|
||||
class Wumpus : IReadable, IWritable
|
||||
{
|
||||
private int a = 11,
|
||||
b = 112,
|
||||
c = 1024;
|
||||
|
||||
void read (IReader input)
|
||||
{
|
||||
input (a) (b) (c);
|
||||
}
|
||||
|
||||
void write (IWriter output)
|
||||
{
|
||||
output (a) (b) (c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// define a serializable class (via interfaces)
|
||||
class Wombat : IReadable, IWritable
|
||||
{
|
||||
private Wumpus wumpus;
|
||||
private char[] x = "xyz";
|
||||
private bool y = true;
|
||||
private float z = 3.14159;
|
||||
|
||||
this (Wumpus wumpus)
|
||||
{
|
||||
this.wumpus = wumpus;
|
||||
}
|
||||
|
||||
void read (IReader input)
|
||||
{
|
||||
input (x) (y) (z) (wumpus);
|
||||
}
|
||||
|
||||
void write (IWriter output)
|
||||
{
|
||||
output (x) (y) (z) (wumpus);
|
||||
}
|
||||
}
|
||||
|
||||
// construct a Wombat
|
||||
auto wombat = new Wombat (new Wumpus);
|
||||
|
||||
// open a file for IO
|
||||
auto file = new FileConduit ("random.bin", FileConduit.ReadWriteCreate);
|
||||
|
||||
// construct reader & writer upon the file, with binary IO
|
||||
auto output = new Writer (file);
|
||||
auto input = new Reader (file);
|
||||
|
||||
// write both Wombat & Wumpus (and flush them)
|
||||
output (wombat) ();
|
||||
|
||||
// rewind to file start
|
||||
file.seek (0);
|
||||
|
||||
// read both back again
|
||||
input (wombat);
|
||||
}
|
||||
|
||||
30
tango/example/conduits/filebubbler.d
Normal file
30
tango/example/conduits/filebubbler.d
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
private import tango.io.Console,
|
||||
tango.io.FileScan,
|
||||
tango.io.FileConst;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
This example sweeps a named sub-directory tree for html files,
|
||||
and moves them to the current directory. The existing directory
|
||||
hierarchy is flattened into a naming scheme where a '.' is used
|
||||
to replace the traditional path-separator
|
||||
|
||||
Used by the Tango project to help manage renderings of the source
|
||||
code.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main(char[][] args)
|
||||
{
|
||||
// sweep all html files in the specified subdir
|
||||
if (args.length is 2)
|
||||
foreach (proxy; (new FileScan).sweep(args[1], ".html").files)
|
||||
{
|
||||
auto other = new FilePath (proxy.toString);
|
||||
proxy.rename (other.replace (FileConst.PathSeparatorChar, '.'));
|
||||
}
|
||||
else
|
||||
Cout ("usage is filebubbler subdir").newline;
|
||||
}
|
||||
|
||||
26
tango/example/conduits/filecat.d
Normal file
26
tango/example/conduits/filecat.d
Normal file
@@ -0,0 +1,26 @@
|
||||
private import tango.io.Console,
|
||||
tango.io.FileConduit;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Concatenate a number of files onto a single destination
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main(char[][] args)
|
||||
{
|
||||
if (args.length > 2)
|
||||
{
|
||||
// open the file for writing
|
||||
auto dst = new FileConduit (args[1], FileConduit.WriteCreate);
|
||||
|
||||
// copy each file onto dst
|
||||
foreach (char[] arg; args[2..args.length])
|
||||
dst.copy (new FileConduit(arg));
|
||||
|
||||
// flush output and close
|
||||
dst.close;
|
||||
}
|
||||
else
|
||||
Cout ("usage: filecat target source1 ... sourceN");
|
||||
}
|
||||
23
tango/example/conduits/filecopy.d
Normal file
23
tango/example/conduits/filecopy.d
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
private import tango.io.Console,
|
||||
tango.io.FileConduit;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
open a file, and stream directly to console
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main (char[][] args)
|
||||
{
|
||||
if (args.length is 2)
|
||||
{
|
||||
// open a file for reading
|
||||
auto fc = new FileConduit (args[1]);
|
||||
|
||||
// stream directly to console
|
||||
Cout.stream.copy (fc);
|
||||
}
|
||||
else
|
||||
Cout ("usage is: filecopy filename").newline;
|
||||
}
|
||||
26
tango/example/conduits/fileops.d
Normal file
26
tango/example/conduits/fileops.d
Normal file
@@ -0,0 +1,26 @@
|
||||
/*****************************************************
|
||||
|
||||
Example that shows some simple file operations
|
||||
|
||||
Put into public domain by Lars Ivar Igesund
|
||||
|
||||
*****************************************************/
|
||||
|
||||
import tango.io.Stdout;
|
||||
|
||||
import tango.io.FilePath;
|
||||
|
||||
void main (char[][] args)
|
||||
{
|
||||
auto src = args[0] ~ ".d";
|
||||
auto dst = new FilePath (args[0] ~ ".d.copy");
|
||||
|
||||
Stdout.formatln ("copy file {} to {}", src, dst);
|
||||
dst.copy (src);
|
||||
assert (dst.exists);
|
||||
|
||||
Stdout.formatln ("removing file {}", dst);
|
||||
dst.remove;
|
||||
|
||||
assert (dst.exists is false);
|
||||
}
|
||||
11
tango/example/conduits/filepathname.d
Normal file
11
tango/example/conduits/filepathname.d
Normal file
@@ -0,0 +1,11 @@
|
||||
import tango.io.Console;
|
||||
|
||||
import tango.io.FilePath;
|
||||
|
||||
void main(){
|
||||
Cout ((new FilePath(r"d:\path\foo.bat")).name).newline;
|
||||
Cout ((new FilePath(r"d:\path.two\bar")).name).newline;
|
||||
Cout ((new FilePath("/home/user.name/bar.")).name).newline;
|
||||
Cout ((new FilePath(r"d:\path.two\bar")).name).newline;
|
||||
Cout ((new FilePath("/home/user/.resource")).name).newline;
|
||||
}
|
||||
32
tango/example/conduits/filescan.d
Normal file
32
tango/example/conduits/filescan.d
Normal file
@@ -0,0 +1,32 @@
|
||||
private import tango.io.Stdout,
|
||||
tango.io.FileScan;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
List ".d" files and enclosing folders visible via a directory given
|
||||
as a command-line argument. In this example we're also postponing a
|
||||
flush on Stdout until output is complete. Stdout is usually flushed
|
||||
on each invocation of newline or formatln, but here we're using '\n'
|
||||
to illustrate how to avoid flushing many individual lines
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main(char[][] args)
|
||||
{
|
||||
char[] root = args.length < 2 ? "." : args[1];
|
||||
Stdout.formatln ("Scanning '{}'", root);
|
||||
|
||||
auto scan = (new FileScan)(root, ".d");
|
||||
|
||||
Stdout.format ("\n{} Folders\n", scan.folders.length);
|
||||
foreach (folder; scan.folders)
|
||||
Stdout.format ("{}\n", folder);
|
||||
|
||||
Stdout.format ("\n{0} Files\n", scan.files.length);
|
||||
foreach (file; scan.files)
|
||||
Stdout.format ("{}\n", file);
|
||||
|
||||
Stdout.formatln ("\n{} Errors", scan.errors.length);
|
||||
foreach (error; scan.errors)
|
||||
Stdout (error).newline;
|
||||
}
|
||||
40
tango/example/conduits/filescanregex.d
Normal file
40
tango/example/conduits/filescanregex.d
Normal file
@@ -0,0 +1,40 @@
|
||||
/**************************************************************
|
||||
|
||||
Example that use FileScan and Regex as a filter.
|
||||
|
||||
Put into public domain by Lars Ivar Igesund
|
||||
|
||||
**************************************************************/
|
||||
|
||||
import tango.io.File,
|
||||
tango.io.Stdout,
|
||||
tango.io.FileScan,
|
||||
tango.text.Regex;
|
||||
|
||||
void main(char[][] args) {
|
||||
uint total;
|
||||
|
||||
if (args.length < 2) {
|
||||
Stdout("Please pass a directory to search").newline;
|
||||
return;
|
||||
}
|
||||
|
||||
scope scan = new FileScan;
|
||||
scope regex = Regex(r"\.(d|obj)$");
|
||||
|
||||
scan(args[1], delegate bool (FilePath fp, bool isDir) {
|
||||
++total;
|
||||
return isDir || regex.test(fp.toString);
|
||||
});
|
||||
|
||||
|
||||
foreach (file; scan.files)
|
||||
Stdout(file).newline;
|
||||
|
||||
Stdout.formatln("Found {} matches in {} entries", scan.files.length, total);
|
||||
|
||||
Stdout.formatln ("\n{} Errors", scan.errors.length);
|
||||
foreach (error; scan.errors)
|
||||
Stdout (error).newline;
|
||||
}
|
||||
|
||||
29
tango/example/conduits/lineio.d
Normal file
29
tango/example/conduits/lineio.d
Normal file
@@ -0,0 +1,29 @@
|
||||
|
||||
private import tango.io.Console,
|
||||
tango.io.FileConduit;
|
||||
|
||||
private import tango.text.stream.LineIterator;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Read a file line-by-line, sending each one to the console. This
|
||||
illustrates how to bind a conduit to a stream iterator (iterators
|
||||
also support the binding of a buffer). Note that stream iterators
|
||||
are templated for char, wchar and dchar types.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main (char[][] args)
|
||||
{
|
||||
if (args.length is 2)
|
||||
{
|
||||
// open a file for reading
|
||||
scope file = new FileConduit (args[1]);
|
||||
|
||||
// process file one line at a time
|
||||
foreach (line; new LineIterator!(char)(file))
|
||||
Cout (line).newline;
|
||||
}
|
||||
else
|
||||
Cout ("usage: lineio filename").newline;
|
||||
}
|
||||
24
tango/example/conduits/mmap.d
Normal file
24
tango/example/conduits/mmap.d
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
private import tango.io.Console,
|
||||
tango.io.FileConduit,
|
||||
tango.io.MappedBuffer;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
open a file, map it into memory, and copy to console
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main (char[][] args)
|
||||
{
|
||||
if (args.length is 2)
|
||||
{
|
||||
// open a file for reading
|
||||
auto mmap = new MappedBuffer (new FileConduit (args[1]));
|
||||
|
||||
// copy content to console
|
||||
Cout (cast(char[]) mmap.slice) ();
|
||||
}
|
||||
else
|
||||
Cout ("usage is: mmap filename").newline;
|
||||
}
|
||||
13
tango/example/conduits/paths.d
Normal file
13
tango/example/conduits/paths.d
Normal file
@@ -0,0 +1,13 @@
|
||||
/*****************************************************
|
||||
|
||||
How to create a path with all ancestors
|
||||
|
||||
*****************************************************/
|
||||
|
||||
import tango.io.FilePath;
|
||||
|
||||
void main (char[][] args)
|
||||
{
|
||||
auto path = new FilePath (r"d/tango/foo/bar/wumpus");
|
||||
assert (path.create.exists && path.isFolder);
|
||||
}
|
||||
38
tango/example/conduits/randomio.d
Normal file
38
tango/example/conduits/randomio.d
Normal file
@@ -0,0 +1,38 @@
|
||||
|
||||
private import tango.io.FileConduit;
|
||||
|
||||
private import tango.io.protocol.Reader,
|
||||
tango.io.protocol.Writer;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Create a file for random access. Write some stuff to it, rewind to
|
||||
file start and read back.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main()
|
||||
{
|
||||
// open a file for reading
|
||||
auto fc = new FileConduit ("random.bin", FileConduit.ReadWriteCreate);
|
||||
|
||||
// construct (binary) reader & writer upon this conduit
|
||||
auto read = new Reader (fc);
|
||||
auto write = new Writer (fc);
|
||||
|
||||
int x=10, y=20;
|
||||
|
||||
// write some data and flush output since IO is buffered
|
||||
write (x) (y) ();
|
||||
|
||||
// rewind to file start
|
||||
fc.seek (0);
|
||||
|
||||
// read data back again, but swap destinations
|
||||
read (y) (x);
|
||||
|
||||
assert (y is 10);
|
||||
assert (x is 20);
|
||||
|
||||
fc.close();
|
||||
}
|
||||
25
tango/example/conduits/unifile.d
Normal file
25
tango/example/conduits/unifile.d
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
private import tango.io.Console,
|
||||
tango.io.UnicodeFile;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Open a unicode file of an unknown encoding, and converts to UTF-8
|
||||
for console display. UnicodeFile is templated for char/wchar/dchar
|
||||
target encodings
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main (char[][] args)
|
||||
{
|
||||
if (args.length is 2)
|
||||
{
|
||||
// open a file for reading
|
||||
auto file = new UnicodeFile!(char) (args[1], Encoding.Unknown);
|
||||
|
||||
// display on console
|
||||
Cout (file.read).newline;
|
||||
}
|
||||
else
|
||||
Cout ("usage is: unifile filename").newline;
|
||||
}
|
||||
17
tango/example/console/buffered.d
Normal file
17
tango/example/console/buffered.d
Normal file
@@ -0,0 +1,17 @@
|
||||
private import tango.stdc.stdio;
|
||||
|
||||
private import tango.io.Console;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Demonstrates buffered output. Console output (and Stdout etc) is
|
||||
buffered, requiring a flush or newline to render on the console.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main (char[][] args)
|
||||
{
|
||||
Cout ("how now ");
|
||||
printf ("printf\n");
|
||||
Cout ("brown cow").newline;
|
||||
}
|
||||
21
tango/example/console/hello.d
Normal file
21
tango/example/console/hello.d
Normal file
@@ -0,0 +1,21 @@
|
||||
/*******************************************************************************
|
||||
|
||||
Hello World using tango.io
|
||||
|
||||
This illustrates bare console output, with no fancy formatting.
|
||||
|
||||
Console I/O in Tango is UTF-8 across both linux and Win32. The
|
||||
conversion between various unicode representations is handled
|
||||
by higher level constructs, such as Stdout and Stderr
|
||||
|
||||
Note that Cerr is tied to the console error output, and Cin is
|
||||
tied to the console input.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
import tango.io.Console;
|
||||
|
||||
void main()
|
||||
{
|
||||
Cout ("hello, sweetheart \u263a").newline;
|
||||
}
|
||||
14
tango/example/console/stdout.d
Normal file
14
tango/example/console/stdout.d
Normal file
@@ -0,0 +1,14 @@
|
||||
/*******************************************************************************
|
||||
|
||||
Illustrates the basic console formatting. This is different than
|
||||
the use of tango.io.Console, in that Stdout supports a variety of
|
||||
printf-style formatting, and has unicode-conversion support
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
private import tango.io.Stdout;
|
||||
|
||||
void main()
|
||||
{
|
||||
Stdout ("hello, sweetheart \u263a").newline;
|
||||
}
|
||||
35
tango/example/dsss.conf
Normal file
35
tango/example/dsss.conf
Normal file
@@ -0,0 +1,35 @@
|
||||
[concurrency/fiber_test.d]
|
||||
[conduits/composite.d]
|
||||
[conduits/filebubbler.d]
|
||||
[conduits/filecat.d]
|
||||
[conduits/filecopy.d]
|
||||
[conduits/fileops.d]
|
||||
[conduits/filepathname.d]
|
||||
[conduits/filescan.d]
|
||||
[conduits/filescanregex.d]
|
||||
[conduits/lineio.d]
|
||||
[conduits/mmap.d]
|
||||
[conduits/paths.d]
|
||||
[conduits/randomio.d]
|
||||
[conduits/unifile.d]
|
||||
[console/hello.d]
|
||||
[console/stdout.d]
|
||||
[logging/chainsaw.d]
|
||||
[logging/logging.d]
|
||||
[logging/multilog.d]
|
||||
[manual/chapterStorage.d]
|
||||
[networking/homepage.d]
|
||||
[networking/httpget.d]
|
||||
[networking/selector.d]
|
||||
[networking/sockethello.d]
|
||||
[networking/socketserver.d]
|
||||
[system/arguments.d]
|
||||
[system/localtime.d]
|
||||
[system/normpath.d]
|
||||
[system/process.d]
|
||||
[text/formatalign.d]
|
||||
[text/formatindex.d]
|
||||
[text/formatspec.d]
|
||||
[text/localetime.d]
|
||||
[text/properties.d]
|
||||
[text/token.d]
|
||||
42
tango/example/external/GlueFlectioned.d
vendored
Normal file
42
tango/example/external/GlueFlectioned.d
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
import tango.core.Exception;
|
||||
import cn.kuehne.flectioned;
|
||||
|
||||
|
||||
TracedExceptionInfo traceHandler( void* ptr = null )
|
||||
{
|
||||
class FlectionedTrace :
|
||||
TracedExceptionInfo
|
||||
{
|
||||
this( void* ptr = null )
|
||||
{
|
||||
if( ptr )
|
||||
m_trace = Trace.getTrace( cast(size_t) ptr );
|
||||
else
|
||||
m_trace = Trace.getTrace();
|
||||
}
|
||||
|
||||
int opApply( int delegate( inout char[] ) dg )
|
||||
{
|
||||
int ret = 0;
|
||||
foreach( t; m_trace )
|
||||
{
|
||||
char[] buf = t.toString;
|
||||
ret = dg( buf );
|
||||
if( ret != 0 )
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
Trace[] m_trace;
|
||||
}
|
||||
|
||||
return new FlectionedTrace( ptr );
|
||||
}
|
||||
|
||||
|
||||
static this()
|
||||
{
|
||||
setTraceHandler( &traceHandler );
|
||||
}
|
||||
76
tango/example/jake-all.bat
Normal file
76
tango/example/jake-all.bat
Normal file
@@ -0,0 +1,76 @@
|
||||
@rem ###########################################################################
|
||||
@rem # CONCURRENCY EXAMPLES
|
||||
@rem ###########################################################################
|
||||
|
||||
@jake concurrency\fiber_test.d -I.. -op -unittest
|
||||
|
||||
@rem ###########################################################################
|
||||
@rem # CONDUIT EXAMPLES
|
||||
@rem ###########################################################################
|
||||
|
||||
@jake conduits\composite.d -I.. -op
|
||||
@jake conduits\filebubbler.d -I.. -op
|
||||
@jake -c conduits\filebucket.d -I.. -op
|
||||
@jake conduits\filecat.d -I.. -op
|
||||
@jake conduits\filecopy.d -I.. -op
|
||||
@jake conduits\filepathname.d -I.. -op
|
||||
@jake conduits\filescan.d -I.. -op
|
||||
@jake conduits\filescanregex.d -I.. -op
|
||||
@jake conduits\lineio.d -I.. -op
|
||||
@jake conduits\mmap.d -I.. -op
|
||||
@jake conduits\randomio.d -I.. -op
|
||||
@jake conduits\unifile.d -I.. -op
|
||||
|
||||
@rem ###########################################################################
|
||||
@rem # CONSOLE EXAMPLES
|
||||
@rem ###########################################################################
|
||||
|
||||
@jake console\hello.d -I.. -op
|
||||
@jake console\stdout.d -I.. -op
|
||||
|
||||
@rem ###########################################################################
|
||||
@rem # LOGGING EXAMPLES
|
||||
@rem ###########################################################################
|
||||
|
||||
@jake logging\chainsaw.d -I.. -op
|
||||
@jake logging\logging.d -I.. -op
|
||||
|
||||
@rem ###########################################################################
|
||||
@rem # REFERENCE MANUAL EXAMPLES
|
||||
@rem ###########################################################################
|
||||
|
||||
@jake manual\chapterStorage.d -I.. -op
|
||||
|
||||
@rem ###########################################################################
|
||||
@rem # NETWORKING EXAMPLES
|
||||
@rem ###########################################################################
|
||||
|
||||
@jake networking\homepage.d -I.. -op
|
||||
@jake networking\httpget.d -I.. -op
|
||||
@jake networking\sockethello.d -I.. -op
|
||||
@jake networking\socketserver.d -I.. -op
|
||||
@jake networking\selector.d -I.. -op
|
||||
|
||||
@rem ###########################################################################
|
||||
@rem # SYSTEM EXAMPLES
|
||||
@rem ###########################################################################
|
||||
|
||||
@jake system\argparser.d -I.. -op
|
||||
@jake system\localtime.d -I.. -op
|
||||
@jake system\normpath.d -I.. -op
|
||||
@jake system\process.d -I.. -op
|
||||
|
||||
@rem ###########################################################################
|
||||
@rem # TEXT EXAMPLES
|
||||
@rem ###########################################################################
|
||||
|
||||
@jake text\formatalign.d -I.. -op
|
||||
@jake text\formatindex.d -I.. -op
|
||||
@jake text\formatspec.d -I.. -op
|
||||
@jake text\localetime.d -I.. -op
|
||||
@jake text\token.d -I.. -op
|
||||
|
||||
@rem FINI
|
||||
|
||||
@del *.map
|
||||
@dir *.exe
|
||||
89
tango/example/linux.mak
Normal file
89
tango/example/linux.mak
Normal file
@@ -0,0 +1,89 @@
|
||||
# Makefile to build the examples of tango for Linux
|
||||
# Designed to work with GNU make
|
||||
# Targets:
|
||||
# make
|
||||
# Same as make all
|
||||
# make all
|
||||
# Build all examples
|
||||
#
|
||||
# make <executable-name>
|
||||
# Build a specified example
|
||||
# make clean
|
||||
# remove all build examples
|
||||
#
|
||||
#
|
||||
|
||||
# Relative path to the tango include dir
|
||||
# This is where the tango tree is located
|
||||
TANGO_DIR = ..
|
||||
|
||||
# The build tool executable from dsource.org/projects/build
|
||||
BUILDTOOL = bud
|
||||
BUILDOPTS = -noautoimport -op -clean -full -g -debug -I$(TANGO_DIR)
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
# Standard target
|
||||
all :
|
||||
|
||||
# networking/httpserver \
|
||||
# networking/servlets \
|
||||
# networking/servletserver\
|
||||
|
||||
SIMPLE_EXAMPLES =\
|
||||
concurrency/fiber_test \
|
||||
conduits/FileBucket \
|
||||
conduits/composite \
|
||||
conduits/filebubbler \
|
||||
conduits/filecat \
|
||||
conduits/filecopy \
|
||||
conduits/fileops \
|
||||
conduits/filepathname \
|
||||
conduits/filescan \
|
||||
conduits/filescanregex \
|
||||
conduits/lineio \
|
||||
conduits/mmap \
|
||||
conduits/randomio \
|
||||
conduits/unifile \
|
||||
console/hello \
|
||||
console/stdout \
|
||||
logging/chainsaw \
|
||||
logging/logging \
|
||||
networking/homepage \
|
||||
networking/httpget \
|
||||
networking/sockethello \
|
||||
networking/socketserver \
|
||||
system/argparser \
|
||||
system/localtime \
|
||||
system/normpath \
|
||||
system/process \
|
||||
networking/selector \
|
||||
text/formatalign \
|
||||
text/formatindex \
|
||||
text/formatspec \
|
||||
text/localetime \
|
||||
text/properties \
|
||||
text/token
|
||||
|
||||
REFERENCE_EXAMPLES = \
|
||||
./reference/chapter4 \
|
||||
./reference/chapter11
|
||||
|
||||
$(SIMPLE_EXAMPLES) : % : %.d
|
||||
@echo "Building : " $@
|
||||
$(BUILDTOOL) $< $(BUILDOPTS) -T$@ -unittest
|
||||
|
||||
$(REFERENCE_EXAMPLES) : % : %.d
|
||||
@echo "Building : " $@
|
||||
$(BUILDTOOL) $< $(BUILDOPTS) -T$@
|
||||
|
||||
all : $(SIMPLE_EXAMPLES)
|
||||
|
||||
clean :
|
||||
@echo "Removing all examples"
|
||||
rm -f $(SIMPLE_EXAMPLES) $(REFERENCE_EXAMPLES)
|
||||
rm -f conduits/random.bin
|
||||
|
||||
|
||||
|
||||
|
||||
30
tango/example/logging/chainsaw.d
Normal file
30
tango/example/logging/chainsaw.d
Normal file
@@ -0,0 +1,30 @@
|
||||
import tango.core.Thread;
|
||||
|
||||
import tango.util.log.Log,
|
||||
tango.util.log.Log4Layout,
|
||||
tango.util.log.SocketAppender;
|
||||
|
||||
import tango.net.InternetAddress;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Hooks up to Chainsaw for remote log capture. Chainsaw should be
|
||||
configured to listen with an XMLSocketReciever
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main()
|
||||
{
|
||||
// get a logger to represent this module
|
||||
auto logger = Log.getLogger ("example.chainsaw");
|
||||
|
||||
// hook up an appender for XML output
|
||||
logger.addAppender (new SocketAppender (new InternetAddress("127.0.0.1", 4448), new Log4Layout));
|
||||
|
||||
while (true)
|
||||
{
|
||||
logger.info ("Hello Chainsaw!");
|
||||
Thread.sleep (1.0);
|
||||
}
|
||||
}
|
||||
322
tango/example/logging/context.d
Normal file
322
tango/example/logging/context.d
Normal file
@@ -0,0 +1,322 @@
|
||||
/*******************************************************************************
|
||||
|
||||
copyright: Copyright (c) 2007 Stonecobra. All rights reserved
|
||||
|
||||
license: BSD style: $(LICENSE)
|
||||
|
||||
version: Initial release: December 2007
|
||||
|
||||
author: stonecobra
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
module context;
|
||||
|
||||
import tango.core.Thread,
|
||||
tango.util.log.Log,
|
||||
tango.util.log.Event,
|
||||
tango.util.log.EventLayout,
|
||||
tango.util.log.ConsoleAppender;
|
||||
|
||||
import tango.util.log.model.IHierarchy;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Allows the dynamic setting of log levels on a per-thread basis.
|
||||
Imagine that a user request comes into your production threaded
|
||||
server. You can't afford to turn logging up to trace for the sake
|
||||
of debugging this one users problem, but you also can't afford to
|
||||
find the problem and fix it. So now you just set the override log
|
||||
level to TRACE for the thread the user is on, and you get full trace
|
||||
output for only that user.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
class ThreadLocalDiagnosticContext : IHierarchy.Context
|
||||
{
|
||||
private ThreadLocal!(DCData) dcData;
|
||||
private char[128] tmp;
|
||||
|
||||
/***********************************************************************
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
public this()
|
||||
{
|
||||
dcData = new ThreadLocal!(DCData);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
||||
set the 'diagnostic' Level for logging. This overrides
|
||||
the Level in the current Logger. The default level starts
|
||||
at NONE, so as not to modify the behavior of existing clients
|
||||
of tango.util.log
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
void setLevel (ILevel.Level level)
|
||||
{
|
||||
auto data = dcData.val;
|
||||
data.level = level;
|
||||
dcData.val = data;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
||||
All log appends will be checked against this to see if a
|
||||
log level needs to be temporarily adjusted.
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
bool isEnabled (ILevel.Level setting, ILevel.Level level = ILevel.Level.Trace)
|
||||
{
|
||||
return level >= setting || level >= dcData.val.level;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
||||
Return the label to use for the current log message. Usually
|
||||
called by the Layout. This implementation returns "{}".
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
char[] label ()
|
||||
{
|
||||
return dcData.val.getLabel;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
||||
Push another string into the 'stack'. This strings will be
|
||||
appened together when getLabel is called.
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
void push (char[] label)
|
||||
{
|
||||
auto data = dcData.val;
|
||||
data.push(label);
|
||||
dcData.val = data;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
||||
pop the current label off the stack.
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
void pop ()
|
||||
{
|
||||
auto data = dcData.val;
|
||||
data.pop;
|
||||
dcData.val = data;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
||||
Clear the label stack.
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
void clear()
|
||||
{
|
||||
auto data = dcData.val;
|
||||
data.clear;
|
||||
dcData.val = data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
The thread locally stored struct to hold the logging level and
|
||||
the label stack.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
private struct DCData {
|
||||
|
||||
ILevel.Level level = ILevel.Level.None;
|
||||
char[][8] stack;
|
||||
bool shouldUpdate = true;
|
||||
int stackIndex = 0;
|
||||
uint labelLength;
|
||||
char[256] labelContent;
|
||||
|
||||
|
||||
char[] getLabel() {
|
||||
if (shouldUpdate) {
|
||||
labelLength = 0;
|
||||
append(" {");
|
||||
for (int i = 0; i < stackIndex; i++) {
|
||||
append(stack[i]);
|
||||
if (i < stackIndex - 1) {
|
||||
append(" ");
|
||||
}
|
||||
}
|
||||
append("}");
|
||||
shouldUpdate = false;
|
||||
}
|
||||
return labelContent[0..labelLength];
|
||||
}
|
||||
|
||||
void append(char[] x) {
|
||||
uint addition = x.length;
|
||||
uint newLength = labelLength + x.length;
|
||||
|
||||
if (newLength < labelContent.length)
|
||||
{
|
||||
labelContent [labelLength..newLength] = x[0..addition];
|
||||
labelLength = newLength;
|
||||
}
|
||||
}
|
||||
|
||||
void push(char[] label) {
|
||||
shouldUpdate = true;
|
||||
stack[stackIndex] = label.dup;
|
||||
stackIndex++;
|
||||
}
|
||||
|
||||
void pop() {
|
||||
shouldUpdate = true;
|
||||
if (stackIndex > 0) {
|
||||
stack[stackIndex] = null;
|
||||
stackIndex--;
|
||||
}
|
||||
}
|
||||
|
||||
void clear() {
|
||||
shouldUpdate = true;
|
||||
for (int i = 0; i < stack.length; i++) {
|
||||
stack[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Simple console appender that counts the number of log lines it
|
||||
has written.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
class TestingConsoleAppender : ConsoleAppender {
|
||||
|
||||
int events = 0;
|
||||
|
||||
this (EventLayout layout = null)
|
||||
{
|
||||
super(layout);
|
||||
}
|
||||
|
||||
override void append (Event event)
|
||||
{
|
||||
events++;
|
||||
super.append(event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Testing harness for the DiagnosticContext functionality.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main(char[][] args)
|
||||
{
|
||||
//set up our appender that counts the log output. This is the configuration
|
||||
//equivalent of importing tango.util.log.Configurator.
|
||||
auto appender = new TestingConsoleAppender(new SimpleTimerLayout);
|
||||
Log.getRootLogger.addAppender(appender);
|
||||
|
||||
char[128] tmp = 0;
|
||||
auto log = Log.getLogger("context");
|
||||
log.setLevel(log.Level.Info);
|
||||
|
||||
//first test, use all defaults, validating it is working. None of the trace()
|
||||
//calls should count in the test.
|
||||
for (int i=0;i < 10; i++) {
|
||||
log.info(log.format(tmp, "test1 {}", i));
|
||||
log.trace(log.format(tmp, "test1 {}", i));
|
||||
}
|
||||
if (appender.events !is 10) {
|
||||
log.error(log.format(tmp, "events:{}", appender.events));
|
||||
throw new Exception("Incorrect Number of events in normal mode");
|
||||
}
|
||||
|
||||
appender.events = 0;
|
||||
|
||||
//test the thread local implementation without any threads, as a baseline.
|
||||
//should be same result as test1
|
||||
auto context = new ThreadLocalDiagnosticContext;
|
||||
Log.getHierarchy.context(context);
|
||||
for (int i=0;i < 10; i++) {
|
||||
log.info(log.format(tmp, "test2 {}", i));
|
||||
log.trace(log.format(tmp, "test2 {}", i));
|
||||
}
|
||||
if (appender.events !is 10) {
|
||||
log.error(log.format(tmp, "events:{}", appender.events));
|
||||
throw new Exception("Incorrect Number of events in TLS single thread mode");
|
||||
}
|
||||
|
||||
appender.events = 0;
|
||||
|
||||
//test the thread local implementation without any threads, as a baseline.
|
||||
//This should count all logging requests, because the DiagnosticContext has
|
||||
//'overridden' the logging level on ALL loggers up to TRACE.
|
||||
context.setLevel(log.Level.Trace);
|
||||
for (int i=0;i < 10; i++) {
|
||||
log.info(log.format(tmp, "test3 {}", i));
|
||||
log.trace(log.format(tmp, "test3 {}", i));
|
||||
}
|
||||
if (appender.events !is 20) {
|
||||
log.error(log.format(tmp, "events:{}", appender.events));
|
||||
throw new Exception("Incorrect Number of events in TLS single thread mode with level set");
|
||||
}
|
||||
|
||||
appender.events = 0;
|
||||
|
||||
//test the thread local implementation without any threads, as a baseline.
|
||||
context.setLevel(log.Level.None);
|
||||
for (int i=0;i < 10; i++) {
|
||||
log.info(log.format(tmp, "test4 {}", i));
|
||||
log.trace(log.format(tmp, "test4 {}", i));
|
||||
}
|
||||
if (appender.events !is 10) {
|
||||
log.error(log.format(tmp, "events:{}", appender.events));
|
||||
throw new Exception("Incorrect Number of events in TLS single thread mode after level reset");
|
||||
}
|
||||
|
||||
//Now test threading. set up a trace context in one thread, with a label, while
|
||||
//keeping the second thread at the normal configuration.
|
||||
appender.events = 0;
|
||||
ThreadGroup tg = new ThreadGroup();
|
||||
tg.create({
|
||||
char[128] tmp = 0;
|
||||
context.setLevel(log.Level.Trace);
|
||||
context.push("specialthread");
|
||||
context.push("2ndlevel");
|
||||
for (int i=0;i < 10; i++) {
|
||||
log.info(log.format(tmp, "test5 {}", i));
|
||||
log.trace(log.format(tmp, "test5 {}", i));
|
||||
}
|
||||
});
|
||||
tg.create({
|
||||
char[128] tmp = 0;
|
||||
context.setLevel(log.Level.None);
|
||||
for (int i=0;i < 10; i++) {
|
||||
log.info(log.format(tmp, "test6 {}", i));
|
||||
log.trace(log.format(tmp, "test6 {}", i));
|
||||
}
|
||||
});
|
||||
tg.joinAll();
|
||||
|
||||
if (appender.events !is 30) {
|
||||
log.error(log.format(tmp, "events:{}", appender.events));
|
||||
throw new Exception("Incorrect Number of events in TLS multi thread mode");
|
||||
}
|
||||
}
|
||||
|
||||
102
tango/example/logging/logging.d
Normal file
102
tango/example/logging/logging.d
Normal file
@@ -0,0 +1,102 @@
|
||||
/*******************************************************************************
|
||||
|
||||
Shows how the basic functionality of Logger operates.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
private import tango.util.log.Log,
|
||||
tango.util.log.Configurator;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Search for a set of prime numbers
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void compute (Logger log, uint max)
|
||||
{
|
||||
byte* feld;
|
||||
int teste=1,
|
||||
mom,
|
||||
hits=0,
|
||||
s=0,
|
||||
e = 1;
|
||||
int count;
|
||||
char tmp[128] = void;
|
||||
|
||||
void set (byte* f, uint x)
|
||||
{
|
||||
*(f+(x)/16) |= 1 << (((x)%16)/2);
|
||||
}
|
||||
|
||||
byte test (byte* f, uint x)
|
||||
{
|
||||
return cast(byte) (*(f+(x)/16) & (1 << (((x)%16)/2)));
|
||||
}
|
||||
|
||||
// information level
|
||||
log.info (log.format (tmp, "Searching prime numbers up to {}", max));
|
||||
|
||||
feld = (new byte[max / 16 + 1]).ptr;
|
||||
|
||||
// get milliseconds since application began
|
||||
auto begin = log.runtime;
|
||||
|
||||
while ((teste += 2) < max)
|
||||
if (! test (feld, teste))
|
||||
{
|
||||
if ((++hits & 0x0f) == 0)
|
||||
// more information level
|
||||
log.info (log.format (tmp, "found {}", hits));
|
||||
|
||||
for (mom=3*teste; mom < max; mom += teste<<1)
|
||||
set (feld, mom);
|
||||
}
|
||||
|
||||
// get number of milliseconds we took to compute
|
||||
auto period = log.runtime - begin;
|
||||
|
||||
if (hits)
|
||||
// more information
|
||||
log.info (log.format (tmp, "{} prime numbers found in {} millsecs", hits, period));
|
||||
else
|
||||
// a warning level
|
||||
log.warn ("no prime numbers found");
|
||||
|
||||
// check to see if we're enabled for
|
||||
// tracing before we expend a lot of effort
|
||||
if (log.isEnabled (log.Level.Trace))
|
||||
{
|
||||
e = max;
|
||||
count = 0 - 2;
|
||||
if (s % 2 is 0)
|
||||
count++;
|
||||
|
||||
while ((count+=2) < e)
|
||||
// log trace information
|
||||
if (! test (feld, count))
|
||||
log.trace (log.format (tmp, "prime found: {}", count));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Compute a bunch of prime numbers
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main()
|
||||
{
|
||||
// get a logger to represent this module. We could just as
|
||||
// easily share a name with some other module(s)
|
||||
auto log = Log.getLogger ("example.logging");
|
||||
try {
|
||||
compute (log, 1000);
|
||||
|
||||
} catch (Exception x)
|
||||
{
|
||||
// log the exception as an error
|
||||
log.error ("Exception: " ~ x.toString);
|
||||
}
|
||||
}
|
||||
31
tango/example/logging/multilog.d
Normal file
31
tango/example/logging/multilog.d
Normal file
@@ -0,0 +1,31 @@
|
||||
import tango.util.log.Log;
|
||||
import tango.util.log.Log4Layout;
|
||||
import tango.util.log.FileAppender;
|
||||
import tango.util.log.ConsoleAppender;
|
||||
import tango.util.log.RollingFileAppender;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Shows how to setup multiple appenders on logging tree
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main ()
|
||||
{
|
||||
// set default logging level at the root
|
||||
auto log = Log.getRootLogger;
|
||||
log.setLevel (log.Level.Trace);
|
||||
|
||||
// 10 logs, all with 10 mbs each
|
||||
log.addAppender (new RollingFileAppender("rolling.log", 9, 1024*1024*10));
|
||||
|
||||
// a single file appender, with an XML layout
|
||||
log.addAppender (new FileAppender ("single.log", new Log4Layout));
|
||||
|
||||
// console appender
|
||||
log.addAppender (new ConsoleAppender);
|
||||
|
||||
// log to all
|
||||
log.trace ("three-way logging");
|
||||
}
|
||||
|
||||
237
tango/example/manual/chapterStorage.d
Normal file
237
tango/example/manual/chapterStorage.d
Normal file
@@ -0,0 +1,237 @@
|
||||
module example.reference.chapter11;
|
||||
|
||||
import tango.util.collection.HashMap;
|
||||
import tango.util.collection.ArrayBag;
|
||||
import tango.util.collection.LinkSeq;
|
||||
import tango.util.collection.CircularSeq;
|
||||
import tango.util.collection.ArraySeq;
|
||||
import tango.util.collection.TreeBag;
|
||||
import tango.util.collection.iterator.FilteringIterator;
|
||||
import tango.util.collection.iterator.InterleavingIterator;
|
||||
|
||||
import tango.io.Stdout;
|
||||
import tango.core.Exception;
|
||||
|
||||
import tango.util.collection.model.Comparator;
|
||||
import tango.util.collection.impl.BagCollection;
|
||||
import tango.util.collection.impl.SeqCollection;
|
||||
import Ascii = tango.text.Ascii;
|
||||
|
||||
void linkedListExample(){
|
||||
Stdout.format( "linkedListExample" ).newline;
|
||||
alias LinkSeq!(char[]) StrList;
|
||||
StrList lst = new StrList();
|
||||
|
||||
lst.append( "value1" );
|
||||
lst.append( "value2" );
|
||||
lst.append( "value3" );
|
||||
|
||||
auto it = lst.elements();
|
||||
// The call to .more gives true, if there are more elements
|
||||
// and switches the iterator to the next one if available.
|
||||
while( it.more ){
|
||||
char[] item_value = it.get;
|
||||
Stdout.format( "Value:{0}", item_value ).newline;
|
||||
}
|
||||
}
|
||||
|
||||
void hashMapExample(){
|
||||
Stdout.format( "hashMapExample" ).newline;
|
||||
alias HashMap!(char[], char[]) StrStrMap;
|
||||
StrStrMap map = new StrStrMap();
|
||||
map.add( "key1", "value1" );
|
||||
char[] key = "key1";
|
||||
Stdout.format( "Key: {0}, Value:{1}", key, map.get( key )).newline;
|
||||
|
||||
|
||||
auto it = map.keys();
|
||||
// The call to .more gives true, if there are more elements
|
||||
// and switches the iterator to the next one if available.
|
||||
while( it.more ){
|
||||
char[] item_key = void;
|
||||
char[] item_value = it.get( item_key ); // only for maps, the key is returns via inout
|
||||
Stdout.format( "Key: {0}, Value:{1}", item_key, item_value ).newline;
|
||||
}
|
||||
}
|
||||
|
||||
void testComparator(){
|
||||
char[][] result;
|
||||
|
||||
// Create and fill the containers
|
||||
auto nameSet = new TreeBag!(char[])( null, new class() Comparator!(char[]){
|
||||
int compare( char[] first, char[] second ){
|
||||
return Ascii.icompare( first, second );
|
||||
}
|
||||
});
|
||||
|
||||
nameSet.addIf( "Alice" );
|
||||
nameSet.addIf( "Bob" );
|
||||
nameSet.addIf( "aliCe" );
|
||||
|
||||
// use foreach to iterate over the container
|
||||
foreach ( char[] i; nameSet )
|
||||
result ~= i;
|
||||
foreach( char[] i; result ) Stdout.format( "{0} ", i );
|
||||
Stdout.newline;
|
||||
|
||||
// test the result
|
||||
assert( result == [ "Alice", "Bob" ], "testIterator" );
|
||||
}
|
||||
|
||||
void testSreener(){
|
||||
int[] result;
|
||||
|
||||
// Create and fill the containers
|
||||
auto ratioSamples = new ArraySeq!(float)( (float v){
|
||||
return v >= 0.0f && v < 1.0f;
|
||||
});
|
||||
|
||||
ratioSamples.append( 0.0f );
|
||||
ratioSamples.append( 0.5f );
|
||||
ratioSamples.append( 0.99999f );
|
||||
// try to insert a value that is not allowed
|
||||
try{
|
||||
ratioSamples.append( 1.0f );
|
||||
// will never get here
|
||||
assert( false );
|
||||
} catch( IllegalElementException e ){
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void testForeach(){
|
||||
int[] result;
|
||||
|
||||
// Create and fill the containers
|
||||
auto l1 = new CircularSeq!(int);
|
||||
for( int i = 0; i < 6; i+=2 ){
|
||||
l1.append( i );
|
||||
}
|
||||
|
||||
// use foreach to iterate over the container
|
||||
foreach ( int i; l1 )
|
||||
result ~= i;
|
||||
// foreach_reverse ( int i; l1 )
|
||||
// result ~= i;
|
||||
|
||||
// test the result
|
||||
assert( result == [ 0, 2, 4 ], "testIterator" );
|
||||
}
|
||||
|
||||
void testIterator(){
|
||||
int[] result;
|
||||
|
||||
// Create and fill the containers
|
||||
auto l1 = new LinkSeq!(int);
|
||||
for( int i = 0; i < 6; i+=2 ){
|
||||
l1.append( i );
|
||||
}
|
||||
|
||||
// define the Iterator
|
||||
auto it = l1.elements();
|
||||
|
||||
// use the Iterator to iterate over the container
|
||||
while (it.more())
|
||||
result ~= it.get();
|
||||
|
||||
// test the result
|
||||
assert( result == [ 0, 2, 4 ], "testIterator" );
|
||||
}
|
||||
|
||||
void testFilteringIterator(){
|
||||
int[] result;
|
||||
alias ArrayBag!(int) IntBag;
|
||||
|
||||
// Create and fill the container
|
||||
auto ib = new IntBag;
|
||||
for( int i = 0; i < 20; i++ ){
|
||||
ib.add( i );
|
||||
}
|
||||
|
||||
// define the FilteringIterator with a function literal
|
||||
auto it = new FilteringIterator!(int)( ib.elements(), (int i){
|
||||
return i >= 3 && i < 7;
|
||||
});
|
||||
|
||||
// use the Iterator with the more()/get() pattern
|
||||
while (it.more())
|
||||
result ~= it.get();
|
||||
|
||||
// test the result
|
||||
assert( result == [ 3, 4, 5, 6 ], "testFilteringIterator" );
|
||||
|
||||
}
|
||||
|
||||
void testFilteringIteratorRemove(){
|
||||
int[] result;
|
||||
|
||||
// Create and fill the container
|
||||
auto container = new LinkSeq!(int);
|
||||
for( int i = 0; i < 10; i++ ){
|
||||
container.append( i );
|
||||
}
|
||||
|
||||
// 1. Build a list of elements to delete
|
||||
auto dellist = new LinkSeq!(int);
|
||||
foreach( int i; container ){
|
||||
if( i < 3 || i >= 7 ){
|
||||
// container.remove( i ); /* NOT POSSIBLE */
|
||||
dellist.append( i );
|
||||
}
|
||||
}
|
||||
// 2. Iterate over this deletion list and
|
||||
// delete the items in the original container.
|
||||
foreach( int i; dellist ){
|
||||
container.remove( i );
|
||||
}
|
||||
|
||||
foreach ( int i; container )
|
||||
result ~= i;
|
||||
|
||||
// test the result
|
||||
assert( result == [ 3, 4, 5, 6 ], "testFilteringIterator" );
|
||||
|
||||
}
|
||||
|
||||
void testInterleavingIterator(){
|
||||
int[] result;
|
||||
|
||||
// Create and fill the containers
|
||||
auto l1 = new LinkSeq!(int);
|
||||
auto l2 = new ArraySeq!(int);
|
||||
for( int i = 0; i < 6; i+=2 ){
|
||||
l1.append( i );
|
||||
l2.append( i+1 );
|
||||
}
|
||||
|
||||
// define the InterleavingIterator
|
||||
auto it = new InterleavingIterator!(int)( l1.elements(), l2.elements() );
|
||||
|
||||
// use the InterleavingIterator to iterate over the container
|
||||
while (it.more())
|
||||
result ~= it.get();
|
||||
|
||||
// test the result
|
||||
assert( result == [ 0, 1, 2, 3, 4, 5 ], "testInterleavingIterator" );
|
||||
}
|
||||
|
||||
// foreach( int i; result ) Stdout.format( "{0} ", i );
|
||||
// Stdout.newline;
|
||||
|
||||
void main(){
|
||||
Stdout.format( "reference - Chapter 11 Example" ).newline;
|
||||
hashMapExample();
|
||||
linkedListExample();
|
||||
|
||||
testSreener();
|
||||
testComparator();
|
||||
testForeach();
|
||||
testIterator();
|
||||
testFilteringIterator();
|
||||
testInterleavingIterator();
|
||||
testFilteringIteratorRemove();
|
||||
|
||||
Stdout.format( "=== End ===" ).newline;
|
||||
}
|
||||
|
||||
|
||||
30
tango/example/networking/homepage.d
Normal file
30
tango/example/networking/homepage.d
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
private import tango.io.Console;
|
||||
|
||||
private import tango.net.http.HttpClient,
|
||||
tango.net.http.HttpHeaders;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Shows how to use HttpClient to retrieve content from the D website
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main()
|
||||
{
|
||||
auto client = new HttpClient (HttpClient.Get, "http://www.digitalmars.com/d/intro.html");
|
||||
|
||||
// open the client and get the input stream
|
||||
auto input = client.open;
|
||||
scope (exit)
|
||||
client.close;
|
||||
|
||||
// display returned content on console
|
||||
if (client.isResponseOK)
|
||||
Cout.stream.copy (input);
|
||||
else
|
||||
Cout ("failed to return the D home page");
|
||||
|
||||
// flush the console
|
||||
Cout.newline;
|
||||
}
|
||||
27
tango/example/networking/httpget.d
Normal file
27
tango/example/networking/httpget.d
Normal file
@@ -0,0 +1,27 @@
|
||||
private import tango.io.Console;
|
||||
|
||||
private import tango.net.http.HttpGet;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Read a page from a website, gathering the entire page before
|
||||
returning any content. This illustrates a high-level approach
|
||||
to retrieving web-content, whereas the homepage example shows
|
||||
a somewhat lower-level approach.
|
||||
|
||||
Note that this expects a fully qualified URL (with scheme),
|
||||
such as "http://www.digitalmars.com/d/intro.html"
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main (char[][] args)
|
||||
{
|
||||
char[] url = (args.length is 2) ? args[1] : "http://www.digitalmars.com/d/intro.html";
|
||||
|
||||
// open a web-page for reading (see HttpPost for writing)
|
||||
auto page = new HttpGet (url);
|
||||
|
||||
// retrieve and flush display content
|
||||
Cout (cast(char[]) page.read) ();
|
||||
}
|
||||
|
||||
399
tango/example/networking/selector.d
Normal file
399
tango/example/networking/selector.d
Normal file
@@ -0,0 +1,399 @@
|
||||
/*******************************************************************************
|
||||
copyright: Copyright (c) 2006 Juan Jose Comellas. All rights reserved
|
||||
license: BSD style: $(LICENSE)
|
||||
author: Juan Jose Comellas <juanjo@comellas.com.ar>
|
||||
*******************************************************************************/
|
||||
|
||||
private
|
||||
{
|
||||
version (Posix)
|
||||
{
|
||||
import tango.io.selector.PollSelector;
|
||||
}
|
||||
else version (linux)
|
||||
{
|
||||
import tango.io.selector.EpollSelector;
|
||||
import tango.sys.linux.linux;
|
||||
}
|
||||
|
||||
import tango.io.selector.model.ISelector;
|
||||
import tango.io.selector.Selector;
|
||||
import tango.io.selector.SelectSelector;
|
||||
import tango.io.selector.SelectorException;
|
||||
import tango.io.Conduit;
|
||||
import tango.net.Socket;
|
||||
import tango.net.SocketConduit;
|
||||
import tango.net.ServerSocket;
|
||||
import tango.time.Clock;
|
||||
import tango.util.log.Log;
|
||||
import tango.util.log.ConsoleAppender;
|
||||
import tango.util.log.DateLayout;
|
||||
import tango.text.convert.Sprint;
|
||||
import tango.core.Exception;
|
||||
import tango.core.Thread;
|
||||
import tango.sys.Common;
|
||||
import tango.stdc.errno;
|
||||
}
|
||||
|
||||
|
||||
const uint HANDLE_COUNT = 4;
|
||||
const uint EVENT_COUNT = 4;
|
||||
const uint LOOP_COUNT = 50000;
|
||||
const char[] SERVER_ADDR = "127.0.0.1";
|
||||
const ushort SERVER_PORT = 4000;
|
||||
const uint MAX_LENGTH = 16;
|
||||
|
||||
int main(char[][] args)
|
||||
{
|
||||
Logger log = Log.getLogger("selector");
|
||||
Sprint!(char) sprint = new Sprint!(char)(256);
|
||||
|
||||
log.addAppender(new ConsoleAppender(new DateLayout()));
|
||||
|
||||
ISelector selector;
|
||||
|
||||
for (int i = 0; i < 1; i++)
|
||||
{
|
||||
// Testing the SelectSelector
|
||||
log.info(sprint("Pass {0}: Testing the select-based selector", i + 1));
|
||||
selector = new SelectSelector();
|
||||
testSelector(selector);
|
||||
}
|
||||
|
||||
// Testing the PollSelector
|
||||
version (Posix)
|
||||
{
|
||||
for (int i = 0; i < 1; i++)
|
||||
{
|
||||
log.info(sprint("Pass {0}: Testing the poll-based selector", i + 1));
|
||||
selector = new PollSelector();
|
||||
testSelector(selector);
|
||||
}
|
||||
}
|
||||
|
||||
// Testing the EpollSelector
|
||||
version (linux)
|
||||
{
|
||||
for (int i = 0; i < 1; i++)
|
||||
{
|
||||
log.info(sprint("Pass {0}: Testing the epoll-based selector", i + 1));
|
||||
selector = new EpollSelector();
|
||||
testSelector(selector);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a server socket and run the Selector on it.
|
||||
*/
|
||||
void testSelector(ISelector selector)
|
||||
{
|
||||
Logger log = Log.getLogger("selector.server");
|
||||
Sprint!(char) sprint = new Sprint!(char)(512);
|
||||
|
||||
uint connectCount = 0;
|
||||
uint receiveCount = 0;
|
||||
uint sendCount = 0;
|
||||
uint failedConnectCount = 0;
|
||||
uint failedReceiveCount = 0;
|
||||
uint failedSendCount = 0;
|
||||
uint closeCount = 0;
|
||||
uint errorCount = 0;
|
||||
Time start = Clock.now;
|
||||
Thread clientThread;
|
||||
|
||||
selector.open(HANDLE_COUNT, EVENT_COUNT);
|
||||
|
||||
clientThread = new Thread(&clientThreadFunc);
|
||||
clientThread.start();
|
||||
|
||||
try
|
||||
{
|
||||
TimeSpan timeout = TimeSpan.seconds(1);
|
||||
InternetAddress addr = new InternetAddress(SERVER_ADDR, SERVER_PORT);
|
||||
ServerSocket serverSocket = new ServerSocket(addr, 5);
|
||||
SocketConduit clientSocket;
|
||||
char[MAX_LENGTH] buffer;
|
||||
int eventCount;
|
||||
uint count;
|
||||
int i = 0;
|
||||
|
||||
debug (selector)
|
||||
log.trace("Registering server socket to Selector");
|
||||
|
||||
selector.register(serverSocket, Event.Read);
|
||||
|
||||
while (true)
|
||||
{
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] Waiting for events from Selector", i));
|
||||
|
||||
eventCount = selector.select(timeout);
|
||||
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] {1} events received from Selector", i, eventCount));
|
||||
|
||||
if (eventCount > 0)
|
||||
{
|
||||
foreach (SelectionKey selectionKey; selector.selectedSet())
|
||||
{
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] Event mask for socket {1} is 0x{2:x4}",
|
||||
i, cast(int) selectionKey.conduit.fileHandle(),
|
||||
cast(uint) selectionKey.events));
|
||||
|
||||
if (selectionKey.isReadable())
|
||||
{
|
||||
if (selectionKey.conduit is serverSocket)
|
||||
{
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] New connection from client", i));
|
||||
|
||||
clientSocket = serverSocket.accept();
|
||||
if (clientSocket !is null)
|
||||
{
|
||||
selector.register(clientSocket, Event.Read);
|
||||
connectCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] New connection attempt failed", i));
|
||||
failedConnectCount++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reading from a client socket
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] Receiving message from client", i));
|
||||
|
||||
count = (cast(SocketConduit) selectionKey.conduit).read(buffer);
|
||||
if (count != IConduit.Eof)
|
||||
{
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] Received {1} from client ({2} bytes)",
|
||||
i, buffer[0..count], count));
|
||||
selector.reregister(selectionKey.conduit, Event.Write);
|
||||
receiveCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] Handle {1} was closed; removing it from Selector",
|
||||
i, cast(int) selectionKey.conduit.fileHandle()));
|
||||
selector.unregister(selectionKey.conduit);
|
||||
(cast(SocketConduit) selectionKey.conduit).close();
|
||||
failedReceiveCount++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (selectionKey.isWritable())
|
||||
{
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] Sending PONG to client", i));
|
||||
|
||||
count = (cast(SocketConduit) selectionKey.conduit).write("PONG");
|
||||
if (count != IConduit.Eof)
|
||||
{
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] Sent PONG to client ({1} bytes)", i, count));
|
||||
|
||||
selector.reregister(selectionKey.conduit, Event.Read);
|
||||
sendCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] Handle {1} was closed; removing it from Selector",
|
||||
i, selectionKey.conduit.fileHandle()));
|
||||
selector.unregister(selectionKey.conduit);
|
||||
(cast(SocketConduit) selectionKey.conduit).close();
|
||||
failedSendCount++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (selectionKey.isError() || selectionKey.isHangup() || selectionKey.isInvalidHandle())
|
||||
{
|
||||
char[] status;
|
||||
|
||||
if (selectionKey.isHangup())
|
||||
{
|
||||
closeCount++;
|
||||
status = "Hangup";
|
||||
}
|
||||
else
|
||||
{
|
||||
errorCount++;
|
||||
if (selectionKey.isInvalidHandle())
|
||||
status = "Invalid request";
|
||||
else
|
||||
status = "Error";
|
||||
}
|
||||
|
||||
debug (selector)
|
||||
{
|
||||
log.trace(sprint("[{0}] {1} in handle {2} from Selector",
|
||||
i, status, cast(int) selectionKey.conduit.fileHandle()));
|
||||
|
||||
log.trace(sprint("[{0}] Unregistering handle {1} from Selector",
|
||||
i, cast(int) selectionKey.conduit.fileHandle()));
|
||||
}
|
||||
selector.unregister(selectionKey.conduit);
|
||||
(cast(Conduit) selectionKey.conduit).close();
|
||||
|
||||
if (selectionKey.conduit !is serverSocket)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] No more pending events in Selector; aborting", i));
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
|
||||
// Thread.sleep(1.0);
|
||||
/*
|
||||
if (i % 100 == 0)
|
||||
{
|
||||
fullCollect();
|
||||
getStats(gc)
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
serverSocket.socket().detach;
|
||||
}
|
||||
catch (SelectorException e)
|
||||
{
|
||||
log.error(sprint("Selector exception caught:\n{0}", e.toString()));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.error(sprint("Exception caught:\n{0}", e.toString()));
|
||||
}
|
||||
|
||||
log.info(sprint("Success: connect={0}; recv={1}; send={2}; close={3}",
|
||||
connectCount, receiveCount, sendCount, closeCount));
|
||||
log.info(sprint("Failure: connect={0}, recv={1}; send={2}; error={3}",
|
||||
failedConnectCount, failedReceiveCount, failedSendCount, errorCount));
|
||||
|
||||
log.info(sprint("Total time: {0} ms", cast(uint) (Clock.now - start).millis));
|
||||
|
||||
clientThread.join();
|
||||
|
||||
selector.close;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Thread that creates a client socket and sends messages to the server socket.
|
||||
*/
|
||||
void clientThreadFunc()
|
||||
{
|
||||
Logger log = Log.getLogger("selector.client");
|
||||
Sprint!(char) sprint = new Sprint!(char)(256);
|
||||
SocketConduit socket = new SocketConduit();
|
||||
|
||||
Thread.sleep(0.010); // 10 milliseconds
|
||||
|
||||
try
|
||||
{
|
||||
InternetAddress addr = new InternetAddress(SERVER_ADDR, SERVER_PORT);
|
||||
char[MAX_LENGTH] buffer;
|
||||
uint count;
|
||||
int i;
|
||||
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] Connecting to server", i));
|
||||
|
||||
socket.connect(addr);
|
||||
|
||||
for (i = 1; i <= LOOP_COUNT; i++)
|
||||
{
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] Sending PING to server", i));
|
||||
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
count = socket.write("PING");
|
||||
break;
|
||||
}
|
||||
catch (SocketException e)
|
||||
{
|
||||
if (errno != EINTR)
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
if (count != IConduit.Eof)
|
||||
{
|
||||
debug (selector)
|
||||
{
|
||||
log.trace(sprint("[{0}] Sent PING to server ({1} bytes)", i, count));
|
||||
|
||||
log.trace(sprint("[{0}] Receiving message from server", i));
|
||||
}
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
count = socket.read(buffer);
|
||||
break;
|
||||
}
|
||||
catch (SocketException e)
|
||||
{
|
||||
if (errno != EINTR)
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
if (count != IConduit.Eof)
|
||||
{
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] Received {1} from server ({2} bytes)",
|
||||
i, buffer[0..count], count));
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] Handle was closed; aborting",
|
||||
i, socket.fileHandle()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] Handle {1} was closed; aborting",
|
||||
i, socket.fileHandle()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
socket.shutdown();
|
||||
socket.close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.error(sprint("Exception caught:\n{0}", e.toString()));
|
||||
}
|
||||
debug (selector)
|
||||
log.trace("Leaving thread");
|
||||
|
||||
return 0;
|
||||
}
|
||||
29
tango/example/networking/sockethello.d
Normal file
29
tango/example/networking/sockethello.d
Normal file
@@ -0,0 +1,29 @@
|
||||
/*******************************************************************************
|
||||
|
||||
Shows how to create a basic socket client, and how to converse with
|
||||
a remote server. The server must be running for this to succeed
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
private import tango.io.Console;
|
||||
|
||||
private import tango.net.SocketConduit,
|
||||
tango.net.InternetAddress;
|
||||
|
||||
void main()
|
||||
{
|
||||
// make a connection request to the server
|
||||
auto request = new SocketConduit;
|
||||
request.connect (new InternetAddress ("localhost", 8080));
|
||||
request.output.write ("hello\n");
|
||||
|
||||
// wait for response (there is an optional timeout supported)
|
||||
char[64] response;
|
||||
auto size = request.input.read (response);
|
||||
|
||||
// close socket
|
||||
request.close;
|
||||
|
||||
// display server response
|
||||
Cout (response[0..size]).newline;
|
||||
}
|
||||
53
tango/example/networking/socketserver.d
Normal file
53
tango/example/networking/socketserver.d
Normal file
@@ -0,0 +1,53 @@
|
||||
/*******************************************************************************
|
||||
|
||||
Shows how to create a basic socket server, and how to talk to
|
||||
it from a socket client. Note that both the server and client
|
||||
are entirely simplistic, and therefore this is for illustration
|
||||
purposes only. See HttpServer for something more robust.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
private import tango.core.Thread;
|
||||
|
||||
private import tango.io.Console;
|
||||
|
||||
private import tango.net.ServerSocket,
|
||||
tango.net.SocketConduit;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Create a socket server, and have it respond to a request
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main()
|
||||
{
|
||||
const int port = 8080;
|
||||
|
||||
// thread body for socket-listener
|
||||
void run()
|
||||
{
|
||||
auto server = new ServerSocket (new InternetAddress(port));
|
||||
|
||||
// wait for requests
|
||||
auto request = server.accept;
|
||||
|
||||
// write a response
|
||||
request.output.write ("server replies 'hello'");
|
||||
}
|
||||
|
||||
// start server in a separate thread, and wait for it to start
|
||||
(new Thread (&run)).start;
|
||||
Thread.sleep (0.250);
|
||||
|
||||
// make a connection request to the server
|
||||
auto request = new SocketConduit;
|
||||
request.connect (new InternetAddress("localhost", port));
|
||||
|
||||
// wait for and display response (there is an optional timeout)
|
||||
char[64] response;
|
||||
auto len = request.input.read (response);
|
||||
Cout (response[0..len]).newline;
|
||||
|
||||
request.close;
|
||||
}
|
||||
138
tango/example/synchronization/barrier.d
Normal file
138
tango/example/synchronization/barrier.d
Normal file
@@ -0,0 +1,138 @@
|
||||
/*******************************************************************************
|
||||
copyright: Copyright (c) 2006 Juan Jose Comellas. All rights reserved
|
||||
license: BSD style: $(LICENSE)
|
||||
author: Juan Jose Comellas <juanjo@comellas.com.ar>
|
||||
Converted to use core.sync by Sean Kelly <sean@f4.ca>
|
||||
*******************************************************************************/
|
||||
|
||||
private import tango.core.sync.Barrier;
|
||||
private import tango.core.sync.Mutex;
|
||||
private import tango.core.Exception;
|
||||
private import tango.core.Thread;
|
||||
private import tango.io.Stdout;
|
||||
private import tango.text.convert.Integer;
|
||||
debug (barrier)
|
||||
{
|
||||
private import tango.util.log.Log;
|
||||
private import tango.util.log.ConsoleAppender;
|
||||
private import tango.util.log.DateLayout;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Example program for the tango.core.sync.Barrier module.
|
||||
*/
|
||||
void main(char[][] args)
|
||||
{
|
||||
const uint MaxThreadCount = 100;
|
||||
const uint LoopsPerThread = 10000;
|
||||
|
||||
debug (barrier)
|
||||
{
|
||||
Logger log = Log.getLogger("barrier");
|
||||
|
||||
log.addAppender(new ConsoleAppender(new DateLayout()));
|
||||
|
||||
log.info("Barrier test");
|
||||
}
|
||||
|
||||
Barrier barrier = new Barrier(MaxThreadCount);
|
||||
Mutex mutex = new Mutex();
|
||||
uint count = 0;
|
||||
uint correctCount = 0;
|
||||
|
||||
void barrierTestThread()
|
||||
{
|
||||
debug (barrier)
|
||||
{
|
||||
Logger log = Log.getLogger("barrier." ~ Thread.getThis().name());
|
||||
|
||||
log.trace("Starting thread");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
for (uint i; i < LoopsPerThread; ++i)
|
||||
{
|
||||
// 'count' is a resource shared by multiple threads, so we must
|
||||
// acquire the mutex before modifying it.
|
||||
synchronized (mutex)
|
||||
{
|
||||
// debug (barrier)
|
||||
// log.trace("Acquired mutex");
|
||||
count++;
|
||||
// debug (barrier)
|
||||
// log.trace("Releasing mutex");
|
||||
}
|
||||
}
|
||||
|
||||
// We wait for all the threads to finish counting.
|
||||
debug (barrier)
|
||||
log.trace("Waiting on barrier");
|
||||
barrier.wait();
|
||||
debug (barrier)
|
||||
log.trace("Barrier was opened");
|
||||
|
||||
// We make sure that all the threads exited the barrier after
|
||||
// *all* of them had finished counting.
|
||||
synchronized (mutex)
|
||||
{
|
||||
// debug (barrier)
|
||||
// log.trace("Acquired mutex");
|
||||
if (count == MaxThreadCount * LoopsPerThread)
|
||||
{
|
||||
++correctCount;
|
||||
}
|
||||
// debug (barrier)
|
||||
// log.trace("Releasing mutex");
|
||||
}
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Stderr.formatln("Sync exception caught in Barrier test thread {0}:\n{1}\n",
|
||||
Thread.getThis().name, e.toString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Stderr.formatln("Unexpected exception caught in Barrier test thread {0}:\n{1}\n",
|
||||
Thread.getThis().name, e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
ThreadGroup group = new ThreadGroup();
|
||||
Thread thread;
|
||||
char[10] tmp;
|
||||
|
||||
for (uint i = 0; i < MaxThreadCount; ++i)
|
||||
{
|
||||
thread = new Thread(&barrierTestThread);
|
||||
thread.name = "thread-" ~ format(tmp, i);
|
||||
|
||||
group.add(thread);
|
||||
debug (barrier)
|
||||
log.trace("Created thread " ~ thread.name);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
debug (barrier)
|
||||
log.trace("Waiting for threads to finish");
|
||||
group.joinAll();
|
||||
|
||||
if (count == MaxThreadCount * LoopsPerThread)
|
||||
{
|
||||
debug (barrier)
|
||||
log.info("The Barrier test was successful");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (barrier)
|
||||
{
|
||||
log.error("The Barrier is not working properly: the counter has an incorrect value");
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false, "The Barrier is not working properly: the counter has an incorrect value");
|
||||
}
|
||||
}
|
||||
}
|
||||
307
tango/example/synchronization/condition.d
Normal file
307
tango/example/synchronization/condition.d
Normal file
@@ -0,0 +1,307 @@
|
||||
/*******************************************************************************
|
||||
copyright: Copyright (c) 2006 Juan Jose Comellas. All rights reserved
|
||||
license: BSD style: $(LICENSE)
|
||||
author: Juan Jose Comellas <juanjo@comellas.com.ar>
|
||||
Converted to use core.sync by Sean Kelly <sean@f4.ca>
|
||||
*******************************************************************************/
|
||||
|
||||
private import tango.core.sync.Condition;
|
||||
private import tango.core.Exception;
|
||||
private import tango.core.Thread;
|
||||
private import tango.text.convert.Integer;
|
||||
private import tango.io.Stdout;
|
||||
debug (condition)
|
||||
{
|
||||
private import tango.util.log.Log;
|
||||
private import tango.util.log.ConsoleAppender;
|
||||
private import tango.util.log.DateLayout;
|
||||
}
|
||||
|
||||
|
||||
void main(char[][] args)
|
||||
{
|
||||
debug (condition)
|
||||
{
|
||||
Logger log = Log.getLogger("condition");
|
||||
|
||||
log.addAppender(new ConsoleAppender(new DateLayout()));
|
||||
|
||||
log.info("Condition test");
|
||||
}
|
||||
|
||||
testNotifyOne();
|
||||
testNotifyAll();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test for Condition.notify().
|
||||
*/
|
||||
void testNotifyOne()
|
||||
{
|
||||
debug (condition)
|
||||
{
|
||||
Logger log = Log.getLogger("condition.notify-one");
|
||||
}
|
||||
|
||||
scope Mutex mutex = new Mutex();
|
||||
scope Condition cond = new Condition(mutex);
|
||||
int waiting = 0;
|
||||
Thread thread;
|
||||
|
||||
void notifyOneTestThread()
|
||||
{
|
||||
debug (condition)
|
||||
{
|
||||
Logger log = Log.getLogger("condition.notify-one." ~ Thread.getThis().name());
|
||||
|
||||
log.trace("Starting thread");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
synchronized (mutex)
|
||||
{
|
||||
debug (condition)
|
||||
log.trace("Acquired mutex");
|
||||
|
||||
scope(exit)
|
||||
{
|
||||
debug (condition)
|
||||
log.trace("Releasing mutex");
|
||||
}
|
||||
|
||||
waiting++;
|
||||
|
||||
while (waiting != 2)
|
||||
{
|
||||
debug (condition)
|
||||
log.trace("Waiting on condition variable");
|
||||
cond.wait();
|
||||
}
|
||||
|
||||
debug (condition)
|
||||
log.trace("Condition variable was signaled");
|
||||
}
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Stderr.formatln("Sync exception caught in Condition test thread {0}:\n{1}",
|
||||
Thread.getThis().name(), e.toString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Stderr.formatln("Unexpected exception caught in Condition test thread {0}:\n{1}",
|
||||
Thread.getThis().name(), e.toString());
|
||||
}
|
||||
debug (condition)
|
||||
log.trace("Exiting thread");
|
||||
}
|
||||
|
||||
thread = new Thread(¬ifyOneTestThread);
|
||||
thread.name = "thread-1";
|
||||
|
||||
debug (condition)
|
||||
log.trace("Created thread " ~ thread.name);
|
||||
thread.start();
|
||||
|
||||
try
|
||||
{
|
||||
// Poor man's barrier: wait until the other thread is waiting.
|
||||
while (true)
|
||||
{
|
||||
synchronized (mutex)
|
||||
{
|
||||
if (waiting != 1)
|
||||
{
|
||||
Thread.yield();
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (mutex)
|
||||
{
|
||||
debug (condition)
|
||||
log.trace("Acquired mutex");
|
||||
|
||||
waiting++;
|
||||
|
||||
debug (condition)
|
||||
log.trace("Notifying test thread");
|
||||
cond.notify();
|
||||
|
||||
debug (condition)
|
||||
log.trace("Releasing mutex");
|
||||
}
|
||||
|
||||
thread.join();
|
||||
|
||||
if (waiting == 2)
|
||||
{
|
||||
debug (condition)
|
||||
log.info("The Condition notification test to one thread was successful");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (condition)
|
||||
{
|
||||
log.error("The condition variable notification to one thread is not working");
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false, "The condition variable notification to one thread is not working");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Stderr.formatln("Sync exception caught in main thread:\n{0}", e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test for Condition.notifyAll().
|
||||
*/
|
||||
void testNotifyAll()
|
||||
{
|
||||
const uint MaxThreadCount = 10;
|
||||
|
||||
debug (condition)
|
||||
{
|
||||
Logger log = Log.getLogger("condition.notify-all");
|
||||
}
|
||||
|
||||
scope Mutex mutex = new Mutex();
|
||||
scope Condition cond = new Condition(mutex);
|
||||
int waiting = 0;
|
||||
|
||||
/**
|
||||
* This thread waits for a notification from the main thread.
|
||||
*/
|
||||
void notifyAllTestThread()
|
||||
{
|
||||
debug (condition)
|
||||
{
|
||||
Logger log = Log.getLogger("condition.notify-all." ~ Thread.getThis().name());
|
||||
|
||||
log.trace("Starting thread");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
synchronized (mutex)
|
||||
{
|
||||
debug (condition)
|
||||
log.trace("Acquired mutex");
|
||||
|
||||
waiting++;
|
||||
|
||||
while (waiting != MaxThreadCount + 1)
|
||||
{
|
||||
debug (condition)
|
||||
log.trace("Waiting on condition variable");
|
||||
cond.wait();
|
||||
}
|
||||
|
||||
debug (condition)
|
||||
log.trace("Condition variable was signaled");
|
||||
|
||||
debug (condition)
|
||||
log.trace("Releasing mutex");
|
||||
}
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Stderr.formatln("Sync exception caught in Condition test thread {0}:\n{1}",
|
||||
Thread.getThis().name(), e.toString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Stderr.formatln("Unexpected exception caught in Condition test thread {0}:\n{1}",
|
||||
Thread.getThis().name(), e.toString());
|
||||
}
|
||||
debug (condition)
|
||||
log.trace("Exiting thread");
|
||||
}
|
||||
|
||||
ThreadGroup group = new ThreadGroup();
|
||||
Thread thread;
|
||||
char[10] tmp;
|
||||
|
||||
for (uint i = 0; i < MaxThreadCount; ++i)
|
||||
{
|
||||
thread = new Thread(¬ifyAllTestThread);
|
||||
thread.name = "thread-" ~ format(tmp, i);
|
||||
|
||||
group.add(thread);
|
||||
debug (condition)
|
||||
log.trace("Created thread " ~ thread.name);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Poor man's barrier: wait until all the threads are waiting.
|
||||
while (true)
|
||||
{
|
||||
synchronized (mutex)
|
||||
{
|
||||
if (waiting != MaxThreadCount)
|
||||
{
|
||||
Thread.yield();
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (mutex)
|
||||
{
|
||||
debug (condition)
|
||||
log.trace("Acquired mutex");
|
||||
|
||||
waiting++;
|
||||
|
||||
debug (condition)
|
||||
log.trace("Notifying all threads");
|
||||
cond.notifyAll();
|
||||
|
||||
debug (condition)
|
||||
log.trace("Releasing mutex");
|
||||
}
|
||||
|
||||
debug (condition)
|
||||
log.trace("Waiting for threads to finish");
|
||||
group.joinAll();
|
||||
|
||||
if (waiting == MaxThreadCount + 1)
|
||||
{
|
||||
debug (condition)
|
||||
log.info("The Condition notification test to many threads was successful");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (condition)
|
||||
{
|
||||
log.error("The condition variable notification to many threads is not working");
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false, "The condition variable notification to many threads is not working");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Stderr.formatln("Sync exception caught in main thread:\n{0}", e.toString());
|
||||
}
|
||||
}
|
||||
248
tango/example/synchronization/mutex.d
Normal file
248
tango/example/synchronization/mutex.d
Normal file
@@ -0,0 +1,248 @@
|
||||
/*******************************************************************************
|
||||
copyright: Copyright (c) 2006 Juan Jose Comellas. All rights reserved
|
||||
license: BSD style: $(LICENSE)
|
||||
author: Juan Jose Comellas <juanjo@comellas.com.ar>
|
||||
Converted to use core.sync by Sean Kelly <sean@f4.ca>
|
||||
*******************************************************************************/
|
||||
|
||||
private import tango.core.sync.Mutex;
|
||||
private import tango.core.Exception;
|
||||
private import tango.core.Thread;
|
||||
private import tango.io.Stdout;
|
||||
private import tango.text.convert.Integer;
|
||||
debug (mutex)
|
||||
{
|
||||
private import tango.util.log.Log;
|
||||
private import tango.util.log.ConsoleAppender;
|
||||
private import tango.util.log.DateLayout;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Example program for the tango.core.sync.Mutex module.
|
||||
*/
|
||||
void main(char[][] args)
|
||||
{
|
||||
debug (mutex)
|
||||
{
|
||||
Logger log = Log.getLogger("mutex");
|
||||
|
||||
log.addAppender(new ConsoleAppender(new DateLayout()));
|
||||
|
||||
log.info("Mutex test");
|
||||
}
|
||||
|
||||
testNonRecursive();
|
||||
testLocking();
|
||||
testRecursive();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that non-recursive mutexes actually do what they're supposed to do.
|
||||
*
|
||||
* Remarks:
|
||||
* Windows only supports recursive mutexes.
|
||||
*/
|
||||
void testNonRecursive()
|
||||
{
|
||||
version (Posix)
|
||||
{
|
||||
debug (mutex)
|
||||
{
|
||||
Logger log = Log.getLogger("mutex.non-recursive");
|
||||
}
|
||||
|
||||
Mutex mutex = new Mutex(Mutex.Type.NonRecursive);
|
||||
bool couldLock;
|
||||
|
||||
try
|
||||
{
|
||||
mutex.lock();
|
||||
debug (mutex)
|
||||
log.trace("Acquired mutex");
|
||||
couldLock = mutex.tryLock();
|
||||
if (couldLock)
|
||||
{
|
||||
debug (mutex)
|
||||
{
|
||||
log.trace("Re-acquired mutex");
|
||||
log.trace("Releasing mutex");
|
||||
}
|
||||
mutex.unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (mutex)
|
||||
log.trace("Re-acquiring the mutex failed");
|
||||
}
|
||||
debug (mutex)
|
||||
log.trace("Releasing mutex");
|
||||
mutex.unlock();
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Stderr.formatln("Sync exception caught when testing non-recursive mutexes:\n{0}\n", e.toString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Stderr.formatln("Unexpected exception caught when testing non-recursive mutexes:\n{0}\n", e.toString());
|
||||
}
|
||||
|
||||
if (!couldLock)
|
||||
{
|
||||
debug (mutex)
|
||||
log.info("The non-recursive Mutex test was successful");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (mutex)
|
||||
{
|
||||
log.error("Non-recursive mutexes are not working: "
|
||||
"Mutex.tryAcquire() did not fail on an already acquired mutex");
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false, "Non-recursive mutexes are not working: "
|
||||
"Mutex.tryAcquire() did not fail on an already acquired mutex");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create several threads that acquire and release a mutex several times.
|
||||
*/
|
||||
void testLocking()
|
||||
{
|
||||
const uint MaxThreadCount = 10;
|
||||
const uint LoopsPerThread = 1000;
|
||||
|
||||
debug (mutex)
|
||||
{
|
||||
Logger log = Log.getLogger("mutex.locking");
|
||||
}
|
||||
|
||||
Mutex mutex = new Mutex();
|
||||
uint lockCount = 0;
|
||||
|
||||
void mutexLockingThread()
|
||||
{
|
||||
try
|
||||
{
|
||||
for (uint i; i < LoopsPerThread; i++)
|
||||
{
|
||||
synchronized (mutex)
|
||||
{
|
||||
lockCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Stderr.formatln("Sync exception caught inside mutex testing thread:\n{0}\n", e.toString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Stderr.formatln("Unexpected exception caught inside mutex testing thread:\n{0}\n", e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
ThreadGroup group = new ThreadGroup();
|
||||
Thread thread;
|
||||
char[10] tmp;
|
||||
|
||||
for (uint i = 0; i < MaxThreadCount; i++)
|
||||
{
|
||||
thread = new Thread(&mutexLockingThread);
|
||||
thread.name = "thread-" ~ format(tmp, i);
|
||||
|
||||
debug (mutex)
|
||||
log.trace("Created thread " ~ thread.name);
|
||||
thread.start();
|
||||
|
||||
group.add(thread);
|
||||
}
|
||||
|
||||
debug (mutex)
|
||||
log.trace("Waiting for threads to finish");
|
||||
group.joinAll();
|
||||
|
||||
if (lockCount == MaxThreadCount * LoopsPerThread)
|
||||
{
|
||||
debug (mutex)
|
||||
log.info("The Mutex locking test was successful");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (mutex)
|
||||
{
|
||||
log.error("Mutex locking is not working properly: "
|
||||
"the number of times the mutex was acquired is incorrect");
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false,"Mutex locking is not working properly: "
|
||||
"the number of times the mutex was acquired is incorrect");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that recursive mutexes actually do what they're supposed to do.
|
||||
*/
|
||||
void testRecursive()
|
||||
{
|
||||
const uint LoopsPerThread = 1000;
|
||||
|
||||
debug (mutex)
|
||||
{
|
||||
Logger log = Log.getLogger("mutex.recursive");
|
||||
}
|
||||
|
||||
Mutex mutex = new Mutex;
|
||||
uint lockCount = 0;
|
||||
|
||||
try
|
||||
{
|
||||
for (uint i = 0; i < LoopsPerThread; i++)
|
||||
{
|
||||
mutex.lock();
|
||||
lockCount++;
|
||||
}
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Stderr.formatln("Sync exception caught in recursive mutex test:\n{0}\n", e.toString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Stderr.formatln("Unexpected exception caught in recursive mutex test:\n{0}\n", e.toString());
|
||||
}
|
||||
|
||||
for (uint i = 0; i < lockCount; i++)
|
||||
{
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
if (lockCount == LoopsPerThread)
|
||||
{
|
||||
debug (mutex)
|
||||
log.info("The recursive Mutex test was successful");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (mutex)
|
||||
{
|
||||
log.error("Recursive mutexes are not working: "
|
||||
"the number of times the mutex was acquired is incorrect");
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false, "Recursive mutexes are not working: "
|
||||
"the number of times the mutex was acquired is incorrect");
|
||||
}
|
||||
}
|
||||
}
|
||||
145
tango/example/synchronization/readwritemutex.d
Normal file
145
tango/example/synchronization/readwritemutex.d
Normal file
@@ -0,0 +1,145 @@
|
||||
/*******************************************************************************
|
||||
copyright: Copyright (c) 2006 Juan Jose Comellas. All rights reserved
|
||||
license: BSD style: $(LICENSE)
|
||||
author: Juan Jose Comellas <juanjo@comellas.com.ar>
|
||||
Converted to use core.sync by Sean Kelly <sean@f4.ca>
|
||||
*******************************************************************************/
|
||||
|
||||
private import tango.core.sync.ReadWriteMutex;
|
||||
private import tango.core.sync.Mutex;
|
||||
private import tango.core.Thread;
|
||||
private import tango.text.convert.Integer;
|
||||
debug (readwritemutex)
|
||||
{
|
||||
private import tango.util.log.Log;
|
||||
private import tango.util.log.ConsoleAppender;
|
||||
private import tango.util.log.DateLayout;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Example program for the tango.core.sync.ReadWriteMutex module.
|
||||
*/
|
||||
void main(char[][] args)
|
||||
{
|
||||
const uint ReaderThreads = 100;
|
||||
const uint WriterThreads = 20;
|
||||
const uint LoopsPerReader = 10000;
|
||||
const uint LoopsPerWriter = 1000;
|
||||
const uint CounterIncrement = 3;
|
||||
|
||||
debug (readwritemutex)
|
||||
{
|
||||
Logger log = Log.getLogger("readwritemutex");
|
||||
|
||||
log.addAppender(new ConsoleAppender(new DateLayout()));
|
||||
|
||||
log.info("ReadWriteMutex test");
|
||||
}
|
||||
|
||||
ReadWriteMutex rwlock = new ReadWriteMutex();
|
||||
Mutex mutex = new Mutex();
|
||||
uint readCount = 0;
|
||||
uint passed = 0;
|
||||
uint failed = 0;
|
||||
|
||||
void mutexReaderThread()
|
||||
{
|
||||
debug (readwritemutex)
|
||||
{
|
||||
Logger log = Log.getLogger("readwritemutex." ~ Thread.getThis().name());
|
||||
|
||||
log.trace("Starting reader thread");
|
||||
}
|
||||
|
||||
for (uint i = 0; i < LoopsPerReader; ++i)
|
||||
{
|
||||
// All the reader threads acquire the mutex for reading and when they are
|
||||
// all done
|
||||
synchronized (rwlock.reader)
|
||||
{
|
||||
for (uint j = 0; j < CounterIncrement; ++j)
|
||||
{
|
||||
synchronized (mutex)
|
||||
{
|
||||
++readCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mutexWriterThread()
|
||||
{
|
||||
debug (readwritemutex)
|
||||
{
|
||||
Logger log = Log.getLogger("readwritemutex." ~ Thread.getThis().name());
|
||||
|
||||
log.trace("Starting writer thread");
|
||||
}
|
||||
|
||||
for (uint i = 0; i < LoopsPerWriter; ++i)
|
||||
{
|
||||
synchronized (rwlock.writer)
|
||||
{
|
||||
synchronized (mutex)
|
||||
{
|
||||
if (readCount % 3 == 0)
|
||||
{
|
||||
++passed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ThreadGroup group = new ThreadGroup();
|
||||
Thread thread;
|
||||
char[10] tmp;
|
||||
|
||||
for (uint i = 0; i < ReaderThreads; ++i)
|
||||
{
|
||||
thread = new Thread(&mutexReaderThread);
|
||||
thread.name = "reader-" ~ format(tmp, i);
|
||||
|
||||
debug (readwritemutex)
|
||||
log.trace("Created reader thread " ~ thread.name);
|
||||
thread.start();
|
||||
|
||||
group.add(thread);
|
||||
}
|
||||
|
||||
for (uint i = 0; i < WriterThreads; ++i)
|
||||
{
|
||||
thread = new Thread(&mutexWriterThread);
|
||||
thread.name = "writer-" ~ format(tmp, i);
|
||||
|
||||
debug (readwritemutex)
|
||||
log.trace("Created writer thread " ~ thread.name);
|
||||
thread.start();
|
||||
|
||||
group.add(thread);
|
||||
}
|
||||
|
||||
debug (readwritemutex)
|
||||
log.trace("Waiting for threads to finish");
|
||||
group.joinAll();
|
||||
|
||||
if (passed == WriterThreads * LoopsPerWriter)
|
||||
{
|
||||
debug (readwritemutex)
|
||||
log.info("The ReadWriteMutex test was successful");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (readwritemutex)
|
||||
{
|
||||
log.error("The ReadWriteMutex is not working properly: the counter has an incorrect value");
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false, "The ReadWriteMutex is not working properly: the counter has an incorrect value");
|
||||
}
|
||||
}
|
||||
}
|
||||
340
tango/example/synchronization/semaphore.d
Normal file
340
tango/example/synchronization/semaphore.d
Normal file
@@ -0,0 +1,340 @@
|
||||
/*******************************************************************************
|
||||
copyright: Copyright (c) 2007 Juan Jose Comellas. All rights reserved
|
||||
license: BSD style: $(LICENSE)
|
||||
author: Juan Jose Comellas <juanjo@comellas.com.ar>
|
||||
Converted to use core.sync by Sean Kelly <sean@f4.ca>
|
||||
*******************************************************************************/
|
||||
|
||||
module semaphore;
|
||||
|
||||
private import tango.core.sync.Semaphore;
|
||||
private import tango.core.sync.Mutex;
|
||||
private import tango.core.Exception;
|
||||
private import tango.core.Exception;
|
||||
private import tango.core.Thread;
|
||||
private import tango.io.Console;
|
||||
private import tango.text.stream.LineIterator;
|
||||
private import tango.text.convert.Integer;
|
||||
private import tango.sys.Process;
|
||||
|
||||
debug (semaphore)
|
||||
{
|
||||
private import tango.util.log.Log;
|
||||
private import tango.util.log.ConsoleAppender;
|
||||
private import tango.util.log.DateLayout;
|
||||
}
|
||||
|
||||
const char[] SemaphoreName = "TestProcessSemaphore";
|
||||
|
||||
|
||||
/**
|
||||
* Example program for the tango.core.sync.Barrier module.
|
||||
*/
|
||||
int main(char[][] args)
|
||||
{
|
||||
if (args.length == 1)
|
||||
{
|
||||
debug (semaphore)
|
||||
{
|
||||
Logger log = Log.getLogger("semaphore");
|
||||
|
||||
log.addAppender(new ConsoleAppender(new DateLayout()));
|
||||
|
||||
log.info("Semaphore test");
|
||||
}
|
||||
|
||||
testSemaphore();
|
||||
testProcessSemaphore(args[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return testSecondProcessSemaphore();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for single-process (multi-threaded) semaphores.
|
||||
*/
|
||||
void testSemaphore()
|
||||
{
|
||||
const uint MaxThreadCount = 10;
|
||||
|
||||
// Semaphore used in the tests. Start it "locked" (i.e., its initial
|
||||
// count is 0).
|
||||
Semaphore sem = new Semaphore(MaxThreadCount - 1);
|
||||
Mutex mutex = new Mutex();
|
||||
uint count = 0;
|
||||
bool passed = false;
|
||||
|
||||
void semaphoreTestThread()
|
||||
{
|
||||
debug (semaphore)
|
||||
{
|
||||
Logger log = Log.getLogger("semaphore.single." ~ Thread.getThis().name());
|
||||
|
||||
log.trace("Starting thread");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
uint threadNumber;
|
||||
|
||||
// 'count' is a resource shared by multiple threads, so we must
|
||||
// acquire the mutex before modifying it.
|
||||
synchronized (mutex)
|
||||
{
|
||||
// debug (semaphore)
|
||||
// log.trace("Acquired mutex");
|
||||
threadNumber = ++count;
|
||||
// debug (semaphore)
|
||||
// log.trace("Releasing mutex");
|
||||
}
|
||||
|
||||
// We wait for all the threads to finish counting.
|
||||
if (threadNumber < MaxThreadCount)
|
||||
{
|
||||
sem.wait();
|
||||
debug (semaphore)
|
||||
log.trace("Acquired semaphore");
|
||||
|
||||
while (true)
|
||||
{
|
||||
synchronized (mutex)
|
||||
{
|
||||
if (count >= MaxThreadCount + 1)
|
||||
break;
|
||||
}
|
||||
Thread.yield();
|
||||
}
|
||||
|
||||
debug (semaphore)
|
||||
log.trace("Releasing semaphore");
|
||||
sem.notify();
|
||||
}
|
||||
else
|
||||
{
|
||||
passed = !sem.tryWait();
|
||||
if (passed)
|
||||
{
|
||||
debug (semaphore)
|
||||
log.trace("Tried to acquire the semaphore too many times and failed: OK");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (semaphore)
|
||||
log.error("Tried to acquire the semaphore too may times and succeeded: FAILED");
|
||||
|
||||
debug (semaphore)
|
||||
log.trace("Releasing semaphore");
|
||||
sem.notify();
|
||||
}
|
||||
synchronized (mutex)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Cerr("Sync exception caught in Semaphore test thread " ~ Thread.getThis().name ~
|
||||
":\n" ~ e.toString()).newline;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Cerr("Unexpected exception caught in Semaphore test thread " ~ Thread.getThis().name ~
|
||||
":\n" ~ e.toString()).newline;
|
||||
}
|
||||
}
|
||||
|
||||
debug (semaphore)
|
||||
{
|
||||
Logger log = Log.getLogger("semaphore.single");
|
||||
}
|
||||
|
||||
ThreadGroup group = new ThreadGroup();
|
||||
Thread thread;
|
||||
char[10] tmp;
|
||||
|
||||
for (uint i = 0; i < MaxThreadCount; ++i)
|
||||
{
|
||||
thread = new Thread(&semaphoreTestThread);
|
||||
thread.name = "thread-" ~ tango.text.convert.Integer.format(tmp, i);
|
||||
|
||||
group.add(thread);
|
||||
debug (semaphore)
|
||||
log.trace("Created thread " ~ thread.name);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
debug (semaphore)
|
||||
log.trace("Waiting for threads to finish");
|
||||
group.joinAll();
|
||||
|
||||
if (passed)
|
||||
{
|
||||
debug (semaphore)
|
||||
log.info("The Semaphore test was successful");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (semaphore)
|
||||
{
|
||||
log.error("The Semaphore is not working properly: it allowed "
|
||||
"to be acquired more than it should have done");
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false, "The Semaphore is not working properly: it allowed "
|
||||
"to be acquired more than it should have done");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for multi-process semaphores: this test works by creating a copy of
|
||||
* this process that tries to acquire the ProcessSemaphore that was created
|
||||
* in this function. If everything works as expected, the attempt should fail,
|
||||
* as the count of the semaphore is set to 1.
|
||||
*/
|
||||
void testProcessSemaphore(char[] programName)
|
||||
{
|
||||
/+
|
||||
bool success = false;
|
||||
|
||||
debug (semaphore)
|
||||
{
|
||||
Logger log = Log.getLogger("semaphore.multi");
|
||||
Logger childLog = Log.getLogger("semaphore.multi.child");
|
||||
|
||||
log.info("ProcessSemaphore test");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
scope ProcessSemaphore sem = new ProcessSemaphore(SemaphoreName, 1);
|
||||
Process proc = new Process(programName, "2");
|
||||
|
||||
debug (semaphore)
|
||||
log.trace("Created ProcessSemaphore('" ~ SemaphoreName ~ "')'");
|
||||
|
||||
sem.wait();
|
||||
debug (semaphore)
|
||||
log.trace("Acquired semaphore in main process");
|
||||
|
||||
debug (semaphore)
|
||||
log.trace("Executing child test process: " ~ proc.toString());
|
||||
proc.execute();
|
||||
|
||||
debug (semaphore)
|
||||
{
|
||||
foreach (line; new LineIterator!(char)(proc.stdout))
|
||||
{
|
||||
childLog.trace(line);
|
||||
}
|
||||
}
|
||||
foreach (line; new LineIterator!(char)(proc.stderr))
|
||||
{
|
||||
Cerr(line).newline;
|
||||
}
|
||||
|
||||
debug (semaphore)
|
||||
log.trace("Waiting for child process to finish");
|
||||
auto result = proc.wait();
|
||||
|
||||
success = (result.reason == Process.Result.Exit && result.status == 2);
|
||||
|
||||
debug (semaphore)
|
||||
log.trace("Releasing semaphore in main process");
|
||||
sem.notify();
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Cerr("Sync exception caught in ProcessSemaphore main test process:\n" ~ e.toString()).newline;
|
||||
}
|
||||
catch (ProcessException e)
|
||||
{
|
||||
Cerr("Process exception caught in ProcessSemaphore main test process:\n" ~ e.toString()).newline;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Cerr("Unexpected exception caught in ProcessSemaphore main test process:\n" ~ e.toString()).newline;
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
debug (semaphore)
|
||||
log.info("The ProcessSemaphore test was successful");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (semaphore)
|
||||
{
|
||||
log.error("The multi-process semaphore is not working");
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false, "The multi-process semaphore is not working");
|
||||
}
|
||||
}
|
||||
+/
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for multi-process semaphores (second process).
|
||||
*/
|
||||
int testSecondProcessSemaphore()
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
/+
|
||||
debug (semaphore)
|
||||
{
|
||||
Cout("Starting child process\n");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
scope ProcessSemaphore sem = new ProcessSemaphore(SemaphoreName);
|
||||
bool success;
|
||||
|
||||
success = !sem.tryAcquire();
|
||||
if (success)
|
||||
{
|
||||
debug (semaphore)
|
||||
Cout("Tried to acquire semaphore in child process and failed: OK\n");
|
||||
rc = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (semaphore)
|
||||
{
|
||||
Cout("Acquired semaphore in child process: this should not have happened\n");
|
||||
Cout("Releasing semaphore in child process\n");
|
||||
}
|
||||
sem.notify();
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Cerr("Sync exception caught in ProcessSemaphore child test process:\n" ~ e.toString()).newline;
|
||||
}
|
||||
catch (ProcessException e)
|
||||
{
|
||||
Cerr("Process exception caught in ProcessSemaphore child test process:\n" ~ e.toString()).newline;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Cerr("Unexpected exception caught in ProcessSemaphore child test process:\n" ~ e.toString()).newline;
|
||||
}
|
||||
|
||||
debug (semaphore)
|
||||
Cout("Leaving child process\n");
|
||||
|
||||
+/
|
||||
return rc;
|
||||
}
|
||||
97
tango/example/system/arguments.d
Normal file
97
tango/example/system/arguments.d
Normal file
@@ -0,0 +1,97 @@
|
||||
/*******************************************************************************
|
||||
Illustrates use of the Arguments class.
|
||||
*******************************************************************************/
|
||||
|
||||
import tango.util.Arguments;
|
||||
import tango.io.Stdout;
|
||||
import tango.io.FileConduit;
|
||||
import tango.text.stream.LineIterator;
|
||||
|
||||
void usage()
|
||||
{
|
||||
Stdout("Usage: [OPTIONS]... FILES...").newline;
|
||||
Stdout("This is a program that does something.").newline;
|
||||
Stdout.newline;
|
||||
Stdout("OPTIONS: ").newline;
|
||||
Stdout("Output this help message: -?, --help").newline;
|
||||
Stdout("Do cool things to your files: -c, -C, --cool").newline;
|
||||
Stdout("Use filename as response file: -r, -R, --response").newline;
|
||||
}
|
||||
|
||||
void main(char[][] cmdlArgs)
|
||||
{
|
||||
char[][] implicitArguments = ["files"];
|
||||
|
||||
char[][][] argumentAliases;
|
||||
argumentAliases ~= ["help", "?"];
|
||||
argumentAliases ~= ["cool", "C", "c"];
|
||||
argumentAliases ~= ["response", "R", "r"];
|
||||
|
||||
auto args = new Arguments(cmdlArgs, implicitArguments, argumentAliases);
|
||||
|
||||
bool fileExistsValidation(char[] arg)
|
||||
{
|
||||
bool rtn;
|
||||
FilePath argFile = new FilePath(arg);
|
||||
rtn = argFile.exists;
|
||||
if (!rtn)
|
||||
Stdout.format("Specified path does not exist: {}", arg).newline;
|
||||
return rtn;
|
||||
}
|
||||
|
||||
bool singleFileValidation(char[][] args, inout char[] invalidArg)
|
||||
{
|
||||
if (args.length > 1)
|
||||
{
|
||||
Stdout("Cannot specify multiple paths for argument.").newline;
|
||||
invalidArg = args[1];
|
||||
}
|
||||
else
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
args.addValidation("response", &fileExistsValidation);
|
||||
args.addValidation("response", &singleFileValidation);
|
||||
args.addValidation("files", true, true);
|
||||
|
||||
bool argsValidated = true;
|
||||
try
|
||||
args.validate;
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
if (ex.reason == ArgumentException.ExceptionReason.MISSING_ARGUMENT)
|
||||
Stdout.format("Missing Argument: {} ({})", ex.name, ex.msg).newline;
|
||||
else if (ex.reason == ArgumentException.ExceptionReason.MISSING_PARAMETER)
|
||||
Stdout.format("Missing Parameter to Argument: {} ({})", ex.name, ex.msg).newline;
|
||||
else if (ex.reason == ArgumentException.ExceptionReason.INVALID_PARAMETER)
|
||||
Stdout.format("Invalid Parameter: {} ({})", ex.name, ex.msg).newline;
|
||||
Stdout.newline;
|
||||
argsValidated = false;
|
||||
}
|
||||
|
||||
if ((!argsValidated) || ("help" in args))
|
||||
usage();
|
||||
else
|
||||
{// ready to run
|
||||
if ("response" in args)
|
||||
{
|
||||
Stdout(args["response"][0]).newline;
|
||||
auto file = new FileConduit(args["response"][0]);
|
||||
auto lines = new LineIterator!(char)(file);
|
||||
char[][] arguments;
|
||||
foreach (line; lines)
|
||||
arguments ~= line.dup;
|
||||
args.parse(arguments, implicitArguments, argumentAliases);
|
||||
}
|
||||
if ("cool" in args)
|
||||
{
|
||||
Stdout ("Listing the files to be actioned in a cool way.").newline;
|
||||
foreach (char[] file; args["files"])
|
||||
Stdout.format("{}", file).newline;
|
||||
Stdout ("Cool and secret action performed.").newline;
|
||||
}
|
||||
if ("x" in args)
|
||||
Stdout.format("User set the X factor to '{}'", args["x"]).newline;
|
||||
}
|
||||
}
|
||||
54
tango/example/system/localtime.d
Normal file
54
tango/example/system/localtime.d
Normal file
@@ -0,0 +1,54 @@
|
||||
/*******************************************************************************
|
||||
|
||||
localtime.d
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
private import tango.io.Stdout;
|
||||
|
||||
private import tango.time.WallClock;
|
||||
|
||||
/******************************************************************************
|
||||
|
||||
Example code to format a local time in the following format:
|
||||
"Wed Dec 31 16:00:00 GMT-0800 1969". The day and month names
|
||||
would typically be extracted from a locale instance, but we
|
||||
convert them locally here for the sake of simplicity
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
void main ()
|
||||
{
|
||||
/// list of day names
|
||||
static char[][] days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
||||
|
||||
/// list of month names
|
||||
static char[][] months =
|
||||
[
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
|
||||
];
|
||||
|
||||
// retreive local time
|
||||
auto dt = WallClock.toDate;
|
||||
|
||||
// get GMT difference in minutes
|
||||
auto tz = cast(int) WallClock.zone.minutes;
|
||||
char sign = '+';
|
||||
if (tz < 0)
|
||||
tz = -tz, sign = '-';
|
||||
|
||||
// format date
|
||||
Stdout.formatln ("{}, {} {:d2} {:d2}:{:d2}:{:d2} GMT{}{:d2}:{:d2} {}",
|
||||
days[dt.date.dow],
|
||||
months[dt.date.month-1],
|
||||
dt.date.day,
|
||||
dt.time.hours,
|
||||
dt.time.minutes,
|
||||
dt.time.seconds,
|
||||
sign,
|
||||
tz / 60,
|
||||
tz % 60,
|
||||
dt.date.year
|
||||
);
|
||||
}
|
||||
51
tango/example/system/normpath.d
Normal file
51
tango/example/system/normpath.d
Normal file
@@ -0,0 +1,51 @@
|
||||
/*****************************************************************
|
||||
|
||||
Simple example that shows possible inputs to normalize and the
|
||||
corresponding outputs.
|
||||
|
||||
Put into public domain by Lars Ivar Igesund.
|
||||
|
||||
*****************************************************************/
|
||||
|
||||
import tango.io.Stdout;
|
||||
|
||||
import tango.util.PathUtil;
|
||||
|
||||
int main()
|
||||
{
|
||||
version (Posix) {
|
||||
Stdout(normalize ( "/foo/../john")).newline;
|
||||
Stdout(normalize ( "foo/../john")).newline;
|
||||
Stdout(normalize ( "foo/bar/..")).newline;
|
||||
Stdout(normalize ( "foo/bar/../john")).newline;
|
||||
Stdout(normalize ( "foo/bar/doe/../../john")).newline;
|
||||
Stdout(normalize ( "foo/bar/doe/../../john/../bar")).newline;
|
||||
Stdout(normalize ( "./foo/bar/doe")).newline;
|
||||
Stdout(normalize ( "./foo/bar/doe/../../john/../bar")).newline;
|
||||
Stdout(normalize ( "./foo/bar/../../john/../bar")).newline;
|
||||
Stdout(normalize ( "foo/bar/./doe/../../john")).newline;
|
||||
Stdout(normalize ( "../../foo/bar/./doe/../../john")).newline;
|
||||
Stdout(normalize ( "../../../foo/bar")).newline;
|
||||
Stdout("** Should now throw exception as the following path is invalid for normalization.").newline;
|
||||
Stdout(normalize ( "/../../../foo/bar")).newline;
|
||||
}
|
||||
version (Windows) {
|
||||
Stdout(normalize ( "C:\\foo\\..\\john")).newline;
|
||||
Stdout(normalize ( "foo\\..\\john")).newline;
|
||||
Stdout(normalize ( "foo\\bar\\..")).newline;
|
||||
Stdout(normalize ( "foo\\bar\\..\\john")).newline;
|
||||
Stdout(normalize ( "foo\\bar\\doe\\..\\..\\john")).newline;
|
||||
Stdout(normalize ( "foo\\bar\\doe\\..\\..\\john\\..\\bar")).newline;
|
||||
Stdout(normalize ( ".\\foo\\bar\\doe")).newline;
|
||||
Stdout(normalize ( ".\\foo\\bar\\doe\\..\\..\\john\\..\\bar")).newline;
|
||||
Stdout(normalize ( ".\\foo\\bar\\..\\..\\john\\..\\bar")).newline;
|
||||
Stdout(normalize ( "foo\\bar\\.\\doe\\..\\..\\john")).newline;
|
||||
Stdout(normalize ( "..\\..\\foo\\bar\\.\\doe\\..\\..\\john")).newline;
|
||||
Stdout(normalize ( "..\\..\\..\\foo\\bar")).newline;
|
||||
Stdout("** Should now throw exception as the following path is invalid for normalization.").newline;
|
||||
Stdout(normalize ( "C:\\..\\..\\..\\foo\\bar")).newline;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
60
tango/example/system/process.d
Normal file
60
tango/example/system/process.d
Normal file
@@ -0,0 +1,60 @@
|
||||
/*******************************************************************************
|
||||
copyright: Copyright (c) 2006 Juan Jose Comellas. All rights reserved
|
||||
license: BSD style: $(LICENSE)
|
||||
author: Juan Jose Comellas <juanjo@comellas.com.ar>
|
||||
*******************************************************************************/
|
||||
|
||||
private import tango.io.Stdout;
|
||||
private import tango.sys.Process;
|
||||
private import tango.core.Exception;
|
||||
|
||||
private import tango.text.stream.LineIterator;
|
||||
|
||||
|
||||
/**
|
||||
* Example program for the tango.sys.Process class.
|
||||
*/
|
||||
void main()
|
||||
{
|
||||
version (Windows)
|
||||
char[] command = "ping -n 4 localhost";
|
||||
else version (Posix)
|
||||
char[] command = "ping -c 4 localhost";
|
||||
else
|
||||
assert(false, "Unsupported platform");
|
||||
|
||||
try
|
||||
{
|
||||
auto p = new Process(command, null);
|
||||
|
||||
Stdout.formatln("Executing {0}", p.toString());
|
||||
p.execute();
|
||||
|
||||
Stdout.formatln("Output from process: {0} (pid {1})\n---",
|
||||
p.programName, p.pid);
|
||||
|
||||
foreach (line; new LineIterator!(char)(p.stdout))
|
||||
{
|
||||
Stdout.formatln("{0}", line);
|
||||
}
|
||||
|
||||
Stdout.print("---\n");
|
||||
|
||||
auto result = p.wait();
|
||||
|
||||
Stdout.formatln("Process '{0}' ({1}) finished: {2}",
|
||||
p.programName, p.pid, result.toString());
|
||||
}
|
||||
catch (ProcessException e)
|
||||
{
|
||||
Stdout.formatln("Process execution failed: {0}", e.toString());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Stdout.formatln("Input/output exception caught: {0}", e.toString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Stdout.formatln("Unexpected exception caught: {0}", e.toString());
|
||||
}
|
||||
}
|
||||
20
tango/example/text/formatalign.d
Normal file
20
tango/example/text/formatalign.d
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
|
||||
Example showing how the alignment component in a format string argument works.
|
||||
|
||||
Put into public domain by Lars Ivar Igesund
|
||||
|
||||
*/
|
||||
|
||||
import tango.io.Stdout;
|
||||
|
||||
void main(){
|
||||
char[] myFName = "Johnny";
|
||||
Stdout.formatln("First Name = |{0,15}|", myFName);
|
||||
Stdout.formatln("Last Name = |{0,15}|", "Foo de Bar");
|
||||
|
||||
Stdout.formatln("First Name = |{0,-15}|", myFName);
|
||||
Stdout.formatln("Last Name = |{0,-15}|", "Foo de Bar");
|
||||
|
||||
Stdout.formatln("First name = |{0,5}|", myFName);
|
||||
}
|
||||
15
tango/example/text/formatindex.d
Normal file
15
tango/example/text/formatindex.d
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
|
||||
Example that shows how the format specifiers can be used to index into
|
||||
the argument list.
|
||||
|
||||
Put into public domain by Lars Ivar Igesund.
|
||||
|
||||
*/
|
||||
|
||||
import tango.io.Stdout;
|
||||
|
||||
void main(){
|
||||
Stdout.formatln("Many {1} can now be {0} around to make {2} easier,\n and {1} can also be repeated.",
|
||||
"switched", "arguments", "localization");
|
||||
}
|
||||
17
tango/example/text/formatspec.d
Normal file
17
tango/example/text/formatspec.d
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
|
||||
Example showing how to use format specifier components in a format string's
|
||||
argument.
|
||||
|
||||
Put into public domain by Lars Ivar Igesund
|
||||
|
||||
*/
|
||||
|
||||
import tango.io.Stdout;
|
||||
|
||||
void main(){
|
||||
double avogadros = 6.0221415e23;
|
||||
Stdout.formatln("I have {0:C} in cash.", 100);
|
||||
Stdout.formatln("Avogadro's number is {0:E}.", avogadros);
|
||||
Stdout.formatln("Avogadro's number (with alignment) is {0,4:E}.", avogadros);
|
||||
}
|
||||
21
tango/example/text/localetime.d
Normal file
21
tango/example/text/localetime.d
Normal file
@@ -0,0 +1,21 @@
|
||||
/******************************************************************************
|
||||
|
||||
Example to format a locale-based time. For a default locale of
|
||||
en-gb, this examples formats in the following manner:
|
||||
|
||||
"Thu, 27 April 2006 18:20:47 +1"
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
private import tango.io.Console;
|
||||
|
||||
private import tango.time.Clock;
|
||||
|
||||
private import tango.text.locale.Locale;
|
||||
|
||||
void main ()
|
||||
{
|
||||
auto layout = new Locale;
|
||||
|
||||
Cout (layout ("{:ddd, dd MMMM yyyy HH:mm:ss z}", Clock.now)).newline;
|
||||
}
|
||||
32
tango/example/text/properties.d
Normal file
32
tango/example/text/properties.d
Normal file
@@ -0,0 +1,32 @@
|
||||
private import tango.io.Buffer,
|
||||
tango.io.Console;
|
||||
|
||||
private import tango.text.Properties;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Illustrates simple usage of tango.text.Properties
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main()
|
||||
{
|
||||
char[][char[]] aa;
|
||||
aa ["foo"] = "something";
|
||||
aa ["bar"] = "something else";
|
||||
aa ["wumpus"] = "";
|
||||
|
||||
// write associative-array to a buffer; could use a file
|
||||
auto props = new Properties!(char);
|
||||
auto buffer = new Buffer (256);
|
||||
props.save (buffer, aa);
|
||||
|
||||
// reset and repopulate AA from the buffer
|
||||
aa = null;
|
||||
props.load (buffer, (char[] name, char[] value){aa[name] = value;});
|
||||
|
||||
// display result
|
||||
foreach (name, value; aa)
|
||||
Cout (name) (" = ") (value).newline;
|
||||
}
|
||||
|
||||
25
tango/example/text/token.d
Normal file
25
tango/example/text/token.d
Normal file
@@ -0,0 +1,25 @@
|
||||
/*******************************************************************************
|
||||
|
||||
Tokenize input from the console. There are a variety of handy
|
||||
tokenizers in the tango.text package ~ this illustrates usage
|
||||
of an iterator that recognizes quoted-strings within an input
|
||||
array, and splits elements on a provided set of delimiters
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
import tango.io.Console;
|
||||
|
||||
import Text = tango.text.Util;
|
||||
|
||||
void main()
|
||||
{
|
||||
// flush the console output, since we have no newline present
|
||||
Cout ("Please enter some space-separated tokens: ") ();
|
||||
|
||||
// create quote-aware iterator for handling space-delimited
|
||||
// tokens from the console input
|
||||
foreach (element; Text.quotes (Text.trim(Cin.get), " \t"))
|
||||
Cout ("<") (element) ("> ");
|
||||
|
||||
Cout.newline;
|
||||
}
|
||||
286
tango/lib/common/tango/core/BitManip.d
Normal file
286
tango/lib/common/tango/core/BitManip.d
Normal file
@@ -0,0 +1,286 @@
|
||||
/**
|
||||
* This module contains a collection of bit-level operations.
|
||||
*
|
||||
* Copyright: Public Domain
|
||||
* License: Public Domain
|
||||
* Authors: Sean Kelly
|
||||
*/
|
||||
module tango.core.BitManip;
|
||||
|
||||
|
||||
version( DDoc )
|
||||
{
|
||||
/**
|
||||
* Scans the bits in v starting with bit 0, looking
|
||||
* for the first set bit.
|
||||
* Returns:
|
||||
* The bit number of the first bit set.
|
||||
* The return value is undefined if v is zero.
|
||||
*/
|
||||
int bsf( uint v );
|
||||
|
||||
|
||||
/**
|
||||
* Scans the bits in v from the most significant bit
|
||||
* to the least significant bit, looking
|
||||
* for the first set bit.
|
||||
* Returns:
|
||||
* The bit number of the first bit set.
|
||||
* The return value is undefined if v is zero.
|
||||
* Example:
|
||||
* ---
|
||||
* import std.intrinsic;
|
||||
*
|
||||
* int main()
|
||||
* {
|
||||
* uint v;
|
||||
* int x;
|
||||
*
|
||||
* v = 0x21;
|
||||
* x = bsf(v);
|
||||
* printf("bsf(x%x) = %d\n", v, x);
|
||||
* x = bsr(v);
|
||||
* printf("bsr(x%x) = %d\n", v, x);
|
||||
* return 0;
|
||||
* }
|
||||
* ---
|
||||
* Output:
|
||||
* bsf(x21) = 0<br>
|
||||
* bsr(x21) = 5
|
||||
*/
|
||||
int bsr( uint v );
|
||||
|
||||
|
||||
/**
|
||||
* Tests the bit.
|
||||
*/
|
||||
int bt( uint* p, uint bitnum );
|
||||
|
||||
|
||||
/**
|
||||
* Tests and complements the bit.
|
||||
*/
|
||||
int btc( uint* p, uint bitnum );
|
||||
|
||||
|
||||
/**
|
||||
* Tests and resets (sets to 0) the bit.
|
||||
*/
|
||||
int btr( uint* p, uint bitnum );
|
||||
|
||||
|
||||
/**
|
||||
* Tests and sets the bit.
|
||||
* Params:
|
||||
* p = a non-NULL pointer to an array of uints.
|
||||
* index = a bit number, starting with bit 0 of p[0],
|
||||
* and progressing. It addresses bits like the expression:
|
||||
---
|
||||
p[index / (uint.sizeof*8)] & (1 << (index & ((uint.sizeof*8) - 1)))
|
||||
---
|
||||
* Returns:
|
||||
* A non-zero value if the bit was set, and a zero
|
||||
* if it was clear.
|
||||
*
|
||||
* Example:
|
||||
* ---
|
||||
import std.intrinsic;
|
||||
|
||||
int main()
|
||||
{
|
||||
uint array[2];
|
||||
|
||||
array[0] = 2;
|
||||
array[1] = 0x100;
|
||||
|
||||
printf("btc(array, 35) = %d\n", <b>btc</b>(array, 35));
|
||||
printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
|
||||
|
||||
printf("btc(array, 35) = %d\n", <b>btc</b>(array, 35));
|
||||
printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
|
||||
|
||||
printf("bts(array, 35) = %d\n", <b>bts</b>(array, 35));
|
||||
printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
|
||||
|
||||
printf("btr(array, 35) = %d\n", <b>btr</b>(array, 35));
|
||||
printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
|
||||
|
||||
printf("bt(array, 1) = %d\n", <b>bt</b>(array, 1));
|
||||
printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
* ---
|
||||
* Output:
|
||||
<pre>
|
||||
btc(array, 35) = 0
|
||||
array = [0]:x2, [1]:x108
|
||||
btc(array, 35) = -1
|
||||
array = [0]:x2, [1]:x100
|
||||
bts(array, 35) = 0
|
||||
array = [0]:x2, [1]:x108
|
||||
btr(array, 35) = -1
|
||||
array = [0]:x2, [1]:x100
|
||||
bt(array, 1) = -1
|
||||
array = [0]:x2, [1]:x100
|
||||
</pre>
|
||||
*/
|
||||
int bts( uint* p, uint bitnum );
|
||||
|
||||
|
||||
/**
|
||||
* Swaps bytes in a 4 byte uint end-to-end, i.e. byte 0 becomes
|
||||
* byte 3, byte 1 becomes byte 2, byte 2 becomes byte 1, byte 3
|
||||
* becomes byte 0.
|
||||
*/
|
||||
uint bswap( uint v );
|
||||
|
||||
|
||||
/**
|
||||
* Reads I/O port at port_address.
|
||||
*/
|
||||
ubyte inp( uint port_address );
|
||||
|
||||
|
||||
/**
|
||||
* ditto
|
||||
*/
|
||||
ushort inpw( uint port_address );
|
||||
|
||||
|
||||
/**
|
||||
* ditto
|
||||
*/
|
||||
uint inpl( uint port_address );
|
||||
|
||||
|
||||
/**
|
||||
* Writes and returns value to I/O port at port_address.
|
||||
*/
|
||||
ubyte outp( uint port_address, ubyte value );
|
||||
|
||||
|
||||
/**
|
||||
* ditto
|
||||
*/
|
||||
ushort outpw( uint port_address, ushort value );
|
||||
|
||||
|
||||
/**
|
||||
* ditto
|
||||
*/
|
||||
uint outpl( uint port_address, uint value );
|
||||
}
|
||||
else
|
||||
{
|
||||
public import std.intrinsic;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the number of set bits in a 32-bit integer.
|
||||
*/
|
||||
int popcnt( uint x )
|
||||
{
|
||||
// Avoid branches, and the potential for cache misses which
|
||||
// could be incurred with a table lookup.
|
||||
|
||||
// We need to mask alternate bits to prevent the
|
||||
// sum from overflowing.
|
||||
// add neighbouring bits. Each bit is 0 or 1.
|
||||
x = x - ((x>>1) & 0x5555_5555);
|
||||
// now each two bits of x is a number 00,01 or 10.
|
||||
// now add neighbouring pairs
|
||||
x = ((x&0xCCCC_CCCC)>>2) + (x&0x3333_3333);
|
||||
// now each nibble holds 0000-0100. Adding them won't
|
||||
// overflow any more, so we don't need to mask any more
|
||||
|
||||
// Now add the nibbles, then the bytes, then the words
|
||||
// We still need to mask to prevent double-counting.
|
||||
// Note that if we used a rotate instead of a shift, we
|
||||
// wouldn't need the masks, and could just divide the sum
|
||||
// by 8 to account for the double-counting.
|
||||
// On some CPUs, it may be faster to perform a multiply.
|
||||
|
||||
x += (x>>4);
|
||||
x &= 0x0F0F_0F0F;
|
||||
x += (x>>8);
|
||||
x &= 0x00FF_00FF;
|
||||
x += (x>>16);
|
||||
x &= 0xFFFF;
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
debug( UnitTest )
|
||||
{
|
||||
unittest
|
||||
{
|
||||
assert( popcnt( 0 ) == 0 );
|
||||
assert( popcnt( 7 ) == 3 );
|
||||
assert( popcnt( 0xAA )== 4 );
|
||||
assert( popcnt( 0x8421_1248 ) == 8 );
|
||||
assert( popcnt( 0xFFFF_FFFF ) == 32 );
|
||||
assert( popcnt( 0xCCCC_CCCC ) == 16 );
|
||||
assert( popcnt( 0x7777_7777 ) == 24 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reverses the order of bits in a 32-bit integer.
|
||||
*/
|
||||
uint bitswap( uint x )
|
||||
{
|
||||
|
||||
version( D_InlineAsm_X86 )
|
||||
{
|
||||
asm
|
||||
{
|
||||
// Author: Tiago Gasiba.
|
||||
mov EDX, EAX;
|
||||
shr EAX, 1;
|
||||
and EDX, 0x5555_5555;
|
||||
and EAX, 0x5555_5555;
|
||||
shl EDX, 1;
|
||||
or EAX, EDX;
|
||||
mov EDX, EAX;
|
||||
shr EAX, 2;
|
||||
and EDX, 0x3333_3333;
|
||||
and EAX, 0x3333_3333;
|
||||
shl EDX, 2;
|
||||
or EAX, EDX;
|
||||
mov EDX, EAX;
|
||||
shr EAX, 4;
|
||||
and EDX, 0x0f0f_0f0f;
|
||||
and EAX, 0x0f0f_0f0f;
|
||||
shl EDX, 4;
|
||||
or EAX, EDX;
|
||||
bswap EAX;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// swap odd and even bits
|
||||
x = ((x >> 1) & 0x5555_5555) | ((x & 0x5555_5555) << 1);
|
||||
// swap consecutive pairs
|
||||
x = ((x >> 2) & 0x3333_3333) | ((x & 0x3333_3333) << 2);
|
||||
// swap nibbles
|
||||
x = ((x >> 4) & 0x0F0F_0F0F) | ((x & 0x0F0F_0F0F) << 4);
|
||||
// swap bytes
|
||||
x = ((x >> 8) & 0x00FF_00FF) | ((x & 0x00FF_00FF) << 8);
|
||||
// swap 2-byte long pairs
|
||||
x = ( x >> 16 ) | ( x << 16);
|
||||
return x;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
debug( UnitTest )
|
||||
{
|
||||
unittest
|
||||
{
|
||||
assert( bitswap( 0x8000_0100 ) == 0x0080_0001 );
|
||||
}
|
||||
}
|
||||
622
tango/lib/common/tango/core/Exception.d
Normal file
622
tango/lib/common/tango/core/Exception.d
Normal file
@@ -0,0 +1,622 @@
|
||||
/**
|
||||
* The exception module defines all system-level exceptions and provides a
|
||||
* mechanism to alter system-level error handling.
|
||||
*
|
||||
* Copyright: Copyright (C) 2005-2006 Sean Kelly, Kris Bell. All rights reserved.
|
||||
* License: BSD style: $(LICENSE)
|
||||
* Authors: Sean Kelly, Kris Bell
|
||||
*/
|
||||
module tango.core.Exception;
|
||||
|
||||
|
||||
private
|
||||
{
|
||||
alias void function( char[] file, size_t line, char[] msg = null ) assertHandlerType;
|
||||
alias TracedExceptionInfo function( void* ptr = null ) traceHandlerType;
|
||||
|
||||
assertHandlerType assertHandler = null;
|
||||
traceHandlerType traceHandler = null;
|
||||
}
|
||||
|
||||
|
||||
interface TracedExceptionInfo
|
||||
{
|
||||
int opApply( int delegate( inout char[] ) );
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
- Exception
|
||||
- OutOfMemoryException
|
||||
|
||||
- TracedException
|
||||
- SwitchException
|
||||
- AssertException
|
||||
- ArrayBoundsException
|
||||
- FinalizeException
|
||||
|
||||
- PlatformException
|
||||
- ProcessException
|
||||
- ThreadException
|
||||
- FiberException
|
||||
- SyncException
|
||||
- IOException
|
||||
- SocketException
|
||||
- SocketAcceptException
|
||||
- AddressException
|
||||
- HostException
|
||||
- VfsException
|
||||
- ClusterException
|
||||
|
||||
- NoSuchElementException
|
||||
- CorruptedIteratorException
|
||||
|
||||
- IllegalArgumentException
|
||||
- IllegalElementException
|
||||
|
||||
- TextException
|
||||
- RegexException
|
||||
- LocaleException
|
||||
- UnicodeException
|
||||
|
||||
- PayloadException
|
||||
*/
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Thrown on an out of memory error.
|
||||
*/
|
||||
class OutOfMemoryException : Exception
|
||||
{
|
||||
this( char[] file, size_t line )
|
||||
{
|
||||
super( "Memory allocation failed", file, line );
|
||||
}
|
||||
|
||||
char[] toString()
|
||||
{
|
||||
return msg ? super.toString() : "Memory allocation failed";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stores a stack trace when thrown.
|
||||
*/
|
||||
class TracedException : Exception
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
m_info = traceContext();
|
||||
}
|
||||
|
||||
this( char[] msg, Exception e )
|
||||
{
|
||||
super( msg, e );
|
||||
m_info = traceContext();
|
||||
}
|
||||
|
||||
this( char[] msg, char[] file, size_t line )
|
||||
{
|
||||
super( msg, file, line );
|
||||
m_info = traceContext();
|
||||
}
|
||||
|
||||
char[] toString()
|
||||
{
|
||||
if( m_info is null )
|
||||
return super.toString();
|
||||
char[] buf = super.toString();
|
||||
buf ~= "\n----------------";
|
||||
foreach( line; m_info )
|
||||
buf ~= "\n" ~ line;
|
||||
return buf;
|
||||
}
|
||||
|
||||
int opApply( int delegate( inout char[] buf ) dg )
|
||||
{
|
||||
if( m_info is null )
|
||||
return 0;
|
||||
return m_info.opApply( dg );
|
||||
}
|
||||
|
||||
private:
|
||||
TracedExceptionInfo m_info;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base class for operating system or library exceptions.
|
||||
*/
|
||||
class PlatformException : TracedException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown on an assert error.
|
||||
*/
|
||||
class AssertException : TracedException
|
||||
{
|
||||
this( char[] file, size_t line )
|
||||
{
|
||||
super( "Assertion failure", file, line );
|
||||
}
|
||||
|
||||
this( char[] msg, char[] file, size_t line )
|
||||
{
|
||||
super( msg, file, line );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Thrown on an array bounds error.
|
||||
*/
|
||||
class ArrayBoundsException : TracedException
|
||||
{
|
||||
this( char[] file, size_t line )
|
||||
{
|
||||
super( "Array index out of bounds", file, line );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Thrown on finalize error.
|
||||
*/
|
||||
class FinalizeException : TracedException
|
||||
{
|
||||
ClassInfo info;
|
||||
|
||||
this( ClassInfo c, Exception e = null )
|
||||
{
|
||||
super( "Finalization error", e );
|
||||
info = c;
|
||||
}
|
||||
|
||||
char[] toString()
|
||||
{
|
||||
//return "An exception was thrown while finalizing an instance of class " ~ info.name;
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Thrown on a switch error.
|
||||
*/
|
||||
class SwitchException : TracedException
|
||||
{
|
||||
this( char[] file, size_t line )
|
||||
{
|
||||
super( "No appropriate switch clause found", file, line );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Represents a text processing error.
|
||||
*/
|
||||
class TextException : TracedException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown on a unicode conversion error.
|
||||
*/
|
||||
class UnicodeException : TextException
|
||||
{
|
||||
size_t idx;
|
||||
|
||||
this( char[] msg, size_t idx )
|
||||
{
|
||||
super( msg );
|
||||
this.idx = idx;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base class for thread exceptions.
|
||||
*/
|
||||
class ThreadException : PlatformException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base class for fiber exceptions.
|
||||
*/
|
||||
class FiberException : ThreadException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base class for synchronization exceptions.
|
||||
*/
|
||||
class SyncException : PlatformException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The basic exception thrown by the tango.io package. One should try to ensure
|
||||
* that all Tango exceptions related to IO are derived from this one.
|
||||
*/
|
||||
class IOException : PlatformException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The basic exception thrown by the tango.io.vfs package.
|
||||
*/
|
||||
private class VfsException : IOException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The basic exception thrown by the tango.io.cluster package.
|
||||
*/
|
||||
private class ClusterException : IOException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for socket exceptions.
|
||||
*/
|
||||
class SocketException : IOException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base class for exception thrown by an InternetHost.
|
||||
*/
|
||||
class HostException : IOException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base class for exceptiond thrown by an Address.
|
||||
*/
|
||||
class AddressException : IOException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Thrown when a socket failed to accept an incoming connection.
|
||||
*/
|
||||
class SocketAcceptException : SocketException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Thrown on a process error.
|
||||
*/
|
||||
class ProcessException : PlatformException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base class for regluar expression exceptions.
|
||||
*/
|
||||
class RegexException : TextException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base class for locale exceptions.
|
||||
*/
|
||||
class LocaleException : TextException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* RegistryException is thrown when the NetworkRegistry encounters a
|
||||
* problem during proxy registration, or when it sees an unregistered
|
||||
* guid.
|
||||
*/
|
||||
class RegistryException : TracedException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Thrown when an illegal argument is encountered.
|
||||
*/
|
||||
class IllegalArgumentException : TracedException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* IllegalElementException is thrown by Collection methods
|
||||
* that add (or replace) elements (and/or keys) when their
|
||||
* arguments are null or do not pass screeners.
|
||||
*
|
||||
*/
|
||||
class IllegalElementException : IllegalArgumentException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Thrown on past-the-end errors by iterators and containers.
|
||||
*/
|
||||
class NoSuchElementException : TracedException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Thrown when a corrupt iterator is detected.
|
||||
*/
|
||||
class CorruptedIteratorException : NoSuchElementException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Overrides
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Overrides the default assert hander with a user-supplied version.
|
||||
*
|
||||
* Params:
|
||||
* h = The new assert handler. Set to null to use the default handler.
|
||||
*/
|
||||
void setAssertHandler( assertHandlerType h )
|
||||
{
|
||||
assertHandler = h;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overrides the default trace hander with a user-supplied version.
|
||||
*
|
||||
* Params:
|
||||
* h = The new trace handler. Set to null to use the default handler.
|
||||
*/
|
||||
void setTraceHandler( traceHandlerType h )
|
||||
{
|
||||
traceHandler = h;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Overridable Callbacks
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* A callback for assert errors in D. The user-supplied assert handler will
|
||||
* be called if one has been supplied, otherwise an AssertException will be
|
||||
* thrown.
|
||||
*
|
||||
* Params:
|
||||
* file = The name of the file that signaled this error.
|
||||
* line = The line number on which this error occurred.
|
||||
*/
|
||||
extern (C) void onAssertError( char[] file, size_t line )
|
||||
{
|
||||
if( assertHandler is null )
|
||||
throw new AssertException( file, line );
|
||||
assertHandler( file, line );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A callback for assert errors in D. The user-supplied assert handler will
|
||||
* be called if one has been supplied, otherwise an AssertException will be
|
||||
* thrown.
|
||||
*
|
||||
* Params:
|
||||
* file = The name of the file that signaled this error.
|
||||
* line = The line number on which this error occurred.
|
||||
* msg = An error message supplied by the user.
|
||||
*/
|
||||
extern (C) void onAssertErrorMsg( char[] file, size_t line, char[] msg )
|
||||
{
|
||||
if( assertHandler is null )
|
||||
throw new AssertException( msg, file, line );
|
||||
assertHandler( file, line, msg );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function will be called when a TracedException is constructed. The
|
||||
* user-supplied trace handler will be called if one has been supplied,
|
||||
* otherwise no trace will be generated.
|
||||
*
|
||||
* Params:
|
||||
* ptr = A pointer to the location from which to generate the trace, or null
|
||||
* if the trace should be generated from within the trace handler
|
||||
* itself.
|
||||
*
|
||||
* Returns:
|
||||
* An object describing the current calling context or null if no handler is
|
||||
* supplied.
|
||||
*/
|
||||
TracedExceptionInfo traceContext( void* ptr = null )
|
||||
{
|
||||
if( traceHandler is null )
|
||||
return null;
|
||||
return traceHandler( ptr );
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Internal Error Callbacks
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* A callback for array bounds errors in D. An ArrayBoundsException will be
|
||||
* thrown.
|
||||
*
|
||||
* Params:
|
||||
* file = The name of the file that signaled this error.
|
||||
* line = The line number on which this error occurred.
|
||||
*
|
||||
* Throws:
|
||||
* ArrayBoundsException.
|
||||
*/
|
||||
extern (C) void onArrayBoundsError( char[] file, size_t line )
|
||||
{
|
||||
throw new ArrayBoundsException( file, line );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A callback for finalize errors in D. A FinalizeException will be thrown.
|
||||
*
|
||||
* Params:
|
||||
* e = The exception thrown during finalization.
|
||||
*
|
||||
* Throws:
|
||||
* FinalizeException.
|
||||
*/
|
||||
extern (C) void onFinalizeError( ClassInfo info, Exception ex )
|
||||
{
|
||||
throw new FinalizeException( info, ex );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A callback for out of memory errors in D. An OutOfMemoryException will be
|
||||
* thrown.
|
||||
*
|
||||
* Throws:
|
||||
* OutOfMemoryException.
|
||||
*/
|
||||
extern (C) void onOutOfMemoryError()
|
||||
{
|
||||
// NOTE: Since an out of memory condition exists, no allocation must occur
|
||||
// while generating this object.
|
||||
throw cast(OutOfMemoryException) cast(void*) OutOfMemoryException.classinfo.init;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A callback for switch errors in D. A SwitchException will be thrown.
|
||||
*
|
||||
* Params:
|
||||
* file = The name of the file that signaled this error.
|
||||
* line = The line number on which this error occurred.
|
||||
*
|
||||
* Throws:
|
||||
* SwitchException.
|
||||
*/
|
||||
extern (C) void onSwitchError( char[] file, size_t line )
|
||||
{
|
||||
throw new SwitchException( file, line );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A callback for unicode errors in D. A UnicodeException will be thrown.
|
||||
*
|
||||
* Params:
|
||||
* msg = Information about the error.
|
||||
* idx = String index where this error was detected.
|
||||
*
|
||||
* Throws:
|
||||
* UnicodeException.
|
||||
*/
|
||||
extern (C) void onUnicodeError( char[] msg, size_t idx )
|
||||
{
|
||||
throw new UnicodeException( msg, idx );
|
||||
}
|
||||
458
tango/lib/common/tango/core/Memory.d
Normal file
458
tango/lib/common/tango/core/Memory.d
Normal file
@@ -0,0 +1,458 @@
|
||||
/**
|
||||
* The memory module provides an interface to the garbage collector and to
|
||||
* any other OS or API-level memory management facilities.
|
||||
*
|
||||
* Copyright: Copyright (C) 2005-2006 Sean Kelly. All rights reserved.
|
||||
* License: BSD style: $(LICENSE)
|
||||
* Authors: Sean Kelly
|
||||
*/
|
||||
module tango.core.Memory;
|
||||
|
||||
|
||||
private
|
||||
{
|
||||
extern (C) void gc_init();
|
||||
extern (C) void gc_term();
|
||||
|
||||
extern (C) void gc_enable();
|
||||
extern (C) void gc_disable();
|
||||
extern (C) void gc_collect();
|
||||
|
||||
extern (C) uint gc_getAttr( void* p );
|
||||
extern (C) uint gc_setAttr( void* p, uint a );
|
||||
extern (C) uint gc_clrAttr( void* p, uint a );
|
||||
|
||||
extern (C) void* gc_malloc( size_t sz, uint ba = 0 );
|
||||
extern (C) void* gc_calloc( size_t sz, uint ba = 0 );
|
||||
extern (C) void* gc_realloc( void* p, size_t sz, uint ba = 0 );
|
||||
extern (C) size_t gc_extend( void* p, size_t mx, size_t sz );
|
||||
extern (C) void gc_free( void* p );
|
||||
|
||||
extern (C) void* gc_addrOf( void* p );
|
||||
extern (C) size_t gc_sizeOf( void* p );
|
||||
|
||||
struct BlkInfo_
|
||||
{
|
||||
void* base;
|
||||
size_t size;
|
||||
uint attr;
|
||||
}
|
||||
|
||||
extern (C) BlkInfo_ gc_query( void* p );
|
||||
|
||||
extern (C) void gc_addRoot( void* p );
|
||||
extern (C) void gc_addRange( void* p, size_t sz );
|
||||
|
||||
extern (C) void gc_removeRoot( void* p );
|
||||
extern (C) void gc_removeRange( void* p );
|
||||
|
||||
alias bool function( Object obj ) collectHandlerType;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This struct encapsulates all garbage collection functionality for the D
|
||||
* programming language.
|
||||
*/
|
||||
struct GC
|
||||
{
|
||||
/**
|
||||
* Enables the garbage collector if collections have previously been
|
||||
* suspended by a call to disable. This function is reentrant, and
|
||||
* must be called once for every call to disable before the garbage
|
||||
* collector is enabled.
|
||||
*/
|
||||
static void enable()
|
||||
{
|
||||
gc_enable();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Disables the garbage collector. This function is reentrant, but
|
||||
* enable must be called once for each call to disable.
|
||||
*/
|
||||
static void disable()
|
||||
{
|
||||
gc_disable();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Begins a full collection. While the meaning of this may change based
|
||||
* on the garbage collector implementation, typical behavior is to scan
|
||||
* all stack segments for roots, mark accessible memory blocks as alive,
|
||||
* and then to reclaim free space. This action may need to suspend all
|
||||
* running threads for at least part of the collection process.
|
||||
*/
|
||||
static void collect()
|
||||
{
|
||||
gc_collect();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Elements for a bit field representing memory block attributes. These
|
||||
* are manipulated via the getAttr, setAttr, clrAttr functions.
|
||||
*/
|
||||
enum BlkAttr : uint
|
||||
{
|
||||
FINALIZE = 0b0000_0001, /// Finalize the data in this block on collect.
|
||||
NO_SCAN = 0b0000_0010, /// Do not scan through this block on collect.
|
||||
NO_MOVE = 0b0000_0100 /// Do not move this memory block on collect.
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Contains aggregate information about a block of managed memory. The
|
||||
* purpose of this struct is to support a more efficient query style in
|
||||
* instances where detailed information is needed.
|
||||
*
|
||||
* base = A pointer to the base of the block in question.
|
||||
* size = The size of the block, calculated from base.
|
||||
* attr = Attribute bits set on the memory block.
|
||||
*/
|
||||
alias BlkInfo_ BlkInfo;
|
||||
|
||||
|
||||
/**
|
||||
* Returns a bit field representing all block attributes set for the memory
|
||||
* referenced by p. If p references memory not originally allocated by this
|
||||
* garbage collector, points to the interior of a memory block, or if p is
|
||||
* null, zero will be returned.
|
||||
*
|
||||
* Params:
|
||||
* p = A pointer to the root of a valid memory block or to null.
|
||||
*
|
||||
* Returns:
|
||||
* A bit field containing any bits set for the memory block referenced by
|
||||
* p or zero on error.
|
||||
*/
|
||||
static uint getAttr( void* p )
|
||||
{
|
||||
return gc_getAttr( p );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the specified bits for the memory references by p. If p references
|
||||
* memory not originally allocated by this garbage collector, points to the
|
||||
* interior of a memory block, or if p is null, no action will be performed.
|
||||
*
|
||||
* Params:
|
||||
* p = A pointer to the root of a valid memory block or to null.
|
||||
* a = A bit field containing any bits to set for this memory block.
|
||||
*
|
||||
* The result of a call to getAttr after the specified bits have been
|
||||
* set.
|
||||
*/
|
||||
static uint setAttr( void* p, uint a )
|
||||
{
|
||||
return gc_setAttr( p, a );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clears the specified bits for the memory references by p. If p
|
||||
* references memory not originally allocated by this garbage collector,
|
||||
* points to the interior of a memory block, or if p is null, no action
|
||||
* will be performed.
|
||||
*
|
||||
* Params:
|
||||
* p = A pointer to the root of a valid memory block or to null.
|
||||
* a = A bit field containing any bits to clear for this memory block.
|
||||
*
|
||||
* Returns:
|
||||
* The result of a call to getAttr after the specified bits have been
|
||||
* cleared.
|
||||
*/
|
||||
static uint clrAttr( void* p, uint a )
|
||||
{
|
||||
return gc_clrAttr( p, a );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Requests an aligned block of managed memory from the garbage collector.
|
||||
* This memory may be deleted at will with a call to free, or it may be
|
||||
* discarded and cleaned up automatically during a collection run. If
|
||||
* allocation fails, this function will call onOutOfMemory which is
|
||||
* expected to throw an OutOfMemoryException.
|
||||
*
|
||||
* Params:
|
||||
* sz = The desired allocation size in bytes.
|
||||
* ba = A bitmask of the attributes to set on this block.
|
||||
*
|
||||
* Returns:
|
||||
* A reference to the allocated memory or null if insufficient memory
|
||||
* is available.
|
||||
*
|
||||
* Throws:
|
||||
* OutOfMemoryException on allocation failure.
|
||||
*/
|
||||
static void* malloc( size_t sz, uint ba = 0 )
|
||||
{
|
||||
return gc_malloc( sz, ba );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Requests an aligned block of managed memory from the garbage collector,
|
||||
* which is initialized with all bits set to zero. This memory may be
|
||||
* deleted at will with a call to free, or it may be discarded and cleaned
|
||||
* up automatically during a collection run. If allocation fails, this
|
||||
* function will call onOutOfMemory which is expected to throw an
|
||||
* OutOfMemoryException.
|
||||
*
|
||||
* Params:
|
||||
* sz = The desired allocation size in bytes.
|
||||
* ba = A bitmask of the attributes to set on this block.
|
||||
*
|
||||
* Returns:
|
||||
* A reference to the allocated memory or null if insufficient memory
|
||||
* is available.
|
||||
*
|
||||
* Throws:
|
||||
* OutOfMemoryException on allocation failure.
|
||||
*/
|
||||
static void* calloc( size_t sz, uint ba = 0 )
|
||||
{
|
||||
return gc_calloc( sz, ba );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If sz is zero, the memory referenced by p will be deallocated as if
|
||||
* by a call to free. A new memory block of size sz will then be
|
||||
* allocated as if by a call to malloc, or the implementation may instead
|
||||
* resize the memory block in place. The contents of the new memory block
|
||||
* will be the same as the contents of the old memory block, up to the
|
||||
* lesser of the new and old sizes. Note that existing memory will only
|
||||
* be freed by realloc if sz is equal to zero. The garbage collector is
|
||||
* otherwise expected to later reclaim the memory block if it is unused.
|
||||
* If allocation fails, this function will call onOutOfMemory which is
|
||||
* expected to throw an OutOfMemoryException. If p references memory not
|
||||
* originally allocated by this garbage collector, or if it points to the
|
||||
* interior of a memory block, no action will be taken. If ba is zero
|
||||
* (the default) and p references the head of a valid, known memory block
|
||||
* then any bits set on the current block will be set on the new block if a
|
||||
* reallocation is required. If ba is not zero and p references the head
|
||||
* of a valid, known memory block then the bits in ba will replace those on
|
||||
* the current memory block and will also be set on the new block if a
|
||||
* reallocation is required.
|
||||
*
|
||||
* Params:
|
||||
* p = A pointer to the root of a valid memory block or to null.
|
||||
* sz = The desired allocation size in bytes.
|
||||
* ba = A bitmask of the attributes to set on this block.
|
||||
*
|
||||
* Returns:
|
||||
* A reference to the allocated memory on success or null if sz is
|
||||
* zero. On failure, the original value of p is returned.
|
||||
*
|
||||
* Throws:
|
||||
* OutOfMemoryException on allocation failure.
|
||||
*/
|
||||
static void* realloc( void* p, size_t sz, uint ba = 0 )
|
||||
{
|
||||
return gc_realloc( p, sz, ba );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Requests that the managed memory block referenced by p be extended in
|
||||
* place by at least mx bytes, with a desired extension of sz bytes. If an
|
||||
* extension of the required size is not possible, if p references memory
|
||||
* not originally allocated by this garbage collector, or if p points to
|
||||
* the interior of a memory block, no action will be taken.
|
||||
*
|
||||
* Params:
|
||||
* mx = The minimum extension size in bytes.
|
||||
* sz = The desired extension size in bytes.
|
||||
*
|
||||
* Returns:
|
||||
* The size in bytes of the extended memory block referenced by p or zero
|
||||
* if no extension occurred.
|
||||
*/
|
||||
static size_t extend( void* p, size_t mx, size_t sz )
|
||||
{
|
||||
return gc_extend( p, mx, sz );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deallocates the memory referenced by p. If p is null, no action
|
||||
* occurs. If p references memory not originally allocated by this
|
||||
* garbage collector, or if it points to the interior of a memory block,
|
||||
* no action will be taken. The block will not be finalized regardless
|
||||
* of whether the FINALIZE attribute is set. If finalization is desired,
|
||||
* use delete instead.
|
||||
*
|
||||
* Params:
|
||||
* p = A pointer to the root of a valid memory block or to null.
|
||||
*/
|
||||
static void free( void* p )
|
||||
{
|
||||
gc_free( p );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the base address of the memory block containing p. This value
|
||||
* is useful to determine whether p is an interior pointer, and the result
|
||||
* may be passed to routines such as sizeOf which may otherwise fail. If p
|
||||
* references memory not originally allocated by this garbage collector, if
|
||||
* p is null, or if the garbage collector does not support this operation,
|
||||
* null will be returned.
|
||||
*
|
||||
* Params:
|
||||
* p = A pointer to the root or the interior of a valid memory block or to
|
||||
* null.
|
||||
*
|
||||
* Returns:
|
||||
* The base address of the memory block referenced by p or null on error.
|
||||
*/
|
||||
static void* addrOf( void* p )
|
||||
{
|
||||
return gc_addrOf( p );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the true size of the memory block referenced by p. This value
|
||||
* represents the maximum number of bytes for which a call to realloc may
|
||||
* resize the existing block in place. If p references memory not
|
||||
* originally allocated by this garbage collector, points to the interior
|
||||
* of a memory block, or if p is null, zero will be returned.
|
||||
*
|
||||
* Params:
|
||||
* p = A pointer to the root of a valid memory block or to null.
|
||||
*
|
||||
* Returns:
|
||||
* The size in bytes of the memory block referenced by p or zero on error.
|
||||
*/
|
||||
static size_t sizeOf( void* p )
|
||||
{
|
||||
return gc_sizeOf( p );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns aggregate information about the memory block containing p. If p
|
||||
* references memory not originally allocated by this garbage collector, if
|
||||
* p is null, or if the garbage collector does not support this operation,
|
||||
* BlkInfo.init will be returned. Typically, support for this operation
|
||||
* is dependent on support for addrOf.
|
||||
*
|
||||
* Params:
|
||||
* p = A pointer to the root or the interior of a valid memory block or to
|
||||
* null.
|
||||
*
|
||||
* Returns:
|
||||
* Information regarding the memory block referenced by p or BlkInfo.init
|
||||
* on error.
|
||||
*/
|
||||
static BlkInfo query( void* p )
|
||||
{
|
||||
return gc_query( p );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds the memory address referenced by p to an internal list of roots to
|
||||
* be scanned during a collection. If p is null, no operation is
|
||||
* performed.
|
||||
*
|
||||
* Params:
|
||||
* p = A pointer to a valid memory address or to null.
|
||||
*/
|
||||
static void addRoot( void* p )
|
||||
{
|
||||
gc_addRoot( p );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds the memory block referenced by p and of size sz to an internal list
|
||||
* of ranges to be scanned during a collection. If p is null, no operation
|
||||
* is performed.
|
||||
*
|
||||
* Params:
|
||||
* p = A pointer to a valid memory address or to null.
|
||||
* sz = The size in bytes of the block to add. If sz is zero then the
|
||||
* no operation will occur. If p is null then sz must be zero.
|
||||
*/
|
||||
static void addRange( void* p, size_t sz )
|
||||
{
|
||||
gc_addRange( p, sz );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes the memory block referenced by p from an internal list of roots
|
||||
* to be scanned during a collection. If p is null or does not represent
|
||||
* a value previously passed to add(void*) then no operation is performed.
|
||||
*
|
||||
* p = A pointer to a valid memory address or to null.
|
||||
*/
|
||||
static void removeRoot( void* p )
|
||||
{
|
||||
gc_removeRoot( p );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes the memory block referenced by p from an internal list of ranges
|
||||
* to be scanned during a collection. If p is null or does not represent
|
||||
* a value previously passed to add(void*, size_t) then no operation is
|
||||
* performed.
|
||||
*
|
||||
* Params:
|
||||
* p = A pointer to a valid memory address or to null.
|
||||
*/
|
||||
static void removeRange( void* p )
|
||||
{
|
||||
gc_removeRange( p );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overrides the default collect hander with a user-supplied version.
|
||||
*
|
||||
* Params:
|
||||
* h = The new collect handler. Set to null to use the default handler.
|
||||
*/
|
||||
static void collectHandler( collectHandlerType h )
|
||||
{
|
||||
sm_collectHandler = h;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
static collectHandlerType sm_collectHandler = null;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Overridable Callbacks
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* This function will be called when resource objects (ie. objects with a dtor)
|
||||
* are finalized by the garbage collector. The user-supplied collect handler
|
||||
* will be called if one has been supplied, otherwise no action will be taken.
|
||||
*
|
||||
* Params:
|
||||
* obj = The object being collected.
|
||||
*
|
||||
* Returns:
|
||||
* true if the runtime should call this object's dtor and false if not.
|
||||
* Default behavior is to return true.
|
||||
*/
|
||||
extern (C) bool onCollectResource( Object obj )
|
||||
{
|
||||
if( GC.sm_collectHandler is null )
|
||||
return true;
|
||||
return GC.sm_collectHandler( obj );
|
||||
}
|
||||
87
tango/lib/common/tango/core/Runtime.d
Normal file
87
tango/lib/common/tango/core/Runtime.d
Normal file
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* The runtime module exposes information specific to the D runtime code.
|
||||
*
|
||||
* Copyright: Copyright (C) 2005-2006 Sean Kelly. All rights reserved.
|
||||
* License: BSD style: $(LICENSE)
|
||||
* Authors: Sean Kelly
|
||||
*/
|
||||
module tango.core.Runtime;
|
||||
|
||||
|
||||
private
|
||||
{
|
||||
extern (C) bool rt_isHalting();
|
||||
|
||||
alias bool function() moduleUnitTesterType;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Runtime
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* This struct encapsulates all functionality related to the underlying runtime
|
||||
* module for the calling context.
|
||||
*/
|
||||
struct Runtime
|
||||
{
|
||||
/**
|
||||
* Returns true if the runtime is halting. Under normal circumstances,
|
||||
* this will be set between the time that normal application code has
|
||||
* exited and before module dtors are called.
|
||||
*
|
||||
* Returns:
|
||||
* true if the runtime is halting.
|
||||
*/
|
||||
static bool isHalting()
|
||||
{
|
||||
return rt_isHalting();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overrides the default module unit tester with a user-supplied version.
|
||||
*
|
||||
* Params:
|
||||
* h = The new unit tester. Set to null to use the default unit tester.
|
||||
*/
|
||||
static void moduleUnitTester( moduleUnitTesterType h )
|
||||
{
|
||||
sm_moduleUnitTester = h;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
static moduleUnitTesterType sm_moduleUnitTester = null;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Overridable Callbacks
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* This routine is called by the runtime to run module unit tests on startup.
|
||||
* The user-supplied unit tester will be called if one has been supplied,
|
||||
* otherwise all unit tests will be run in sequence.
|
||||
*
|
||||
* Returns:
|
||||
* true if execution should continue after testing is complete and false if
|
||||
* not. Default behavior is to return true.
|
||||
*/
|
||||
extern (C) bool runModuleUnitTests()
|
||||
{
|
||||
if( Runtime.sm_moduleUnitTester is null )
|
||||
{
|
||||
foreach( m; ModuleInfo )
|
||||
{
|
||||
if( m.unitTest )
|
||||
m.unitTest();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return Runtime.sm_moduleUnitTester();
|
||||
}
|
||||
3256
tango/lib/common/tango/core/Thread.d
Normal file
3256
tango/lib/common/tango/core/Thread.d
Normal file
File diff suppressed because it is too large
Load Diff
136
tango/lib/common/tango/core/ThreadASM.S
Normal file
136
tango/lib/common/tango/core/ThreadASM.S
Normal file
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* Tango Fiber switching assembler code.
|
||||
*
|
||||
* Author: Mikola Lysenko
|
||||
*/
|
||||
|
||||
/************************************************************************************
|
||||
* POWER PC ASM BITS
|
||||
************************************************************************************/
|
||||
#if defined( __ppc__ ) || defined( __PPC__ ) || defined( __powerpc__ )
|
||||
|
||||
|
||||
/**
|
||||
* Performs a context switch.
|
||||
*
|
||||
* r3 - old context pointer
|
||||
* r4 - new context pointer
|
||||
*
|
||||
*/
|
||||
.text
|
||||
.align 2
|
||||
.globl _fiber_switchContext
|
||||
_fiber_switchContext:
|
||||
|
||||
/* Save linkage area */
|
||||
mflr r0
|
||||
mfcr r5
|
||||
stw r0, 8(r1)
|
||||
stw r5, 4(r1)
|
||||
|
||||
/* Save GPRs */
|
||||
stw r11, (-1 * 4)(r1)
|
||||
stw r13, (-2 * 4)(r1)
|
||||
stw r14, (-3 * 4)(r1)
|
||||
stw r15, (-4 * 4)(r1)
|
||||
stw r16, (-5 * 4)(r1)
|
||||
stw r17, (-6 * 4)(r1)
|
||||
stw r18, (-7 * 4)(r1)
|
||||
stw r19, (-8 * 4)(r1)
|
||||
stw r20, (-9 * 4)(r1)
|
||||
stw r21, (-10 * 4)(r1)
|
||||
stw r22, (-11 * 4)(r1)
|
||||
stw r23, (-12 * 4)(r1)
|
||||
stw r24, (-13 * 4)(r1)
|
||||
stw r25, (-14 * 4)(r1)
|
||||
stw r26, (-15 * 4)(r1)
|
||||
stw r27, (-16 * 4)(r1)
|
||||
stw r28, (-17 * 4)(r1)
|
||||
stw r29, (-18 * 4)(r1)
|
||||
stw r30, (-19 * 4)(r1)
|
||||
stwu r31, (-20 * 4)(r1)
|
||||
|
||||
/* We update the stack pointer here, since we do not want the GC to
|
||||
scan the floating point registers. */
|
||||
|
||||
/* Save FPRs */
|
||||
stfd f14, (-1 * 8)(r1)
|
||||
stfd f15, (-2 * 8)(r1)
|
||||
stfd f16, (-3 * 8)(r1)
|
||||
stfd f17, (-4 * 8)(r1)
|
||||
stfd f18, (-5 * 8)(r1)
|
||||
stfd f19, (-6 * 8)(r1)
|
||||
stfd f20, (-7 * 8)(r1)
|
||||
stfd f21, (-8 * 8)(r1)
|
||||
stfd f22, (-9 * 8)(r1)
|
||||
stfd f23, (-10 * 8)(r1)
|
||||
stfd f24, (-11 * 8)(r1)
|
||||
stfd f25, (-12 * 8)(r1)
|
||||
stfd f26, (-13 * 8)(r1)
|
||||
stfd f27, (-14 * 8)(r1)
|
||||
stfd f28, (-15 * 8)(r1)
|
||||
stfd f29, (-16 * 8)(r1)
|
||||
stfd f30, (-17 * 8)(r1)
|
||||
stfd f31, (-18 * 8)(r1)
|
||||
|
||||
/* Update the old stack pointer */
|
||||
stw r1, 0(r3)
|
||||
|
||||
/* Set new stack pointer */
|
||||
addi r1, r4, 20 * 4
|
||||
|
||||
/* Restore linkage area */
|
||||
lwz r0, 8(r1)
|
||||
lwz r5, 4(r1)
|
||||
|
||||
/* Restore GPRs */
|
||||
lwz r11, (-1 * 4)(r1)
|
||||
lwz r13, (-2 * 4)(r1)
|
||||
lwz r14, (-3 * 4)(r1)
|
||||
lwz r15, (-4 * 4)(r1)
|
||||
lwz r16, (-5 * 4)(r1)
|
||||
lwz r17, (-6 * 4)(r1)
|
||||
lwz r18, (-7 * 4)(r1)
|
||||
lwz r19, (-8 * 4)(r1)
|
||||
lwz r20, (-9 * 4)(r1)
|
||||
lwz r21, (-10 * 4)(r1)
|
||||
lwz r22, (-11 * 4)(r1)
|
||||
lwz r23, (-12 * 4)(r1)
|
||||
lwz r24, (-13 * 4)(r1)
|
||||
lwz r25, (-14 * 4)(r1)
|
||||
lwz r26, (-15 * 4)(r1)
|
||||
lwz r27, (-16 * 4)(r1)
|
||||
lwz r28, (-17 * 4)(r1)
|
||||
lwz r29, (-18 * 4)(r1)
|
||||
lwz r30, (-19 * 4)(r1)
|
||||
lwz r31, (-20 * 4)(r1)
|
||||
|
||||
|
||||
/* Restore FPRs */
|
||||
lfd f14, (-1 * 8)(r4)
|
||||
lfd f15, (-2 * 8)(r4)
|
||||
lfd f16, (-3 * 8)(r4)
|
||||
lfd f17, (-4 * 8)(r4)
|
||||
lfd f18, (-5 * 8)(r4)
|
||||
lfd f19, (-6 * 8)(r4)
|
||||
lfd f20, (-7 * 8)(r4)
|
||||
lfd f21, (-8 * 8)(r4)
|
||||
lfd f22, (-9 * 8)(r4)
|
||||
lfd f23, (-10 * 8)(r4)
|
||||
lfd f24, (-11 * 8)(r4)
|
||||
lfd f25, (-12 * 8)(r4)
|
||||
lfd f26, (-13 * 8)(r4)
|
||||
lfd f27, (-14 * 8)(r4)
|
||||
lfd f28, (-15 * 8)(r4)
|
||||
lfd f29, (-16 * 8)(r4)
|
||||
lfd f30, (-17 * 8)(r4)
|
||||
lfd f31, (-18 * 8)(r4)
|
||||
|
||||
/* Set condition and link register */
|
||||
mtcr r5
|
||||
mtlr r0
|
||||
|
||||
/* Return and switch context */
|
||||
blr
|
||||
|
||||
#endif
|
||||
139
tango/lib/common/tango/llvmdc.mak
Normal file
139
tango/lib/common/tango/llvmdc.mak
Normal file
@@ -0,0 +1,139 @@
|
||||
# Makefile to build the common D runtime library for LLVM
|
||||
# Designed to work with GNU make
|
||||
# Targets:
|
||||
# make
|
||||
# Same as make all
|
||||
# make lib
|
||||
# Build the common library
|
||||
# make doc
|
||||
# Generate documentation
|
||||
# make clean
|
||||
# Delete unneeded files created by build process
|
||||
|
||||
LIB_TARGET=libtango-cc-tango.a
|
||||
LIB_MASK=libtango-cc-tango*.a
|
||||
|
||||
CP=cp -f
|
||||
RM=rm -f
|
||||
MD=mkdir -p
|
||||
|
||||
ADD_CFLAGS=
|
||||
ADD_DFLAGS=
|
||||
|
||||
CFLAGS=-O $(ADD_CFLAGS)
|
||||
#CFLAGS=-g $(ADD_CFLAGS)
|
||||
|
||||
DFLAGS=-release -O -inline -w -nofloat $(ADD_DFLAGS)
|
||||
#DFLAGS=-g -w -nofloat $(ADD_DFLAGS)
|
||||
|
||||
TFLAGS=-O -inline -w -nofloat $(ADD_DFLAGS)
|
||||
#TFLAGS=-g -w -nofloat $(ADD_DFLAGS)
|
||||
|
||||
DOCFLAGS=-version=DDoc
|
||||
|
||||
CC=gcc
|
||||
LC=llvm-ar rsv
|
||||
DC=llvmdc
|
||||
LLC=llvm-as
|
||||
|
||||
INC_DEST=../../../tango
|
||||
LIB_DEST=..
|
||||
DOC_DEST=../../../doc/tango
|
||||
|
||||
.SUFFIXES: .s .S .c .cpp .d .ll .html .o .bc
|
||||
|
||||
.s.o:
|
||||
$(CC) -c $(CFLAGS) $< -o$@
|
||||
|
||||
.S.o:
|
||||
$(CC) -c $(CFLAGS) $< -o$@
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(CFLAGS) $< -o$@
|
||||
|
||||
.cpp.o:
|
||||
g++ -c $(CFLAGS) $< -o$@
|
||||
|
||||
.d.bc:
|
||||
$(DC) -c $(DFLAGS) -Hf$*.di $< -of$@
|
||||
# $(DC) -c $(DFLAGS) $< -of$@
|
||||
|
||||
.ll.bc:
|
||||
$(LLC) -f -o=$@ $<
|
||||
|
||||
.d.html:
|
||||
$(DC) -c -o- $(DOCFLAGS) -Df$*.html $<
|
||||
# $(DC) -c -o- $(DOCFLAGS) -Df$*.html tango.ddoc $<
|
||||
|
||||
targets : lib doc
|
||||
all : lib doc
|
||||
tango : lib
|
||||
lib : tango.lib
|
||||
doc : tango.doc
|
||||
|
||||
######################################################
|
||||
|
||||
OBJ_CORE= \
|
||||
core/BitManip.bc \
|
||||
core/Exception.bc \
|
||||
core/Memory.bc \
|
||||
core/Runtime.bc \
|
||||
core/Thread.bc
|
||||
# core/ThreadASM.o
|
||||
|
||||
OBJ_STDC= \
|
||||
stdc/wrap.bc
|
||||
|
||||
OBJ_STDC_POSIX= \
|
||||
stdc/posix/pthread_darwin.o
|
||||
|
||||
ALL_OBJS= \
|
||||
$(OBJ_CORE) \
|
||||
$(OBJ_STDC)
|
||||
# $(OBJ_STDC_POSIX)
|
||||
|
||||
######################################################
|
||||
|
||||
DOC_CORE= \
|
||||
core/BitManip.html \
|
||||
core/Exception.html \
|
||||
core/Memory.html \
|
||||
core/Runtime.html \
|
||||
core/Thread.html
|
||||
|
||||
|
||||
ALL_DOCS=
|
||||
|
||||
######################################################
|
||||
|
||||
tango.lib : $(LIB_TARGET)
|
||||
|
||||
$(LIB_TARGET) : $(ALL_OBJS)
|
||||
$(RM) $@
|
||||
$(LC) $@ $(ALL_OBJS)
|
||||
|
||||
tango.doc : $(ALL_DOCS)
|
||||
echo Documentation generated.
|
||||
|
||||
######################################################
|
||||
|
||||
### stdc/posix
|
||||
|
||||
#stdc/posix/pthread_darwin.o : stdc/posix/pthread_darwin.d
|
||||
# $(DC) -c $(DFLAGS) stdc/posix/pthread_darwin.d -of$@
|
||||
|
||||
######################################################
|
||||
|
||||
clean :
|
||||
find . -name "*.di" | xargs $(RM)
|
||||
$(RM) $(ALL_OBJS)
|
||||
$(RM) $(ALL_DOCS)
|
||||
find . -name "$(LIB_MASK)" | xargs $(RM)
|
||||
|
||||
install :
|
||||
$(MD) $(INC_DEST)
|
||||
find . -name "*.di" -exec cp -f {} $(INC_DEST)/{} \;
|
||||
$(MD) $(DOC_DEST)
|
||||
find . -name "*.html" -exec cp -f {} $(DOC_DEST)/{} \;
|
||||
$(MD) $(LIB_DEST)
|
||||
find . -name "$(LIB_MASK)" -exec cp -f {} $(LIB_DEST)/{} \;
|
||||
135
tango/lib/common/tango/posix.mak
Normal file
135
tango/lib/common/tango/posix.mak
Normal file
@@ -0,0 +1,135 @@
|
||||
# Makefile to build the common D runtime library for Linux
|
||||
# Designed to work with GNU make
|
||||
# Targets:
|
||||
# make
|
||||
# Same as make all
|
||||
# make lib
|
||||
# Build the common library
|
||||
# make doc
|
||||
# Generate documentation
|
||||
# make clean
|
||||
# Delete unneeded files created by build process
|
||||
|
||||
LIB_TARGET=libtango-cc-tango.a
|
||||
LIB_MASK=libtango-cc-tango*.a
|
||||
|
||||
CP=cp -f
|
||||
RM=rm -f
|
||||
MD=mkdir -p
|
||||
|
||||
ADD_CFLAGS=
|
||||
ADD_DFLAGS=
|
||||
|
||||
CFLAGS=-O -m32 $(ADD_CFLAGS)
|
||||
#CFLAGS=-g -m32 $(ADD_CFLAGS)
|
||||
|
||||
DFLAGS=-release -O -inline -w -nofloat -version=Posix $(ADD_DFLAGS)
|
||||
#DFLAGS=-g -w -nofloat -version=Posix $(ADD_DFLAGS)
|
||||
|
||||
TFLAGS=-O -inline -w -nofloat -version=Posix $(ADD_DFLAGS)
|
||||
#TFLAGS=-g -w -nofloat -version=Posix $(ADD_DFLAGS)
|
||||
|
||||
DOCFLAGS=-version=DDoc -version=Posix
|
||||
|
||||
CC=gcc
|
||||
LC=$(AR) -qsv
|
||||
DC=dmd
|
||||
|
||||
INC_DEST=../../../tango
|
||||
LIB_DEST=..
|
||||
DOC_DEST=../../../doc/tango
|
||||
|
||||
.SUFFIXES: .s .S .c .cpp .d .html .o
|
||||
|
||||
.s.o:
|
||||
$(CC) -c $(CFLAGS) $< -o$@
|
||||
|
||||
.S.o:
|
||||
$(CC) -c $(CFLAGS) $< -o$@
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(CFLAGS) $< -o$@
|
||||
|
||||
.cpp.o:
|
||||
g++ -c $(CFLAGS) $< -o$@
|
||||
|
||||
.d.o:
|
||||
$(DC) -c $(DFLAGS) -Hf$*.di $< -of$@
|
||||
# $(DC) -c $(DFLAGS) $< -of$@
|
||||
|
||||
.d.html:
|
||||
$(DC) -c -o- $(DOCFLAGS) -Df$*.html $<
|
||||
# $(DC) -c -o- $(DOCFLAGS) -Df$*.html tango.ddoc $<
|
||||
|
||||
targets : lib doc
|
||||
all : lib doc
|
||||
tango : lib
|
||||
lib : tango.lib
|
||||
doc : tango.doc
|
||||
|
||||
######################################################
|
||||
|
||||
OBJ_CORE= \
|
||||
core/BitManip.o \
|
||||
core/Exception.o \
|
||||
core/Memory.o \
|
||||
core/Runtime.o \
|
||||
core/Thread.o \
|
||||
core/ThreadASM.o
|
||||
|
||||
OBJ_STDC= \
|
||||
stdc/wrap.o
|
||||
|
||||
OBJ_STDC_POSIX= \
|
||||
stdc/posix/pthread_darwin.o
|
||||
|
||||
ALL_OBJS= \
|
||||
$(OBJ_CORE) \
|
||||
$(OBJ_STDC) \
|
||||
$(OBJ_STDC_POSIX)
|
||||
|
||||
######################################################
|
||||
|
||||
DOC_CORE= \
|
||||
core/BitManip.html \
|
||||
core/Exception.html \
|
||||
core/Memory.html \
|
||||
core/Runtime.html \
|
||||
core/Thread.html
|
||||
|
||||
|
||||
ALL_DOCS=
|
||||
|
||||
######################################################
|
||||
|
||||
tango.lib : $(LIB_TARGET)
|
||||
|
||||
$(LIB_TARGET) : $(ALL_OBJS)
|
||||
$(RM) $@
|
||||
$(LC) $@ $(ALL_OBJS)
|
||||
|
||||
tango.doc : $(ALL_DOCS)
|
||||
echo Documentation generated.
|
||||
|
||||
######################################################
|
||||
|
||||
### stdc/posix
|
||||
|
||||
stdc/posix/pthread_darwin.o : stdc/posix/pthread_darwin.d
|
||||
$(DC) -c $(DFLAGS) stdc/posix/pthread_darwin.d -of$@
|
||||
|
||||
######################################################
|
||||
|
||||
clean :
|
||||
find . -name "*.di" | xargs $(RM)
|
||||
$(RM) $(ALL_OBJS)
|
||||
$(RM) $(ALL_DOCS)
|
||||
find . -name "$(LIB_MASK)" | xargs $(RM)
|
||||
|
||||
install :
|
||||
$(MD) $(INC_DEST)
|
||||
find . -name "*.di" -exec cp -f {} $(INC_DEST)/{} \;
|
||||
$(MD) $(DOC_DEST)
|
||||
find . -name "*.html" -exec cp -f {} $(DOC_DEST)/{} \;
|
||||
$(MD) $(LIB_DEST)
|
||||
find . -name "$(LIB_MASK)" -exec cp -f {} $(LIB_DEST)/{} \;
|
||||
334
tango/lib/common/tango/stdc/posix/pthread_darwin.d
Normal file
334
tango/lib/common/tango/stdc/posix/pthread_darwin.d
Normal file
@@ -0,0 +1,334 @@
|
||||
/**
|
||||
* D header file for POSIX.
|
||||
*
|
||||
* Copyright: Public Domain
|
||||
* License: Public Domain
|
||||
* Authors: Sean Kelly
|
||||
* Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition
|
||||
*/
|
||||
module tango.stdc.posix.pthread;
|
||||
|
||||
public import tango.stdc.posix.sys.types;
|
||||
public import tango.stdc.posix.sched;
|
||||
public import tango.stdc.posix.time;
|
||||
private import tango.stdc.stdlib;
|
||||
|
||||
extern (C):
|
||||
|
||||
//
|
||||
// Required
|
||||
//
|
||||
|
||||
version( darwin )
|
||||
{
|
||||
int pthread_cond_broadcast(pthread_cond_t*);
|
||||
int pthread_cond_destroy(pthread_cond_t*);
|
||||
int pthread_cond_init(pthread_cond_t*, pthread_condattr_t*);
|
||||
//int pthread_cond_signal(pthread_cond_t*);
|
||||
//int pthread_cond_timedwait(pthread_cond_t*, pthread_mutex_t*, timespec*);
|
||||
int pthread_cond_wait(pthread_cond_t*, pthread_mutex_t*);
|
||||
|
||||
int pthread_mutex_destroy(pthread_mutex_t*);
|
||||
int pthread_mutex_init(pthread_mutex_t*, pthread_mutexattr_t*);
|
||||
int pthread_mutex_lock(pthread_mutex_t*);
|
||||
int pthread_mutex_trylock(pthread_mutex_t*);
|
||||
int pthread_mutex_unlock(pthread_mutex_t*);
|
||||
|
||||
//int pthread_rwlock_destroy(pthread_rwlock_t*);
|
||||
//int pthread_rwlock_init(pthread_rwlock_t*, pthread_rwlockattr_t*);
|
||||
//int pthread_rwlock_rdlock(pthread_rwlock_t*);
|
||||
int pthread_rwlock_tryrdlock(pthread_rwlock_t*);
|
||||
int pthread_rwlock_trywrlock(pthread_rwlock_t*);
|
||||
//int pthread_rwlock_unlock(pthread_rwlock_t*);
|
||||
//int pthread_rwlock_wrlock(pthread_rwlock_t*);
|
||||
}
|
||||
|
||||
//
|
||||
// Barrier (BAR)
|
||||
//
|
||||
/*
|
||||
PTHREAD_BARRIER_SERIAL_THREAD
|
||||
|
||||
int pthread_barrier_destroy(pthread_barrier_t*);
|
||||
int pthread_barrier_init(pthread_barrier_t*, pthread_barrierattr_t*, uint);
|
||||
int pthread_barrier_wait(pthread_barrier_t*);
|
||||
int pthread_barrierattr_destroy(pthread_barrierattr_t*);
|
||||
int pthread_barrierattr_getpshared(pthread_barrierattr_t*, int*); (BAR|TSH)
|
||||
int pthread_barrierattr_init(pthread_barrierattr_t*);
|
||||
int pthread_barrierattr_setpshared(pthread_barrierattr_t*, int); (BAR|TSH)
|
||||
*/
|
||||
|
||||
version( darwin )
|
||||
{
|
||||
const PTHREAD_BARRIER_SERIAL_THREAD = -1;
|
||||
|
||||
// defined in tango.stdc.posix.pthread and redefined here
|
||||
enum
|
||||
{
|
||||
PTHREAD_PROCESS_PRIVATE,
|
||||
PTHREAD_PROCESS_SHARED
|
||||
}
|
||||
|
||||
int pthread_barrier_destroy( pthread_barrier_t* barrier )
|
||||
{
|
||||
if( barrier is null )
|
||||
return EINVAL;
|
||||
if( barrier.b_waiters > 0 )
|
||||
return EBUSY;
|
||||
int mret = pthread_mutex_destroy( &barrier.b_lock );
|
||||
int cret = pthread_cond_destroy( &barrier.b_cond );
|
||||
free( barrier );
|
||||
return mret ? mret : cret;
|
||||
}
|
||||
|
||||
int pthread_barrier_init( pthread_barrier_t* barrier,
|
||||
pthread_barrierattr_t* attr,
|
||||
uint count )
|
||||
{
|
||||
if( barrier is null || count <= 0 )
|
||||
return EINVAL;
|
||||
|
||||
pthread_barrier_t* newbarrier = cast(pthread_barrier_t*)
|
||||
malloc( pthread_barrier_t.sizeof );
|
||||
if( newbarrier is null )
|
||||
return ENOMEM;
|
||||
|
||||
int ret;
|
||||
if( ( ret = pthread_mutex_init( &newbarrier.b_lock, null ) ) != 0 )
|
||||
{
|
||||
free( newbarrier );
|
||||
return ret;
|
||||
}
|
||||
if( ( ret = pthread_cond_init( &newbarrier.b_cond, null ) ) != 0 )
|
||||
{
|
||||
pthread_mutex_destroy( &newbarrier.b_lock );
|
||||
free( newbarrier );
|
||||
return ret;
|
||||
}
|
||||
newbarrier.b_waiters = 0;
|
||||
newbarrier.b_count = count;
|
||||
newbarrier.b_generation = 0;
|
||||
*barrier = *newbarrier;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_barrier_wait( pthread_barrier_t* barrier )
|
||||
{
|
||||
if( barrier is null )
|
||||
return EINVAL;
|
||||
|
||||
int ret;
|
||||
if( ( ret = pthread_mutex_lock( &barrier.b_lock ) ) != 0 )
|
||||
return ret;
|
||||
|
||||
if( ++barrier.b_waiters == barrier.b_count )
|
||||
{
|
||||
// current thread is lastest thread
|
||||
barrier.b_generation++;
|
||||
barrier.b_waiters = 0;
|
||||
if( ( ret = pthread_cond_broadcast( &barrier.b_cond ) ) == 0 )
|
||||
ret = PTHREAD_BARRIER_SERIAL_THREAD;
|
||||
}
|
||||
else
|
||||
{
|
||||
int gen = barrier.b_generation;
|
||||
do
|
||||
{
|
||||
ret = pthread_cond_wait( &barrier.b_cond, &barrier.b_lock );
|
||||
// test generation to avoid bogus wakeup
|
||||
} while( ret == 0 && gen == barrier.b_generation );
|
||||
}
|
||||
pthread_mutex_unlock( &barrier.b_lock );
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pthread_barrierattr_destroy( pthread_barrierattr_t* attr )
|
||||
{
|
||||
if( attr is null )
|
||||
return EINVAL;
|
||||
free( attr );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_barrierattr_getpshared( pthread_barrierattr_t* attr, int* pshared )
|
||||
{
|
||||
if( attr is null )
|
||||
return EINVAL;
|
||||
*pshared = attr.pshared;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_barrierattr_init( pthread_barrierattr_t* attr )
|
||||
{
|
||||
if( attr is null )
|
||||
return EINVAL;
|
||||
if( ( attr = cast(pthread_barrierattr_t*)
|
||||
malloc( pthread_barrierattr_t.sizeof ) ) is null )
|
||||
return ENOMEM;
|
||||
attr.pshared = PTHREAD_PROCESS_PRIVATE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_barrierattr_setpshared( pthread_barrierattr_t* attr, int pshared )
|
||||
{
|
||||
if( attr is null )
|
||||
return EINVAL;
|
||||
// only PTHREAD_PROCESS_PRIVATE is supported
|
||||
if( pshared != PTHREAD_PROCESS_PRIVATE )
|
||||
return EINVAL;
|
||||
attr.pshared = pshared;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Timeouts (TMO)
|
||||
//
|
||||
/*
|
||||
int pthread_mutex_timedlock(pthread_mutex_t*, timespec*);
|
||||
int pthread_rwlock_timedrdlock(pthread_rwlock_t*, timespec*);
|
||||
int pthread_rwlock_timedwrlock(pthread_rwlock_t*, timespec*);
|
||||
*/
|
||||
|
||||
version( darwin )
|
||||
{
|
||||
private
|
||||
{
|
||||
import tango.stdc.errno;
|
||||
import tango.stdc.posix.unistd;
|
||||
import tango.stdc.posix.sys.time;
|
||||
|
||||
extern (D)
|
||||
{
|
||||
void timerclear( timeval* tvp )
|
||||
{
|
||||
tvp.tv_sec = tvp.tv_usec = 0;
|
||||
}
|
||||
|
||||
bool timerisset( timeval* tvp )
|
||||
{
|
||||
return tvp.tv_sec || tvp.tv_usec;
|
||||
}
|
||||
|
||||
bool timer_cmp_leq( timeval* tvp, timeval* uvp )
|
||||
{
|
||||
return tvp.tv_sec == uvp.tv_sec ?
|
||||
tvp.tv_usec <= uvp.tv_usec :
|
||||
tvp.tv_sec <= uvp.tv_sec;
|
||||
}
|
||||
|
||||
void timeradd( timeval* tvp, timeval* uvp, timeval* vvp )
|
||||
{
|
||||
vvp.tv_sec = tvp.tv_sec + uvp.tv_sec;
|
||||
vvp.tv_usec = tvp.tv_usec + uvp.tv_usec;
|
||||
if( vvp.tv_usec >= 1000000 )
|
||||
{
|
||||
vvp.tv_sec++;
|
||||
vvp.tv_usec -= 1000000;
|
||||
}
|
||||
}
|
||||
|
||||
void timersub( timeval* tvp, timeval* uvp, timeval* vvp )
|
||||
{
|
||||
vvp.tv_sec = tvp.tv_sec - uvp.tv_sec;
|
||||
vvp.tv_usec = tvp.tv_usec - uvp.tv_usec;
|
||||
if( vvp.tv_usec < 0 )
|
||||
{
|
||||
vvp.tv_sec--;
|
||||
vvp.tv_usec += 1000000;
|
||||
}
|
||||
}
|
||||
|
||||
void TIMEVAL_TO_TIMESPEC( timeval* tv, timespec* ts )
|
||||
{
|
||||
ts.tv_sec = tv.tv_sec;
|
||||
ts.tv_nsec = tv.tv_usec * 1000;
|
||||
}
|
||||
|
||||
void TIMESPEC_TO_TIMEVAL( timeval* tv, timespec* ts )
|
||||
{
|
||||
tv.tv_sec = ts.tv_sec;
|
||||
tv.tv_usec = ts.tv_nsec / 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int pthread_mutex_timedlock( pthread_mutex_t* m, timespec* t )
|
||||
{
|
||||
timeval currtime;
|
||||
timeval maxwait;
|
||||
TIMESPEC_TO_TIMEVAL( &maxwait, t );
|
||||
timeval waittime;
|
||||
waittime.tv_usec = 100;
|
||||
|
||||
while( timer_cmp_leq( &currtime, &maxwait ) )
|
||||
{
|
||||
int ret = pthread_mutex_trylock( m );
|
||||
switch( ret )
|
||||
{
|
||||
case 0: // locked successfully
|
||||
return ret;
|
||||
case EBUSY: // waiting
|
||||
timeradd( &currtime, &waittime, &currtime );
|
||||
break;
|
||||
default:
|
||||
return ret;
|
||||
}
|
||||
usleep( waittime.tv_usec );
|
||||
}
|
||||
return ETIMEDOUT;
|
||||
}
|
||||
|
||||
int pthread_rwlock_timedrdlock( pthread_rwlock_t *rwlock, timespec* t )
|
||||
{
|
||||
timeval currtime;
|
||||
timeval maxwait;
|
||||
TIMESPEC_TO_TIMEVAL( &maxwait, t );
|
||||
timeval waittime;
|
||||
waittime.tv_usec = 100;
|
||||
|
||||
while( timer_cmp_leq( &currtime, &maxwait ) )
|
||||
{
|
||||
int ret = pthread_rwlock_tryrdlock( rwlock );
|
||||
switch( ret )
|
||||
{
|
||||
case 0: // locked successfully
|
||||
return ret;
|
||||
case EBUSY: // waiting
|
||||
timeradd( &currtime, &waittime, &currtime );
|
||||
break;
|
||||
default:
|
||||
return ret;
|
||||
}
|
||||
usleep( waittime.tv_usec );
|
||||
}
|
||||
return ETIMEDOUT;
|
||||
}
|
||||
|
||||
int pthread_rwlock_timedwrlock( pthread_rwlock_t* l, timespec* t )
|
||||
{
|
||||
timeval currtime;
|
||||
timeval maxwait;
|
||||
TIMESPEC_TO_TIMEVAL( &maxwait, t );
|
||||
timeval waittime;
|
||||
waittime.tv_usec = 100;
|
||||
|
||||
while( timer_cmp_leq( &currtime, &maxwait ) )
|
||||
{
|
||||
int ret = pthread_rwlock_trywrlock( l );
|
||||
switch( ret )
|
||||
{
|
||||
case 0: // locked successfully
|
||||
return ret;
|
||||
case EBUSY: // waiting
|
||||
timeradd( &currtime, &waittime, &currtime );
|
||||
break;
|
||||
default:
|
||||
return ret;
|
||||
}
|
||||
usleep( waittime.tv_usec );
|
||||
}
|
||||
return ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
14
tango/lib/common/tango/stdc/wrap.c
Normal file
14
tango/lib/common/tango/stdc/wrap.c
Normal file
@@ -0,0 +1,14 @@
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
int getErrno()
|
||||
{
|
||||
return errno;
|
||||
}
|
||||
|
||||
|
||||
int setErrno( int val )
|
||||
{
|
||||
errno = val;
|
||||
return val;
|
||||
}
|
||||
14
tango/lib/common/tango/stdc/wrap.ll
Normal file
14
tango/lib/common/tango/stdc/wrap.ll
Normal file
@@ -0,0 +1,14 @@
|
||||
; ModuleID = 'wrap.bc'
|
||||
@errno = external global i32 ; <i32*> [#uses=2]
|
||||
|
||||
define i32 @getErrno() {
|
||||
entry:
|
||||
%tmp = load i32* @errno ; <i32> [#uses=1]
|
||||
ret i32 %tmp
|
||||
}
|
||||
|
||||
define i32 @setErrno(i32 %val) {
|
||||
entry:
|
||||
store i32 %val, i32* @errno
|
||||
ret i32 %val
|
||||
}
|
||||
126
tango/lib/common/tango/win32.mak
Normal file
126
tango/lib/common/tango/win32.mak
Normal file
@@ -0,0 +1,126 @@
|
||||
# Makefile to build the common D runtime library for Win32
|
||||
# Designed to work with DigitalMars make
|
||||
# Targets:
|
||||
# make
|
||||
# Same as make all
|
||||
# make lib
|
||||
# Build the common library
|
||||
# make doc
|
||||
# Generate documentation
|
||||
# make clean
|
||||
# Delete unneeded files created by build process
|
||||
|
||||
LIB_TARGET=tango-cc-tango.lib
|
||||
LIB_MASK=tango-cc-tango*.lib
|
||||
|
||||
CP=xcopy /y
|
||||
RM=del /f
|
||||
MD=mkdir
|
||||
|
||||
ADD_CFLAGS=
|
||||
ADD_DFLAGS=
|
||||
|
||||
CFLAGS=-mn -6 -r $(ADD_CFLAGS)
|
||||
#CFLAGS=-g -mn -6 -r $(ADD_CFLAGS)
|
||||
|
||||
DFLAGS=-release -O -inline -w -nofloat $(ADD_DFLAGS)
|
||||
#DFLAGS=-g -w -nofloat $(ADD_DFLAGS)
|
||||
|
||||
TFLAGS=-O -inline -w -nofloat $(ADD_DFLAGS)
|
||||
#TFLAGS=-g -w -nofloat $(ADD_DFLAGS)
|
||||
|
||||
DOCFLAGS=-version=DDoc
|
||||
|
||||
CC=dmc
|
||||
LC=lib
|
||||
DC=dmd
|
||||
|
||||
INC_DEST=..\..\..\tango
|
||||
LIB_DEST=..
|
||||
DOC_DEST=..\..\..\doc\tango
|
||||
|
||||
.DEFAULT: .asm .c .cpp .d .html .obj
|
||||
|
||||
.asm.obj:
|
||||
$(CC) -c $<
|
||||
|
||||
.c.obj:
|
||||
$(CC) -c $(CFLAGS) $< -o$@
|
||||
|
||||
.cpp.obj:
|
||||
$(CC) -c $(CFLAGS) $< -o$@
|
||||
|
||||
.d.obj:
|
||||
$(DC) -c $(DFLAGS) -Hf$*.di $< -of$@
|
||||
# $(DC) -c $(DFLAGS) $< -of$@
|
||||
|
||||
.d.html:
|
||||
$(DC) -c -o- $(DOCFLAGS) -Df$*.html $<
|
||||
# $(DC) -c -o- $(DOCFLAGS) -Df$*.html tango.ddoc $<
|
||||
|
||||
targets : lib doc
|
||||
all : lib doc
|
||||
tango : lib
|
||||
lib : tango.lib
|
||||
doc : tango.doc
|
||||
|
||||
######################################################
|
||||
|
||||
OBJ_CORE= \
|
||||
core\BitManip.obj \
|
||||
core\Exception.obj \
|
||||
core\Memory.obj \
|
||||
core\Runtime.obj \
|
||||
core\Thread.obj
|
||||
|
||||
OBJ_STDC= \
|
||||
stdc\wrap.obj
|
||||
|
||||
ALL_OBJS= \
|
||||
$(OBJ_CORE) \
|
||||
$(OBJ_STDC)
|
||||
|
||||
######################################################
|
||||
|
||||
DOC_CORE= \
|
||||
core\BitManip.html \
|
||||
core\Exception.html \
|
||||
core\Memory.html \
|
||||
core\Runtime.html \
|
||||
core\Thread.html
|
||||
|
||||
ALL_DOCS=
|
||||
|
||||
######################################################
|
||||
|
||||
tango.lib : $(LIB_TARGET)
|
||||
|
||||
$(LIB_TARGET) : $(ALL_OBJS)
|
||||
$(RM) $@
|
||||
$(LC) -c -n $@ $(ALL_OBJS)
|
||||
|
||||
tango.doc : $(ALL_DOCS)
|
||||
@echo Documentation generated.
|
||||
|
||||
######################################################
|
||||
|
||||
### config
|
||||
|
||||
# config.obj : config.d
|
||||
# $(DC) -c $(DFLAGS) config.d -of$@
|
||||
|
||||
######################################################
|
||||
|
||||
clean :
|
||||
$(RM) /s .\*.di
|
||||
$(RM) $(ALL_OBJS)
|
||||
$(RM) $(ALL_DOCS)
|
||||
$(RM) $(LIB_MASK)
|
||||
|
||||
install :
|
||||
$(MD) $(INC_DEST)
|
||||
$(CP) /s *.di $(INC_DEST)\.
|
||||
$(MD) $(DOC_DEST)
|
||||
$(CP) /s *.html $(DOC_DEST)\.
|
||||
$(MD) $(LIB_DEST)
|
||||
$(CP) $(LIB_MASK) $(LIB_DEST)\.
|
||||
406
tango/lib/compiler/llvmdc/aApply.d
Normal file
406
tango/lib/compiler/llvmdc/aApply.d
Normal file
@@ -0,0 +1,406 @@
|
||||
/**
|
||||
* Part of the D programming language runtime library.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
|
||||
* Written by Walter Bright
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, in both source and binary form, subject to the following
|
||||
* restrictions:
|
||||
*
|
||||
* o The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* o Altered source versions must be plainly marked as such, and must not
|
||||
* be misrepresented as being the original software.
|
||||
* o This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by Sean Kelly <sean@f4.ca> for use with Tango.
|
||||
*/
|
||||
|
||||
/* This code handles decoding UTF strings for foreach loops.
|
||||
* There are 6 combinations of conversions between char, wchar,
|
||||
* and dchar, and 2 of each of those.
|
||||
*/
|
||||
|
||||
private import util.utf;
|
||||
|
||||
/**********************************************
|
||||
*/
|
||||
|
||||
// dg is D, but _aApplycd() is C
|
||||
extern (D) typedef int delegate(void *) dg_t;
|
||||
|
||||
extern (C) int _aApplycd1(char[] aa, dg_t dg)
|
||||
{ int result;
|
||||
size_t i;
|
||||
size_t len = aa.length;
|
||||
|
||||
debug(apply) printf("_aApplycd1(), len = %d\n", len);
|
||||
for (i = 0; i < len; )
|
||||
{ dchar d;
|
||||
|
||||
d = aa[i];
|
||||
if (d & 0x80)
|
||||
d = decode(aa, i);
|
||||
else
|
||||
i++;
|
||||
result = dg(cast(void *)&d);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C) int _aApplywd1(wchar[] aa, dg_t dg)
|
||||
{ int result;
|
||||
size_t i;
|
||||
size_t len = aa.length;
|
||||
|
||||
debug(apply) printf("_aApplywd1(), len = %d\n", len);
|
||||
for (i = 0; i < len; )
|
||||
{ dchar d;
|
||||
|
||||
d = aa[i];
|
||||
if (d & ~0x7F)
|
||||
d = decode(aa, i);
|
||||
else
|
||||
i++;
|
||||
result = dg(cast(void *)&d);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C) int _aApplycw1(char[] aa, dg_t dg)
|
||||
{ int result;
|
||||
size_t i;
|
||||
size_t len = aa.length;
|
||||
|
||||
debug(apply) printf("_aApplycw1(), len = %d\n", len);
|
||||
for (i = 0; i < len; )
|
||||
{ dchar d;
|
||||
wchar w;
|
||||
|
||||
w = aa[i];
|
||||
if (w & 0x80)
|
||||
{ d = decode(aa, i);
|
||||
if (d <= 0xFFFF)
|
||||
w = cast(wchar) d;
|
||||
else
|
||||
{
|
||||
w = cast(wchar)((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||
result = dg(cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
w = cast(wchar)(((d - 0x10000) & 0x3FF) + 0xDC00);
|
||||
}
|
||||
}
|
||||
else
|
||||
i++;
|
||||
result = dg(cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C) int _aApplywc1(wchar[] aa, dg_t dg)
|
||||
{ int result;
|
||||
size_t i;
|
||||
size_t len = aa.length;
|
||||
|
||||
debug(apply) printf("_aApplywc1(), len = %d\n", len);
|
||||
for (i = 0; i < len; )
|
||||
{ dchar d;
|
||||
wchar w;
|
||||
char c;
|
||||
|
||||
w = aa[i];
|
||||
if (w & ~0x7F)
|
||||
{
|
||||
char[4] buf;
|
||||
|
||||
d = decode(aa, i);
|
||||
auto b = toUTF8(buf, d);
|
||||
foreach (char c2; b)
|
||||
{
|
||||
result = dg(cast(void *)&c2);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{ c = cast(char)w;
|
||||
i++;
|
||||
}
|
||||
result = dg(cast(void *)&c);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C) int _aApplydc1(dchar[] aa, dg_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplydc1(), len = %d\n", aa.length);
|
||||
foreach (dchar d; aa)
|
||||
{
|
||||
char c;
|
||||
|
||||
if (d & ~0x7F)
|
||||
{
|
||||
char[4] buf;
|
||||
|
||||
auto b = toUTF8(buf, d);
|
||||
foreach (char c2; b)
|
||||
{
|
||||
result = dg(cast(void *)&c2);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
c = cast(char)d;
|
||||
}
|
||||
result = dg(cast(void *)&c);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C) int _aApplydw1(dchar[] aa, dg_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplydw1(), len = %d\n", aa.length);
|
||||
foreach (dchar d; aa)
|
||||
{
|
||||
wchar w;
|
||||
|
||||
if (d <= 0xFFFF)
|
||||
w = cast(wchar) d;
|
||||
else
|
||||
{
|
||||
w = cast(wchar)((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||
result = dg(cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
w = cast(wchar)(((d - 0x10000) & 0x3FF) + 0xDC00);
|
||||
}
|
||||
result = dg(cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
// dg is D, but _aApplycd2() is C
|
||||
extern (D) typedef int delegate(void *, void *) dg2_t;
|
||||
|
||||
extern (C) int _aApplycd2(char[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
size_t i;
|
||||
size_t n;
|
||||
size_t len = aa.length;
|
||||
|
||||
debug(apply) printf("_aApplycd2(), len = %d\n", len);
|
||||
for (i = 0; i < len; i += n)
|
||||
{ dchar d;
|
||||
|
||||
d = aa[i];
|
||||
if (d & 0x80)
|
||||
{
|
||||
n = i;
|
||||
d = decode(aa, n);
|
||||
n -= i;
|
||||
}
|
||||
else
|
||||
n = 1;
|
||||
result = dg(&i, cast(void *)&d);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C) int _aApplywd2(wchar[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
size_t i;
|
||||
size_t n;
|
||||
size_t len = aa.length;
|
||||
|
||||
debug(apply) printf("_aApplywd2(), len = %d\n", len);
|
||||
for (i = 0; i < len; i += n)
|
||||
{ dchar d;
|
||||
|
||||
d = aa[i];
|
||||
if (d & ~0x7F)
|
||||
{
|
||||
n = i;
|
||||
d = decode(aa, n);
|
||||
n -= i;
|
||||
}
|
||||
else
|
||||
n = 1;
|
||||
result = dg(&i, cast(void *)&d);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C) int _aApplycw2(char[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
size_t i;
|
||||
size_t n;
|
||||
size_t len = aa.length;
|
||||
|
||||
debug(apply) printf("_aApplycw2(), len = %d\n", len);
|
||||
for (i = 0; i < len; i += n)
|
||||
{ dchar d;
|
||||
wchar w;
|
||||
|
||||
w = aa[i];
|
||||
if (w & 0x80)
|
||||
{ n = i;
|
||||
d = decode(aa, n);
|
||||
n -= i;
|
||||
if (d <= 0xFFFF)
|
||||
w = cast(wchar) d;
|
||||
else
|
||||
{
|
||||
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||
result = dg(&i, cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
|
||||
}
|
||||
}
|
||||
else
|
||||
n = 1;
|
||||
result = dg(&i, cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C) int _aApplywc2(wchar[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
size_t i;
|
||||
size_t n;
|
||||
size_t len = aa.length;
|
||||
|
||||
debug(apply) printf("_aApplywc2(), len = %d\n", len);
|
||||
for (i = 0; i < len; i += n)
|
||||
{ dchar d;
|
||||
wchar w;
|
||||
char c;
|
||||
|
||||
w = aa[i];
|
||||
if (w & ~0x7F)
|
||||
{
|
||||
char[4] buf;
|
||||
|
||||
n = i;
|
||||
d = decode(aa, n);
|
||||
n -= i;
|
||||
auto b = toUTF8(buf, d);
|
||||
foreach (char c2; b)
|
||||
{
|
||||
result = dg(&i, cast(void *)&c2);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{ c = cast(char)w;
|
||||
n = 1;
|
||||
}
|
||||
result = dg(&i, cast(void *)&c);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C) int _aApplydc2(dchar[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
size_t i;
|
||||
size_t len = aa.length;
|
||||
|
||||
debug(apply) printf("_aApplydc2(), len = %d\n", len);
|
||||
for (i = 0; i < len; i++)
|
||||
{ dchar d;
|
||||
char c;
|
||||
|
||||
d = aa[i];
|
||||
if (d & ~0x7F)
|
||||
{
|
||||
char[4] buf;
|
||||
|
||||
auto b = toUTF8(buf, d);
|
||||
foreach (char c2; b)
|
||||
{
|
||||
result = dg(&i, cast(void *)&c2);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{ c = cast(char)d;
|
||||
}
|
||||
result = dg(&i, cast(void *)&c);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C) int _aApplydw2(dchar[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplydw2(), len = %d\n", aa.length);
|
||||
foreach (size_t i, dchar d; aa)
|
||||
{
|
||||
wchar w;
|
||||
auto j = i;
|
||||
|
||||
if (d <= 0xFFFF)
|
||||
w = cast(wchar) d;
|
||||
else
|
||||
{
|
||||
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||
result = dg(&j, cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
|
||||
}
|
||||
result = dg(&j, cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
975
tango/lib/compiler/llvmdc/aApplyR.d
Normal file
975
tango/lib/compiler/llvmdc/aApplyR.d
Normal file
@@ -0,0 +1,975 @@
|
||||
|
||||
/**
|
||||
* Part of the D programming language runtime library.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
|
||||
* Written by Walter Bright
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, in both source and binary form, subject to the following
|
||||
* restrictions:
|
||||
*
|
||||
* o The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* o Altered source versions must be plainly marked as such, and must not
|
||||
* be misrepresented as being the original software.
|
||||
* o This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by Sean Kelly <sean@f4.ca> for use with Tango.
|
||||
*/
|
||||
|
||||
/* This code handles decoding UTF strings for foreach_reverse loops.
|
||||
* There are 6 combinations of conversions between char, wchar,
|
||||
* and dchar, and 2 of each of those.
|
||||
*/
|
||||
|
||||
private import util.utf;
|
||||
|
||||
/**********************************************/
|
||||
/* 1 argument versions */
|
||||
|
||||
// dg is D, but _aApplyRcd() is C
|
||||
extern (D) typedef int delegate(void *) dg_t;
|
||||
|
||||
extern (C) int _aApplyRcd1(in char[] aa, dg_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRcd1(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0; )
|
||||
{ dchar d;
|
||||
|
||||
i--;
|
||||
d = aa[i];
|
||||
if (d & 0x80)
|
||||
{ char c = cast(char)d;
|
||||
uint j;
|
||||
uint m = 0x3F;
|
||||
d = 0;
|
||||
while ((c & 0xC0) != 0xC0)
|
||||
{ if (i == 0)
|
||||
onUnicodeError("Invalid UTF-8 sequence", 0);
|
||||
i--;
|
||||
d |= (c & 0x3F) << j;
|
||||
j += 6;
|
||||
m >>= 1;
|
||||
c = aa[i];
|
||||
}
|
||||
d |= (c & m) << j;
|
||||
}
|
||||
result = dg(cast(void *)&d);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRcd1.unittest\n");
|
||||
|
||||
auto s = "hello"c;
|
||||
int i;
|
||||
|
||||
foreach_reverse(dchar d; s)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(dchar d; s)
|
||||
{
|
||||
//printf("i = %d, d = %x\n", i, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'b'); break;
|
||||
case 1: assert(d == '\U00100456'); break;
|
||||
case 2: assert(d == '\u1234'); break;
|
||||
case 3: assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 4);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
||||
extern (C) int _aApplyRwd1(in wchar[] aa, dg_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRwd1(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0; )
|
||||
{ dchar d;
|
||||
|
||||
i--;
|
||||
d = aa[i];
|
||||
if (d >= 0xDC00 && d <= 0xDFFF)
|
||||
{ if (i == 0)
|
||||
onUnicodeError("Invalid UTF-16 sequence", 0);
|
||||
i--;
|
||||
d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
|
||||
}
|
||||
result = dg(cast(void *)&d);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRwd1.unittest\n");
|
||||
|
||||
auto s = "hello"w;
|
||||
int i;
|
||||
|
||||
foreach_reverse(dchar d; s)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(dchar d; s)
|
||||
{
|
||||
//printf("i = %d, d = %x\n", i, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'b'); break;
|
||||
case 1: assert(d == '\U00100456'); break;
|
||||
case 2: assert(d == '\u1234'); break;
|
||||
case 3: assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 4);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
||||
extern (C) int _aApplyRcw1(in char[] aa, dg_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRcw1(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0; )
|
||||
{ dchar d;
|
||||
wchar w;
|
||||
|
||||
i--;
|
||||
w = aa[i];
|
||||
if (w & 0x80)
|
||||
{ char c = cast(char)w;
|
||||
uint j;
|
||||
uint m = 0x3F;
|
||||
d = 0;
|
||||
while ((c & 0xC0) != 0xC0)
|
||||
{ if (i == 0)
|
||||
onUnicodeError("Invalid UTF-8 sequence", 0);
|
||||
i--;
|
||||
d |= (c & 0x3F) << j;
|
||||
j += 6;
|
||||
m >>= 1;
|
||||
c = aa[i];
|
||||
}
|
||||
d |= (c & m) << j;
|
||||
|
||||
if (d <= 0xFFFF)
|
||||
w = cast(wchar) d;
|
||||
else
|
||||
{
|
||||
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||
result = dg(cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
|
||||
}
|
||||
}
|
||||
result = dg(cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRcw1.unittest\n");
|
||||
|
||||
auto s = "hello"c;
|
||||
int i;
|
||||
|
||||
foreach_reverse(wchar d; s)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(wchar d; s)
|
||||
{
|
||||
//printf("i = %d, d = %x\n", i, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'b'); break;
|
||||
case 1: assert(d == 0xDBC1); break;
|
||||
case 2: assert(d == 0xDC56); break;
|
||||
case 3: assert(d == 0x1234); break;
|
||||
case 4: assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
||||
extern (C) int _aApplyRwc1(in wchar[] aa, dg_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRwc1(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0; )
|
||||
{ dchar d;
|
||||
char c;
|
||||
|
||||
i--;
|
||||
d = aa[i];
|
||||
if (d >= 0xDC00 && d <= 0xDFFF)
|
||||
{ if (i == 0)
|
||||
onUnicodeError("Invalid UTF-16 sequence", 0);
|
||||
i--;
|
||||
d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
|
||||
}
|
||||
|
||||
if (d & ~0x7F)
|
||||
{
|
||||
char[4] buf;
|
||||
|
||||
auto b = toUTF8(buf, d);
|
||||
foreach (char c2; b)
|
||||
{
|
||||
result = dg(cast(void *)&c2);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
c = cast(char)d;
|
||||
result = dg(cast(void *)&c);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRwc1.unittest\n");
|
||||
|
||||
auto s = "hello"w;
|
||||
int i;
|
||||
|
||||
foreach_reverse(char d; s)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(char d; s)
|
||||
{
|
||||
//printf("i = %d, d = %x\n", i, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'b'); break;
|
||||
case 1: assert(d == 0xF4); break;
|
||||
case 2: assert(d == 0x80); break;
|
||||
case 3: assert(d == 0x91); break;
|
||||
case 4: assert(d == 0x96); break;
|
||||
case 5: assert(d == 0xE1); break;
|
||||
case 6: assert(d == 0x88); break;
|
||||
case 7: assert(d == 0xB4); break;
|
||||
case 8: assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 9);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
||||
extern (C) int _aApplyRdc1(in dchar[] aa, dg_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRdc1(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0;)
|
||||
{ dchar d = aa[--i];
|
||||
char c;
|
||||
|
||||
if (d & ~0x7F)
|
||||
{
|
||||
char[4] buf;
|
||||
|
||||
auto b = toUTF8(buf, d);
|
||||
foreach (char c2; b)
|
||||
{
|
||||
result = dg(cast(void *)&c2);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
c = cast(char)d;
|
||||
}
|
||||
result = dg(cast(void *)&c);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRdc1.unittest\n");
|
||||
|
||||
auto s = "hello"d;
|
||||
int i;
|
||||
|
||||
foreach_reverse(char d; s)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(char d; s)
|
||||
{
|
||||
//printf("i = %d, d = %x\n", i, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'b'); break;
|
||||
case 1: assert(d == 0xF4); break;
|
||||
case 2: assert(d == 0x80); break;
|
||||
case 3: assert(d == 0x91); break;
|
||||
case 4: assert(d == 0x96); break;
|
||||
case 5: assert(d == 0xE1); break;
|
||||
case 6: assert(d == 0x88); break;
|
||||
case 7: assert(d == 0xB4); break;
|
||||
case 8: assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 9);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
||||
extern (C) int _aApplyRdw1(in dchar[] aa, dg_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRdw1(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0; )
|
||||
{ dchar d = aa[--i];
|
||||
wchar w;
|
||||
|
||||
if (d <= 0xFFFF)
|
||||
w = cast(wchar) d;
|
||||
else
|
||||
{
|
||||
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||
result = dg(cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
|
||||
}
|
||||
result = dg(cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRdw1.unittest\n");
|
||||
|
||||
auto s = "hello"d;
|
||||
int i;
|
||||
|
||||
foreach_reverse(wchar d; s)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(wchar d; s)
|
||||
{
|
||||
//printf("i = %d, d = %x\n", i, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'b'); break;
|
||||
case 1: assert(d == 0xDBC1); break;
|
||||
case 2: assert(d == 0xDC56); break;
|
||||
case 3: assert(d == 0x1234); break;
|
||||
case 4: assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
/* 2 argument versions */
|
||||
|
||||
// dg is D, but _aApplyRcd2() is C
|
||||
extern (D) typedef int delegate(void *, void *) dg2_t;
|
||||
|
||||
extern (C) int _aApplyRcd2(in char[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
size_t i;
|
||||
size_t len = aa.length;
|
||||
|
||||
debug(apply) printf("_aApplyRcd2(), len = %d\n", len);
|
||||
for (i = len; i != 0; )
|
||||
{ dchar d;
|
||||
|
||||
i--;
|
||||
d = aa[i];
|
||||
if (d & 0x80)
|
||||
{ char c = cast(char)d;
|
||||
uint j;
|
||||
uint m = 0x3F;
|
||||
d = 0;
|
||||
while ((c & 0xC0) != 0xC0)
|
||||
{ if (i == 0)
|
||||
onUnicodeError("Invalid UTF-8 sequence", 0);
|
||||
i--;
|
||||
d |= (c & 0x3F) << j;
|
||||
j += 6;
|
||||
m >>= 1;
|
||||
c = aa[i];
|
||||
}
|
||||
d |= (c & m) << j;
|
||||
}
|
||||
result = dg(&i, cast(void *)&d);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRcd2.unittest\n");
|
||||
|
||||
auto s = "hello"c;
|
||||
int i;
|
||||
|
||||
foreach_reverse(k, dchar d; s)
|
||||
{
|
||||
assert(k == 4 - i);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(k, dchar d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'b'); assert(k == 8); break;
|
||||
case 1: assert(d == '\U00100456'); assert(k == 4); break;
|
||||
case 2: assert(d == '\u1234'); assert(k == 1); break;
|
||||
case 3: assert(d == 'a'); assert(k == 0); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 4);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
||||
extern (C) int _aApplyRwd2(in wchar[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRwd2(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0; )
|
||||
{ dchar d;
|
||||
|
||||
i--;
|
||||
d = aa[i];
|
||||
if (d >= 0xDC00 && d <= 0xDFFF)
|
||||
{ if (i == 0)
|
||||
onUnicodeError("Invalid UTF-16 sequence", 0);
|
||||
i--;
|
||||
d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
|
||||
}
|
||||
result = dg(&i, cast(void *)&d);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRwd2.unittest\n");
|
||||
|
||||
auto s = "hello"w;
|
||||
int i;
|
||||
|
||||
foreach_reverse(k, dchar d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
assert(k == 4 - i);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(k, dchar d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(k == 4); assert(d == 'b'); break;
|
||||
case 1: assert(k == 2); assert(d == '\U00100456'); break;
|
||||
case 2: assert(k == 1); assert(d == '\u1234'); break;
|
||||
case 3: assert(k == 0); assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 4);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
||||
extern (C) int _aApplyRcw2(in char[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRcw2(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0; )
|
||||
{ dchar d;
|
||||
wchar w;
|
||||
|
||||
i--;
|
||||
w = aa[i];
|
||||
if (w & 0x80)
|
||||
{ char c = cast(char)w;
|
||||
uint j;
|
||||
uint m = 0x3F;
|
||||
d = 0;
|
||||
while ((c & 0xC0) != 0xC0)
|
||||
{ if (i == 0)
|
||||
onUnicodeError("Invalid UTF-8 sequence", 0);
|
||||
i--;
|
||||
d |= (c & 0x3F) << j;
|
||||
j += 6;
|
||||
m >>= 1;
|
||||
c = aa[i];
|
||||
}
|
||||
d |= (c & m) << j;
|
||||
|
||||
if (d <= 0xFFFF)
|
||||
w = cast(wchar) d;
|
||||
else
|
||||
{
|
||||
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||
result = dg(&i, cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
|
||||
}
|
||||
}
|
||||
result = dg(&i, cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRcw2.unittest\n");
|
||||
|
||||
auto s = "hello"c;
|
||||
int i;
|
||||
|
||||
foreach_reverse(k, wchar d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
assert(k == 4 - i);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(k, wchar d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(k == 8); assert(d == 'b'); break;
|
||||
case 1: assert(k == 4); assert(d == 0xDBC1); break;
|
||||
case 2: assert(k == 4); assert(d == 0xDC56); break;
|
||||
case 3: assert(k == 1); assert(d == 0x1234); break;
|
||||
case 4: assert(k == 0); assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
||||
extern (C) int _aApplyRwc2(in wchar[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRwc2(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0; )
|
||||
{ dchar d;
|
||||
char c;
|
||||
|
||||
i--;
|
||||
d = aa[i];
|
||||
if (d >= 0xDC00 && d <= 0xDFFF)
|
||||
{ if (i == 0)
|
||||
onUnicodeError("Invalid UTF-16 sequence", 0);
|
||||
i--;
|
||||
d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
|
||||
}
|
||||
|
||||
if (d & ~0x7F)
|
||||
{
|
||||
char[4] buf;
|
||||
|
||||
auto b = toUTF8(buf, d);
|
||||
foreach (char c2; b)
|
||||
{
|
||||
result = dg(&i, cast(void *)&c2);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
c = cast(char)d;
|
||||
result = dg(&i, cast(void *)&c);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRwc2.unittest\n");
|
||||
|
||||
auto s = "hello"w;
|
||||
int i;
|
||||
|
||||
foreach_reverse(k, char d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
assert(k == 4 - i);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(k, char d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(k == 4); assert(d == 'b'); break;
|
||||
case 1: assert(k == 2); assert(d == 0xF4); break;
|
||||
case 2: assert(k == 2); assert(d == 0x80); break;
|
||||
case 3: assert(k == 2); assert(d == 0x91); break;
|
||||
case 4: assert(k == 2); assert(d == 0x96); break;
|
||||
case 5: assert(k == 1); assert(d == 0xE1); break;
|
||||
case 6: assert(k == 1); assert(d == 0x88); break;
|
||||
case 7: assert(k == 1); assert(d == 0xB4); break;
|
||||
case 8: assert(k == 0); assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 9);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
||||
extern (C) int _aApplyRdc2(in dchar[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRdc2(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0; )
|
||||
{ dchar d = aa[--i];
|
||||
char c;
|
||||
|
||||
if (d & ~0x7F)
|
||||
{
|
||||
char[4] buf;
|
||||
|
||||
auto b = toUTF8(buf, d);
|
||||
foreach (char c2; b)
|
||||
{
|
||||
result = dg(&i, cast(void *)&c2);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{ c = cast(char)d;
|
||||
}
|
||||
result = dg(&i, cast(void *)&c);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRdc2.unittest\n");
|
||||
|
||||
auto s = "hello"d;
|
||||
int i;
|
||||
|
||||
foreach_reverse(k, char d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
assert(k == 4 - i);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(k, char d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(k == 3); assert(d == 'b'); break;
|
||||
case 1: assert(k == 2); assert(d == 0xF4); break;
|
||||
case 2: assert(k == 2); assert(d == 0x80); break;
|
||||
case 3: assert(k == 2); assert(d == 0x91); break;
|
||||
case 4: assert(k == 2); assert(d == 0x96); break;
|
||||
case 5: assert(k == 1); assert(d == 0xE1); break;
|
||||
case 6: assert(k == 1); assert(d == 0x88); break;
|
||||
case 7: assert(k == 1); assert(d == 0xB4); break;
|
||||
case 8: assert(k == 0); assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 9);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
||||
extern (C) int _aApplyRdw2(in dchar[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRdw2(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0; )
|
||||
{ dchar d = aa[--i];
|
||||
wchar w;
|
||||
|
||||
if (d <= 0xFFFF)
|
||||
w = cast(wchar) d;
|
||||
else
|
||||
{
|
||||
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||
result = dg(&i, cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
|
||||
}
|
||||
result = dg(&i, cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRdw2.unittest\n");
|
||||
|
||||
auto s = "hello"d;
|
||||
int i;
|
||||
|
||||
foreach_reverse(k, wchar d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
assert(k == 4 - i);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(k, wchar d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(k == 3); assert(d == 'b'); break;
|
||||
case 1: assert(k == 2); assert(d == 0xDBC1); break;
|
||||
case 2: assert(k == 2); assert(d == 0xDC56); break;
|
||||
case 3: assert(k == 1); assert(d == 0x1234); break;
|
||||
case 4: assert(k == 0); assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
}
|
||||
|
||||
|
||||
843
tango/lib/compiler/llvmdc/aaA.d
Normal file
843
tango/lib/compiler/llvmdc/aaA.d
Normal file
@@ -0,0 +1,843 @@
|
||||
//_ aaA.d
|
||||
|
||||
/**
|
||||
* Part of the D programming language runtime library.
|
||||
* Implementation of associative arrays.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000-2007 by Digital Mars, www.digitalmars.com
|
||||
* Written by Walter Bright
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, subject to the following restrictions:
|
||||
*
|
||||
* o The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* o Altered source versions must be plainly marked as such, and must not
|
||||
* be misrepresented as being the original software.
|
||||
* o This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by Sean Kelly <sean@f4.ca> for use with Tango.
|
||||
*/
|
||||
|
||||
private
|
||||
{
|
||||
import tango.stdc.stdarg;
|
||||
import tango.stdc.string;
|
||||
|
||||
enum BlkAttr : uint
|
||||
{
|
||||
FINALIZE = 0b0000_0001,
|
||||
NO_SCAN = 0b0000_0010,
|
||||
NO_MOVE = 0b0000_0100,
|
||||
ALL_BITS = 0b1111_1111
|
||||
}
|
||||
|
||||
extern (C) void* gc_malloc( size_t sz, uint ba = 0 );
|
||||
extern (C) void* gc_calloc( size_t sz, uint ba = 0 );
|
||||
extern (C) void gc_free( void* p );
|
||||
}
|
||||
|
||||
// Auto-rehash and pre-allocate - Dave Fladebo
|
||||
|
||||
static size_t[] prime_list = [
|
||||
97UL, 389UL,
|
||||
1543UL, 6151UL,
|
||||
24593UL, 98317UL,
|
||||
393241UL, 1572869UL,
|
||||
6291469UL, 25165843UL,
|
||||
100663319UL, 402653189UL,
|
||||
1610612741UL, 4294967291UL
|
||||
];
|
||||
|
||||
/* This is the type of the return value for dynamic arrays.
|
||||
* It should be a type that is returned in registers.
|
||||
* Although DMD will return types of Array in registers,
|
||||
* gcc will not, so we instead use a 'long'.
|
||||
*/
|
||||
alias long ArrayRet_t;
|
||||
|
||||
struct Array
|
||||
{
|
||||
size_t length;
|
||||
void* ptr;
|
||||
}
|
||||
|
||||
struct aaA
|
||||
{
|
||||
aaA *left;
|
||||
aaA *right;
|
||||
hash_t hash;
|
||||
/* key */
|
||||
/* value */
|
||||
}
|
||||
|
||||
struct BB
|
||||
{
|
||||
aaA*[] b;
|
||||
size_t nodes; // total number of aaA nodes
|
||||
}
|
||||
|
||||
/* This is the type actually seen by the programmer, although
|
||||
* it is completely opaque.
|
||||
*/
|
||||
|
||||
struct AA
|
||||
{
|
||||
BB* a;
|
||||
}
|
||||
|
||||
/**********************************
|
||||
* Align to next pointer boundary, so that
|
||||
* GC won't be faced with misaligned pointers
|
||||
* in value.
|
||||
*/
|
||||
|
||||
size_t aligntsize(size_t tsize)
|
||||
{
|
||||
// Is pointer alignment on the x64 4 bytes or 8?
|
||||
return (tsize + size_t.sizeof - 1) & ~(size_t.sizeof - 1);
|
||||
}
|
||||
|
||||
extern (C):
|
||||
|
||||
/*************************************************
|
||||
* Invariant for aa.
|
||||
*/
|
||||
|
||||
/+
|
||||
void _aaInvAh(aaA*[] aa)
|
||||
{
|
||||
for (size_t i = 0; i < aa.length; i++)
|
||||
{
|
||||
if (aa[i])
|
||||
_aaInvAh_x(aa[i]);
|
||||
}
|
||||
}
|
||||
|
||||
private int _aaCmpAh_x(aaA *e1, aaA *e2)
|
||||
{ int c;
|
||||
|
||||
c = e1.hash - e2.hash;
|
||||
if (c == 0)
|
||||
{
|
||||
c = e1.key.length - e2.key.length;
|
||||
if (c == 0)
|
||||
c = memcmp((char *)e1.key, (char *)e2.key, e1.key.length);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
private void _aaInvAh_x(aaA *e)
|
||||
{
|
||||
hash_t key_hash;
|
||||
aaA *e1;
|
||||
aaA *e2;
|
||||
|
||||
key_hash = getHash(e.key);
|
||||
assert(key_hash == e.hash);
|
||||
|
||||
while (1)
|
||||
{ int c;
|
||||
|
||||
e1 = e.left;
|
||||
if (e1)
|
||||
{
|
||||
_aaInvAh_x(e1); // ordinary recursion
|
||||
do
|
||||
{
|
||||
c = _aaCmpAh_x(e1, e);
|
||||
assert(c < 0);
|
||||
e1 = e1.right;
|
||||
} while (e1 != null);
|
||||
}
|
||||
|
||||
e2 = e.right;
|
||||
if (e2)
|
||||
{
|
||||
do
|
||||
{
|
||||
c = _aaCmpAh_x(e, e2);
|
||||
assert(c < 0);
|
||||
e2 = e2.left;
|
||||
} while (e2 != null);
|
||||
e = e.right; // tail recursion
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
+/
|
||||
|
||||
/****************************************************
|
||||
* Determine number of entries in associative array.
|
||||
*/
|
||||
|
||||
size_t _aaLen(AA aa)
|
||||
in
|
||||
{
|
||||
//printf("_aaLen()+\n");
|
||||
//_aaInv(aa);
|
||||
}
|
||||
out (result)
|
||||
{
|
||||
size_t len = 0;
|
||||
|
||||
void _aaLen_x(aaA* ex)
|
||||
{
|
||||
auto e = ex;
|
||||
len++;
|
||||
|
||||
while (1)
|
||||
{
|
||||
if (e.right)
|
||||
_aaLen_x(e.right);
|
||||
e = e.left;
|
||||
if (!e)
|
||||
break;
|
||||
len++;
|
||||
}
|
||||
}
|
||||
|
||||
if (aa.a)
|
||||
{
|
||||
foreach (e; aa.a.b)
|
||||
{
|
||||
if (e)
|
||||
_aaLen_x(e);
|
||||
}
|
||||
}
|
||||
assert(len == result);
|
||||
|
||||
//printf("_aaLen()-\n");
|
||||
}
|
||||
body
|
||||
{
|
||||
return aa.a ? aa.a.nodes : 0;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Get pointer to value in associative array indexed by key.
|
||||
* Add entry for key if it is not already there.
|
||||
*/
|
||||
|
||||
void* _aaGet(AA* aa, TypeInfo keyti, size_t valuesize, ...)
|
||||
in
|
||||
{
|
||||
assert(aa);
|
||||
}
|
||||
out (result)
|
||||
{
|
||||
assert(result);
|
||||
assert(aa.a);
|
||||
assert(aa.a.b.length);
|
||||
//assert(_aaInAh(*aa.a, key));
|
||||
}
|
||||
body
|
||||
{
|
||||
auto pkey = cast(void *)(&valuesize + 1);
|
||||
size_t i;
|
||||
aaA *e;
|
||||
auto keysize = aligntsize(keyti.tsize());
|
||||
|
||||
if (!aa.a)
|
||||
aa.a = new BB();
|
||||
|
||||
if (!aa.a.b.length)
|
||||
{
|
||||
alias aaA *pa;
|
||||
auto len = prime_list[0];
|
||||
|
||||
aa.a.b = new pa[len];
|
||||
}
|
||||
|
||||
auto key_hash = keyti.getHash(pkey);
|
||||
//printf("hash = %d\n", key_hash);
|
||||
i = key_hash % aa.a.b.length;
|
||||
auto pe = &aa.a.b[i];
|
||||
while ((e = *pe) !is null)
|
||||
{
|
||||
if (key_hash == e.hash)
|
||||
{
|
||||
auto c = keyti.compare(pkey, e + 1);
|
||||
if (c == 0)
|
||||
goto Lret;
|
||||
pe = (c < 0) ? &e.left : &e.right;
|
||||
}
|
||||
else
|
||||
pe = (key_hash < e.hash) ? &e.left : &e.right;
|
||||
}
|
||||
|
||||
// Not found, create new elem
|
||||
//printf("create new one\n");
|
||||
size_t size = aaA.sizeof + keysize + valuesize;
|
||||
uint bits = keysize < (void*).sizeof &&
|
||||
keysize > (void).sizeof &&
|
||||
valuesize < (void*).sizeof &&
|
||||
valuesize > (void).sizeof ? BlkAttr.NO_SCAN : 0;
|
||||
e = cast(aaA *) gc_calloc(size, bits);
|
||||
memcpy(e + 1, pkey, keysize);
|
||||
e.hash = key_hash;
|
||||
*pe = e;
|
||||
|
||||
auto nodes = ++aa.a.nodes;
|
||||
//printf("length = %d, nodes = %d\n", (*aa.a).length, nodes);
|
||||
if (nodes > aa.a.b.length * 4)
|
||||
{
|
||||
_aaRehash(aa,keyti);
|
||||
}
|
||||
|
||||
Lret:
|
||||
return cast(void *)(e + 1) + keysize;
|
||||
}
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Get pointer to value in associative array indexed by key.
|
||||
* Returns null if it is not already there.
|
||||
*/
|
||||
|
||||
void* _aaGetRvalue(AA aa, TypeInfo keyti, size_t valuesize, ...)
|
||||
{
|
||||
//printf("_aaGetRvalue(valuesize = %u)\n", valuesize);
|
||||
if (!aa.a)
|
||||
return null;
|
||||
|
||||
auto pkey = cast(void *)(&valuesize + 1);
|
||||
auto keysize = aligntsize(keyti.tsize());
|
||||
auto len = aa.a.b.length;
|
||||
|
||||
if (len)
|
||||
{
|
||||
auto key_hash = keyti.getHash(pkey);
|
||||
//printf("hash = %d\n", key_hash);
|
||||
size_t i = key_hash % len;
|
||||
auto e = aa.a.b[i];
|
||||
while (e !is null)
|
||||
{
|
||||
if (key_hash == e.hash)
|
||||
{
|
||||
auto c = keyti.compare(pkey, e + 1);
|
||||
if (c == 0)
|
||||
return cast(void *)(e + 1) + keysize;
|
||||
e = (c < 0) ? e.left : e.right;
|
||||
}
|
||||
else
|
||||
e = (key_hash < e.hash) ? e.left : e.right;
|
||||
}
|
||||
}
|
||||
return null; // not found, caller will throw exception
|
||||
}
|
||||
|
||||
|
||||
/*************************************************
|
||||
* Determine if key is in aa.
|
||||
* Returns:
|
||||
* null not in aa
|
||||
* !=null in aa, return pointer to value
|
||||
*/
|
||||
|
||||
void* _aaIn(AA aa, TypeInfo keyti, ...)
|
||||
in
|
||||
{
|
||||
}
|
||||
out (result)
|
||||
{
|
||||
//assert(result == 0 || result == 1);
|
||||
}
|
||||
body
|
||||
{
|
||||
if (aa.a)
|
||||
{
|
||||
auto pkey = cast(void *)(&keyti + 1);
|
||||
|
||||
//printf("_aaIn(), .length = %d, .ptr = %x\n", aa.a.length, cast(uint)aa.a.ptr);
|
||||
auto len = aa.a.b.length;
|
||||
|
||||
if (len)
|
||||
{
|
||||
auto key_hash = keyti.getHash(pkey);
|
||||
//printf("hash = %d\n", key_hash);
|
||||
size_t i = key_hash % len;
|
||||
auto e = aa.a.b[i];
|
||||
while (e !is null)
|
||||
{
|
||||
if (key_hash == e.hash)
|
||||
{
|
||||
auto c = keyti.compare(pkey, e + 1);
|
||||
if (c == 0)
|
||||
return cast(void *)(e + 1) + aligntsize(keyti.tsize());
|
||||
e = (c < 0) ? e.left : e.right;
|
||||
}
|
||||
else
|
||||
e = (key_hash < e.hash) ? e.left : e.right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Not found
|
||||
return null;
|
||||
}
|
||||
|
||||
/*************************************************
|
||||
* Delete key entry in aa[].
|
||||
* If key is not in aa[], do nothing.
|
||||
*/
|
||||
|
||||
void _aaDel(AA aa, TypeInfo keyti, ...)
|
||||
{
|
||||
auto pkey = cast(void *)(&keyti + 1);
|
||||
aaA *e;
|
||||
|
||||
if (aa.a && aa.a.b.length)
|
||||
{
|
||||
auto key_hash = keyti.getHash(pkey);
|
||||
//printf("hash = %d\n", key_hash);
|
||||
size_t i = key_hash % aa.a.b.length;
|
||||
auto pe = &aa.a.b[i];
|
||||
while ((e = *pe) !is null) // null means not found
|
||||
{
|
||||
if (key_hash == e.hash)
|
||||
{
|
||||
auto c = keyti.compare(pkey, e + 1);
|
||||
if (c == 0)
|
||||
{
|
||||
if (!e.left && !e.right)
|
||||
{
|
||||
*pe = null;
|
||||
}
|
||||
else if (e.left && !e.right)
|
||||
{
|
||||
*pe = e.left;
|
||||
e.left = null;
|
||||
}
|
||||
else if (!e.left && e.right)
|
||||
{
|
||||
*pe = e.right;
|
||||
e.right = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pe = e.left;
|
||||
e.left = null;
|
||||
do
|
||||
pe = &(*pe).right;
|
||||
while (*pe);
|
||||
*pe = e.right;
|
||||
e.right = null;
|
||||
}
|
||||
|
||||
aa.a.nodes--;
|
||||
|
||||
// Should notify GC that e can be free'd now
|
||||
break;
|
||||
}
|
||||
pe = (c < 0) ? &e.left : &e.right;
|
||||
}
|
||||
else
|
||||
pe = (key_hash < e.hash) ? &e.left : &e.right;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/********************************************
|
||||
* Produce array of values from aa.
|
||||
*/
|
||||
|
||||
ArrayRet_t _aaValues(AA aa, size_t keysize, size_t valuesize)
|
||||
in
|
||||
{
|
||||
assert(keysize == aligntsize(keysize));
|
||||
}
|
||||
body
|
||||
{
|
||||
size_t resi;
|
||||
Array a;
|
||||
|
||||
void _aaValues_x(aaA* e)
|
||||
{
|
||||
do
|
||||
{
|
||||
memcpy(a.ptr + resi * valuesize,
|
||||
cast(byte*)e + aaA.sizeof + keysize,
|
||||
valuesize);
|
||||
resi++;
|
||||
if (e.left)
|
||||
{ if (!e.right)
|
||||
{ e = e.left;
|
||||
continue;
|
||||
}
|
||||
_aaValues_x(e.left);
|
||||
}
|
||||
e = e.right;
|
||||
} while (e !is null);
|
||||
}
|
||||
|
||||
if (aa.a)
|
||||
{
|
||||
a.length = _aaLen(aa);
|
||||
a.ptr = cast(byte*) gc_malloc(a.length * valuesize,
|
||||
valuesize < (void*).sizeof &&
|
||||
valuesize > (void).sizeof ? BlkAttr.NO_SCAN : 0);
|
||||
resi = 0;
|
||||
foreach (e; aa.a.b)
|
||||
{
|
||||
if (e)
|
||||
_aaValues_x(e);
|
||||
}
|
||||
assert(resi == a.length);
|
||||
}
|
||||
return *cast(ArrayRet_t*)(&a);
|
||||
}
|
||||
|
||||
|
||||
/********************************************
|
||||
* Rehash an array.
|
||||
*/
|
||||
|
||||
void* _aaRehash(AA* paa, TypeInfo keyti)
|
||||
in
|
||||
{
|
||||
//_aaInvAh(paa);
|
||||
}
|
||||
out (result)
|
||||
{
|
||||
//_aaInvAh(result);
|
||||
}
|
||||
body
|
||||
{
|
||||
BB newb;
|
||||
|
||||
void _aaRehash_x(aaA* olde)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
auto left = olde.left;
|
||||
auto right = olde.right;
|
||||
olde.left = null;
|
||||
olde.right = null;
|
||||
|
||||
aaA *e;
|
||||
|
||||
//printf("rehash %p\n", olde);
|
||||
auto key_hash = olde.hash;
|
||||
size_t i = key_hash % newb.b.length;
|
||||
auto pe = &newb.b[i];
|
||||
while ((e = *pe) !is null)
|
||||
{
|
||||
//printf("\te = %p, e.left = %p, e.right = %p\n", e, e.left, e.right);
|
||||
assert(e.left != e);
|
||||
assert(e.right != e);
|
||||
if (key_hash == e.hash)
|
||||
{
|
||||
auto c = keyti.compare(olde + 1, e + 1);
|
||||
assert(c != 0);
|
||||
pe = (c < 0) ? &e.left : &e.right;
|
||||
}
|
||||
else
|
||||
pe = (key_hash < e.hash) ? &e.left : &e.right;
|
||||
}
|
||||
*pe = olde;
|
||||
|
||||
if (right)
|
||||
{
|
||||
if (!left)
|
||||
{ olde = right;
|
||||
continue;
|
||||
}
|
||||
_aaRehash_x(right);
|
||||
}
|
||||
if (!left)
|
||||
break;
|
||||
olde = left;
|
||||
}
|
||||
}
|
||||
|
||||
//printf("Rehash\n");
|
||||
if (paa.a)
|
||||
{
|
||||
auto aa = paa.a;
|
||||
auto len = _aaLen(*paa);
|
||||
if (len)
|
||||
{ size_t i;
|
||||
|
||||
for (i = 0; i < prime_list.length - 1; i++)
|
||||
{
|
||||
if (len <= prime_list[i])
|
||||
break;
|
||||
}
|
||||
len = prime_list[i];
|
||||
newb.b = new aaA*[len];
|
||||
|
||||
foreach (e; aa.b)
|
||||
{
|
||||
if (e)
|
||||
_aaRehash_x(e);
|
||||
}
|
||||
|
||||
newb.nodes = aa.nodes;
|
||||
}
|
||||
|
||||
*paa.a = newb;
|
||||
}
|
||||
return (*paa).a;
|
||||
}
|
||||
|
||||
|
||||
/********************************************
|
||||
* Produce array of N byte keys from aa.
|
||||
*/
|
||||
|
||||
ArrayRet_t _aaKeys(AA aa, size_t keysize)
|
||||
{
|
||||
byte[] res;
|
||||
size_t resi;
|
||||
|
||||
void _aaKeys_x(aaA* e)
|
||||
{
|
||||
do
|
||||
{
|
||||
memcpy(&res[resi * keysize], cast(byte*)(e + 1), keysize);
|
||||
resi++;
|
||||
if (e.left)
|
||||
{ if (!e.right)
|
||||
{ e = e.left;
|
||||
continue;
|
||||
}
|
||||
_aaKeys_x(e.left);
|
||||
}
|
||||
e = e.right;
|
||||
} while (e !is null);
|
||||
}
|
||||
|
||||
auto len = _aaLen(aa);
|
||||
if (!len)
|
||||
return 0;
|
||||
res = (cast(byte*) gc_malloc(len * keysize,
|
||||
keysize < (void*).sizeof &&
|
||||
keysize > (void).sizeof ? BlkAttr.NO_SCAN : 0))[0 .. len * keysize];
|
||||
resi = 0;
|
||||
foreach (e; aa.a.b)
|
||||
{
|
||||
if (e)
|
||||
_aaKeys_x(e);
|
||||
}
|
||||
assert(resi == len);
|
||||
|
||||
Array a;
|
||||
a.length = len;
|
||||
a.ptr = res.ptr;
|
||||
return *cast(ArrayRet_t*)(&a);
|
||||
}
|
||||
|
||||
|
||||
/**********************************************
|
||||
* 'apply' for associative arrays - to support foreach
|
||||
*/
|
||||
|
||||
// dg is D, but _aaApply() is C
|
||||
extern (D) typedef int delegate(void *) dg_t;
|
||||
|
||||
int _aaApply(AA aa, size_t keysize, dg_t dg)
|
||||
in
|
||||
{
|
||||
assert(aligntsize(keysize) == keysize);
|
||||
}
|
||||
body
|
||||
{ int result;
|
||||
|
||||
//printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa.a, keysize, dg);
|
||||
|
||||
int treewalker(aaA* e)
|
||||
{ int result;
|
||||
|
||||
do
|
||||
{
|
||||
//printf("treewalker(e = %p, dg = x%llx)\n", e, dg);
|
||||
result = dg(cast(void *)(e + 1) + keysize);
|
||||
if (result)
|
||||
break;
|
||||
if (e.right)
|
||||
{ if (!e.left)
|
||||
{
|
||||
e = e.right;
|
||||
continue;
|
||||
}
|
||||
result = treewalker(e.right);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
e = e.left;
|
||||
} while (e);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (aa.a)
|
||||
{
|
||||
foreach (e; aa.a.b)
|
||||
{
|
||||
if (e)
|
||||
{
|
||||
result = treewalker(e);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// dg is D, but _aaApply2() is C
|
||||
extern (D) typedef int delegate(void *, void *) dg2_t;
|
||||
|
||||
int _aaApply2(AA aa, size_t keysize, dg2_t dg)
|
||||
in
|
||||
{
|
||||
assert(aligntsize(keysize) == keysize);
|
||||
}
|
||||
body
|
||||
{ int result;
|
||||
|
||||
//printf("_aaApply(aa = x%llx, keysize = %d, dg = x%llx)\n", aa.a, keysize, dg);
|
||||
|
||||
int treewalker(aaA* e)
|
||||
{ int result;
|
||||
|
||||
do
|
||||
{
|
||||
//printf("treewalker(e = %p, dg = x%llx)\n", e, dg);
|
||||
result = dg(cast(void *)(e + 1), cast(void *)(e + 1) + keysize);
|
||||
if (result)
|
||||
break;
|
||||
if (e.right)
|
||||
{ if (!e.left)
|
||||
{
|
||||
e = e.right;
|
||||
continue;
|
||||
}
|
||||
result = treewalker(e.right);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
e = e.left;
|
||||
} while (e);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
if (aa.a)
|
||||
{
|
||||
foreach (e; aa.a.b)
|
||||
{
|
||||
if (e)
|
||||
{
|
||||
result = treewalker(e);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/***********************************
|
||||
* Construct an associative array of type ti from
|
||||
* length pairs of key/value pairs.
|
||||
*/
|
||||
|
||||
/+
|
||||
|
||||
extern (C)
|
||||
BB* _d_assocarrayliteralT(TypeInfo_AssociativeArray ti, size_t length, ...)
|
||||
{
|
||||
auto valuesize = ti.next.tsize(); // value size
|
||||
auto keyti = ti.key;
|
||||
auto keysize = keyti.tsize(); // key size
|
||||
BB* result;
|
||||
|
||||
//printf("_d_assocarrayliteralT(keysize = %d, valuesize = %d, length = %d)\n", keysize, valuesize, length);
|
||||
//printf("tivalue = %.*s\n", ti.next.classinfo.name);
|
||||
if (length == 0 || valuesize == 0 || keysize == 0)
|
||||
{
|
||||
;
|
||||
}
|
||||
else
|
||||
{
|
||||
va_list q;
|
||||
va_start!(size_t)(q, length);
|
||||
|
||||
result = new BB();
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < prime_list.length - 1; i++)
|
||||
{
|
||||
if (length <= prime_list[i])
|
||||
break;
|
||||
}
|
||||
auto len = prime_list[i];
|
||||
result.b = new aaA*[len];
|
||||
|
||||
size_t keystacksize = (keysize + int.sizeof - 1) & ~(int.sizeof - 1);
|
||||
size_t valuestacksize = (valuesize + int.sizeof - 1) & ~(int.sizeof - 1);
|
||||
|
||||
size_t keytsize = aligntsize(keysize);
|
||||
|
||||
for (size_t j = 0; j < length; j++)
|
||||
{ void* pkey = q;
|
||||
q += keystacksize;
|
||||
void* pvalue = q;
|
||||
q += valuestacksize;
|
||||
aaA* e;
|
||||
|
||||
auto key_hash = keyti.getHash(pkey);
|
||||
//printf("hash = %d\n", key_hash);
|
||||
i = key_hash % len;
|
||||
auto pe = &result.b[i];
|
||||
while (1)
|
||||
{
|
||||
e = *pe;
|
||||
if (!e)
|
||||
{
|
||||
// Not found, create new elem
|
||||
//printf("create new one\n");
|
||||
e = cast(aaA *) cast(void*) new void[aaA.sizeof + keytsize + valuesize];
|
||||
memcpy(e + 1, pkey, keysize);
|
||||
e.hash = key_hash;
|
||||
*pe = e;
|
||||
result.nodes++;
|
||||
break;
|
||||
}
|
||||
if (key_hash == e.hash)
|
||||
{
|
||||
auto c = keyti.compare(pkey, e + 1);
|
||||
if (c == 0)
|
||||
break;
|
||||
pe = (c < 0) ? &e.left : &e.right;
|
||||
}
|
||||
else
|
||||
pe = (key_hash < e.hash) ? &e.left : &e.right;
|
||||
}
|
||||
memcpy(cast(void *)(e + 1) + keytsize, pvalue, valuesize);
|
||||
}
|
||||
|
||||
va_end(q);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
+/
|
||||
614
tango/lib/compiler/llvmdc/adi.d
Normal file
614
tango/lib/compiler/llvmdc/adi.d
Normal file
@@ -0,0 +1,614 @@
|
||||
//_ adi.d
|
||||
|
||||
/**
|
||||
* Part of the D programming language runtime library.
|
||||
* Dynamic array property support routines
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2000-2006 by Digital Mars, www.digitalmars.com
|
||||
* Written by Walter Bright
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, in both source and binary form, subject to the following
|
||||
* restrictions:
|
||||
*
|
||||
* o The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* o Altered source versions must be plainly marked as such, and must not
|
||||
* be misrepresented as being the original software.
|
||||
* o This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by Sean Kelly <sean@f4.ca> for use with Tango.
|
||||
*/
|
||||
|
||||
|
||||
//debug=adi; // uncomment to turn on debugging printf's
|
||||
|
||||
private
|
||||
{
|
||||
import tango.stdc.string;
|
||||
import tango.stdc.stdlib;
|
||||
import util.utf;
|
||||
|
||||
enum BlkAttr : uint
|
||||
{
|
||||
FINALIZE = 0b0000_0001,
|
||||
NO_SCAN = 0b0000_0010,
|
||||
NO_MOVE = 0b0000_0100,
|
||||
ALL_BITS = 0b1111_1111
|
||||
}
|
||||
|
||||
extern (C) void* gc_malloc( size_t sz, uint ba = 0 );
|
||||
extern (C) void* gc_calloc( size_t sz, uint ba = 0 );
|
||||
extern (C) void gc_free( void* p );
|
||||
}
|
||||
|
||||
|
||||
struct Array
|
||||
{
|
||||
size_t length;
|
||||
void* ptr;
|
||||
}
|
||||
|
||||
/**********************************************
|
||||
* Reverse array of chars.
|
||||
* Handled separately because embedded multibyte encodings should not be
|
||||
* reversed.
|
||||
*/
|
||||
|
||||
extern (C) long _adReverseChar(char[] a)
|
||||
{
|
||||
if (a.length > 1)
|
||||
{
|
||||
char[6] tmp;
|
||||
char[6] tmplo;
|
||||
char* lo = a.ptr;
|
||||
char* hi = &a[length - 1];
|
||||
|
||||
while (lo < hi)
|
||||
{ auto clo = *lo;
|
||||
auto chi = *hi;
|
||||
|
||||
debug(adi) printf("lo = %d, hi = %d\n", lo, hi);
|
||||
if (clo <= 0x7F && chi <= 0x7F)
|
||||
{
|
||||
debug(adi) printf("\tascii\n");
|
||||
*lo = chi;
|
||||
*hi = clo;
|
||||
lo++;
|
||||
hi--;
|
||||
continue;
|
||||
}
|
||||
|
||||
uint stridelo = UTF8stride[clo];
|
||||
|
||||
uint stridehi = 1;
|
||||
while ((chi & 0xC0) == 0x80)
|
||||
{
|
||||
chi = *--hi;
|
||||
stridehi++;
|
||||
assert(hi >= lo);
|
||||
}
|
||||
if (lo == hi)
|
||||
break;
|
||||
|
||||
debug(adi) printf("\tstridelo = %d, stridehi = %d\n", stridelo, stridehi);
|
||||
if (stridelo == stridehi)
|
||||
{
|
||||
|
||||
memcpy(tmp.ptr, lo, stridelo);
|
||||
memcpy(lo, hi, stridelo);
|
||||
memcpy(hi, tmp.ptr, stridelo);
|
||||
lo += stridelo;
|
||||
hi--;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Shift the whole array. This is woefully inefficient
|
||||
*/
|
||||
memcpy(tmp.ptr, hi, stridehi);
|
||||
memcpy(tmplo.ptr, lo, stridelo);
|
||||
memmove(lo + stridehi, lo + stridelo , cast(size_t)(hi - lo) - stridelo);
|
||||
memcpy(lo, tmp.ptr, stridehi);
|
||||
memcpy(hi + stridehi - stridelo, tmplo.ptr, stridelo);
|
||||
|
||||
lo += stridehi;
|
||||
hi = hi - 1 + (stridehi - stridelo);
|
||||
}
|
||||
}
|
||||
return *cast(long*)(&a);
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
auto a = "abcd"c;
|
||||
|
||||
auto r = a.dup.reverse;
|
||||
//writefln(r);
|
||||
assert(r == "dcba");
|
||||
|
||||
a = "a\u1235\u1234c";
|
||||
//writefln(a);
|
||||
r = a.dup.reverse;
|
||||
//writefln(r);
|
||||
assert(r == "c\u1234\u1235a");
|
||||
|
||||
a = "ab\u1234c";
|
||||
//writefln(a);
|
||||
r = a.dup.reverse;
|
||||
//writefln(r);
|
||||
assert(r == "c\u1234ba");
|
||||
|
||||
a = "\u3026\u2021\u3061\n";
|
||||
r = a.dup.reverse;
|
||||
assert(r == "\n\u3061\u2021\u3026");
|
||||
}
|
||||
|
||||
|
||||
/**********************************************
|
||||
* Reverse array of wchars.
|
||||
* Handled separately because embedded multiword encodings should not be
|
||||
* reversed.
|
||||
*/
|
||||
|
||||
extern (C) long _adReverseWchar(wchar[] a)
|
||||
{
|
||||
if (a.length > 1)
|
||||
{
|
||||
wchar[2] tmp;
|
||||
wchar* lo = a.ptr;
|
||||
wchar* hi = &a[length - 1];
|
||||
|
||||
while (lo < hi)
|
||||
{ auto clo = *lo;
|
||||
auto chi = *hi;
|
||||
|
||||
if ((clo < 0xD800 || clo > 0xDFFF) &&
|
||||
(chi < 0xD800 || chi > 0xDFFF))
|
||||
{
|
||||
*lo = chi;
|
||||
*hi = clo;
|
||||
lo++;
|
||||
hi--;
|
||||
continue;
|
||||
}
|
||||
|
||||
int stridelo = 1 + (clo >= 0xD800 && clo <= 0xDBFF);
|
||||
|
||||
int stridehi = 1;
|
||||
if (chi >= 0xDC00 && chi <= 0xDFFF)
|
||||
{
|
||||
chi = *--hi;
|
||||
stridehi++;
|
||||
assert(hi >= lo);
|
||||
}
|
||||
if (lo == hi)
|
||||
break;
|
||||
|
||||
if (stridelo == stridehi)
|
||||
{ int stmp;
|
||||
|
||||
assert(stridelo == 2);
|
||||
assert(stmp.sizeof == 2 * (*lo).sizeof);
|
||||
stmp = *cast(int*)lo;
|
||||
*cast(int*)lo = *cast(int*)hi;
|
||||
*cast(int*)hi = stmp;
|
||||
lo += stridelo;
|
||||
hi--;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Shift the whole array. This is woefully inefficient
|
||||
*/
|
||||
memcpy(tmp.ptr, hi, stridehi * wchar.sizeof);
|
||||
memcpy(hi + stridehi - stridelo, lo, stridelo * wchar.sizeof);
|
||||
memmove(lo + stridehi, lo + stridelo , (hi - (lo + stridelo)) * wchar.sizeof);
|
||||
memcpy(lo, tmp.ptr, stridehi * wchar.sizeof);
|
||||
|
||||
lo += stridehi;
|
||||
hi = hi - 1 + (stridehi - stridelo);
|
||||
}
|
||||
}
|
||||
return *cast(long*)(&a);
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
wstring a = "abcd";
|
||||
wstring r;
|
||||
|
||||
r = a.dup.reverse;
|
||||
assert(r == "dcba");
|
||||
|
||||
a = "a\U00012356\U00012346c";
|
||||
r = a.dup.reverse;
|
||||
assert(r == "c\U00012346\U00012356a");
|
||||
|
||||
a = "ab\U00012345c";
|
||||
r = a.dup.reverse;
|
||||
assert(r == "c\U00012345ba");
|
||||
}
|
||||
|
||||
|
||||
/**********************************************
|
||||
* Support for array.reverse property.
|
||||
*/
|
||||
|
||||
extern (C) long _adReverse(Array a, size_t szelem)
|
||||
out (result)
|
||||
{
|
||||
assert(result is *cast(long*)(&a));
|
||||
}
|
||||
body
|
||||
{
|
||||
if (a.length >= 2)
|
||||
{
|
||||
byte* tmp;
|
||||
byte[16] buffer;
|
||||
|
||||
void* lo = a.ptr;
|
||||
void* hi = a.ptr + (a.length - 1) * szelem;
|
||||
|
||||
tmp = buffer.ptr;
|
||||
if (szelem > 16)
|
||||
{
|
||||
//version (Win32)
|
||||
tmp = cast(byte*) alloca(szelem);
|
||||
//else
|
||||
//tmp = gc_malloc(szelem);
|
||||
}
|
||||
|
||||
for (; lo < hi; lo += szelem, hi -= szelem)
|
||||
{
|
||||
memcpy(tmp, lo, szelem);
|
||||
memcpy(lo, hi, szelem);
|
||||
memcpy(hi, tmp, szelem);
|
||||
}
|
||||
|
||||
version (Win32)
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
//if (szelem > 16)
|
||||
// BUG: bad code is generate for delete pointer, tries
|
||||
// to call delclass.
|
||||
//gc_free(tmp);
|
||||
}
|
||||
}
|
||||
return *cast(long*)(&a);
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(adi) printf("array.reverse.unittest\n");
|
||||
|
||||
int[] a = new int[5];
|
||||
int[] b;
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
a[i] = i;
|
||||
b = a.reverse;
|
||||
assert(b is a);
|
||||
for (i = 0; i < 5; i++)
|
||||
assert(a[i] == 4 - i);
|
||||
|
||||
struct X20
|
||||
{ // More than 16 bytes in size
|
||||
int a;
|
||||
int b, c, d, e;
|
||||
}
|
||||
|
||||
X20[] c = new X20[5];
|
||||
X20[] d;
|
||||
|
||||
for (i = 0; i < 5; i++)
|
||||
{ c[i].a = i;
|
||||
c[i].e = 10;
|
||||
}
|
||||
d = c.reverse;
|
||||
assert(d is c);
|
||||
for (i = 0; i < 5; i++)
|
||||
{
|
||||
assert(c[i].a == 4 - i);
|
||||
assert(c[i].e == 10);
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************
|
||||
* Sort array of chars.
|
||||
*/
|
||||
|
||||
extern (C) long _adSortChar(char[] a)
|
||||
{
|
||||
if (a.length > 1)
|
||||
{
|
||||
dchar[] da = toUTF32(a);
|
||||
da.sort;
|
||||
size_t i = 0;
|
||||
foreach (dchar d; da)
|
||||
{ char[4] buf;
|
||||
auto t = toUTF8(buf, d);
|
||||
a[i .. i + t.length] = t[];
|
||||
i += t.length;
|
||||
}
|
||||
delete da;
|
||||
}
|
||||
return *cast(long*)(&a);
|
||||
}
|
||||
|
||||
/**********************************************
|
||||
* Sort array of wchars.
|
||||
*/
|
||||
|
||||
extern (C) long _adSortWchar(wchar[] a)
|
||||
{
|
||||
if (a.length > 1)
|
||||
{
|
||||
dchar[] da = toUTF32(a);
|
||||
da.sort;
|
||||
size_t i = 0;
|
||||
foreach (dchar d; da)
|
||||
{ wchar[2] buf;
|
||||
auto t = toUTF16(buf, d);
|
||||
a[i .. i + t.length] = t[];
|
||||
i += t.length;
|
||||
}
|
||||
delete da;
|
||||
}
|
||||
return *cast(long*)(&a);
|
||||
}
|
||||
|
||||
/***************************************
|
||||
* Support for array equality test.
|
||||
*/
|
||||
|
||||
extern (C) int _adEq(Array a1, Array a2, TypeInfo ti)
|
||||
{
|
||||
debug(adi) printf("_adEq(a1.length = %d, a2.length = %d)\n", a1.length, a2.length);
|
||||
if (a1.length != a2.length)
|
||||
return 0; // not equal
|
||||
auto sz = ti.tsize();
|
||||
auto p1 = a1.ptr;
|
||||
auto p2 = a2.ptr;
|
||||
|
||||
/+
|
||||
for (int i = 0; i < a1.length; i++)
|
||||
{
|
||||
printf("%4x %4x\n", (cast(short*)p1)[i], (cast(short*)p2)[i]);
|
||||
}
|
||||
+/
|
||||
|
||||
if (sz == 1)
|
||||
// We should really have a ti.isPOD() check for this
|
||||
return (memcmp(p1, p2, a1.length) == 0);
|
||||
|
||||
for (size_t i = 0; i < a1.length; i++)
|
||||
{
|
||||
if (!ti.equals(p1 + i * sz, p2 + i * sz))
|
||||
return 0; // not equal
|
||||
}
|
||||
return 1; // equal
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(adi) printf("array.Eq unittest\n");
|
||||
|
||||
auto a = "hello"c;
|
||||
|
||||
assert(a != "hel");
|
||||
assert(a != "helloo");
|
||||
assert(a != "betty");
|
||||
assert(a == "hello");
|
||||
assert(a != "hxxxx");
|
||||
}
|
||||
|
||||
/***************************************
|
||||
* Support for array compare test.
|
||||
*/
|
||||
|
||||
extern (C) int _adCmp(Array a1, Array a2, TypeInfo ti)
|
||||
{
|
||||
debug(adi) printf("adCmp()\n");
|
||||
auto len = a1.length;
|
||||
if (a2.length < len)
|
||||
len = a2.length;
|
||||
auto sz = ti.tsize();
|
||||
void *p1 = a1.ptr;
|
||||
void *p2 = a2.ptr;
|
||||
|
||||
if (sz == 1)
|
||||
{ // We should really have a ti.isPOD() check for this
|
||||
auto c = memcmp(p1, p2, len);
|
||||
if (c)
|
||||
return c;
|
||||
}
|
||||
else
|
||||
{
|
||||
for (size_t i = 0; i < len; i++)
|
||||
{
|
||||
auto c = ti.compare(p1 + i * sz, p2 + i * sz);
|
||||
if (c)
|
||||
return c;
|
||||
}
|
||||
}
|
||||
if (a1.length == a2.length)
|
||||
return 0;
|
||||
return (a1.length > a2.length) ? 1 : -1;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(adi) printf("array.Cmp unittest\n");
|
||||
|
||||
auto a = "hello"c;
|
||||
|
||||
assert(a > "hel");
|
||||
assert(a >= "hel");
|
||||
assert(a < "helloo");
|
||||
assert(a <= "helloo");
|
||||
assert(a > "betty");
|
||||
assert(a >= "betty");
|
||||
assert(a == "hello");
|
||||
assert(a <= "hello");
|
||||
assert(a >= "hello");
|
||||
}
|
||||
|
||||
/***************************************
|
||||
* Support for array compare test.
|
||||
*/
|
||||
|
||||
extern (C) int _adCmpChar(Array a1, Array a2)
|
||||
{
|
||||
version (X86)
|
||||
{
|
||||
asm
|
||||
{ naked ;
|
||||
|
||||
push EDI ;
|
||||
push ESI ;
|
||||
|
||||
mov ESI,a1+4[4+ESP] ;
|
||||
mov EDI,a2+4[4+ESP] ;
|
||||
|
||||
mov ECX,a1[4+ESP] ;
|
||||
mov EDX,a2[4+ESP] ;
|
||||
|
||||
cmp ECX,EDX ;
|
||||
jb GotLength ;
|
||||
|
||||
mov ECX,EDX ;
|
||||
|
||||
GotLength:
|
||||
cmp ECX,4 ;
|
||||
jb DoBytes ;
|
||||
|
||||
// Do alignment if neither is dword aligned
|
||||
test ESI,3 ;
|
||||
jz Aligned ;
|
||||
|
||||
test EDI,3 ;
|
||||
jz Aligned ;
|
||||
DoAlign:
|
||||
mov AL,[ESI] ; //align ESI to dword bounds
|
||||
mov DL,[EDI] ;
|
||||
|
||||
cmp AL,DL ;
|
||||
jnz Unequal ;
|
||||
|
||||
inc ESI ;
|
||||
inc EDI ;
|
||||
|
||||
test ESI,3 ;
|
||||
|
||||
lea ECX,[ECX-1] ;
|
||||
jnz DoAlign ;
|
||||
Aligned:
|
||||
mov EAX,ECX ;
|
||||
|
||||
// do multiple of 4 bytes at a time
|
||||
|
||||
shr ECX,2 ;
|
||||
jz TryOdd ;
|
||||
|
||||
repe ;
|
||||
cmpsd ;
|
||||
|
||||
jnz UnequalQuad ;
|
||||
|
||||
TryOdd:
|
||||
mov ECX,EAX ;
|
||||
DoBytes:
|
||||
// if still equal and not end of string, do up to 3 bytes slightly
|
||||
// slower.
|
||||
|
||||
and ECX,3 ;
|
||||
jz Equal ;
|
||||
|
||||
repe ;
|
||||
cmpsb ;
|
||||
|
||||
jnz Unequal ;
|
||||
Equal:
|
||||
mov EAX,a1[4+ESP] ;
|
||||
mov EDX,a2[4+ESP] ;
|
||||
|
||||
sub EAX,EDX ;
|
||||
pop ESI ;
|
||||
|
||||
pop EDI ;
|
||||
ret ;
|
||||
|
||||
UnequalQuad:
|
||||
mov EDX,[EDI-4] ;
|
||||
mov EAX,[ESI-4] ;
|
||||
|
||||
cmp AL,DL ;
|
||||
jnz Unequal ;
|
||||
|
||||
cmp AH,DH ;
|
||||
jnz Unequal ;
|
||||
|
||||
shr EAX,16 ;
|
||||
|
||||
shr EDX,16 ;
|
||||
|
||||
cmp AL,DL ;
|
||||
jnz Unequal ;
|
||||
|
||||
cmp AH,DH ;
|
||||
Unequal:
|
||||
sbb EAX,EAX ;
|
||||
pop ESI ;
|
||||
|
||||
or EAX,1 ;
|
||||
pop EDI ;
|
||||
|
||||
ret ;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int len;
|
||||
int c;
|
||||
|
||||
debug(adi) printf("adCmpChar()\n");
|
||||
len = cast(int)a1.length;
|
||||
if (a2.length < len)
|
||||
len = cast(int)a2.length;
|
||||
c = memcmp(cast(char *)a1.ptr, cast(char *)a2.ptr, len);
|
||||
if (!c)
|
||||
c = cast(int)a1.length - cast(int)a2.length;
|
||||
return c;
|
||||
}
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(adi) printf("array.CmpChar unittest\n");
|
||||
|
||||
auto a = "hello"c;
|
||||
|
||||
assert(a > "hel");
|
||||
assert(a >= "hel");
|
||||
assert(a < "helloo");
|
||||
assert(a <= "helloo");
|
||||
assert(a > "betty");
|
||||
assert(a >= "betty");
|
||||
assert(a == "hello");
|
||||
assert(a <= "hello");
|
||||
assert(a >= "hello");
|
||||
}
|
||||
109
tango/lib/compiler/llvmdc/arrays.d
Normal file
109
tango/lib/compiler/llvmdc/arrays.d
Normal file
@@ -0,0 +1,109 @@
|
||||
private import llvm.intrinsic;
|
||||
|
||||
extern(C):
|
||||
|
||||
int memcmp(void*,void*,size_t);
|
||||
size_t strlen(char*);
|
||||
|
||||
version(LLVM64)
|
||||
alias llvm_memcpy_i64 llvm_memcpy;
|
||||
else
|
||||
alias llvm_memcpy_i32 llvm_memcpy;
|
||||
|
||||
// per-element array init routines
|
||||
|
||||
void _d_array_init_i1(bool* a, size_t n, bool v)
|
||||
{
|
||||
auto p = a;
|
||||
auto end = a+n;
|
||||
while (p !is end)
|
||||
*p++ = v;
|
||||
}
|
||||
|
||||
void _d_array_init_i8(ubyte* a, size_t n, ubyte v)
|
||||
{
|
||||
auto p = a;
|
||||
auto end = a+n;
|
||||
while (p !is end)
|
||||
*p++ = v;
|
||||
}
|
||||
|
||||
void _d_array_init_i16(ushort* a, size_t n, ushort v)
|
||||
{
|
||||
auto p = a;
|
||||
auto end = a+n;
|
||||
while (p !is end)
|
||||
*p++ = v;
|
||||
}
|
||||
|
||||
void _d_array_init_i32(uint* a, size_t n, uint v)
|
||||
{
|
||||
auto p = a;
|
||||
auto end = a+n;
|
||||
while (p !is end)
|
||||
*p++ = v;
|
||||
}
|
||||
|
||||
void _d_array_init_i64(ulong* a, size_t n, ulong v)
|
||||
{
|
||||
auto p = a;
|
||||
auto end = a+n;
|
||||
while (p !is end)
|
||||
*p++ = v;
|
||||
}
|
||||
|
||||
void _d_array_init_float(float* a, size_t n, float v)
|
||||
{
|
||||
auto p = a;
|
||||
auto end = a+n;
|
||||
while (p !is end)
|
||||
*p++ = v;
|
||||
}
|
||||
|
||||
void _d_array_init_double(double* a, size_t n, double v)
|
||||
{
|
||||
auto p = a;
|
||||
auto end = a+n;
|
||||
while (p !is end)
|
||||
*p++ = v;
|
||||
}
|
||||
|
||||
void _d_array_init_pointer(void** a, size_t n, void* v)
|
||||
{
|
||||
auto p = a;
|
||||
auto end = a+n;
|
||||
while (p !is end)
|
||||
*p++ = v;
|
||||
}
|
||||
|
||||
void _d_array_init_mem(void* a, size_t na, void* v, size_t nv)
|
||||
{
|
||||
auto p = a;
|
||||
auto end = a + na*nv;
|
||||
while (p !is end) {
|
||||
llvm_memcpy(p,v,nv,0);
|
||||
p += nv;
|
||||
}
|
||||
}
|
||||
|
||||
// for array cast
|
||||
size_t _d_array_cast_len(size_t len, size_t elemsz, size_t newelemsz)
|
||||
{
|
||||
if (newelemsz == 1) {
|
||||
return len*elemsz;
|
||||
}
|
||||
else if (len % newelemsz) {
|
||||
throw new Exception("Bad array cast");
|
||||
}
|
||||
return (len*elemsz)/newelemsz;
|
||||
}
|
||||
|
||||
// creating args for main
|
||||
void _d_main_args(uint n, char** args, ref char[][] res)
|
||||
{
|
||||
assert(res.length == n);
|
||||
foreach(i,v; args[0..n])
|
||||
{
|
||||
res[i] = v[0 .. strlen(v)];
|
||||
}
|
||||
}
|
||||
182
tango/lib/compiler/llvmdc/cast.d
Normal file
182
tango/lib/compiler/llvmdc/cast.d
Normal file
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
|
||||
* Written by Walter Bright
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, in both source and binary form, subject to the following
|
||||
* restrictions:
|
||||
*
|
||||
* o The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* o Altered source versions must be plainly marked as such, and must not
|
||||
* be misrepresented as being the original software.
|
||||
* o This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by Sean Kelly <sean@f4.ca> for use with Tango.
|
||||
*/
|
||||
|
||||
extern (C):
|
||||
|
||||
/******************************************
|
||||
* Given a pointer:
|
||||
* If it is an Object, return that Object.
|
||||
* If it is an interface, return the Object implementing the interface.
|
||||
* If it is null, return null.
|
||||
* Else, undefined crash
|
||||
*/
|
||||
|
||||
Object _d_toObject(void* p)
|
||||
{ Object o;
|
||||
|
||||
if (p)
|
||||
{
|
||||
o = cast(Object)p;
|
||||
ClassInfo oc = o.classinfo;
|
||||
Interface *pi = **cast(Interface ***)p;
|
||||
|
||||
/* Interface.offset lines up with ClassInfo.name.ptr,
|
||||
* so we rely on pointers never being less than 64K,
|
||||
* and Objects never being greater.
|
||||
*/
|
||||
if (pi.offset < 0x10000)
|
||||
{
|
||||
//printf("\tpi.offset = %d\n", pi.offset);
|
||||
o = cast(Object)(p - pi.offset);
|
||||
}
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
/*************************************
|
||||
* Attempts to cast Object o to class c.
|
||||
* Returns o if successful, null if not.
|
||||
*/
|
||||
|
||||
Object _d_interface_cast(void* p, ClassInfo c)
|
||||
{ Object o;
|
||||
|
||||
//printf("_d_interface_cast(p = %p, c = '%.*s')\n", p, c.name);
|
||||
if (p)
|
||||
{
|
||||
Interface *pi = **cast(Interface ***)p;
|
||||
|
||||
//printf("\tpi.offset = %d\n", pi.offset);
|
||||
o = cast(Object)(p - pi.offset);
|
||||
return _d_dynamic_cast(o, c);
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
Object _d_dynamic_cast(Object o, ClassInfo c)
|
||||
{ ClassInfo oc;
|
||||
size_t offset = 0;
|
||||
|
||||
//printf("_d_dynamic_cast(o = %p, c = '%.*s')\n", o, c.name);
|
||||
|
||||
if (o)
|
||||
{
|
||||
oc = o.classinfo;
|
||||
if (_d_isbaseof2(oc, c, offset))
|
||||
{
|
||||
//printf("\toffset = %d\n", offset);
|
||||
o = cast(Object)(cast(void*)o + offset);
|
||||
}
|
||||
else
|
||||
o = null;
|
||||
}
|
||||
//printf("\tresult = %p\n", o);
|
||||
return o;
|
||||
}
|
||||
|
||||
int _d_isbaseof2(ClassInfo oc, ClassInfo c, inout size_t offset)
|
||||
{ int i;
|
||||
|
||||
if (oc is c)
|
||||
return 1;
|
||||
do
|
||||
{
|
||||
if (oc.base is c)
|
||||
return 1;
|
||||
for (i = 0; i < oc.interfaces.length; i++)
|
||||
{
|
||||
ClassInfo ic;
|
||||
|
||||
ic = oc.interfaces[i].classinfo;
|
||||
if (ic is c)
|
||||
{ offset = cast(size_t)oc.interfaces[i].offset;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
for (i = 0; i < oc.interfaces.length; i++)
|
||||
{
|
||||
ClassInfo ic;
|
||||
|
||||
ic = oc.interfaces[i].classinfo;
|
||||
if (_d_isbaseof2(ic, c, offset))
|
||||
{ offset = cast(size_t)oc.interfaces[i].offset;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
oc = oc.base;
|
||||
} while (oc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _d_isbaseof(ClassInfo oc, ClassInfo c)
|
||||
{ int i;
|
||||
|
||||
if (oc is c)
|
||||
return 1;
|
||||
do
|
||||
{
|
||||
if (oc.base is c)
|
||||
return 1;
|
||||
for (i = 0; i < oc.interfaces.length; i++)
|
||||
{
|
||||
ClassInfo ic;
|
||||
|
||||
ic = oc.interfaces[i].classinfo;
|
||||
if (ic is c || _d_isbaseof(ic, c))
|
||||
return 1;
|
||||
}
|
||||
oc = oc.base;
|
||||
} while (oc);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*********************************
|
||||
* Find the vtbl[] associated with Interface ic.
|
||||
*/
|
||||
|
||||
void *_d_interface_vtbl(ClassInfo ic, Object o)
|
||||
{ int i;
|
||||
ClassInfo oc;
|
||||
|
||||
//printf("__d_interface_vtbl(o = %p, ic = %p)\n", o, ic);
|
||||
|
||||
assert(o);
|
||||
|
||||
oc = o.classinfo;
|
||||
for (i = 0; i < oc.interfaces.length; i++)
|
||||
{
|
||||
ClassInfo oic;
|
||||
|
||||
oic = oc.interfaces[i].classinfo;
|
||||
if (oic is ic)
|
||||
{
|
||||
return cast(void *)oc.interfaces[i].vtbl;
|
||||
}
|
||||
}
|
||||
assert(0);
|
||||
}
|
||||
12
tango/lib/compiler/llvmdc/contract.d
Normal file
12
tango/lib/compiler/llvmdc/contract.d
Normal file
@@ -0,0 +1,12 @@
|
||||
extern(C):
|
||||
|
||||
void exit(int);
|
||||
int printf(char*,...);
|
||||
|
||||
void _d_assert(bool cond, uint line, char[] msg)
|
||||
{
|
||||
if (!cond) {
|
||||
printf("Aborted(%u): %.*s\n", line, msg.length, msg.ptr);
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
1175
tango/lib/compiler/llvmdc/genobj.d
Normal file
1175
tango/lib/compiler/llvmdc/genobj.d
Normal file
File diff suppressed because it is too large
Load Diff
1033
tango/lib/compiler/llvmdc/lifetime.d
Normal file
1033
tango/lib/compiler/llvmdc/lifetime.d
Normal file
File diff suppressed because it is too large
Load Diff
138
tango/lib/compiler/llvmdc/llvm/intrinsic.d
Normal file
138
tango/lib/compiler/llvmdc/llvm/intrinsic.d
Normal file
@@ -0,0 +1,138 @@
|
||||
// code generator intrinsics
|
||||
/*
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.returnaddress")
|
||||
void* llvm_returnaddress(uint level);
|
||||
*/
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.frameaddress")
|
||||
void* llvm_frameaddress(uint level);
|
||||
/*
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.stacksave")
|
||||
void* llvm_stacksave();
|
||||
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.stackrestore")
|
||||
void llvm_stackrestore(void* ptr);
|
||||
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.pcmarker")
|
||||
void llvm_pcmarker(uint id);
|
||||
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.prefetch")
|
||||
void llvm_prefetch(void* ptr, uint rw, uint locality);
|
||||
*/
|
||||
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.readcyclecounter")
|
||||
ulong readcyclecounter();
|
||||
|
||||
// standard C intrinsics
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.memcpy.i32")
|
||||
void llvm_memcpy_i32(void* dst, void* src, uint len, uint alignment);
|
||||
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.memcpy.i64")
|
||||
void llvm_memcpy_i64(void* dst, void* src, ulong len, uint alignment);
|
||||
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.memmove.i32")
|
||||
void llvm_memmove_i32(void* dst, void* src, uint len, uint alignment);
|
||||
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.memmove.i64")
|
||||
void llvm_memmove_i64(void* dst, void* src, ulong len, int alignment);
|
||||
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.memset.i32")
|
||||
void llvm_memset_i32(void* dst, ubyte val, uint len, uint alignment);
|
||||
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.memset.i64")
|
||||
void llvm_memset_i64(void* dst, ubyte val, ulong len, uint alignment);
|
||||
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.sqrt.f32")
|
||||
float llvm_sqrt(float val);
|
||||
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.sqrt.f64")
|
||||
{
|
||||
double llvm_sqrt(double val);
|
||||
real llvm_sqrt(real val);
|
||||
}
|
||||
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.powi.f32")
|
||||
float llvm_powi(float val, int power);
|
||||
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.powi.f64")
|
||||
{
|
||||
double llvm_powi(double val, int power);
|
||||
real llvm_powi(real val, int power);
|
||||
}
|
||||
|
||||
// bit manipulation intrinsics
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.bswap.i16.i16")
|
||||
ushort llvm_bswap(ushort val);
|
||||
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.bswap.i32.i32")
|
||||
uint llvm_bswap(uint val);
|
||||
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.bswap.i64.i64")
|
||||
ulong llvm_bswap(ulong val);
|
||||
|
||||
/*
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.ctpop.i8")
|
||||
uint llvm_ctpop_i8(ubyte src);
|
||||
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.ctpop.i16")
|
||||
uint llvm_ctpop_i16(ushort src);
|
||||
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.ctpop.i32")
|
||||
uint llvm_ctpop_i32(uint src);
|
||||
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.ctpop.i64")
|
||||
uint llvm_ctpop_i64(ulong src);
|
||||
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.ctlz.i8")
|
||||
uint llvm_ctlz_i8(ubyte src);
|
||||
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.ctlz.i16")
|
||||
uint llvm_ctlz_i16(ushort src);
|
||||
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.ctlz.i32")
|
||||
uint llvm_ctlz_i32(uint src);
|
||||
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.ctlz.i64")
|
||||
uint llvm_ctlz_i64(ulong src);
|
||||
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.cttz.i8")
|
||||
uint llvm_cttz_i8(ubyte src);
|
||||
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.cttz.i16")
|
||||
uint llvm_cttz_i16(ushort src);
|
||||
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.cttz.i32")
|
||||
uint llvm_cttz_i32(uint src);
|
||||
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.cttz.i64")
|
||||
uint llvm_cttz_i64(ulong src);
|
||||
*/
|
||||
|
||||
// atomic operations and synchronization intrinsics
|
||||
// TODO
|
||||
/*
|
||||
|
||||
//declare i8 @llvm.atomic.lcs.i8.i8p.i8.i8( i8* <ptr>, i8 <cmp>, i8 <val> )
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.atomic.lcs.i8.i8p.i8.i8")
|
||||
ubyte llvm_atomic_lcs_i8(void* ptr, ubyte cmp, ubyte val);
|
||||
|
||||
declare i16 @llvm.atomic.lcs.i16.i16p.i16.i16( i16* <ptr>, i16 <cmp>, i16 <val> )
|
||||
declare i32 @llvm.atomic.lcs.i32.i32p.i32.i32( i32* <ptr>, i32 <cmp>, i32 <val> )
|
||||
declare i64 @llvm.atomic.lcs.i64.i64p.i64.i64( i64* <ptr>, i64 <cmp>, i64 <val> )
|
||||
|
||||
declare i8 @llvm.atomic.ls.i8.i8p.i8( i8* <ptr>, i8 <val> )
|
||||
declare i16 @llvm.atomic.ls.i16.i16p.i16( i16* <ptr>, i16 <val> )
|
||||
declare i32 @llvm.atomic.ls.i32.i32p.i32( i32* <ptr>, i32 <val> )
|
||||
declare i64 @llvm.atomic.ls.i64.i64p.i64( i64* <ptr>, i64 <val> )
|
||||
|
||||
declare i8 @llvm.atomic.las.i8.i8p.i8( i8* <ptr>, i8 <delta> )
|
||||
declare i16 @llvm.atomic.las.i16.i16p.i16( i16* <ptr>, i16 <delta> )
|
||||
declare i32 @llvm.atomic.las.i32.i32p.i32( i32* <ptr>, i32 <delta> )
|
||||
declare i64 @llvm.atomic.las.i64.i64p.i64( i64* <ptr>, i64 <delta> )
|
||||
|
||||
declare i8 @llvm.atomic.lss.i8.i8.i8( i8* <ptr>, i8 <delta> )
|
||||
declare i16 @llvm.atomic.lss.i16.i16.i16( i16* <ptr>, i16 <delta> )
|
||||
declare i32 @llvm.atomic.lss.i32.i32.i32( i32* <ptr>, i32 <delta> )
|
||||
declare i64 @llvm.atomic.lss.i64.i64.i64( i64* <ptr>, i64 <delta> )
|
||||
|
||||
declare void @llvm.memory.barrier( i1 <ll>, i1 <ls>, i1 <sl>, i1 <ss> )
|
||||
*/
|
||||
163
tango/lib/compiler/llvmdc/llvmdc.mak
Normal file
163
tango/lib/compiler/llvmdc/llvmdc.mak
Normal file
@@ -0,0 +1,163 @@
|
||||
# Makefile to build the LLVMDC compiler runtime D library for Linux
|
||||
# Designed to work with GNU make
|
||||
# Targets:
|
||||
# make
|
||||
# Same as make all
|
||||
# make lib
|
||||
# Build the compiler runtime library
|
||||
# make doc
|
||||
# Generate documentation
|
||||
# make clean
|
||||
# Delete unneeded files created by build process
|
||||
|
||||
LIB_TARGET=libtango-rt-llvmdc.a
|
||||
LIB_MASK=libtango-rt-llvmdc*.a
|
||||
|
||||
CP=cp -f
|
||||
RM=rm -f
|
||||
MD=mkdir -p
|
||||
|
||||
CFLAGS=-O3 $(ADD_CFLAGS)
|
||||
#CFLAGS=-g $(ADD_CFLAGS)
|
||||
|
||||
DFLAGS=-release -O3 -inline -w $(ADD_DFLAGS)
|
||||
#DFLAGS=-g -w $(ADD_DFLAGS)
|
||||
|
||||
TFLAGS=-O3 -inline -w $(ADD_DFLAGS)
|
||||
#TFLAGS=-g -w $(ADD_DFLAGS)
|
||||
|
||||
DOCFLAGS=-version=DDoc
|
||||
|
||||
CC=gcc
|
||||
LC=llvm-ar rsv
|
||||
DC=llvmdc
|
||||
LLC=llvm-as
|
||||
|
||||
LIB_DEST=..
|
||||
|
||||
.SUFFIXES: .s .S .c .cpp .d .ll .html .o .bc
|
||||
|
||||
.s.o:
|
||||
$(CC) -c $(CFLAGS) $< -o$@
|
||||
|
||||
.S.o:
|
||||
$(CC) -c $(CFLAGS) $< -o$@
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(CFLAGS) $< -o$@
|
||||
|
||||
.cpp.o:
|
||||
g++ -c $(CFLAGS) $< -o$@
|
||||
|
||||
.d.bc:
|
||||
$(DC) -c $(DFLAGS) $< -of$@
|
||||
|
||||
.ll.bc:
|
||||
$(LLC) -f -o=$@ $<
|
||||
|
||||
.d.html:
|
||||
$(DC) -c -o- $(DOCFLAGS) -Df$*.html llvmdc.ddoc $<
|
||||
|
||||
targets : lib doc
|
||||
all : lib doc
|
||||
lib : llvmdc.lib
|
||||
doc : llvmdc.doc
|
||||
|
||||
######################################################
|
||||
|
||||
OBJ_BASE= \
|
||||
aaA.bc \
|
||||
aApply.bc \
|
||||
aApplyR.bc \
|
||||
adi.bc \
|
||||
arrays.bc \
|
||||
cast.bc \
|
||||
contract.bc \
|
||||
genobj.bc \
|
||||
lifetime.bc \
|
||||
mem.bc \
|
||||
memory.bc \
|
||||
qsort2.bc \
|
||||
switch.bc \
|
||||
|
||||
# NOTE: trace.obj and cover.obj are not necessary for a successful build
|
||||
# as both are used for debugging features (profiling and coverage)
|
||||
# NOTE: a pre-compiled minit.obj has been provided in dmd for Win32 and
|
||||
# minit.asm is not used by dmd for linux
|
||||
# NOTE: deh.o is only needed for Win32, linux uses deh2.o
|
||||
|
||||
OBJ_UTIL= \
|
||||
util/console.bc \
|
||||
util/ctype.bc \
|
||||
util/string.bc \
|
||||
util/utf.bc
|
||||
|
||||
OBJ_TI= \
|
||||
typeinfo/ti_AC.bc \
|
||||
typeinfo/ti_Acdouble.bc \
|
||||
typeinfo/ti_Acfloat.bc \
|
||||
typeinfo/ti_Acreal.bc \
|
||||
typeinfo/ti_Adouble.bc \
|
||||
typeinfo/ti_Afloat.bc \
|
||||
typeinfo/ti_Ag.bc \
|
||||
typeinfo/ti_Aint.bc \
|
||||
typeinfo/ti_Along.bc \
|
||||
typeinfo/ti_Areal.bc \
|
||||
typeinfo/ti_Ashort.bc \
|
||||
typeinfo/ti_byte.bc \
|
||||
typeinfo/ti_C.bc \
|
||||
typeinfo/ti_cdouble.bc \
|
||||
typeinfo/ti_cfloat.bc \
|
||||
typeinfo/ti_char.bc \
|
||||
typeinfo/ti_creal.bc \
|
||||
typeinfo/ti_dchar.bc \
|
||||
typeinfo/ti_delegate.bc \
|
||||
typeinfo/ti_double.bc \
|
||||
typeinfo/ti_float.bc \
|
||||
typeinfo/ti_idouble.bc \
|
||||
typeinfo/ti_ifloat.bc \
|
||||
typeinfo/ti_int.bc \
|
||||
typeinfo/ti_ireal.bc \
|
||||
typeinfo/ti_long.bc \
|
||||
typeinfo/ti_ptr.bc \
|
||||
typeinfo/ti_real.bc \
|
||||
typeinfo/ti_short.bc \
|
||||
typeinfo/ti_ubyte.bc \
|
||||
typeinfo/ti_uint.bc \
|
||||
typeinfo/ti_ulong.bc \
|
||||
typeinfo/ti_ushort.bc \
|
||||
typeinfo/ti_void.bc \
|
||||
typeinfo/ti_wchar.bc
|
||||
|
||||
ALL_OBJS= \
|
||||
$(OBJ_BASE) \
|
||||
$(OBJ_UTIL) \
|
||||
$(OBJ_TI) \
|
||||
moduleinfo.bc
|
||||
|
||||
######################################################
|
||||
|
||||
ALL_DOCS=
|
||||
|
||||
######################################################
|
||||
|
||||
llvmdc.lib : $(LIB_TARGET)
|
||||
|
||||
$(LIB_TARGET) : $(ALL_OBJS)
|
||||
$(RM) $@
|
||||
$(LC) $@ $(ALL_OBJS)
|
||||
|
||||
llvmdc.doc : $(ALL_DOCS)
|
||||
echo No documentation available.
|
||||
|
||||
######################################################
|
||||
|
||||
clean :
|
||||
find . -name "*.di" | xargs $(RM)
|
||||
$(RM) $(ALL_OBJS)
|
||||
$(RM) $(ALL_DOCS)
|
||||
$(RM) $(LIB_MASK)
|
||||
|
||||
install :
|
||||
$(MD) $(LIB_DEST)
|
||||
$(CP) $(LIB_MASK) $(LIB_DEST)/.
|
||||
14
tango/lib/compiler/llvmdc/mem.d
Normal file
14
tango/lib/compiler/llvmdc/mem.d
Normal file
@@ -0,0 +1,14 @@
|
||||
extern(C):
|
||||
|
||||
void* realloc(void*,size_t);
|
||||
void free(void*);
|
||||
|
||||
void* _d_realloc(void* ptr, size_t n)
|
||||
{
|
||||
return realloc(ptr, n);
|
||||
}
|
||||
|
||||
void _d_free(void* ptr)
|
||||
{
|
||||
free(ptr);
|
||||
}
|
||||
170
tango/lib/compiler/llvmdc/memory.d
Normal file
170
tango/lib/compiler/llvmdc/memory.d
Normal file
@@ -0,0 +1,170 @@
|
||||
/**
|
||||
* This module exposes functionality for inspecting and manipulating memory.
|
||||
*
|
||||
* Copyright: Copyright (C) 2005-2006 Digital Mars, www.digitalmars.com.
|
||||
* All rights reserved.
|
||||
* License:
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, in both source and binary form, subject to the following
|
||||
* restrictions:
|
||||
*
|
||||
* o The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* o Altered source versions must be plainly marked as such, and must not
|
||||
* be misrepresented as being the original software.
|
||||
* o This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
* Authors: Walter Bright, Sean Kelly
|
||||
*/
|
||||
module memory;
|
||||
|
||||
|
||||
private
|
||||
{
|
||||
version( linux )
|
||||
{
|
||||
//version = SimpleLibcStackEnd;
|
||||
|
||||
version( SimpleLibcStackEnd )
|
||||
{
|
||||
extern (C) extern void* __libc_stack_end;
|
||||
}
|
||||
else
|
||||
{
|
||||
import tango.stdc.posix.dlfcn;
|
||||
}
|
||||
}
|
||||
version(LLVMDC)
|
||||
{
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.frameaddress")
|
||||
{
|
||||
void* llvm_frameaddress(uint level=0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
extern (C) void* rt_stackBottom()
|
||||
{
|
||||
version( Win32 )
|
||||
{
|
||||
asm
|
||||
{
|
||||
naked;
|
||||
mov EAX,FS:4;
|
||||
ret;
|
||||
}
|
||||
}
|
||||
else version( linux )
|
||||
{
|
||||
version( SimpleLibcStackEnd )
|
||||
{
|
||||
return __libc_stack_end;
|
||||
}
|
||||
else
|
||||
{
|
||||
// See discussion: http://autopackage.org/forums/viewtopic.php?t=22
|
||||
static void** libc_stack_end;
|
||||
|
||||
if( libc_stack_end == libc_stack_end.init )
|
||||
{
|
||||
void* handle = dlopen( null, RTLD_NOW );
|
||||
libc_stack_end = cast(void**) dlsym( handle, "__libc_stack_end" );
|
||||
dlclose( handle );
|
||||
}
|
||||
return *libc_stack_end;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
static assert( false, "Operating system not supported." );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
extern (C) void* rt_stackTop()
|
||||
{
|
||||
version( D_InlineAsm_X86 )
|
||||
{
|
||||
asm
|
||||
{
|
||||
naked;
|
||||
mov EAX, ESP;
|
||||
ret;
|
||||
}
|
||||
}
|
||||
else version(LLVMDC)
|
||||
{
|
||||
return llvm_frameaddress();
|
||||
}
|
||||
else
|
||||
{
|
||||
static assert( false, "Architecture not supported." );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private
|
||||
{
|
||||
version( Win32 )
|
||||
{
|
||||
extern (C)
|
||||
{
|
||||
extern int _xi_a; // &_xi_a just happens to be start of data segment
|
||||
extern int _edata; // &_edata is start of BSS segment
|
||||
extern int _end; // &_end is past end of BSS
|
||||
}
|
||||
}
|
||||
else version( linux )
|
||||
{
|
||||
extern (C)
|
||||
{
|
||||
extern int _data;
|
||||
extern int __data_start;
|
||||
extern int _end;
|
||||
extern int _data_start__;
|
||||
extern int _data_end__;
|
||||
extern int _bss_start__;
|
||||
extern int _bss_end__;
|
||||
extern int __fini_array_end;
|
||||
}
|
||||
|
||||
alias __data_start Data_Start;
|
||||
alias _end Data_End;
|
||||
}
|
||||
|
||||
alias void delegate( void*, void* ) scanFn;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
extern (C) void rt_scanStaticData( scanFn scan )
|
||||
{
|
||||
version( Win32 )
|
||||
{
|
||||
scan( &_xi_a, &_end );
|
||||
}
|
||||
else version( linux )
|
||||
{
|
||||
scan( &__data_start, &_end );
|
||||
}
|
||||
else
|
||||
{
|
||||
static assert( false, "Operating system not supported." );
|
||||
}
|
||||
}
|
||||
9
tango/lib/compiler/llvmdc/moduleinfo.ll
Normal file
9
tango/lib/compiler/llvmdc/moduleinfo.ll
Normal file
@@ -0,0 +1,9 @@
|
||||
; ModuleID = 'internal.moduleinit_backend'
|
||||
|
||||
@_d_moduleinfo_array = appending constant [1 x i8*] [ i8* null ]
|
||||
|
||||
define i8** @_d_get_moduleinfo_array() {
|
||||
entry:
|
||||
%tmp = getelementptr [1 x i8*]* @_d_moduleinfo_array, i32 0, i32 0
|
||||
ret i8** %tmp
|
||||
}
|
||||
70
tango/lib/compiler/llvmdc/qsort2.d
Normal file
70
tango/lib/compiler/llvmdc/qsort2.d
Normal file
@@ -0,0 +1,70 @@
|
||||
|
||||
/*
|
||||
* Placed into Public Domain
|
||||
* written by Walter Bright
|
||||
* www.digitalmars.com
|
||||
*
|
||||
* This is a public domain version of qsort.d.
|
||||
* All it does is call C's qsort(), but runs a little slower since
|
||||
* it needs to synchronize a global variable.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by Sean Kelly <sean@f4.ca> for use with Tango.
|
||||
*/
|
||||
|
||||
//debug=qsort;
|
||||
|
||||
private import tango.stdc.stdlib;
|
||||
|
||||
struct Array
|
||||
{
|
||||
size_t length;
|
||||
void* ptr;
|
||||
}
|
||||
|
||||
private TypeInfo tiglobal;
|
||||
|
||||
extern (C) int cmp(void* p1, void* p2)
|
||||
{
|
||||
return tiglobal.compare(p1, p2);
|
||||
}
|
||||
|
||||
extern (C) long _adSort(Array a, TypeInfo ti)
|
||||
{
|
||||
synchronized
|
||||
{
|
||||
tiglobal = ti;
|
||||
tango.stdc.stdlib.qsort(a.ptr, a.length, cast(size_t)ti.tsize(), &cmp);
|
||||
}
|
||||
return *cast(long*)(&a);
|
||||
}
|
||||
|
||||
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(qsort) printf("array.sort.unittest()\n");
|
||||
|
||||
int a[] = new int[10];
|
||||
|
||||
a[0] = 23;
|
||||
a[1] = 1;
|
||||
a[2] = 64;
|
||||
a[3] = 5;
|
||||
a[4] = 6;
|
||||
a[5] = 5;
|
||||
a[6] = 17;
|
||||
a[7] = 3;
|
||||
a[8] = 0;
|
||||
a[9] = -1;
|
||||
|
||||
a.sort;
|
||||
|
||||
for (int i = 0; i < a.length - 1; i++)
|
||||
{
|
||||
//printf("i = %d", i);
|
||||
//printf(" %d %d\n", a[i], a[i + 1]);
|
||||
assert(a[i] <= a[i + 1]);
|
||||
}
|
||||
}
|
||||
265
tango/lib/compiler/llvmdc/std/intrinsic.d
Normal file
265
tango/lib/compiler/llvmdc/std/intrinsic.d
Normal file
@@ -0,0 +1,265 @@
|
||||
|
||||
|
||||
// written by Walter Bright
|
||||
// www.digitalmars.com
|
||||
// Placed into the public domain
|
||||
|
||||
/* NOTE: This file has been patched from the original DMD distribution to
|
||||
work with the GDC compiler.
|
||||
NOTE: This file has been patched from the original GDC distribution to
|
||||
work with the LLVMDC compiler.
|
||||
|
||||
Modified by David Friedman, May 2006
|
||||
Modified by Tomas Lindquist Olsen, August 2007
|
||||
*/
|
||||
|
||||
/** These functions are built-in intrinsics to the compiler.
|
||||
*
|
||||
Intrinsic functions are functions built in to the compiler,
|
||||
usually to take advantage of specific CPU features that
|
||||
are inefficient to handle via external functions.
|
||||
The compiler's optimizer and code generator are fully
|
||||
integrated in with intrinsic functions, bringing to bear
|
||||
their full power on them.
|
||||
This can result in some surprising speedups.
|
||||
* Macros:
|
||||
* WIKI=Phobos/StdIntrinsic
|
||||
*/
|
||||
|
||||
module std.intrinsic;
|
||||
|
||||
/**
|
||||
* Scans the bits in v starting with bit 0, looking
|
||||
* for the first set bit.
|
||||
* Returns:
|
||||
* The bit number of the first bit set.
|
||||
* The return value is undefined if v is zero.
|
||||
*/
|
||||
version (LLVMDC)
|
||||
int bsf(uint v)
|
||||
{
|
||||
uint m = 1;
|
||||
uint i;
|
||||
for (i = 0; i < 32; i++,m<<=1) {
|
||||
if (v&m)
|
||||
return i;
|
||||
}
|
||||
return i; // supposed to be undefined
|
||||
}
|
||||
else
|
||||
int bsf(uint v);
|
||||
|
||||
/**
|
||||
* Scans the bits in v from the most significant bit
|
||||
* to the least significant bit, looking
|
||||
* for the first set bit.
|
||||
* Returns:
|
||||
* The bit number of the first bit set.
|
||||
* The return value is undefined if v is zero.
|
||||
* Example:
|
||||
* ---
|
||||
* import std.intrinsic;
|
||||
*
|
||||
* int main()
|
||||
* {
|
||||
* uint v;
|
||||
* int x;
|
||||
*
|
||||
* v = 0x21;
|
||||
* x = bsf(v);
|
||||
* printf("bsf(x%x) = %d\n", v, x);
|
||||
* x = bsr(v);
|
||||
* printf("bsr(x%x) = %d\n", v, x);
|
||||
* return 0;
|
||||
* }
|
||||
* ---
|
||||
* Output:
|
||||
* bsf(x21) = 0<br>
|
||||
* bsr(x21) = 5
|
||||
*/
|
||||
version (LLVMDC)
|
||||
int bsr(uint v)
|
||||
{
|
||||
uint m = 0x80000000;
|
||||
uint i;
|
||||
for (i = 32; i ; i--,m>>>=1) {
|
||||
if (v&m)
|
||||
return i-1;
|
||||
}
|
||||
return i; // supposed to be undefined
|
||||
}
|
||||
else
|
||||
int bsr(uint v);
|
||||
|
||||
/**
|
||||
* Tests the bit.
|
||||
*/
|
||||
version (LLVMDC)
|
||||
int bt(uint *p, uint bitnum)
|
||||
{
|
||||
return (p[bitnum / (uint.sizeof*8)] & (1<<(bitnum & ((uint.sizeof*8)-1)))) ? -1 : 0 ;
|
||||
}
|
||||
else
|
||||
int bt(uint *p, uint bitnum);
|
||||
|
||||
/**
|
||||
* Tests and complements the bit.
|
||||
*/
|
||||
version (LLVMDC)
|
||||
int btc(uint *p, uint bitnum)
|
||||
{
|
||||
uint * q = p + (bitnum / (uint.sizeof*8));
|
||||
uint mask = 1 << (bitnum & ((uint.sizeof*8) - 1));
|
||||
int result = *q & mask;
|
||||
*q ^= mask;
|
||||
return result ? -1 : 0;
|
||||
}
|
||||
else
|
||||
int btc(uint *p, uint bitnum);
|
||||
|
||||
/**
|
||||
* Tests and resets (sets to 0) the bit.
|
||||
*/
|
||||
version (LLVMDC)
|
||||
int btr(uint *p, uint bitnum)
|
||||
{
|
||||
uint * q = p + (bitnum / (uint.sizeof*8));
|
||||
uint mask = 1 << (bitnum & ((uint.sizeof*8) - 1));
|
||||
int result = *q & mask;
|
||||
*q &= ~mask;
|
||||
return result ? -1 : 0;
|
||||
}
|
||||
else
|
||||
int btr(uint *p, uint bitnum);
|
||||
|
||||
/**
|
||||
* Tests and sets the bit.
|
||||
* Params:
|
||||
* p = a non-NULL pointer to an array of uints.
|
||||
* index = a bit number, starting with bit 0 of p[0],
|
||||
* and progressing. It addresses bits like the expression:
|
||||
---
|
||||
p[index / (uint.sizeof*8)] & (1 << (index & ((uint.sizeof*8) - 1)))
|
||||
---
|
||||
* Returns:
|
||||
* A non-zero value if the bit was set, and a zero
|
||||
* if it was clear.
|
||||
*
|
||||
* Example:
|
||||
* ---
|
||||
import std.intrinsic;
|
||||
|
||||
int main()
|
||||
{
|
||||
uint array[2];
|
||||
|
||||
array[0] = 2;
|
||||
array[1] = 0x100;
|
||||
|
||||
printf("btc(array, 35) = %d\n", <b>btc</b>(array, 35));
|
||||
printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
|
||||
|
||||
printf("btc(array, 35) = %d\n", <b>btc</b>(array, 35));
|
||||
printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
|
||||
|
||||
printf("bts(array, 35) = %d\n", <b>bts</b>(array, 35));
|
||||
printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
|
||||
|
||||
printf("btr(array, 35) = %d\n", <b>btr</b>(array, 35));
|
||||
printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
|
||||
|
||||
printf("bt(array, 1) = %d\n", <b>bt</b>(array, 1));
|
||||
printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
* ---
|
||||
* Output:
|
||||
<pre>
|
||||
btc(array, 35) = 0
|
||||
array = [0]:x2, [1]:x108
|
||||
btc(array, 35) = -1
|
||||
array = [0]:x2, [1]:x100
|
||||
bts(array, 35) = 0
|
||||
array = [0]:x2, [1]:x108
|
||||
btr(array, 35) = -1
|
||||
array = [0]:x2, [1]:x100
|
||||
bt(array, 1) = -1
|
||||
array = [0]:x2, [1]:x100
|
||||
</pre>
|
||||
*/
|
||||
version (LLVMDC)
|
||||
int bts(uint *p, uint bitnum)
|
||||
{
|
||||
uint * q = p + (bitnum / (uint.sizeof*8));
|
||||
uint mask = 1 << (bitnum & ((uint.sizeof*8) - 1));
|
||||
int result = *q & mask;
|
||||
*q |= mask;
|
||||
return result ? -1 : 0;
|
||||
}
|
||||
else
|
||||
int bts(uint *p, uint bitnum);
|
||||
|
||||
|
||||
/**
|
||||
* Swaps bytes in a 4 byte uint end-to-end, i.e. byte 0 becomes
|
||||
byte 3, byte 1 becomes byte 2, byte 2 becomes byte 1, byte 3
|
||||
becomes byte 0.
|
||||
*/
|
||||
version (LLVMDC)
|
||||
pragma(LLVM_internal, "intrinsic", "llvm.bswap.i32")
|
||||
uint bswap(uint val);
|
||||
else
|
||||
uint bswap(uint v);
|
||||
|
||||
|
||||
/**
|
||||
* Reads I/O port at port_address.
|
||||
*/
|
||||
version (LLVMDC)
|
||||
ubyte inp(uint p) { return 0; }
|
||||
else
|
||||
ubyte inp(uint port_address);
|
||||
|
||||
/**
|
||||
* ditto
|
||||
*/
|
||||
version (LLVMDC)
|
||||
ushort inpw(uint p) { return 0; }
|
||||
else
|
||||
ushort inpw(uint port_address);
|
||||
|
||||
/**
|
||||
* ditto
|
||||
*/
|
||||
version (LLVMDC)
|
||||
uint inpl(uint p) { return 0; }
|
||||
else
|
||||
uint inpl(uint port_address);
|
||||
|
||||
|
||||
/**
|
||||
* Writes and returns value to I/O port at port_address.
|
||||
*/
|
||||
version (LLVM)
|
||||
ubyte outp(uint p, ubyte v) { return v; }
|
||||
else
|
||||
ubyte outp(uint port_address, ubyte value);
|
||||
|
||||
/**
|
||||
* ditto
|
||||
*/
|
||||
version (LLVM)
|
||||
ushort outpw(uint p, ushort v) { return v; }
|
||||
else
|
||||
ushort outpw(uint port_address, ushort value);
|
||||
|
||||
/**
|
||||
* ditto
|
||||
*/
|
||||
version (LLVM)
|
||||
uint outpl(uint p, uint v) { return v; }
|
||||
else
|
||||
uint outpl(uint port_address, uint value);
|
||||
|
||||
|
||||
424
tango/lib/compiler/llvmdc/switch.d
Normal file
424
tango/lib/compiler/llvmdc/switch.d
Normal file
@@ -0,0 +1,424 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2007 by Digital Mars, www.digitalmars.com
|
||||
* Written by Walter Bright
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, in both source and binary form, subject to the following
|
||||
* restrictions:
|
||||
*
|
||||
* o The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* o Altered source versions must be plainly marked as such, and must not
|
||||
* be misrepresented as being the original software.
|
||||
* o This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by Sean Kelly <sean@f4.ca> for use with Tango.
|
||||
*/
|
||||
|
||||
private import tango.stdc.string;
|
||||
|
||||
/******************************************************
|
||||
* Support for switch statements switching on strings.
|
||||
* Input:
|
||||
* table[] sorted array of strings generated by compiler
|
||||
* ca string to look up in table
|
||||
* Output:
|
||||
* result index of match in table[]
|
||||
* -1 if not in table
|
||||
*/
|
||||
|
||||
extern (C):
|
||||
|
||||
int _d_switch_string(char[][] table, char[] ca)
|
||||
in
|
||||
{
|
||||
//printf("in _d_switch_string()\n");
|
||||
assert(table.length >= 0);
|
||||
assert(ca.length >= 0);
|
||||
|
||||
// Make sure table[] is sorted correctly
|
||||
int j;
|
||||
|
||||
for (j = 1; j < table.length; j++)
|
||||
{
|
||||
size_t len1 = table[j - 1].length;
|
||||
size_t len2 = table[j].length;
|
||||
|
||||
assert(len1 <= len2);
|
||||
if (len1 == len2)
|
||||
{
|
||||
int ci;
|
||||
|
||||
ci = memcmp(table[j - 1].ptr, table[j].ptr, len1);
|
||||
assert(ci < 0); // ci==0 means a duplicate
|
||||
}
|
||||
}
|
||||
}
|
||||
out (result)
|
||||
{
|
||||
int i;
|
||||
int cj;
|
||||
|
||||
//printf("out _d_switch_string()\n");
|
||||
if (result == -1)
|
||||
{
|
||||
// Not found
|
||||
for (i = 0; i < table.length; i++)
|
||||
{
|
||||
if (table[i].length == ca.length)
|
||||
{ cj = memcmp(table[i].ptr, ca.ptr, ca.length);
|
||||
assert(cj != 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0 <= result && result < table.length);
|
||||
for (i = 0; 1; i++)
|
||||
{
|
||||
assert(i < table.length);
|
||||
if (table[i].length == ca.length)
|
||||
{
|
||||
cj = memcmp(table[i].ptr, ca.ptr, ca.length);
|
||||
if (cj == 0)
|
||||
{
|
||||
assert(i == result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
body
|
||||
{
|
||||
//printf("body _d_switch_string(%.*s)\n", ca);
|
||||
size_t low;
|
||||
size_t high;
|
||||
size_t mid;
|
||||
size_t c;
|
||||
char[] pca;
|
||||
|
||||
low = 0;
|
||||
high = table.length;
|
||||
|
||||
version (none)
|
||||
{
|
||||
// Print table
|
||||
printf("ca[] = '%s'\n", cast(char *)ca);
|
||||
for (mid = 0; mid < high; mid++)
|
||||
{
|
||||
pca = table[mid];
|
||||
printf("table[%d] = %d, '%.*s'\n", mid, pca.length, pca);
|
||||
}
|
||||
}
|
||||
if (high &&
|
||||
ca.length >= table[0].length &&
|
||||
ca.length <= table[high - 1].length)
|
||||
{
|
||||
// Looking for 0 length string, which would only be at the beginning
|
||||
if (ca.length == 0)
|
||||
return 0;
|
||||
|
||||
char c1 = ca[0];
|
||||
|
||||
// Do binary search
|
||||
while (low < high)
|
||||
{
|
||||
mid = (low + high) >> 1;
|
||||
pca = table[mid];
|
||||
c = ca.length - pca.length;
|
||||
if (c == 0)
|
||||
{
|
||||
c = cast(ubyte)c1 - cast(ubyte)pca[0];
|
||||
if (c == 0)
|
||||
{
|
||||
c = memcmp(ca.ptr, pca.ptr, ca.length);
|
||||
if (c == 0)
|
||||
{ //printf("found %d\n", mid);
|
||||
return cast(int)mid;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (c < 0)
|
||||
{
|
||||
high = mid;
|
||||
}
|
||||
else
|
||||
{
|
||||
low = mid + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//printf("not found\n");
|
||||
return -1; // not found
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
switch (cast(char []) "c")
|
||||
{
|
||||
case "coo":
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************
|
||||
* Same thing, but for wide chars.
|
||||
*/
|
||||
|
||||
int _d_switch_ustring(wchar[][] table, wchar[] ca)
|
||||
in
|
||||
{
|
||||
//printf("in _d_switch_ustring()\n");
|
||||
assert(table.length >= 0);
|
||||
assert(ca.length >= 0);
|
||||
|
||||
// Make sure table[] is sorted correctly
|
||||
int j;
|
||||
|
||||
for (j = 1; j < table.length; j++)
|
||||
{
|
||||
size_t len1 = table[j - 1].length;
|
||||
size_t len2 = table[j].length;
|
||||
|
||||
assert(len1 <= len2);
|
||||
if (len1 == len2)
|
||||
{
|
||||
int c;
|
||||
|
||||
c = memcmp(table[j - 1].ptr, table[j].ptr, len1 * wchar.sizeof);
|
||||
assert(c < 0); // c==0 means a duplicate
|
||||
}
|
||||
}
|
||||
}
|
||||
out (result)
|
||||
{
|
||||
int i;
|
||||
int c;
|
||||
|
||||
//printf("out _d_switch_string()\n");
|
||||
if (result == -1)
|
||||
{
|
||||
// Not found
|
||||
for (i = 0; i < table.length; i++)
|
||||
{
|
||||
if (table[i].length == ca.length)
|
||||
{ c = memcmp(table[i].ptr, ca.ptr, ca.length * wchar.sizeof);
|
||||
assert(c != 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0 <= result && result < table.length);
|
||||
for (i = 0; 1; i++)
|
||||
{
|
||||
assert(i < table.length);
|
||||
if (table[i].length == ca.length)
|
||||
{
|
||||
c = memcmp(table[i].ptr, ca.ptr, ca.length * wchar.sizeof);
|
||||
if (c == 0)
|
||||
{
|
||||
assert(i == result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
body
|
||||
{
|
||||
//printf("body _d_switch_ustring()\n");
|
||||
size_t low;
|
||||
size_t high;
|
||||
size_t mid;
|
||||
size_t c;
|
||||
wchar[] pca;
|
||||
|
||||
low = 0;
|
||||
high = table.length;
|
||||
|
||||
/*
|
||||
// Print table
|
||||
wprintf("ca[] = '%.*s'\n", ca);
|
||||
for (mid = 0; mid < high; mid++)
|
||||
{
|
||||
pca = table[mid];
|
||||
wprintf("table[%d] = %d, '%.*s'\n", mid, pca.length, pca);
|
||||
}
|
||||
*/
|
||||
|
||||
// Do binary search
|
||||
while (low < high)
|
||||
{
|
||||
mid = (low + high) >> 1;
|
||||
pca = table[mid];
|
||||
c = ca.length - pca.length;
|
||||
if (c == 0)
|
||||
{
|
||||
c = memcmp(ca.ptr, pca.ptr, ca.length * wchar.sizeof);
|
||||
if (c == 0)
|
||||
{ //printf("found %d\n", mid);
|
||||
return cast(int)mid;
|
||||
}
|
||||
}
|
||||
if (c < 0)
|
||||
{
|
||||
high = mid;
|
||||
}
|
||||
else
|
||||
{
|
||||
low = mid + 1;
|
||||
}
|
||||
}
|
||||
//printf("not found\n");
|
||||
return -1; // not found
|
||||
}
|
||||
|
||||
|
||||
unittest
|
||||
{
|
||||
switch (cast(wchar []) "c")
|
||||
{
|
||||
case "coo":
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**********************************
|
||||
* Same thing, but for wide chars.
|
||||
*/
|
||||
|
||||
int _d_switch_dstring(dchar[][] table, dchar[] ca)
|
||||
in
|
||||
{
|
||||
//printf("in _d_switch_dstring()\n");
|
||||
assert(table.length >= 0);
|
||||
assert(ca.length >= 0);
|
||||
|
||||
// Make sure table[] is sorted correctly
|
||||
int j;
|
||||
|
||||
for (j = 1; j < table.length; j++)
|
||||
{
|
||||
size_t len1 = table[j - 1].length;
|
||||
size_t len2 = table[j].length;
|
||||
|
||||
assert(len1 <= len2);
|
||||
if (len1 == len2)
|
||||
{
|
||||
int c;
|
||||
|
||||
c = memcmp(table[j - 1].ptr, table[j].ptr, len1 * dchar.sizeof);
|
||||
assert(c < 0); // c==0 means a duplicate
|
||||
}
|
||||
}
|
||||
}
|
||||
out (result)
|
||||
{
|
||||
int i;
|
||||
int c;
|
||||
|
||||
//printf("out _d_switch_string()\n");
|
||||
if (result == -1)
|
||||
{
|
||||
// Not found
|
||||
for (i = 0; i < table.length; i++)
|
||||
{
|
||||
if (table[i].length == ca.length)
|
||||
{ c = memcmp(table[i].ptr, ca.ptr, ca.length * dchar.sizeof);
|
||||
assert(c != 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(0 <= result && result < table.length);
|
||||
for (i = 0; 1; i++)
|
||||
{
|
||||
assert(i < table.length);
|
||||
if (table[i].length == ca.length)
|
||||
{
|
||||
c = memcmp(table[i].ptr, ca.ptr, ca.length * dchar.sizeof);
|
||||
if (c == 0)
|
||||
{
|
||||
assert(i == result);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
body
|
||||
{
|
||||
//printf("body _d_switch_ustring()\n");
|
||||
size_t low;
|
||||
size_t high;
|
||||
size_t mid;
|
||||
size_t c;
|
||||
dchar[] pca;
|
||||
|
||||
low = 0;
|
||||
high = table.length;
|
||||
|
||||
/*
|
||||
// Print table
|
||||
wprintf("ca[] = '%.*s'\n", ca);
|
||||
for (mid = 0; mid < high; mid++)
|
||||
{
|
||||
pca = table[mid];
|
||||
wprintf("table[%d] = %d, '%.*s'\n", mid, pca.length, pca);
|
||||
}
|
||||
*/
|
||||
|
||||
// Do binary search
|
||||
while (low < high)
|
||||
{
|
||||
mid = (low + high) >> 1;
|
||||
pca = table[mid];
|
||||
c = ca.length - pca.length;
|
||||
if (c == 0)
|
||||
{
|
||||
c = memcmp(ca.ptr, pca.ptr, ca.length * dchar.sizeof);
|
||||
if (c == 0)
|
||||
{ //printf("found %d\n", mid);
|
||||
return cast(int)mid;
|
||||
}
|
||||
}
|
||||
if (c < 0)
|
||||
{
|
||||
high = mid;
|
||||
}
|
||||
else
|
||||
{
|
||||
low = mid + 1;
|
||||
}
|
||||
}
|
||||
//printf("not found\n");
|
||||
return -1; // not found
|
||||
}
|
||||
|
||||
|
||||
unittest
|
||||
{
|
||||
switch (cast(dchar []) "c")
|
||||
{
|
||||
case "coo":
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
95
tango/lib/compiler/llvmdc/typeinfo/ti_AC.d
Normal file
95
tango/lib/compiler/llvmdc/typeinfo/ti_AC.d
Normal file
@@ -0,0 +1,95 @@
|
||||
module typeinfo.ti_AC;
|
||||
|
||||
// Object[]
|
||||
|
||||
class TypeInfo_AC : TypeInfo
|
||||
{
|
||||
hash_t getHash(void *p)
|
||||
{ Object[] s = *cast(Object[]*)p;
|
||||
hash_t hash = 0;
|
||||
|
||||
foreach (Object o; s)
|
||||
{
|
||||
if (o)
|
||||
hash += o.toHash();
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
int equals(void *p1, void *p2)
|
||||
{
|
||||
Object[] s1 = *cast(Object[]*)p1;
|
||||
Object[] s2 = *cast(Object[]*)p2;
|
||||
|
||||
if (s1.length == s2.length)
|
||||
{
|
||||
for (size_t u = 0; u < s1.length; u++)
|
||||
{ Object o1 = s1[u];
|
||||
Object o2 = s2[u];
|
||||
|
||||
// Do not pass null's to Object.opEquals()
|
||||
if (o1 is o2 ||
|
||||
(!(o1 is null) && !(o2 is null) && o1.opEquals(o2)))
|
||||
continue;
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int compare(void *p1, void *p2)
|
||||
{
|
||||
Object[] s1 = *cast(Object[]*)p1;
|
||||
Object[] s2 = *cast(Object[]*)p2;
|
||||
ptrdiff_t c;
|
||||
|
||||
c = cast(ptrdiff_t)s1.length - cast(ptrdiff_t)s2.length;
|
||||
if (c == 0)
|
||||
{
|
||||
for (size_t u = 0; u < s1.length; u++)
|
||||
{ Object o1 = s1[u];
|
||||
Object o2 = s2[u];
|
||||
|
||||
if (o1 is o2)
|
||||
continue;
|
||||
|
||||
// Regard null references as always being "less than"
|
||||
if (o1)
|
||||
{
|
||||
if (!o2)
|
||||
{ c = 1;
|
||||
break;
|
||||
}
|
||||
c = o1.opCmp(o2);
|
||||
if (c)
|
||||
break;
|
||||
}
|
||||
else
|
||||
{ c = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (c < 0)
|
||||
c = -1;
|
||||
else
|
||||
c = 1;
|
||||
return cast(int)c;
|
||||
}
|
||||
|
||||
size_t tsize()
|
||||
{
|
||||
return (Object[]).sizeof;
|
||||
}
|
||||
|
||||
uint flags()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
TypeInfo next()
|
||||
{
|
||||
return typeid(Object);
|
||||
}
|
||||
}
|
||||
106
tango/lib/compiler/llvmdc/typeinfo/ti_Acdouble.d
Normal file
106
tango/lib/compiler/llvmdc/typeinfo/ti_Acdouble.d
Normal file
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
|
||||
* Written by Walter Bright
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, in both source and binary form, subject to the following
|
||||
* restrictions:
|
||||
*
|
||||
* o The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* o Altered source versions must be plainly marked as such, and must not
|
||||
* be misrepresented as being the original software.
|
||||
* o This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
|
||||
module typeinfo.ti_Acdouble;
|
||||
|
||||
private import typeinfo.ti_cdouble;
|
||||
|
||||
// cdouble[]
|
||||
|
||||
class TypeInfo_Ar : TypeInfo
|
||||
{
|
||||
char[] toString() { return "cdouble[]"; }
|
||||
|
||||
hash_t getHash(void *p)
|
||||
{ cdouble[] s = *cast(cdouble[]*)p;
|
||||
size_t len = s.length;
|
||||
cdouble *str = s.ptr;
|
||||
hash_t hash = 0;
|
||||
|
||||
while (len)
|
||||
{
|
||||
hash *= 9;
|
||||
hash += (cast(uint *)str)[0];
|
||||
hash += (cast(uint *)str)[1];
|
||||
hash += (cast(uint *)str)[2];
|
||||
hash += (cast(uint *)str)[3];
|
||||
str++;
|
||||
len--;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
int equals(void *p1, void *p2)
|
||||
{
|
||||
cdouble[] s1 = *cast(cdouble[]*)p1;
|
||||
cdouble[] s2 = *cast(cdouble[]*)p2;
|
||||
size_t len = s1.length;
|
||||
|
||||
if (len != s2.length)
|
||||
return 0;
|
||||
for (size_t u = 0; u < len; u++)
|
||||
{
|
||||
int c = TypeInfo_r._equals(s1[u], s2[u]);
|
||||
if (c == 0)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int compare(void *p1, void *p2)
|
||||
{
|
||||
cdouble[] s1 = *cast(cdouble[]*)p1;
|
||||
cdouble[] s2 = *cast(cdouble[]*)p2;
|
||||
size_t len = s1.length;
|
||||
|
||||
if (s2.length < len)
|
||||
len = s2.length;
|
||||
for (size_t u = 0; u < len; u++)
|
||||
{
|
||||
int c = TypeInfo_r._compare(s1[u], s2[u]);
|
||||
if (c)
|
||||
return c;
|
||||
}
|
||||
if (s1.length < s2.length)
|
||||
return -1;
|
||||
else if (s1.length > s2.length)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t tsize()
|
||||
{
|
||||
return (cdouble[]).sizeof;
|
||||
}
|
||||
|
||||
uint flags()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
TypeInfo next()
|
||||
{
|
||||
return typeid(cdouble);
|
||||
}
|
||||
}
|
||||
104
tango/lib/compiler/llvmdc/typeinfo/ti_Acfloat.d
Normal file
104
tango/lib/compiler/llvmdc/typeinfo/ti_Acfloat.d
Normal file
@@ -0,0 +1,104 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
|
||||
* Written by Walter Bright
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, in both source and binary form, subject to the following
|
||||
* restrictions:
|
||||
*
|
||||
* o The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* o Altered source versions must be plainly marked as such, and must not
|
||||
* be misrepresented as being the original software.
|
||||
* o This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
|
||||
module typeinfo.ti_Acfloat;
|
||||
|
||||
private import typeinfo.ti_cfloat;
|
||||
|
||||
// cfloat[]
|
||||
|
||||
class TypeInfo_Aq : TypeInfo
|
||||
{
|
||||
char[] toString() { return "cfloat[]"; }
|
||||
|
||||
hash_t getHash(void *p)
|
||||
{ cfloat[] s = *cast(cfloat[]*)p;
|
||||
size_t len = s.length;
|
||||
cfloat *str = s.ptr;
|
||||
hash_t hash = 0;
|
||||
|
||||
while (len)
|
||||
{
|
||||
hash *= 9;
|
||||
hash += (cast(uint *)str)[0];
|
||||
hash += (cast(uint *)str)[1];
|
||||
str++;
|
||||
len--;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
int equals(void *p1, void *p2)
|
||||
{
|
||||
cfloat[] s1 = *cast(cfloat[]*)p1;
|
||||
cfloat[] s2 = *cast(cfloat[]*)p2;
|
||||
size_t len = s1.length;
|
||||
|
||||
if (len != s2.length)
|
||||
return 0;
|
||||
for (size_t u = 0; u < len; u++)
|
||||
{
|
||||
int c = TypeInfo_q._equals(s1[u], s2[u]);
|
||||
if (c == 0)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int compare(void *p1, void *p2)
|
||||
{
|
||||
cfloat[] s1 = *cast(cfloat[]*)p1;
|
||||
cfloat[] s2 = *cast(cfloat[]*)p2;
|
||||
size_t len = s1.length;
|
||||
|
||||
if (s2.length < len)
|
||||
len = s2.length;
|
||||
for (size_t u = 0; u < len; u++)
|
||||
{
|
||||
int c = TypeInfo_q._compare(s1[u], s2[u]);
|
||||
if (c)
|
||||
return c;
|
||||
}
|
||||
if (s1.length < s2.length)
|
||||
return -1;
|
||||
else if (s1.length > s2.length)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t tsize()
|
||||
{
|
||||
return (cfloat[]).sizeof;
|
||||
}
|
||||
|
||||
uint flags()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
TypeInfo next()
|
||||
{
|
||||
return typeid(cfloat);
|
||||
}
|
||||
}
|
||||
107
tango/lib/compiler/llvmdc/typeinfo/ti_Acreal.d
Normal file
107
tango/lib/compiler/llvmdc/typeinfo/ti_Acreal.d
Normal file
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
|
||||
* Written by Walter Bright
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, in both source and binary form, subject to the following
|
||||
* restrictions:
|
||||
*
|
||||
* o The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* o Altered source versions must be plainly marked as such, and must not
|
||||
* be misrepresented as being the original software.
|
||||
* o This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
|
||||
module typeinfo.ti_Acreal;
|
||||
|
||||
private import typeinfo.ti_creal;
|
||||
|
||||
// creal[]
|
||||
|
||||
class TypeInfo_Ac : TypeInfo
|
||||
{
|
||||
char[] toString() { return "creal[]"; }
|
||||
|
||||
hash_t getHash(void *p)
|
||||
{ creal[] s = *cast(creal[]*)p;
|
||||
size_t len = s.length;
|
||||
creal *str = s.ptr;
|
||||
hash_t hash = 0;
|
||||
|
||||
while (len)
|
||||
{
|
||||
hash *= 9;
|
||||
hash += (cast(uint *)str)[0];
|
||||
hash += (cast(uint *)str)[1];
|
||||
hash += (cast(uint *)str)[2];
|
||||
hash += (cast(uint *)str)[3];
|
||||
hash += (cast(uint *)str)[4];
|
||||
str++;
|
||||
len--;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
int equals(void *p1, void *p2)
|
||||
{
|
||||
creal[] s1 = *cast(creal[]*)p1;
|
||||
creal[] s2 = *cast(creal[]*)p2;
|
||||
size_t len = s1.length;
|
||||
|
||||
if (len != s2.length)
|
||||
return 0;
|
||||
for (size_t u = 0; u < len; u++)
|
||||
{
|
||||
int c = TypeInfo_c._equals(s1[u], s2[u]);
|
||||
if (c == 0)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int compare(void *p1, void *p2)
|
||||
{
|
||||
creal[] s1 = *cast(creal[]*)p1;
|
||||
creal[] s2 = *cast(creal[]*)p2;
|
||||
size_t len = s1.length;
|
||||
|
||||
if (s2.length < len)
|
||||
len = s2.length;
|
||||
for (size_t u = 0; u < len; u++)
|
||||
{
|
||||
int c = TypeInfo_c._compare(s1[u], s2[u]);
|
||||
if (c)
|
||||
return c;
|
||||
}
|
||||
if (s1.length < s2.length)
|
||||
return -1;
|
||||
else if (s1.length > s2.length)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t tsize()
|
||||
{
|
||||
return (creal[]).sizeof;
|
||||
}
|
||||
|
||||
uint flags()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
TypeInfo next()
|
||||
{
|
||||
return typeid(creal);
|
||||
}
|
||||
}
|
||||
116
tango/lib/compiler/llvmdc/typeinfo/ti_Adouble.d
Normal file
116
tango/lib/compiler/llvmdc/typeinfo/ti_Adouble.d
Normal file
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
|
||||
* Written by Walter Bright
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, in both source and binary form, subject to the following
|
||||
* restrictions:
|
||||
*
|
||||
* o The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* o Altered source versions must be plainly marked as such, and must not
|
||||
* be misrepresented as being the original software.
|
||||
* o This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
|
||||
module typeinfo.ti_Adouble;
|
||||
|
||||
private import typeinfo.ti_double;
|
||||
|
||||
// double[]
|
||||
|
||||
class TypeInfo_Ad : TypeInfo
|
||||
{
|
||||
char[] toString() { return "double[]"; }
|
||||
|
||||
hash_t getHash(void *p)
|
||||
{ double[] s = *cast(double[]*)p;
|
||||
size_t len = s.length;
|
||||
auto str = s.ptr;
|
||||
hash_t hash = 0;
|
||||
|
||||
while (len)
|
||||
{
|
||||
hash *= 9;
|
||||
hash += (cast(uint *)str)[0];
|
||||
hash += (cast(uint *)str)[1];
|
||||
str++;
|
||||
len--;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
int equals(void *p1, void *p2)
|
||||
{
|
||||
double[] s1 = *cast(double[]*)p1;
|
||||
double[] s2 = *cast(double[]*)p2;
|
||||
size_t len = s1.length;
|
||||
|
||||
if (len != s2.length)
|
||||
return 0;
|
||||
for (size_t u = 0; u < len; u++)
|
||||
{
|
||||
int c = TypeInfo_d._equals(s1[u], s2[u]);
|
||||
if (c == 0)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int compare(void *p1, void *p2)
|
||||
{
|
||||
double[] s1 = *cast(double[]*)p1;
|
||||
double[] s2 = *cast(double[]*)p2;
|
||||
size_t len = s1.length;
|
||||
|
||||
if (s2.length < len)
|
||||
len = s2.length;
|
||||
for (size_t u = 0; u < len; u++)
|
||||
{
|
||||
int c = TypeInfo_d._compare(s1[u], s2[u]);
|
||||
if (c)
|
||||
return c;
|
||||
}
|
||||
if (s1.length < s2.length)
|
||||
return -1;
|
||||
else if (s1.length > s2.length)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t tsize()
|
||||
{
|
||||
return (double[]).sizeof;
|
||||
}
|
||||
|
||||
uint flags()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
TypeInfo next()
|
||||
{
|
||||
return typeid(double);
|
||||
}
|
||||
}
|
||||
|
||||
// idouble[]
|
||||
|
||||
class TypeInfo_Ap : TypeInfo_Ad
|
||||
{
|
||||
char[] toString() { return "idouble[]"; }
|
||||
|
||||
TypeInfo next()
|
||||
{
|
||||
return typeid(idouble);
|
||||
}
|
||||
}
|
||||
115
tango/lib/compiler/llvmdc/typeinfo/ti_Afloat.d
Normal file
115
tango/lib/compiler/llvmdc/typeinfo/ti_Afloat.d
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (C) 2004-2005 by Digital Mars, www.digitalmars.com
|
||||
* Written by Walter Bright
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, in both source and binary form, subject to the following
|
||||
* restrictions:
|
||||
*
|
||||
* o The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* o Altered source versions must be plainly marked as such, and must not
|
||||
* be misrepresented as being the original software.
|
||||
* o This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
|
||||
module typeinfo.ti_Afloat;
|
||||
|
||||
private import typeinfo.ti_float;
|
||||
|
||||
// float[]
|
||||
|
||||
class TypeInfo_Af : TypeInfo
|
||||
{
|
||||
char[] toString() { return "float[]"; }
|
||||
|
||||
hash_t getHash(void *p)
|
||||
{ float[] s = *cast(float[]*)p;
|
||||
size_t len = s.length;
|
||||
auto str = s.ptr;
|
||||
hash_t hash = 0;
|
||||
|
||||
while (len)
|
||||
{
|
||||
hash *= 9;
|
||||
hash += *cast(uint *)str;
|
||||
str++;
|
||||
len--;
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
int equals(void *p1, void *p2)
|
||||
{
|
||||
float[] s1 = *cast(float[]*)p1;
|
||||
float[] s2 = *cast(float[]*)p2;
|
||||
size_t len = s1.length;
|
||||
|
||||
if (len != s2.length)
|
||||
return 0;
|
||||
for (size_t u = 0; u < len; u++)
|
||||
{
|
||||
int c = TypeInfo_f._equals(s1[u], s2[u]);
|
||||
if (c == 0)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int compare(void *p1, void *p2)
|
||||
{
|
||||
float[] s1 = *cast(float[]*)p1;
|
||||
float[] s2 = *cast(float[]*)p2;
|
||||
size_t len = s1.length;
|
||||
|
||||
if (s2.length < len)
|
||||
len = s2.length;
|
||||
for (size_t u = 0; u < len; u++)
|
||||
{
|
||||
int c = TypeInfo_f._compare(s1[u], s2[u]);
|
||||
if (c)
|
||||
return c;
|
||||
}
|
||||
if (s1.length < s2.length)
|
||||
return -1;
|
||||
else if (s1.length > s2.length)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t tsize()
|
||||
{
|
||||
return (float[]).sizeof;
|
||||
}
|
||||
|
||||
uint flags()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
TypeInfo next()
|
||||
{
|
||||
return typeid(float);
|
||||
}
|
||||
}
|
||||
|
||||
// ifloat[]
|
||||
|
||||
class TypeInfo_Ao : TypeInfo_Af
|
||||
{
|
||||
char[] toString() { return "ifloat[]"; }
|
||||
|
||||
TypeInfo next()
|
||||
{
|
||||
return typeid(ifloat);
|
||||
}
|
||||
}
|
||||
206
tango/lib/compiler/llvmdc/typeinfo/ti_Ag.d
Normal file
206
tango/lib/compiler/llvmdc/typeinfo/ti_Ag.d
Normal file
@@ -0,0 +1,206 @@
|
||||
|
||||
module typeinfo.ti_Ag;
|
||||
|
||||
private import tango.stdc.string;
|
||||
private import util.string;
|
||||
|
||||
// byte[]
|
||||
|
||||
class TypeInfo_Ag : TypeInfo
|
||||
{
|
||||
char[] toString() { return "byte[]"; }
|
||||
|
||||
hash_t getHash(void *p)
|
||||
{ byte[] s = *cast(byte[]*)p;
|
||||
size_t len = s.length;
|
||||
byte *str = s.ptr;
|
||||
hash_t hash = 0;
|
||||
|
||||
while (1)
|
||||
{
|
||||
switch (len)
|
||||
{
|
||||
case 0:
|
||||
return hash;
|
||||
|
||||
case 1:
|
||||
hash *= 9;
|
||||
hash += *cast(ubyte *)str;
|
||||
return hash;
|
||||
|
||||
case 2:
|
||||
hash *= 9;
|
||||
hash += *cast(ushort *)str;
|
||||
return hash;
|
||||
|
||||
case 3:
|
||||
hash *= 9;
|
||||
hash += (*cast(ushort *)str << 8) +
|
||||
(cast(ubyte *)str)[2];
|
||||
return hash;
|
||||
|
||||
default:
|
||||
hash *= 9;
|
||||
hash += *cast(uint *)str;
|
||||
str += 4;
|
||||
len -= 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
int equals(void *p1, void *p2)
|
||||
{
|
||||
byte[] s1 = *cast(byte[]*)p1;
|
||||
byte[] s2 = *cast(byte[]*)p2;
|
||||
|
||||
return s1.length == s2.length &&
|
||||
memcmp(cast(byte *)s1, cast(byte *)s2, s1.length) == 0;
|
||||
}
|
||||
|
||||
int compare(void *p1, void *p2)
|
||||
{
|
||||
byte[] s1 = *cast(byte[]*)p1;
|
||||
byte[] s2 = *cast(byte[]*)p2;
|
||||
size_t len = s1.length;
|
||||
|
||||
if (s2.length < len)
|
||||
len = s2.length;
|
||||
for (size_t u = 0; u < len; u++)
|
||||
{
|
||||
int result = s1[u] - s2[u];
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
if (s1.length < s2.length)
|
||||
return -1;
|
||||
else if (s1.length > s2.length)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t tsize()
|
||||
{
|
||||
return (byte[]).sizeof;
|
||||
}
|
||||
|
||||
uint flags()
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
TypeInfo next()
|
||||
{
|
||||
return typeid(byte);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// ubyte[]
|
||||
|
||||
class TypeInfo_Ah : TypeInfo_Ag
|
||||
{
|
||||
char[] toString() { return "ubyte[]"; }
|
||||
|
||||
int compare(void *p1, void *p2)
|
||||
{
|
||||
char[] s1 = *cast(char[]*)p1;
|
||||
char[] s2 = *cast(char[]*)p2;
|
||||
|
||||
return stringCompare(s1, s2);
|
||||
}
|
||||
|
||||
TypeInfo next()
|
||||
{
|
||||
return typeid(ubyte);
|
||||
}
|
||||
}
|
||||
|
||||
// void[]
|
||||
|
||||
class TypeInfo_Av : TypeInfo_Ah
|
||||
{
|
||||
char[] toString() { return "void[]"; }
|
||||
|
||||
TypeInfo next()
|
||||
{
|
||||
return typeid(void);
|
||||
}
|
||||
}
|
||||
|
||||
// bool[]
|
||||
|
||||
class TypeInfo_Ab : TypeInfo_Ah
|
||||
{
|
||||
char[] toString() { return "bool[]"; }
|
||||
|
||||
TypeInfo next()
|
||||
{
|
||||
return typeid(bool);
|
||||
}
|
||||
}
|
||||
|
||||
// char[]
|
||||
|
||||
class TypeInfo_Aa : TypeInfo_Ag
|
||||
{
|
||||
char[] toString() { return "char[]"; }
|
||||
|
||||
hash_t getHash(void *p)
|
||||
{ char[] s = *cast(char[]*)p;
|
||||
hash_t hash = 0;
|
||||
|
||||
version (all)
|
||||
{
|
||||
foreach (char c; s)
|
||||
hash = hash * 11 + c;
|
||||
}
|
||||
else
|
||||
{
|
||||
size_t len = s.length;
|
||||
char *str = s;
|
||||
|
||||
while (1)
|
||||
{
|
||||
switch (len)
|
||||
{
|
||||
case 0:
|
||||
return hash;
|
||||
|
||||
case 1:
|
||||
hash *= 9;
|
||||
hash += *cast(ubyte *)str;
|
||||
return hash;
|
||||
|
||||
case 2:
|
||||
hash *= 9;
|
||||
hash += *cast(ushort *)str;
|
||||
return hash;
|
||||
|
||||
case 3:
|
||||
hash *= 9;
|
||||
hash += (*cast(ushort *)str << 8) +
|
||||
(cast(ubyte *)str)[2];
|
||||
return hash;
|
||||
|
||||
default:
|
||||
hash *= 9;
|
||||
hash += *cast(uint *)str;
|
||||
str += 4;
|
||||
len -= 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
TypeInfo next()
|
||||
{
|
||||
return typeid(char);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user