[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:
Tomas Lindquist Olsen
2008-01-11 17:57:40 +01:00
parent bc08c6fcb1
commit b15b3484c8
524 changed files with 270705 additions and 175 deletions

View File

@@ -1,4 +1,4 @@
[Environment]
DFLAGS=-I%@P%/../lphobos -E%@P%/../lib -L-L=%@P%/../lib
DFLAGS=-I%@P%/../tango -E%@P%/../lib -L-L=%@P%/../lib

4
bin/llvmdc.phobos Normal file
View File

@@ -0,0 +1,4 @@
[Environment]
DFLAGS=-I%@P%/../lphobos -E%@P%/../lib -L-L=%@P%/../lib

4
bin/llvmdc.tango Normal file
View File

@@ -0,0 +1,4 @@
[Environment]
DFLAGS=-I%@P%/../tango -E%@P%/../lib -L-L=%@P%/../lib

View File

@@ -288,7 +288,7 @@ int runLINK()
argv.push((void *)"-lm");
std::string corelibpath = global.params.runtimeImppath;
corelibpath.append("/llvmdcore.bc");
corelibpath.append("/libtango-base-llvmdc.a");
argv.append(global.params.objfiles);
argv.push((void *)corelibpath.c_str());

View File

@@ -77,7 +77,7 @@ Global::Global()
memset(&params, 0, sizeof(Param));
}
char *Loc::toChars()
char *Loc::toChars() const
{
OutBuffer buf;
char *p;
@@ -300,6 +300,8 @@ int main(int argc, char *argv[])
// Predefine version identifiers
#if IN_LLVM
VersionCondition::addPredefinedGlobalIdent("LLVM");
VersionCondition::addPredefinedGlobalIdent("LLVMDC");
VersionCondition::addPredefinedGlobalIdent("Posix");
#endif
#if _WIN32
VersionCondition::addPredefinedGlobalIdent("Windows");

View File

@@ -242,7 +242,7 @@ struct Loc
Loc(Module *mod, unsigned linnum);
char *toChars();
char *toChars() const;
};
#ifndef GCC_SAFE_DMD

View File

@@ -597,6 +597,34 @@ void DtoCatArrays(llvm::Value* arr, Expression* exp1, Expression* exp2)
DtoMemCpy(mem,src2,len2);
}
//////////////////////////////////////////////////////////////////////////////////////////
void DtoCatArrayElement(llvm::Value* arr, Expression* exp1, Expression* exp2)
{
Type* t1 = DtoDType(exp1->type);
Type* t2 = DtoDType(exp2->type);
assert(t1->ty == Tarray);
assert(t2 == DtoDType(t1->next));
DValue* e1 = exp1->toElem(gIR);
DValue* e2 = exp2->toElem(gIR);
llvm::Value *len1, *src1, *res;
llvm::Value* a = e1->getRVal();
len1 = gIR->ir->CreateLoad(DtoGEPi(a,0,0,"tmp"),"tmp");
res = gIR->ir->CreateAdd(len1,DtoConstSize_t(1),"tmp");
llvm::Value* mem = DtoNewDynArray(arr, res, DtoDType(t1->next), false);
src1 = gIR->ir->CreateLoad(DtoGEPi(a,0,1,"tmp"),"tmp");
DtoMemCpy(mem,src1,len1);
mem = gIR->ir->CreateGEP(mem,len1,"tmp");
DVarValue* memval = new DVarValue(e2->getType(), mem, true);
DtoAssign(memval, e2);
}
//////////////////////////////////////////////////////////////////////////////////////////
// helper for eq and cmp
static llvm::Value* DtoArrayEqCmp_impl(const char* func, DValue* l, DValue* r, bool useti)

View File

@@ -25,6 +25,7 @@ llvm::Value* DtoResizeDynArray(llvm::Value* arr, llvm::Value* sz);
void DtoCatAssignElement(llvm::Value* arr, Expression* exp);
void DtoCatAssignArray(llvm::Value* arr, Expression* exp);
void DtoCatArrays(llvm::Value* arr, Expression* e1, Expression* e2);
void DtoCatArrayElement(llvm::Value* arr, Expression* exp1, Expression* exp2);
void DtoStaticArrayCopy(llvm::Value* dst, llvm::Value* src);

View File

@@ -11,6 +11,7 @@
#include "gen/arrays.h"
#include "gen/logger.h"
#include "gen/classes.h"
#include "gen/structs.h"
#include "gen/functions.h"
#include "gen/runtime.h"
#include "gen/dvalue.h"
@@ -32,13 +33,19 @@ static void LLVM_AddBaseClassData(BaseClasses* bcs)
Logger::println("Adding base class members of %s", bc->base->toChars());
LOG_SCOPE;
for (int k=0; k < bc->base->members->dim; k++) {
Array* arr = &bc->base->fields;
for (int k=0; k < arr->dim; k++) {
VarDeclaration* v = (VarDeclaration*)(arr->data[k]);
v->toObjFile();
}
/*for (int k=0; k < bc->base->members->dim; k++) {
Dsymbol* dsym = (Dsymbol*)(bc->base->members->data[k]);
if (dsym->isVarDeclaration())
{
dsym->toObjFile();
}
}
}*/
}
}
@@ -65,7 +72,7 @@ void DtoResolveClass(ClassDeclaration* cd)
}
}
Logger::println("DtoResolveClass(%s)", cd->toPrettyChars());
Logger::println("DtoResolveClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars());
LOG_SCOPE;
assert(cd->type->ty == Tclass);
@@ -113,10 +120,85 @@ void DtoResolveClass(ClassDeclaration* cd)
dsym->toObjFile();
}
// resolve class data fields (possibly unions)
Logger::println("doing class fields");
if (irstruct->offsets.empty())
{
Logger::println("has no fields");
}
else
{
Logger::println("has fields");
unsigned prevsize = (unsigned)-1;
unsigned lastoffset = (unsigned)-1;
const llvm::Type* fieldtype = NULL;
VarDeclaration* fieldinit = NULL;
size_t fieldpad = 0;
int idx = 0;
for (IRStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i) {
// first iteration
if (lastoffset == (unsigned)-1) {
lastoffset = i->first;
fieldtype = i->second.type;
fieldinit = i->second.var;
prevsize = gTargetData->getTypeSize(fieldtype);
i->second.var->llvmFieldIndex = idx;
}
// colliding offset?
else if (lastoffset == i->first) {
size_t s = gTargetData->getTypeSize(i->second.type);
if (s > prevsize) {
fieldpad += s - prevsize;
prevsize = s;
}
cd->llvmHasUnions = true;
i->second.var->llvmFieldIndex = idx;
}
// intersecting offset?
else if (i->first < (lastoffset + prevsize)) {
size_t s = gTargetData->getTypeSize(i->second.type);
assert((i->first + s) <= (lastoffset + prevsize)); // this holds because all types are aligned to their size
cd->llvmHasUnions = true;
i->second.var->llvmFieldIndex = idx;
i->second.var->llvmFieldIndexOffset = (i->first - lastoffset) / s;
}
// fresh offset
else {
// commit the field
fieldtypes.push_back(fieldtype);
irstruct->defaultFields.push_back(fieldinit);
if (fieldpad) {
fieldtypes.push_back(llvm::ArrayType::get(llvm::Type::Int8Ty, fieldpad));
irstruct->defaultFields.push_back(NULL);
idx++;
}
idx++;
// start new
lastoffset = i->first;
fieldtype = i->second.type;
fieldinit = i->second.var;
prevsize = gTargetData->getTypeSize(fieldtype);
i->second.var->llvmFieldIndex = idx;
fieldpad = 0;
}
}
fieldtypes.push_back(fieldtype);
irstruct->defaultFields.push_back(fieldinit);
if (fieldpad) {
fieldtypes.push_back(llvm::ArrayType::get(llvm::Type::Int8Ty, fieldpad));
irstruct->defaultFields.push_back(NULL);
}
}
/*
// add field types
for (IRStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i) {
fieldtypes.push_back(i->second.type);
}
*/
const llvm::StructType* structtype = llvm::StructType::get(fieldtypes);
// refine abstract types for stuff like: class C {C next;}
@@ -214,7 +296,7 @@ void DtoDeclareClass(ClassDeclaration* cd)
if (cd->llvmDeclared) return;
cd->llvmDeclared = true;
Logger::println("DtoDeclareClass(%s)", cd->toPrettyChars());
Logger::println("DtoDeclareClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars());
LOG_SCOPE;
assert(cd->type->ty == Tclass);
@@ -262,7 +344,7 @@ void DtoDeclareClass(ClassDeclaration* cd)
const llvm::StructType* infoTy = llvm::StructType::get(types);
// interface info array
if (needs_definition && cd->vtblInterfaces->dim > 0) {
if (cd->vtblInterfaces->dim > 0) {
// symbol name
std::string nam = "_D";
nam.append(cd->mangle());
@@ -271,7 +353,7 @@ void DtoDeclareClass(ClassDeclaration* cd)
const llvm::ArrayType* arrTy = llvm::ArrayType::get(infoTy, cd->vtblInterfaces->dim);
// declare global
irstruct->interfaceInfosTy = arrTy;
irstruct->interfaceInfos = new llvm::GlobalVariable(arrTy, true, llvm::GlobalValue::InternalLinkage, 0, nam, gIR->module);
irstruct->interfaceInfos = new llvm::GlobalVariable(arrTy, true, _linkage, NULL, nam, gIR->module);
}
// interface vtables
@@ -329,7 +411,7 @@ void DtoConstInitClass(ClassDeclaration* cd)
if (cd->isInterfaceDeclaration())
return; // nothing to do
Logger::println("DtoConstInitClass(%s)", cd->toPrettyChars());
Logger::println("DtoConstInitClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars());
LOG_SCOPE;
IRStruct* irstruct = cd->llvmIRStruct;
@@ -355,19 +437,24 @@ void DtoConstInitClass(ClassDeclaration* cd)
// then comes monitor
fieldinits.push_back(llvm::ConstantPointerNull::get(llvm::PointerType::get(llvm::Type::Int8Ty)));
size_t dataoffset = 2;
// next comes interface vtables
for (IRStruct::InterfaceIter i=irstruct->interfaces.begin(); i!=irstruct->interfaces.end(); ++i)
{
IRInterface* iri = i->second;
assert(iri->vtbl);
fieldinits.push_back(iri->vtbl);
++dataoffset;
}
/*
// rest
for (IRStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i) {
Logger::println("adding fieldinit for: %s", i->second.var->toChars());
fieldinits.push_back(i->second.init);
}
*/
// get the struct (class) type
assert(cd->type->ty == Tclass);
@@ -375,6 +462,22 @@ void DtoConstInitClass(ClassDeclaration* cd)
const llvm::StructType* structtype = isaStruct(ts->llvmType->get());
const llvm::StructType* vtbltype = isaStruct(ts->llvmVtblType->get());
// go through the field inits and build the default initializer
size_t nfi = irstruct->defaultFields.size();
for (size_t i=0; i<nfi; ++i) {
llvm::Constant* c;
if (irstruct->defaultFields[i] != NULL) {
c = irstruct->defaultFields[i]->llvmConstInit;
assert(c);
}
else {
const llvm::ArrayType* arrty = isaArray(structtype->getElementType(i+dataoffset));
std::vector<llvm::Constant*> vals(arrty->getNumElements(), llvm::ConstantInt::get(llvm::Type::Int8Ty, 0, false));
c = llvm::ConstantArray::get(arrty, vals);
}
fieldinits.push_back(c);
}
// generate initializer
#if 0
Logger::cout() << cd->toPrettyChars() << " | " << *structtype << '\n';
@@ -509,7 +612,7 @@ void DtoDefineClass(ClassDeclaration* cd)
if (cd->llvmDefined) return;
cd->llvmDefined = true;
Logger::println("DtoDefineClass(%s)", cd->toPrettyChars());
Logger::println("DtoDefineClass(%s): %s", cd->toPrettyChars(), cd->loc.toChars());
LOG_SCOPE;
// get the struct (class) type
@@ -702,6 +805,119 @@ DValue* DtoCastInterfaceToObject(DValue* val, Type* to)
//////////////////////////////////////////////////////////////////////////////////////////
static unsigned LLVM_ClassOffsetToIndex(ClassDeclaration* cd, unsigned os, unsigned& idx)
{
// start at the bottom of the inheritance chain
if (cd->baseClass != 0) {
unsigned o = LLVM_ClassOffsetToIndex(cd->baseClass, os, idx);
if (o != (unsigned)-1)
return o;
}
// check this class
unsigned i;
for (i=0; i<cd->fields.dim; ++i) {
VarDeclaration* vd = (VarDeclaration*)cd->fields.data[i];
if (os == vd->offset)
return i+idx;
}
idx += i;
return (unsigned)-1;
}
//////////////////////////////////////////////////////////////////////////////////////////
void ClassDeclaration::offsetToIndex(Type* t, unsigned os, std::vector<unsigned>& result)
{
unsigned idx = 0;
unsigned r = LLVM_ClassOffsetToIndex(this, os, idx);
assert(r != (unsigned)-1 && "Offset not found in any aggregate field");
// vtable is 0, monitor is 1
r += 2;
// interface offset further
r += vtblInterfaces->dim;
// the final index was not pushed
result.push_back(r);
}
//////////////////////////////////////////////////////////////////////////////////////////
llvm::Value* DtoIndexClass(llvm::Value* ptr, ClassDeclaration* cd, Type* t, unsigned os, std::vector<unsigned>& idxs)
{
Logger::println("checking for offset %u type %s:", os, t->toChars());
LOG_SCOPE;
if (idxs.empty())
idxs.push_back(0);
const llvm::Type* llt = llvm::PointerType::get(DtoType(t));
const llvm::Type* st = DtoType(cd->type);
if (ptr->getType() != st) {
assert(cd->llvmHasUnions);
ptr = gIR->ir->CreateBitCast(ptr, st, "tmp");
}
unsigned dataoffset = 2 + cd->vtblInterfaces->dim;
IRStruct* irstruct = cd->llvmIRStruct;
for (IRStruct::OffsetMap::iterator i=irstruct->offsets.begin(); i!=irstruct->offsets.end(); ++i) {
//for (unsigned i=0; i<cd->fields.dim; ++i) {
//VarDeclaration* vd = (VarDeclaration*)cd->fields.data[i];
VarDeclaration* vd = i->second.var;
assert(vd);
Type* vdtype = DtoDType(vd->type);
Logger::println("found %u type %s", vd->offset, vdtype->toChars());
assert(vd->llvmFieldIndex >= 0);
if (os == vd->offset && vdtype == t) {
idxs.push_back(vd->llvmFieldIndex + dataoffset);
Logger::cout() << "indexing: " << *ptr << '\n';
ptr = DtoGEP(ptr, idxs, "tmp");
if (ptr->getType() != llt)
ptr = gIR->ir->CreateBitCast(ptr, llt, "tmp");
Logger::cout() << "indexing: " << *ptr << '\n';
if (vd->llvmFieldIndexOffset)
ptr = new llvm::GetElementPtrInst(ptr, DtoConstUint(vd->llvmFieldIndexOffset), "tmp", gIR->scopebb());
Logger::cout() << "indexing: " << *ptr << '\n';
return ptr;
}
else if (vdtype->ty == Tstruct && (vd->offset + vdtype->size()) > os) {
TypeStruct* ts = (TypeStruct*)vdtype;
StructDeclaration* ssd = ts->sym;
idxs.push_back(vd->llvmFieldIndex + dataoffset);
if (vd->llvmFieldIndexOffset) {
Logger::println("has union field offset");
ptr = DtoGEP(ptr, idxs, "tmp");
if (ptr->getType() != llt)
ptr = gIR->ir->CreateBitCast(ptr, llt, "tmp");
ptr = new llvm::GetElementPtrInst(ptr, DtoConstUint(vd->llvmFieldIndexOffset), "tmp", gIR->scopebb());
std::vector<unsigned> tmp;
return DtoIndexStruct(ptr, ssd, t, os-vd->offset, tmp);
}
else {
const llvm::Type* sty = llvm::PointerType::get(DtoType(vd->type));
if (ptr->getType() != sty) {
ptr = gIR->ir->CreateBitCast(ptr, sty, "tmp");
std::vector<unsigned> tmp;
return DtoIndexStruct(ptr, ssd, t, os-vd->offset, tmp);
}
else {
return DtoIndexStruct(ptr, ssd, t, os-vd->offset, idxs);
}
}
}
}
assert(0);
size_t llt_sz = gTargetData->getTypeSize(llt->getContainedType(0));
assert(os % llt_sz == 0);
ptr = gIR->ir->CreateBitCast(ptr, llt, "tmp");
return new llvm::GetElementPtrInst(ptr, DtoConstUint(os / llt_sz), "tmp", gIR->scopebb());
}
//////////////////////////////////////////////////////////////////////////////////////////
void DtoDeclareClassInfo(ClassDeclaration* cd)
{
if (cd->llvmClassDeclared) return;

View File

@@ -31,4 +31,6 @@ DValue* DtoCastClass(DValue* val, Type* to);
DValue* DtoDynamicCastObject(DValue* val, Type* to);
DValue* DtoCastInterfaceToObject(DValue* val, Type* to);
llvm::Value* DtoIndexClass(llvm::Value* ptr, ClassDeclaration* cd, Type* t, unsigned os, std::vector<unsigned>& idxs);
#endif

View File

@@ -189,15 +189,17 @@ const llvm::FunctionType* DtoFunctionType(FuncDeclaration* fdecl)
const llvm::Type* thisty = NULL;
if (fdecl->needThis()) {
if (AggregateDeclaration* ad = fdecl->isMember()) {
Logger::print("isMember = this is: %s\n", ad->type->toChars());
if (AggregateDeclaration* ad = fdecl->isMember2()) {
Logger::println("isMember = this is: %s", ad->type->toChars());
thisty = DtoType(ad->type);
//Logger::cout() << "this llvm type: " << *thisty << '\n';
if (isaStruct(thisty) || (!gIR->structs.empty() && thisty == gIR->topstruct()->recty.get()))
thisty = llvm::PointerType::get(thisty);
}
else
assert(0);
else {
Logger::println("chars: %s type: %s kind: %s", fdecl->toChars(), fdecl->type->toChars(), fdecl->kind());
assert(0);
}
}
else if (fdecl->isNested()) {
thisty = llvm::PointerType::get(llvm::Type::Int8Ty);
@@ -245,7 +247,7 @@ void DtoResolveFunction(FuncDeclaration* fdecl)
if (fdecl->llvmResolved) return;
fdecl->llvmResolved = true;
Logger::println("DtoResolveFunction(%s)", fdecl->toPrettyChars());
Logger::println("DtoResolveFunction(%s): %s", fdecl->toPrettyChars(), fdecl->loc.toChars());
LOG_SCOPE;
if (fdecl->llvmRunTimeHack) {
@@ -289,7 +291,7 @@ void DtoDeclareFunction(FuncDeclaration* fdecl)
if (fdecl->llvmDeclared) return;
fdecl->llvmDeclared = true;
Logger::println("DtoDeclareFunction(%s)", fdecl->toPrettyChars());
Logger::println("DtoDeclareFunction(%s): %s", fdecl->toPrettyChars(), fdecl->loc.toChars());
LOG_SCOPE;
assert(!fdecl->isAbstract());
@@ -352,6 +354,17 @@ void DtoDeclareFunction(FuncDeclaration* fdecl)
if (!vafunc && fdecl->llvmInternal != LLVMintrinsic && fdecl->parent && DtoIsTemplateInstance(fdecl->parent))
func->setLinkage(llvm::GlobalValue::WeakLinkage);
// extern(C) functions are always external
if (f->linkage == LINKc)
func->setLinkage(llvm::GlobalValue::ExternalLinkage);
// intrinsics are always external C
if (fdecl->llvmInternal == LLVMintrinsic)
{
func->setLinkage(llvm::GlobalValue::ExternalLinkage);
func->setCallingConv(llvm::CallingConv::C);
}
fdecl->llvmValue = func;
assert(llvm::isa<llvm::FunctionType>(f->llvmType->get()));
@@ -427,7 +440,7 @@ void DtoDefineFunc(FuncDeclaration* fd)
assert(fd->llvmDeclared);
Logger::println("DtoDefineFunc(%s)", fd->toPrettyChars());
Logger::println("DtoDefineFunc(%s): %s", fd->toPrettyChars(), fd->loc.toChars());
LOG_SCOPE;
// debug info
@@ -495,7 +508,7 @@ void DtoDefineFunc(FuncDeclaration* fd)
vd->llvmValue = v;
}
else {
Logger::attention("some unknown argument: %s", arg ? arg->toChars() : 0);
Logger::attention(fd->loc, "some unknown argument: %s", arg ? arg->toChars() : 0);
}
}

View File

@@ -6,6 +6,8 @@
#include <fstream>
#include <string>
#include "mars.h"
#include "gen/logger.h"
namespace Logger
@@ -67,9 +69,9 @@ namespace Logger
{
return _enabled;
}
void attention(const char* fmt,...)
void attention(const Loc& loc, const char* fmt,...)
{
printf("***ATTENTION*** ");
printf("***ATTENTION***: %s: ", loc.toChars());
va_list va;
va_start(va,fmt);
vprintf(fmt,va);

View File

@@ -3,6 +3,8 @@
#include <iostream>
struct Loc;
namespace Logger
{
void indent();
@@ -14,7 +16,7 @@ namespace Logger
void disable();
bool enabled();
void attention(const char* fmt, ...);
void attention(const Loc& loc, const char* fmt, ...);
struct LoggerScope
{

View File

@@ -7,20 +7,31 @@
#include "root.h"
#include "mars.h"
#include "lexer.h"
#include "dsymbol.h"
#include "mtype.h"
#include "aggregate.h"
#include "gen/runtime.h"
#include "gen/logger.h"
#include "gen/tollvm.h"
static llvm::Module* M = NULL;
static bool runtime_failed = false;
static void LLVM_D_BuildRuntimeModule();
//////////////////////////////////////////////////////////////////////////////////////////////////
bool LLVM_D_InitRuntime()
{
Logger::println("*** Loading D runtime ***");
Logger::println("*** Initializing D runtime declarations ***");
LOG_SCOPE;
LLVM_D_BuildRuntimeModule();
return true;
/*
if (!global.params.runtimeImppath) {
error("You must set the runtime import path with -E");
fatal();
@@ -47,13 +58,15 @@ bool LLVM_D_InitRuntime()
delete buffer;
return retval;
*/
}
void LLVM_D_FreeRuntime()
{
if (M) {
Logger::println("*** Freeing D runtime ***");
Logger::println("*** Freeing D runtime declarations ***");
delete M;
M = NULL;
}
}
@@ -90,9 +103,6 @@ llvm::Function* LLVM_D_GetRuntimeFunction(llvm::Module* target, const char* name
llvm::GlobalVariable* LLVM_D_GetRuntimeGlobal(llvm::Module* target, const char* name)
{
// TODO maybe check the target module first, to allow overriding the runtime on a pre module basis?
// could be done and seems like it could be neat too :)
llvm::GlobalVariable* gv = target->getNamedGlobal(name);
if (gv) {
return gv;
@@ -118,3 +128,508 @@ llvm::GlobalVariable* LLVM_D_GetRuntimeGlobal(llvm::Module* target, const char*
const llvm::PointerType* t = g->getType();
return new llvm::GlobalVariable(t->getElementType(),g->isConstant(),g->getLinkage(),NULL,g->getName(),target);
}
//////////////////////////////////////////////////////////////////////////////////////////////////
static const llvm::Type* rt_ptr(const llvm::Type* t)
{
return llvm::PointerType::get(t);
}
static const llvm::Type* rt_array(const llvm::Type* elemty)
{
std::vector<const llvm::Type*> t;
t.push_back(DtoSize_t());
t.push_back(rt_ptr(elemty));
return rt_ptr(llvm::StructType::get(t));
}
static const llvm::Type* rt_dg1()
{
std::vector<const llvm::Type*> types;
types.push_back(rt_ptr(llvm::Type::Int8Ty));
types.push_back(rt_ptr(llvm::Type::Int8Ty));
const llvm::FunctionType* fty = llvm::FunctionType::get(llvm::Type::Int32Ty, types, false);
std::vector<const llvm::Type*> t;
t.push_back(rt_ptr(llvm::Type::Int8Ty));
t.push_back(rt_ptr(fty));
return rt_ptr(llvm::StructType::get(t));
}
static const llvm::Type* rt_dg2()
{
std::vector<const llvm::Type*> types;
types.push_back(rt_ptr(llvm::Type::Int8Ty));
types.push_back(rt_ptr(llvm::Type::Int8Ty));
types.push_back(rt_ptr(llvm::Type::Int8Ty));
const llvm::FunctionType* fty = llvm::FunctionType::get(llvm::Type::Int32Ty, types, false);
std::vector<const llvm::Type*> t;
t.push_back(rt_ptr(llvm::Type::Int8Ty));
t.push_back(rt_ptr(fty));
return rt_ptr(llvm::StructType::get(t));
}
static void LLVM_D_BuildRuntimeModule()
{
M = new llvm::Module("llvmdc internal runtime");
const llvm::Type* voidTy = llvm::Type::VoidTy;
const llvm::Type* boolTy = llvm::Type::Int1Ty;
const llvm::Type* byteTy = llvm::Type::Int8Ty;
const llvm::Type* shortTy = llvm::Type::Int16Ty;
const llvm::Type* intTy = llvm::Type::Int32Ty;
const llvm::Type* longTy = llvm::Type::Int64Ty;
const llvm::Type* floatTy = llvm::Type::FloatTy;
const llvm::Type* doubleTy = llvm::Type::DoubleTy;
const llvm::Type* sizeTy = DtoSize_t();
const llvm::Type* voidPtrTy = rt_ptr(byteTy);
const llvm::Type* stringTy = rt_array(byteTy);
const llvm::Type* wstringTy = rt_array(shortTy);
const llvm::Type* dstringTy = rt_array(intTy);
const llvm::Type* objectTy = rt_ptr(ClassDeclaration::object->type->llvmType->get());
const llvm::Type* classInfoTy = rt_ptr(ClassDeclaration::classinfo->type->llvmType->get());
const llvm::Type* typeInfoTy = rt_ptr(Type::typeinfo->type->llvmType->get());
const llvm::Type* aaTy = rt_ptr(llvm::OpaqueType::get());
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
// assert
// void _d_assert(bool cond, uint line, char[] msg)
{
std::string fname("_d_assert");
std::vector<const llvm::Type*> types;
types.push_back(boolTy);
types.push_back(intTy);
types.push_back(stringTy);
const llvm::FunctionType* fty = llvm::FunctionType::get(voidTy, types, false);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
}
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
// realloc
// void* _d_realloc(void* ptr, size_t n)
{
std::string fname("_d_realloc");
std::vector<const llvm::Type*> types;
types.push_back(voidPtrTy);
types.push_back(sizeTy);
const llvm::FunctionType* fty = llvm::FunctionType::get(voidPtrTy, types, false);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
}
// free
// void _d_free(void* ptr)
{
std::string fname("_d_free");
std::vector<const llvm::Type*> types;
types.push_back(voidPtrTy);
const llvm::FunctionType* fty = llvm::FunctionType::get(voidTy, types, false);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
}
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
#define ARRAY_INIT(TY,suffix) \
{ \
std::string fname("_d_array_init_"); \
fname.append(suffix); \
std::vector<const llvm::Type*> types; \
types.push_back(rt_ptr(TY)); \
types.push_back(sizeTy); \
types.push_back(TY); \
const llvm::FunctionType* fty = llvm::FunctionType::get(voidTy, types, false); \
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M); \
}
ARRAY_INIT(boolTy,"i1")
ARRAY_INIT(byteTy,"i8")
ARRAY_INIT(shortTy,"i16")
ARRAY_INIT(intTy,"i32")
ARRAY_INIT(longTy,"i64")
ARRAY_INIT(floatTy,"float")
ARRAY_INIT(doubleTy,"double")
ARRAY_INIT(voidPtrTy,"pointer")
#undef ARRAY_INIT
// array init mem
// void _d_array_init_mem(void* a, size_t na, void* v, size_t nv)
{
std::string fname("_d_array_init_mem");
std::vector<const llvm::Type*> types;
types.push_back(voidPtrTy);
types.push_back(sizeTy);
types.push_back(voidPtrTy);
types.push_back(sizeTy);
const llvm::FunctionType* fty = llvm::FunctionType::get(voidTy, types, false);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
}
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
#define STR_APPLY1(TY,a,b) \
{ \
std::string fname(a); \
std::string fname2(b); \
std::vector<const llvm::Type*> types; \
types.push_back(TY); \
types.push_back(rt_dg1()); \
const llvm::FunctionType* fty = llvm::FunctionType::get(intTy, types, false); \
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M); \
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname2, M); \
}
STR_APPLY1(stringTy, "_aApplycw1", "_aApplycd1")
STR_APPLY1(wstringTy, "_aApplywc1", "_aApplywd1")
STR_APPLY1(dstringTy, "_aApplydc1", "_aApplydw1")
#undef STR_APPLY
#define STR_APPLY2(TY,a,b) \
{ \
std::string fname(a); \
std::string fname2(b); \
std::vector<const llvm::Type*> types; \
types.push_back(TY); \
types.push_back(rt_dg2()); \
const llvm::FunctionType* fty = llvm::FunctionType::get(intTy, types, false); \
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M); \
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname2, M); \
}
STR_APPLY2(stringTy, "_aApplycw2", "_aApplycd2")
STR_APPLY2(wstringTy, "_aApplywc2", "_aApplywd2")
STR_APPLY2(dstringTy, "_aApplydc2", "_aApplydw2")
#undef STR_APPLY2
#define STR_APPLY_R1(TY,a,b) \
{ \
std::string fname(a); \
std::string fname2(b); \
std::vector<const llvm::Type*> types; \
types.push_back(TY); \
types.push_back(rt_dg1()); \
const llvm::FunctionType* fty = llvm::FunctionType::get(intTy, types, false); \
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M); \
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname2, M); \
}
STR_APPLY_R1(stringTy, "_aApplyRcw1", "_aApplyRcd1")
STR_APPLY_R1(wstringTy, "_aApplyRwc1", "_aApplyRwd1")
STR_APPLY_R1(dstringTy, "_aApplyRdc1", "_aApplyRdw1")
#undef STR_APPLY
#define STR_APPLY_R2(TY,a,b) \
{ \
std::string fname(a); \
std::string fname2(b); \
std::vector<const llvm::Type*> types; \
types.push_back(TY); \
types.push_back(rt_dg2()); \
const llvm::FunctionType* fty = llvm::FunctionType::get(intTy, types, false); \
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M); \
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname2, M); \
}
STR_APPLY_R2(stringTy, "_aApplyRcw2", "_aApplyRcd2")
STR_APPLY_R2(wstringTy, "_aApplyRwc2", "_aApplyRwd2")
STR_APPLY_R2(dstringTy, "_aApplyRdc2", "_aApplyRdw2")
#undef STR_APPLY2
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
// fixes the length for dynamic array casts
// size_t _d_array_cast_len(size_t len, size_t elemsz, size_t newelemsz)
{
std::string fname("_d_array_cast_len");
std::vector<const llvm::Type*> types;
types.push_back(sizeTy);
types.push_back(sizeTy);
types.push_back(sizeTy);
const llvm::FunctionType* fty = llvm::FunctionType::get(sizeTy, types, false);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
}
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
// builds the d string[] for the D main args from the C main args
// void _d_main_args(uint n, char** args, ref char[][] res)
{
std::string fname("_d_main_args");
std::vector<const llvm::Type*> types;
types.push_back(intTy);
types.push_back(rt_ptr(rt_ptr(byteTy)));
types.push_back(rt_array(stringTy->getContainedType(0)));
const llvm::FunctionType* fty = llvm::FunctionType::get(voidTy, types, false);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
}
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
// cast to object
// Object _d_toObject(void* p)
{
std::string fname("_d_toObject");
std::vector<const llvm::Type*> types;
types.push_back(voidPtrTy);
const llvm::FunctionType* fty = llvm::FunctionType::get(objectTy, types, false);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
}
// cast interface
// Object _d_interface_cast(void* p, ClassInfo c)
{
std::string fname("_d_interface_cast");
std::vector<const llvm::Type*> types;
types.push_back(voidPtrTy);
types.push_back(classInfoTy);
const llvm::FunctionType* fty = llvm::FunctionType::get(objectTy, types, false);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
}
// dynamic cast
// Object _d_dynamic_cast(Object o, ClassInfo c)
{
std::string fname("_d_dynamic_cast");
std::vector<const llvm::Type*> types;
types.push_back(objectTy);
types.push_back(classInfoTy);
const llvm::FunctionType* fty = llvm::FunctionType::get(objectTy, types, false);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
}
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
// char[] _adReverseChar(char[] a)
// char[] _adSortChar(char[] a)
{
std::string fname("_adReverseChar");
std::string fname2("_adSortChar");
std::vector<const llvm::Type*> types;
types.push_back(stringTy);
types.push_back(stringTy);
const llvm::FunctionType* fty = llvm::FunctionType::get(voidTy, types, false);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname2, M);
}
// wchar[] _adReverseWchar(wchar[] a)
// wchar[] _adSortWchar(wchar[] a)
{
std::string fname("_adReverseWchar");
std::string fname2("_adSortWchar");
std::vector<const llvm::Type*> types;
types.push_back(wstringTy);
types.push_back(wstringTy);
const llvm::FunctionType* fty = llvm::FunctionType::get(voidTy, types, false);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname2, M);
}
// Array _adReverse(Array a, size_t szelem)
{
std::string fname("_adReverse");
std::vector<const llvm::Type*> types;
types.push_back(rt_array(byteTy));
types.push_back(rt_array(byteTy));
types.push_back(sizeTy);
const llvm::FunctionType* fty = llvm::FunctionType::get(voidTy, types, false);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
}
// Array _adDupT(TypeInfo ti, Array a)
{
std::string fname("_adDupT");
std::vector<const llvm::Type*> types;
types.push_back(rt_array(byteTy));
types.push_back(typeInfoTy);
types.push_back(rt_array(byteTy));
const llvm::FunctionType* fty = llvm::FunctionType::get(voidTy, types, false);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
}
// int _adEq(Array a1, Array a2, TypeInfo ti)
// int _adCmp(Array a1, Array a2, TypeInfo ti)
{
std::string fname("_adEq");
std::string fname2("_adCmp");
std::vector<const llvm::Type*> types;
types.push_back(rt_array(byteTy));
types.push_back(rt_array(byteTy));
types.push_back(typeInfoTy);
const llvm::FunctionType* fty = llvm::FunctionType::get(intTy, types, false);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname2, M);
}
// int _adCmpChar(Array a1, Array a2)
{
std::string fname("_adCmpChar");
std::vector<const llvm::Type*> types;
types.push_back(rt_array(byteTy));
types.push_back(rt_array(byteTy));
const llvm::FunctionType* fty = llvm::FunctionType::get(intTy, types, false);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
}
// Array _adSort(Array a, TypeInfo ti)
{
std::string fname("_adSort");
std::vector<const llvm::Type*> types;
types.push_back(rt_array(byteTy));
types.push_back(rt_array(byteTy));
types.push_back(typeInfoTy);
const llvm::FunctionType* fty = llvm::FunctionType::get(voidTy, types, false);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
}
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
// size_t _aaLen(AA aa)
{
std::string fname("_aaLen");
std::vector<const llvm::Type*> types;
types.push_back(aaTy);
const llvm::FunctionType* fty = llvm::FunctionType::get(sizeTy, types, false);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
}
// void* _aaGet(AA* aa, TypeInfo keyti, void* pkey, size_t valuesize)
{
std::string fname("_aaGet");
std::vector<const llvm::Type*> types;
types.push_back(aaTy);
types.push_back(typeInfoTy);
types.push_back(voidPtrTy);
types.push_back(sizeTy);
const llvm::FunctionType* fty = llvm::FunctionType::get(voidPtrTy, types, false);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
}
// void* _aaGetRvalue(AA aa, TypeInfo keyti, size_t valuesize, void* pkey)
{
std::string fname("_aaGetRvalue");
std::vector<const llvm::Type*> types;
types.push_back(aaTy);
types.push_back(typeInfoTy);
types.push_back(sizeTy);
types.push_back(voidPtrTy);
const llvm::FunctionType* fty = llvm::FunctionType::get(voidPtrTy, types, false);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
}
// void* _aaIn(AA aa, TypeInfo keyti, void* pkey)
{
std::string fname("_aaIn");
std::vector<const llvm::Type*> types;
types.push_back(aaTy);
types.push_back(typeInfoTy);
types.push_back(voidPtrTy);
const llvm::FunctionType* fty = llvm::FunctionType::get(voidPtrTy, types, false);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
}
// void _aaDel(AA aa, TypeInfo keyti, void* pkey)
{
std::string fname("_aaDel");
std::vector<const llvm::Type*> types;
types.push_back(aaTy);
types.push_back(typeInfoTy);
types.push_back(voidPtrTy);
const llvm::FunctionType* fty = llvm::FunctionType::get(voidTy, types, false);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
}
// ArrayRet_t _aaValues(AA aa, size_t keysize, size_t valuesize)
{
std::string fname("_aaValues");
std::vector<const llvm::Type*> types;
types.push_back(rt_array(byteTy));
types.push_back(aaTy);
types.push_back(sizeTy);
types.push_back(sizeTy);
const llvm::FunctionType* fty = llvm::FunctionType::get(voidTy, types, false);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
}
// void* _aaRehash(AA* paa, TypeInfo keyti)
{
std::string fname("_aaRehash");
std::vector<const llvm::Type*> types;
types.push_back(aaTy);
types.push_back(typeInfoTy);
const llvm::FunctionType* fty = llvm::FunctionType::get(voidPtrTy, types, false);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
}
// ArrayRet_t _aaKeys(AA aa, size_t keysize)
{
std::string fname("_aaKeys");
std::vector<const llvm::Type*> types;
types.push_back(rt_array(byteTy));
types.push_back(aaTy);
types.push_back(sizeTy);
const llvm::FunctionType* fty = llvm::FunctionType::get(voidTy, types, false);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
}
// int _aaApply(AA aa, size_t keysize, dg_t dg)
{
std::string fname("_aaApply");
std::vector<const llvm::Type*> types;
types.push_back(aaTy);
types.push_back(sizeTy);
types.push_back(rt_dg1());
const llvm::FunctionType* fty = llvm::FunctionType::get(intTy, types, false);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
}
// int _aaApply2(AA aa, size_t keysize, dg2_t dg)
{
std::string fname("_aaApply2");
std::vector<const llvm::Type*> types;
types.push_back(aaTy);
types.push_back(sizeTy);
types.push_back(rt_dg1());
const llvm::FunctionType* fty = llvm::FunctionType::get(intTy, types, false);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
}
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////
// void _moduleCtor()
// void _moduleDtor()
{
std::string fname("_moduleCtor");
std::string fname2("_moduleDtor");
std::vector<const llvm::Type*> types;
const llvm::FunctionType* fty = llvm::FunctionType::get(voidTy, types, false);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname, M);
new llvm::Function(fty, llvm::GlobalValue::ExternalLinkage, fname2, M);
}
}

View File

@@ -9,6 +9,7 @@
#include "gen/llvm.h"
#include "llvm/InlineAsm.h"
#include "mars.h"
#include "total.h"
#include "init.h"
#include "mtype.h"
@@ -27,16 +28,14 @@
void CompoundStatement::toIR(IRState* p)
{
Logger::println("CompoundStatement::toIR()");
Logger::println("CompoundStatement::toIR(): %s", loc.toChars());
LOG_SCOPE;
for (int i=0; i<statements->dim; i++)
{
Statement* s = (Statement*)statements->data[i];
if (s)
if (s) {
s->toIR(p);
else {
Logger::println("??? null statement found in CompoundStatement");
}
}
}
@@ -45,8 +44,7 @@ void CompoundStatement::toIR(IRState* p)
void ReturnStatement::toIR(IRState* p)
{
static int rsi = 0;
Logger::println("ReturnStatement::toIR(%d): %s", rsi++, toChars());
Logger::println("ReturnStatement::toIR(): %s", loc.toChars());
LOG_SCOPE;
if (exp)
@@ -126,8 +124,7 @@ void ReturnStatement::toIR(IRState* p)
void ExpStatement::toIR(IRState* p)
{
static int esi = 0;
Logger::println("ExpStatement::toIR(%d): %s", esi++, toChars());
Logger::println("ExpStatement::toIR(): %s", loc.toChars());
LOG_SCOPE;
if (global.params.llvmAnnotate)
@@ -150,7 +147,7 @@ void ExpStatement::toIR(IRState* p)
void IfStatement::toIR(IRState* p)
{
Logger::println("IfStatement::toIR()");
Logger::println("IfStatement::toIR(): %s", loc.toChars());
LOG_SCOPE;
DValue* cond_e = condition->toElem(p);
@@ -195,7 +192,7 @@ void IfStatement::toIR(IRState* p)
void ScopeStatement::toIR(IRState* p)
{
Logger::println("ScopeStatement::toIR()");
Logger::println("ScopeStatement::toIR(): %s", loc.toChars());
LOG_SCOPE;
llvm::BasicBlock* oldend = p->scopeend();
@@ -226,8 +223,7 @@ void ScopeStatement::toIR(IRState* p)
void WhileStatement::toIR(IRState* p)
{
static int wsi = 0;
Logger::println("WhileStatement::toIR(%d): %s", wsi++, toChars());
Logger::println("WhileStatement::toIR(): %s", loc.toChars());
LOG_SCOPE;
// create while blocks
@@ -271,8 +267,7 @@ void WhileStatement::toIR(IRState* p)
void DoStatement::toIR(IRState* p)
{
static int wsi = 0;
Logger::println("DoStatement::toIR(%d): %s", wsi++, toChars());
Logger::println("DoStatement::toIR(): %s", loc.toChars());
LOG_SCOPE;
// create while blocks
@@ -308,8 +303,7 @@ void DoStatement::toIR(IRState* p)
void ForStatement::toIR(IRState* p)
{
static int wsi = 0;
Logger::println("ForStatement::toIR(%d): %s", wsi++, toChars());
Logger::println("ForStatement::toIR(): %s", loc.toChars());
LOG_SCOPE;
// create for blocks
@@ -370,7 +364,7 @@ void ForStatement::toIR(IRState* p)
void BreakStatement::toIR(IRState* p)
{
Logger::println("BreakStatement::toIR(): %s", toChars());
Logger::println("BreakStatement::toIR(): %s", loc.toChars());
LOG_SCOPE;
if (ident != 0) {
@@ -386,7 +380,7 @@ void BreakStatement::toIR(IRState* p)
void ContinueStatement::toIR(IRState* p)
{
Logger::println("ContinueStatement::toIR(): %s", toChars());
Logger::println("ContinueStatement::toIR(): %s", loc.toChars());
LOG_SCOPE;
if (ident != 0) {
@@ -402,7 +396,7 @@ void ContinueStatement::toIR(IRState* p)
void OnScopeStatement::toIR(IRState* p)
{
Logger::println("OnScopeStatement::toIR(): %s", toChars());
Logger::println("OnScopeStatement::toIR(): %s", loc.toChars());
LOG_SCOPE;
assert(statement);
@@ -413,7 +407,7 @@ void OnScopeStatement::toIR(IRState* p)
void TryFinallyStatement::toIR(IRState* p)
{
Logger::println("TryFinallyStatement::toIR(): %s", toChars());
Logger::println("TryFinallyStatement::toIR(): %s", loc.toChars());
LOG_SCOPE;
// create basic blocks
@@ -491,11 +485,10 @@ void TryFinallyStatement::toIR(IRState* p)
void TryCatchStatement::toIR(IRState* p)
{
static int wsi = 0;
Logger::println("TryCatchStatement::toIR(%d): %s", wsi++, toChars());
Logger::println("TryCatchStatement::toIR(): %s", loc.toChars());
LOG_SCOPE;
Logger::attention("try-catch is not yet fully implemented, only the try block will be emitted.");
Logger::attention(loc, "try-catch is not yet fully implemented, only the try block will be emitted.");
assert(body);
body->toIR(p);
@@ -512,11 +505,10 @@ void TryCatchStatement::toIR(IRState* p)
void ThrowStatement::toIR(IRState* p)
{
static int wsi = 0;
Logger::println("ThrowStatement::toIR(%d): %s", wsi++, toChars());
Logger::println("ThrowStatement::toIR(): %s", loc.toChars());
LOG_SCOPE;
Logger::attention("throw is not yet implemented, replacing expression with assert(0);");
Logger::attention(loc, "throw is not yet implemented, replacing expression with assert(0);");
DtoAssert(NULL, &loc, NULL);
@@ -574,7 +566,7 @@ static llvm::Value* call_string_switch_runtime(llvm::GlobalVariable* table, Expr
void SwitchStatement::toIR(IRState* p)
{
Logger::println("SwitchStatement::toIR()");
Logger::println("SwitchStatement::toIR(): %s", loc.toChars());
LOG_SCOPE;
llvm::BasicBlock* oldend = gIR->scopeend();
@@ -725,7 +717,7 @@ void SwitchStatement::toIR(IRState* p)
//////////////////////////////////////////////////////////////////////////////
void CaseStatement::toIR(IRState* p)
{
Logger::println("CaseStatement::toIR(): %s", toChars());
Logger::println("CaseStatement::toIR(): %s", loc.toChars());
LOG_SCOPE;
assert(0);
@@ -735,7 +727,7 @@ void CaseStatement::toIR(IRState* p)
void UnrolledLoopStatement::toIR(IRState* p)
{
Logger::println("UnrolledLoopStatement::toIR(): %s", toChars());
Logger::println("UnrolledLoopStatement::toIR(): %s", loc.toChars());
LOG_SCOPE;
llvm::BasicBlock* oldend = gIR->scopeend();
@@ -760,7 +752,7 @@ void UnrolledLoopStatement::toIR(IRState* p)
void ForeachStatement::toIR(IRState* p)
{
Logger::println("ForeachStatement::toIR(): %s", toChars());
Logger::println("ForeachStatement::toIR(): %s", loc.toChars());
LOG_SCOPE;
//assert(arguments->dim == 1);
@@ -916,7 +908,7 @@ void ForeachStatement::toIR(IRState* p)
void LabelStatement::toIR(IRState* p)
{
Logger::println("LabelStatement::toIR(): %s", toChars());
Logger::println("LabelStatement::toIR(): %s", loc.toChars());
LOG_SCOPE;
assert(tf == NULL);
@@ -940,7 +932,7 @@ void LabelStatement::toIR(IRState* p)
void GotoStatement::toIR(IRState* p)
{
Logger::println("GotoStatement::toIR(): %s", toChars());
Logger::println("GotoStatement::toIR(): %s", loc.toChars());
LOG_SCOPE;
assert(tf == NULL);
@@ -959,7 +951,7 @@ void GotoStatement::toIR(IRState* p)
void WithStatement::toIR(IRState* p)
{
Logger::println("WithStatement::toIR(): %s", toChars());
Logger::println("WithStatement::toIR(): %s", loc.toChars());
LOG_SCOPE;
assert(exp);
@@ -976,10 +968,10 @@ void WithStatement::toIR(IRState* p)
void SynchronizedStatement::toIR(IRState* p)
{
Logger::println("SynchronizedStatement::toIR(): %s", toChars());
Logger::println("SynchronizedStatement::toIR(): %s", loc.toChars());
LOG_SCOPE;
Logger::attention("synchronized is currently ignored. only the body will be emitted");
Logger::attention(loc, "synchronized is currently ignored. only the body will be emitted");
body->toIR(p);
}
@@ -988,7 +980,7 @@ void SynchronizedStatement::toIR(IRState* p)
void AsmStatement::toIR(IRState* p)
{
Logger::println("AsmStatement::toIR(): %s", toChars());
Logger::println("AsmStatement::toIR(): %s", loc.toChars());
LOG_SCOPE;
error("%s: inline asm is not yet implemented", loc.toChars());
fatal();
@@ -1020,6 +1012,18 @@ void AsmStatement::toIR(IRState* p)
//////////////////////////////////////////////////////////////////////////////
void VolatileStatement::toIR(IRState* p)
{
Logger::println("VolatileStatement::toIR(): %s", loc.toChars());
LOG_SCOPE;
Logger::attention(loc, "volatile is currently ignored. only the body will be emitted");
statement->toIR(p);
}
//////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
#define STUBST(x) void x::toIR(IRState * p) {error("Statement type "#x" not implemented: %s", toChars());fatal();}
@@ -1044,7 +1048,7 @@ STUBST(Statement);
//STUBST(AsmStatement);
//STUBST(TryCatchStatement);
//STUBST(TryFinallyStatement);
STUBST(VolatileStatement);
//STUBST(VolatileStatement);
//STUBST(LabelStatement);
//STUBST(ThrowStatement);
STUBST(GotoCaseStatement);

View File

@@ -171,7 +171,7 @@ void DtoResolveStruct(StructDeclaration* sd)
if (sd->llvmResolved) return;
sd->llvmResolved = true;
Logger::println("DtoResolveStruct(%s)", sd->toChars());
Logger::println("DtoResolveStruct(%s): %s", sd->toChars(), sd->loc.toChars());
LOG_SCOPE;
TypeStruct* ts = (TypeStruct*)DtoDType(sd->type);
@@ -180,10 +180,16 @@ void DtoResolveStruct(StructDeclaration* sd)
sd->llvmIRStruct = irstruct;
gIR->structs.push_back(irstruct);
for (int k=0; k < sd->members->dim; k++) {
Array* arr = &sd->fields;
for (int k=0; k < arr->dim; k++) {
VarDeclaration* v = (VarDeclaration*)(arr->data[k]);
v->toObjFile();
}
/*for (int k=0; k < sd->members->dim; k++) {
Dsymbol* dsym = (Dsymbol*)(sd->members->data[k]);
dsym->toObjFile();
}
}*/
Logger::println("doing struct fields");
@@ -293,7 +299,7 @@ void DtoDeclareStruct(StructDeclaration* sd)
if (sd->llvmDeclared) return;
sd->llvmDeclared = true;
Logger::println("DtoDeclareStruct(%s)", sd->toChars());
Logger::println("DtoDeclareStruct(%s): %s", sd->toChars(), sd->loc.toChars());
LOG_SCOPE;
TypeStruct* ts = (TypeStruct*)DtoDType(sd->type);
@@ -318,7 +324,7 @@ void DtoConstInitStruct(StructDeclaration* sd)
if (sd->llvmInitialized) return;
sd->llvmInitialized = true;
Logger::println("DtoConstInitStruct(%s)", sd->toChars());
Logger::println("DtoConstInitStruct(%s): %s", sd->toChars(), sd->loc.toChars());
LOG_SCOPE;
IRStruct* irstruct = sd->llvmIRStruct;
@@ -390,7 +396,7 @@ void DtoDefineStruct(StructDeclaration* sd)
if (sd->llvmDefined) return;
sd->llvmDefined = true;
Logger::println("DtoDefineStruct(%s)", sd->toChars());
Logger::println("DtoDefineStruct(%s): %s", sd->toChars(), sd->loc.toChars());
LOG_SCOPE;
assert(sd->type->ty == Tstruct);

View File

@@ -14,6 +14,7 @@
#include "gen/llvm.h"
#include "attrib.h"
#include "total.h"
#include "init.h"
#include "mtype.h"
@@ -114,10 +115,19 @@ DValue* DeclarationExp::toElem(IRState* p)
Logger::println("TypedefDeclaration");
tdef->type->getTypeInfo(NULL);
}
// attribute declaration
else if (AttribDeclaration* a = declaration->isAttribDeclaration())
{
Logger::println("AttribDeclaration");
for (int i=0; i < a->decl->dim; ++i)
{
DtoForceDeclareDsymbol((Dsymbol*)a->decl->data[i]);
}
}
// unsupported declaration
else
{
error("Unimplemented DeclarationExp type");
error("Unimplemented DeclarationExp type. kind: %s", declaration->kind());
assert(0);
}
return 0;
@@ -261,7 +271,18 @@ llvm::Constant* VarExp::toConstElem(IRState* p)
assert(ts->sym->llvmConstInit);
return ts->sym->llvmConstInit;
}
assert(0 && "Only supported const VarExp is of a SymbolDeclaration");
else if (TypeInfoDeclaration* ti = var->isTypeInfoDeclaration())
{
DtoForceDeclareDsymbol(ti);
assert(ti->llvmValue);
const llvm::Type* vartype = DtoType(type);
llvm::Constant* m = isaConstant(ti->llvmValue);
assert(m);
if (ti->llvmValue->getType() != llvm::PointerType::get(vartype))
m = llvm::ConstantExpr::getBitCast(m, vartype);
return m;
}
assert(0 && "Unsupported const VarExp kind");
return NULL;
}
@@ -836,7 +857,7 @@ DValue* CallExp::toElem(IRState* p)
assert(tf);
}
// va args
// magic stuff
bool va_magic = false;
bool va_intrinsic = false;
DFuncValue* dfv = fn->isFunc();
@@ -867,6 +888,8 @@ DValue* CallExp::toElem(IRState* p)
//Argument* fnarg = Argument::getNth(tf->parameters, 0);
Expression* exp = (Expression*)arguments->data[0];
DValue* expv = exp->toElem(p);
if (expv->getType()->toBasetype()->ty != Tint32)
expv = DtoCast(expv, Type::tint32);
llvm::Value* alloc = new llvm::AllocaInst(llvm::Type::Int8Ty, expv->getRVal(), "alloca", p->scopebb());
return new DImValue(type, alloc);
}
@@ -1315,18 +1338,33 @@ DValue* DotVarExp::toElem(IRState* p)
assert(e1type->next->ty == Tstruct);
TypeStruct* ts = (TypeStruct*)e1type->next;
Logger::println("Struct member offset:%d", vd->offset);
llvm::Value* src = l->getRVal();
std::vector<unsigned> vdoffsets;
arrptr = DtoIndexStruct(src, ts->sym, vd->type, vd->offset, vdoffsets);
}
else if (e1type->ty == Tclass) {
TypeClass* tc = (TypeClass*)e1type;
Logger::println("Class member offset: %d", vd->offset);
std::vector<unsigned> vdoffsets(1,0);
tc->sym->offsetToIndex(vd->type, vd->offset, vdoffsets);
llvm::Value* src = l->getRVal();
//Logger::cout() << "src: " << *src << '\n';
std::vector<unsigned> vdoffsets;
arrptr = DtoIndexClass(src, tc->sym, vd->type, vd->offset, vdoffsets);
/*std::vector<unsigned> vdoffsets(1,0);
tc->sym->offsetToIndex(vd->type, vd->offset, vdoffsets);
llvm::Value* src = l->getRVal();
Logger::println("indices:");
for (size_t i=0; i<vdoffsets.size(); ++i)
Logger::println("%d", vdoffsets[i]);
Logger::cout() << "src: " << *src << '\n';
arrptr = DtoGEP(src,vdoffsets,"tmp",p->scopebb());
Logger::cout() << "dst: " << *arrptr << '\n';*/
}
else
assert(0);
@@ -1609,7 +1647,11 @@ DValue* CmpExp::toElem(IRState* p)
}
if (!skip)
{
eval = new llvm::ICmpInst(cmpop, l->getRVal(), r->getRVal(), "tmp", p->scopebb());
llvm::Value* a = l->getRVal();
llvm::Value* b = r->getRVal();
Logger::cout() << "type 1: " << *a << '\n';
Logger::cout() << "type 2: " << *b << '\n';
eval = new llvm::ICmpInst(cmpop, a, b, "tmp", p->scopebb());
}
}
else if (t->isfloating())
@@ -1810,44 +1852,47 @@ DValue* NewExp::toElem(IRState* p)
llvm::Value* emem = 0;
bool inplace = false;
if (onstack) {
assert(ntype->ty == Tclass);
emem = new llvm::AllocaInst(t->getContainedType(0),"tmp",p->topallocapoint());
}
else if (ntype->ty == Tclass) {
emem = new llvm::MallocInst(t->getContainedType(0),"tmp",p->scopebb());
}
else if (ntype->ty == Tarray) {
assert(arguments);
if (arguments->dim == 1) {
DValue* sz = ((Expression*)arguments->data[0])->toElem(p);
llvm::Value* dimval = sz->getRVal();
Type* nnt = DtoDType(ntype->next);
if (nnt->ty == Tvoid)
nnt = Type::tint8;
if (!p->topexp() || p->topexp()->e2 != this) {
const llvm::Type* restype = DtoType(type);
Logger::cout() << "restype = " << *restype << '\n';
emem = new llvm::AllocaInst(restype,"newstorage",p->topallocapoint());
DtoNewDynArray(emem, dimval, nnt);
return new DVarValue(newtype, emem, true);
{
Logger::println("Allocating memory");
LOG_SCOPE;
if (onstack) {
assert(ntype->ty == Tclass);
emem = new llvm::AllocaInst(t->getContainedType(0),"tmp",p->topallocapoint());
}
else if (ntype->ty == Tclass) {
emem = new llvm::MallocInst(t->getContainedType(0),"tmp",p->scopebb());
}
else if (ntype->ty == Tarray) {
assert(arguments);
if (arguments->dim == 1) {
DValue* sz = ((Expression*)arguments->data[0])->toElem(p);
llvm::Value* dimval = sz->getRVal();
Type* nnt = DtoDType(ntype->next);
if (nnt->ty == Tvoid)
nnt = Type::tint8;
if (p->topexp() && p->topexp()->e2 == this) {
assert(p->topexp()->v);
emem = p->topexp()->v->getLVal();
DtoNewDynArray(emem, dimval, nnt);
inplace = true;
}
else {
const llvm::Type* restype = DtoType(type);
Logger::cout() << "restype = " << *restype << '\n';
emem = new llvm::AllocaInst(restype,"newstorage",p->topallocapoint());
DtoNewDynArray(emem, dimval, nnt);
return new DVarValue(newtype, emem, true);
}
}
else if (p->topexp() && p->topexp()->e2 == this) {
assert(p->topexp()->v);
emem = p->topexp()->v->getLVal();
DtoNewDynArray(emem, dimval, nnt);
inplace = true;
else {
assert(0 && "num args to 'new' != 1");
}
else
assert(0);
}
else {
assert(0);
emem = new llvm::MallocInst(t,"tmp",p->scopebb());
}
}
else {
emem = new llvm::MallocInst(t,"tmp",p->scopebb());
}
if (ntype->ty == Tclass) {
// first apply the static initializer
@@ -1856,13 +1901,20 @@ DValue* NewExp::toElem(IRState* p)
// set the this var for nested classes
if (thisexp) {
Logger::println("Resolving 'this' expression");
LOG_SCOPE;
DValue* thisval = thisexp->toElem(p);
size_t idx = 2;
idx += tc->sym->llvmIRStruct->interfaces.size();
DtoStore(thisval->getRVal(), DtoGEPi(emem,0,idx,"tmp"));
llvm::Value* dst = thisval->getRVal();
llvm::Value* src = DtoGEPi(emem,0,idx,"tmp");
Logger::cout() << "dst: " << *dst << "\nsrc: " << *src << '\n';
DtoStore(dst, src);
}
else if (tc->sym->isNested())
{
Logger::println("Resolving nested context");
LOG_SCOPE;
size_t idx = 2;
idx += tc->sym->llvmIRStruct->interfaces.size();
llvm::Value* nest = p->func()->decl->llvmNested;
@@ -1876,6 +1928,8 @@ DValue* NewExp::toElem(IRState* p)
// then call constructor
if (arguments) {
Logger::println("Calling constructor");
LOG_SCOPE;
assert(member);
assert(member->llvmValue);
llvm::Function* fn = llvm::cast<llvm::Function>(member->llvmValue);
@@ -2336,17 +2390,25 @@ DValue* CatExp::toElem(IRState* p)
Type* t = DtoDType(type);
bool arrNarr = DtoDType(e1->type) == DtoDType(e2->type);
IRExp* ex = p->topexp();
if (ex && ex->e2 == this) {
assert(ex->v);
DtoCatArrays(ex->v->getLVal(),e1,e2);
if (arrNarr)
DtoCatArrays(ex->v->getLVal(),e1,e2);
else
DtoCatArrayElement(ex->v->getLVal(),e1,e2);
return new DImValue(type, ex->v->getLVal(), true);
}
else {
assert(t->ty == Tarray);
const llvm::Type* arrty = DtoType(t);
llvm::Value* dst = new llvm::AllocaInst(arrty, "tmpmem", p->topallocapoint());
DtoCatArrays(dst,e1,e2);
if (arrNarr)
DtoCatArrays(dst,e1,e2);
else
DtoCatArrayElement(dst,e1,e2);
return new DVarValue(type, dst, true);
}
}

View File

@@ -134,6 +134,7 @@ const llvm::Type* DtoType(Type* t)
}
}
}
Logger::println("no type found");
}
TypeClass* tc = (TypeClass*)t;
@@ -349,7 +350,10 @@ llvm::GlobalValue::LinkageTypes DtoLinkage(PROT prot, uint stc)
switch(prot)
{
case PROTprivate:
return llvm::GlobalValue::InternalLinkage;
if (stc & STCextern)
return llvm::GlobalValue::ExternalLinkage;
else
return llvm::GlobalValue::InternalLinkage;
case PROTpublic:
case PROTpackage:
@@ -903,8 +907,12 @@ void DtoAssign(DValue* lhs, DValue* rhs)
else if (t->ty == Tdelegate) {
if (rhs->isNull())
DtoNullDelegate(lhs->getLVal());
else if (!rhs->inPlace())
DtoDelegateCopy(lhs->getLVal(), rhs->getRVal());
else if (!rhs->inPlace()) {
llvm::Value* l = lhs->getLVal();
llvm::Value* r = rhs->getRVal();
Logger::cout() << "assign\nlhs: " << *l << "rhs: " << *r << '\n';
DtoDelegateCopy(l, r);
}
}
else if (t->ty == Tclass) {
assert(t2->ty == Tclass);

View File

@@ -351,6 +351,7 @@ void Module::genmoduleinfo()
for (size_t i = 0; i < aclasses.dim; i++)
{
ClassDeclaration* cd = (ClassDeclaration*)aclasses.data[i];
Logger::println("class: %s", cd->toPrettyChars());
assert(cd->llvmClass);
classInits.push_back(cd->llvmClass);
}
@@ -370,9 +371,8 @@ void Module::genmoduleinfo()
initVec.push_back(c);
// flags
if (needmoduleinfo)
c = DtoConstUint(0); // flags (4 means MIstandalone)
else
c = DtoConstUint(0);
if (!needmoduleinfo)
c = DtoConstUint(4); // flags (4 means MIstandalone)
initVec.push_back(c);
@@ -391,6 +391,22 @@ void Module::genmoduleinfo()
c = unittest ? unittest : moduleinfo->llvmConstInit->getOperand(8);
initVec.push_back(c);
// xgetMembers
c = moduleinfo->llvmConstInit->getOperand(9);
initVec.push_back(c);
// ictor
c = moduleinfo->llvmConstInit->getOperand(10);
initVec.push_back(c);
/*Logger::println("MODULE INFO INITIALIZERS");
for (size_t i=0; i<initVec.size(); ++i)
{
Logger::cout() << *initVec[i] << '\n';
if (initVec[i]->getType() != moduleinfoTy->getElementType(i))
assert(0);
}*/
// create initializer
llvm::Constant* constMI = llvm::ConstantStruct::get(moduleinfoTy, initVec);
@@ -442,42 +458,6 @@ void StructDeclaration::toObjFile()
/* ================================================================== */
static unsigned LLVM_ClassOffsetToIndex(ClassDeclaration* cd, unsigned os, unsigned& idx)
{
// start at the bottom of the inheritance chain
if (cd->baseClass != 0) {
unsigned o = LLVM_ClassOffsetToIndex(cd->baseClass, os, idx);
if (o != (unsigned)-1)
return o;
}
// check this class
unsigned i;
for (i=0; i<cd->fields.dim; ++i) {
VarDeclaration* vd = (VarDeclaration*)cd->fields.data[i];
if (os == vd->offset)
return i+idx;
}
idx += i;
return (unsigned)-1;
}
void ClassDeclaration::offsetToIndex(Type* t, unsigned os, std::vector<unsigned>& result)
{
unsigned idx = 0;
unsigned r = LLVM_ClassOffsetToIndex(this, os, idx);
assert(r != (unsigned)-1 && "Offset not found in any aggregate field");
// vtable is 0, monitor is 1
r += 2;
// interface offset further
r += vtblInterfaces->dim;
// the final index was not pushed
result.push_back(r);
}
/* ================================================================== */
void ClassDeclaration::toObjFile()
{
gIR->resolveList.push_back(this);
@@ -510,6 +490,11 @@ void VarDeclaration::toObjFile()
// global variable or magic
if (isDataseg())
{
// we don't want to touch private static members at all !!!
if ((prot() & PROTprivate) && getModule() != gIR->dmodule)
return;
// don't duplicate work
if (llvmResolved) return;
llvmResolved = true;
llvmDeclared = true;
@@ -548,9 +533,6 @@ void VarDeclaration::toObjFile()
DtoConstInitGlobal(this);
else
gIR->constInitList.push_back(this);
//if (storage_class & STCprivate)
// gvar->setVisibility(llvm::GlobalValue::ProtectedVisibility);
}
// inside aggregate declaration. declare a field.

View File

@@ -251,7 +251,7 @@ void DtoResolveTypeInfo(TypeInfoDeclaration* tid)
if (tid->llvmResolved) return;
tid->llvmResolved = true;
Logger::println("* DtoResolveTypeInfo(%s)", tid->toChars());
Logger::println("DtoResolveTypeInfo(%s)", tid->toChars());
LOG_SCOPE;
tid->llvmIRGlobal = new IRGlobal(tid);
@@ -264,7 +264,7 @@ void DtoDeclareTypeInfo(TypeInfoDeclaration* tid)
if (tid->llvmDeclared) return;
tid->llvmDeclared = true;
Logger::println("* DtoDeclareTypeInfo(%s)", tid->toChars());
Logger::println("DtoDeclareTypeInfo(%s)", tid->toChars());
LOG_SCOPE;
std::string mangled(tid->mangle());
@@ -274,13 +274,24 @@ void DtoDeclareTypeInfo(TypeInfoDeclaration* tid)
// this is a declaration of a builtin __initZ var
if (tid->tinfo->builtinTypeInfo()) {
tid->llvmValue = LLVM_D_GetRuntimeGlobal(gIR->module, mangled.c_str());
assert(tid->llvmValue);
mangled.append("__TYPE");
gIR->module->addTypeName(mangled, tid->llvmValue->getType()->getContainedType(0));
Logger::println("Got typeinfo var: %s", tid->llvmValue->getName().c_str());
tid->llvmInitialized = true;
tid->llvmDefined = true;
llvm::Value* found = gIR->module->getNamedGlobal(mangled);
if (!found)
{
const llvm::Type* t = llvm::OpaqueType::get();
llvm::GlobalVariable* g = new llvm::GlobalVariable(t, true, llvm::GlobalValue::ExternalLinkage, NULL, mangled, gIR->module);
assert(g);
tid->llvmValue = g;
mangled.append("__TYPE");
gIR->module->addTypeName(mangled, tid->llvmValue->getType()->getContainedType(0));
Logger::println("Got typeinfo var: %s", tid->llvmValue->getName().c_str());
tid->llvmInitialized = true;
tid->llvmDefined = true;
}
else if (!tid->llvmValue) {
tid->llvmValue = found;
tid->llvmInitialized = true;
tid->llvmDefined = true;
}
}
// custom typedef
else {
@@ -294,7 +305,7 @@ void DtoConstInitTypeInfo(TypeInfoDeclaration* tid)
if (tid->llvmInitialized) return;
tid->llvmInitialized = true;
Logger::println("* DtoConstInitTypeInfo(%s)", tid->toChars());
Logger::println("DtoConstInitTypeInfo(%s)", tid->toChars());
LOG_SCOPE;
gIR->defineList.push_back(tid);
@@ -305,7 +316,7 @@ void DtoDefineTypeInfo(TypeInfoDeclaration* tid)
if (tid->llvmDefined) return;
tid->llvmDefined = true;
Logger::println("* DtoDefineTypeInfo(%s)", tid->toChars());
Logger::println("DtoDefineTypeInfo(%s)", tid->toChars());
LOG_SCOPE;
tid->llvmDefine();
@@ -912,8 +923,9 @@ void TypeInfoStructDeclaration::llvmDefine()
{
fd = fdx->overloadExactMatch(tftohash);
if (fd) {
DtoForceDeclareDsymbol(fd);
assert(fd->llvmValue != 0);
llvm::Constant* c = llvm::cast_or_null<llvm::Constant>(fd->llvmValue);
llvm::Constant* c = isaConstant(fd->llvmValue);
assert(c);
c = llvm::ConstantExpr::getBitCast(c, ptty);
sinits.push_back(c);
@@ -937,8 +949,9 @@ void TypeInfoStructDeclaration::llvmDefine()
{
fd = fdx->overloadExactMatch(tfeqptr);
if (fd) {
DtoForceDeclareDsymbol(fd);
assert(fd->llvmValue != 0);
llvm::Constant* c = llvm::cast_or_null<llvm::Constant>(fd->llvmValue);
llvm::Constant* c = isaConstant(fd->llvmValue);
assert(c);
c = llvm::ConstantExpr::getBitCast(c, ptty);
sinits.push_back(c);
@@ -964,8 +977,9 @@ void TypeInfoStructDeclaration::llvmDefine()
{
fd = fdx->overloadExactMatch(tftostring);
if (fd) {
DtoForceDeclareDsymbol(fd);
assert(fd->llvmValue != 0);
llvm::Constant* c = llvm::cast_or_null<llvm::Constant>(fd->llvmValue);
llvm::Constant* c = isaConstant(fd->llvmValue);
assert(c);
c = llvm::ConstantExpr::getBitCast(c, ptty);
sinits.push_back(c);

View File

@@ -402,6 +402,178 @@
<path>obj/Debug/utf.d</path>
<path>obj/Debug/version.d</path>
<path>obj</path>
<path>dmd24</path>
<path>dmd24/access.c</path>
<path>dmd24/aggregate.h</path>
<path>dmd24/array.c</path>
<path>dmd24/arraytypes.h</path>
<path>dmd24/attrib.c</path>
<path>dmd24/attrib.h</path>
<path>dmd24/cast.c</path>
<path>dmd24/class.c</path>
<path>dmd24/complex_t.h</path>
<path>dmd24/cond.c</path>
<path>dmd24/cond.h</path>
<path>dmd24/constfold.c</path>
<path>dmd24/dchar.c</path>
<path>dmd24/dchar.h</path>
<path>dmd24/declaration.c</path>
<path>dmd24/declaration.h</path>
<path>dmd24/delegatize.c</path>
<path>dmd24/doc.c</path>
<path>dmd24/doc.h</path>
<path>dmd24/dsymbol.c</path>
<path>dmd24/dsymbol.h</path>
<path>dmd24/dump.c</path>
<path>dmd24/entity.c</path>
<path>dmd24/enum.c</path>
<path>dmd24/enum.h</path>
<path>dmd24/expression.c</path>
<path>dmd24/expression.h</path>
<path>dmd24/func.c</path>
<path>dmd24/gnuc.c</path>
<path>dmd24/gnuc.h</path>
<path>dmd24/hdrgen.c</path>
<path>dmd24/hdrgen.h</path>
<path>dmd24/html.c</path>
<path>dmd24/html.h</path>
<path>dmd24/identifier.c</path>
<path>dmd24/identifier.h</path>
<path>dmd24/idgen.c</path>
<path>dmd24/impcnvgen.c</path>
<path>dmd24/import.c</path>
<path>dmd24/import.h</path>
<path>dmd24/inifile.c</path>
<path>dmd24/init.c</path>
<path>dmd24/init.h</path>
<path>dmd24/inline.c</path>
<path>dmd24/interpret.c</path>
<path>dmd24/lexer.c</path>
<path>dmd24/lexer.h</path>
<path>dmd24/link.c</path>
<path>dmd24/lstring.c</path>
<path>dmd24/lstring.h</path>
<path>dmd24/macro.c</path>
<path>dmd24/macro.h</path>
<path>dmd24/mangle.c</path>
<path>dmd24/mars.c</path>
<path>dmd24/mars.h</path>
<path>dmd24/mem.c</path>
<path>dmd24/mem.h</path>
<path>dmd24/module.c</path>
<path>dmd24/module.h</path>
<path>dmd24/mtype.c</path>
<path>dmd24/mtype.h</path>
<path>dmd24/opover.c</path>
<path>dmd24/optimize.c</path>
<path>dmd24/parse.c</path>
<path>dmd24/parse.h</path>
<path>dmd24/port.h</path>
<path>dmd24/root.c</path>
<path>dmd24/root.h</path>
<path>dmd24/scope.c</path>
<path>dmd24/scope.h</path>
<path>dmd24/statement.c</path>
<path>dmd24/statement.h</path>
<path>dmd24/staticassert.c</path>
<path>dmd24/staticassert.h</path>
<path>dmd24/stringtable.c</path>
<path>dmd24/stringtable.h</path>
<path>dmd24/struct.c</path>
<path>dmd24/template.c</path>
<path>dmd24/template.h</path>
<path>dmd24/total.h</path>
<path>dmd24/unialpha.c</path>
<path>dmd24/utf.c</path>
<path>dmd24/utf.h</path>
<path>dmd24/version.c</path>
<path>dmd24/version.h</path>
<path>dmd25</path>
<path>dmd25/access.c</path>
<path>dmd25/aggregate.h</path>
<path>dmd25/array.c</path>
<path>dmd25/arraytypes.h</path>
<path>dmd25/attrib.c</path>
<path>dmd25/attrib.h</path>
<path>dmd25/cast.c</path>
<path>dmd25/class.c</path>
<path>dmd25/complex_t.h</path>
<path>dmd25/cond.c</path>
<path>dmd25/cond.h</path>
<path>dmd25/constfold.c</path>
<path>dmd25/dchar.c</path>
<path>dmd25/dchar.h</path>
<path>dmd25/declaration.c</path>
<path>dmd25/declaration.h</path>
<path>dmd25/delegatize.c</path>
<path>dmd25/doc.c</path>
<path>dmd25/doc.h</path>
<path>dmd25/dsymbol.c</path>
<path>dmd25/dsymbol.h</path>
<path>dmd25/dump.c</path>
<path>dmd25/entity.c</path>
<path>dmd25/enum.c</path>
<path>dmd25/enum.h</path>
<path>dmd25/expression.c</path>
<path>dmd25/expression.h</path>
<path>dmd25/func.c</path>
<path>dmd25/gnuc.c</path>
<path>dmd25/gnuc.h</path>
<path>dmd25/hdrgen.c</path>
<path>dmd25/hdrgen.h</path>
<path>dmd25/html.c</path>
<path>dmd25/html.h</path>
<path>dmd25/identifier.c</path>
<path>dmd25/identifier.h</path>
<path>dmd25/idgen.c</path>
<path>dmd25/impcnvgen.c</path>
<path>dmd25/import.c</path>
<path>dmd25/import.h</path>
<path>dmd25/inifile.c</path>
<path>dmd25/init.c</path>
<path>dmd25/init.h</path>
<path>dmd25/inline.c</path>
<path>dmd25/interpret.c</path>
<path>dmd25/lexer.c</path>
<path>dmd25/lexer.h</path>
<path>dmd25/link.c</path>
<path>dmd25/lstring.c</path>
<path>dmd25/lstring.h</path>
<path>dmd25/macro.c</path>
<path>dmd25/macro.h</path>
<path>dmd25/mangle.c</path>
<path>dmd25/mars.c</path>
<path>dmd25/mars.h</path>
<path>dmd25/mem.c</path>
<path>dmd25/mem.h</path>
<path>dmd25/module.c</path>
<path>dmd25/module.h</path>
<path>dmd25/mtype.c</path>
<path>dmd25/mtype.h</path>
<path>dmd25/opover.c</path>
<path>dmd25/optimize.c</path>
<path>dmd25/parse.c</path>
<path>dmd25/parse.h</path>
<path>dmd25/port.h</path>
<path>dmd25/root.c</path>
<path>dmd25/root.h</path>
<path>dmd25/scope.c</path>
<path>dmd25/scope.h</path>
<path>dmd25/statement.c</path>
<path>dmd25/statement.h</path>
<path>dmd25/staticassert.c</path>
<path>dmd25/staticassert.h</path>
<path>dmd25/stringtable.c</path>
<path>dmd25/stringtable.h</path>
<path>dmd25/struct.c</path>
<path>dmd25/template.c</path>
<path>dmd25/template.h</path>
<path>dmd25/total.h</path>
<path>dmd25/unialpha.c</path>
<path>dmd25/utf.c</path>
<path>dmd25/utf.h</path>
<path>dmd25/version.c</path>
<path>dmd25/version.h</path>
</blacklist>
<build>
<buildtool>make</buildtool>

View File

@@ -142,9 +142,10 @@ lphobos
lphobos/build.sh
lphobos/crc32.d
lphobos/gc
lphobos/gc/gc.d
lphobos/gc/gcbits.d
lphobos/gc/gclinux.d
lphobos/gc/gcstub.d
lphobos/gc/gcx.d
lphobos/gcstats.d
lphobos/internal
lphobos/internal/aApply.d
@@ -239,6 +240,666 @@ lphobos/typeinfos1.d
lphobos/typeinfos2.d
premake.lua
runalltests.d
tango
tango/lib
tango/lib/common
tango/lib/common/tango
tango/lib/common/tango/core
tango/lib/common/tango/core/BitManip.d
tango/lib/common/tango/core/Exception.d
tango/lib/common/tango/core/Memory.d
tango/lib/common/tango/core/Runtime.d
tango/lib/common/tango/core/Thread.d
tango/lib/common/tango/stdc
tango/lib/common/tango/stdc/posix
tango/lib/common/tango/stdc/posix/pthread_darwin.d
tango/lib/common/tango/stdc/wrap.c
tango/lib/compiler
tango/lib/compiler/dmd
tango/lib/compiler/dmd/aApply.d
tango/lib/compiler/dmd/aApplyR.d
tango/lib/compiler/dmd/aaA.d
tango/lib/compiler/dmd/adi.d
tango/lib/compiler/dmd/alloca.d
tango/lib/compiler/dmd/arraycast.d
tango/lib/compiler/dmd/arraycat.d
tango/lib/compiler/dmd/cast.d
tango/lib/compiler/dmd/cmath2.d
tango/lib/compiler/dmd/compiler.d
tango/lib/compiler/dmd/complex.c
tango/lib/compiler/dmd/cover.d
tango/lib/compiler/dmd/critical.c
tango/lib/compiler/dmd/deh.c
tango/lib/compiler/dmd/deh2.d
tango/lib/compiler/dmd/dmain2.d
tango/lib/compiler/dmd/genobj.d
tango/lib/compiler/dmd/invariant.d
tango/lib/compiler/dmd/lifetime.d
tango/lib/compiler/dmd/llmath.d
tango/lib/compiler/dmd/mars.h
tango/lib/compiler/dmd/memory.d
tango/lib/compiler/dmd/memset.d
tango/lib/compiler/dmd/monitor.c
tango/lib/compiler/dmd/obj.d
tango/lib/compiler/dmd/qsort.d
tango/lib/compiler/dmd/qsort2.d
tango/lib/compiler/dmd/switch.d
tango/lib/compiler/dmd/trace.d
tango/lib/compiler/dmd/typeinfo
tango/lib/compiler/dmd/typeinfo/ti_AC.d
tango/lib/compiler/dmd/typeinfo/ti_Acdouble.d
tango/lib/compiler/dmd/typeinfo/ti_Acfloat.d
tango/lib/compiler/dmd/typeinfo/ti_Acreal.d
tango/lib/compiler/dmd/typeinfo/ti_Adouble.d
tango/lib/compiler/dmd/typeinfo/ti_Afloat.d
tango/lib/compiler/dmd/typeinfo/ti_Ag.d
tango/lib/compiler/dmd/typeinfo/ti_Aint.d
tango/lib/compiler/dmd/typeinfo/ti_Along.d
tango/lib/compiler/dmd/typeinfo/ti_Areal.d
tango/lib/compiler/dmd/typeinfo/ti_Ashort.d
tango/lib/compiler/dmd/typeinfo/ti_C.d
tango/lib/compiler/dmd/typeinfo/ti_byte.d
tango/lib/compiler/dmd/typeinfo/ti_cdouble.d
tango/lib/compiler/dmd/typeinfo/ti_cfloat.d
tango/lib/compiler/dmd/typeinfo/ti_char.d
tango/lib/compiler/dmd/typeinfo/ti_creal.d
tango/lib/compiler/dmd/typeinfo/ti_dchar.d
tango/lib/compiler/dmd/typeinfo/ti_delegate.d
tango/lib/compiler/dmd/typeinfo/ti_double.d
tango/lib/compiler/dmd/typeinfo/ti_float.d
tango/lib/compiler/dmd/typeinfo/ti_idouble.d
tango/lib/compiler/dmd/typeinfo/ti_ifloat.d
tango/lib/compiler/dmd/typeinfo/ti_int.d
tango/lib/compiler/dmd/typeinfo/ti_ireal.d
tango/lib/compiler/dmd/typeinfo/ti_long.d
tango/lib/compiler/dmd/typeinfo/ti_ptr.d
tango/lib/compiler/dmd/typeinfo/ti_real.d
tango/lib/compiler/dmd/typeinfo/ti_short.d
tango/lib/compiler/dmd/typeinfo/ti_ubyte.d
tango/lib/compiler/dmd/typeinfo/ti_uint.d
tango/lib/compiler/dmd/typeinfo/ti_ulong.d
tango/lib/compiler/dmd/typeinfo/ti_ushort.d
tango/lib/compiler/dmd/typeinfo/ti_void.d
tango/lib/compiler/dmd/typeinfo/ti_wchar.d
tango/lib/compiler/dmd/util
tango/lib/compiler/dmd/util/console.d
tango/lib/compiler/dmd/util/ctype.d
tango/lib/compiler/dmd/util/string.d
tango/lib/compiler/dmd/util/utf.d
tango/lib/compiler/gdc
tango/lib/compiler/gdc/aApply.d
tango/lib/compiler/gdc/aApplyR.d
tango/lib/compiler/gdc/aaA.d
tango/lib/compiler/gdc/actest.d
tango/lib/compiler/gdc/adi.d
tango/lib/compiler/gdc/arraycast.d
tango/lib/compiler/gdc/arraycat.d
tango/lib/compiler/gdc/cast.d
tango/lib/compiler/gdc/cmain.d
tango/lib/compiler/gdc/cmath2.d
tango/lib/compiler/gdc/compiler.d
tango/lib/compiler/gdc/config
tango/lib/compiler/gdc/config.h
tango/lib/compiler/gdc/config/darwin8
tango/lib/compiler/gdc/config/gen_config1.c
tango/lib/compiler/gdc/config/gen_math.c
tango/lib/compiler/gdc/config/gen_unix.c
tango/lib/compiler/gdc/config/makestruct.h
tango/lib/compiler/gdc/config/mingw
tango/lib/compiler/gdc/config/skyos
tango/lib/compiler/gdc/critical.c
tango/lib/compiler/gdc/deh.c
tango/lib/compiler/gdc/dgccmain2.d
tango/lib/compiler/gdc/fpmath.d
tango/lib/compiler/gdc/gcc
tango/lib/compiler/gdc/gcc/aix_float.h
tango/lib/compiler/gdc/gcc/builtins.d
tango/lib/compiler/gdc/gcc/cbridge_fdset.c
tango/lib/compiler/gdc/gcc/cbridge_math.c
tango/lib/compiler/gdc/gcc/cbridge_stdio.c
tango/lib/compiler/gdc/gcc/cbridge_time.c
tango/lib/compiler/gdc/gcc/configext.d
tango/lib/compiler/gdc/gcc/configunix.d
tango/lib/compiler/gdc/gcc/deh.d
tango/lib/compiler/gdc/gcc/fpmath.d
tango/lib/compiler/gdc/gcc/support.d
tango/lib/compiler/gdc/gcc/threadsem.d
tango/lib/compiler/gdc/gcc/unwind.d
tango/lib/compiler/gdc/genobj.d
tango/lib/compiler/gdc/invariant.d
tango/lib/compiler/gdc/lifetime.d
tango/lib/compiler/gdc/mars.h
tango/lib/compiler/gdc/memory.d
tango/lib/compiler/gdc/memory_dyld.c
tango/lib/compiler/gdc/memory_freebsd.c
tango/lib/compiler/gdc/memset.d
tango/lib/compiler/gdc/minimal.c
tango/lib/compiler/gdc/monitor.c
tango/lib/compiler/gdc/obj.d
tango/lib/compiler/gdc/qsort2.d
tango/lib/compiler/gdc/qsortg.d
tango/lib/compiler/gdc/rundmain.d
tango/lib/compiler/gdc/std
tango/lib/compiler/gdc/std/intrinsic.d
tango/lib/compiler/gdc/switch.d
tango/lib/compiler/gdc/typeinfo
tango/lib/compiler/gdc/typeinfo/ti_AC.d
tango/lib/compiler/gdc/typeinfo/ti_Acdouble.d
tango/lib/compiler/gdc/typeinfo/ti_Acfloat.d
tango/lib/compiler/gdc/typeinfo/ti_Acreal.d
tango/lib/compiler/gdc/typeinfo/ti_Adouble.d
tango/lib/compiler/gdc/typeinfo/ti_Afloat.d
tango/lib/compiler/gdc/typeinfo/ti_Ag.d
tango/lib/compiler/gdc/typeinfo/ti_Aint.d
tango/lib/compiler/gdc/typeinfo/ti_Along.d
tango/lib/compiler/gdc/typeinfo/ti_Areal.d
tango/lib/compiler/gdc/typeinfo/ti_Ashort.d
tango/lib/compiler/gdc/typeinfo/ti_C.d
tango/lib/compiler/gdc/typeinfo/ti_byte.d
tango/lib/compiler/gdc/typeinfo/ti_cdouble.d
tango/lib/compiler/gdc/typeinfo/ti_cfloat.d
tango/lib/compiler/gdc/typeinfo/ti_char.d
tango/lib/compiler/gdc/typeinfo/ti_creal.d
tango/lib/compiler/gdc/typeinfo/ti_dchar.d
tango/lib/compiler/gdc/typeinfo/ti_delegate.d
tango/lib/compiler/gdc/typeinfo/ti_double.d
tango/lib/compiler/gdc/typeinfo/ti_float.d
tango/lib/compiler/gdc/typeinfo/ti_idouble.d
tango/lib/compiler/gdc/typeinfo/ti_ifloat.d
tango/lib/compiler/gdc/typeinfo/ti_int.d
tango/lib/compiler/gdc/typeinfo/ti_ireal.d
tango/lib/compiler/gdc/typeinfo/ti_long.d
tango/lib/compiler/gdc/typeinfo/ti_ptr.d
tango/lib/compiler/gdc/typeinfo/ti_real.d
tango/lib/compiler/gdc/typeinfo/ti_short.d
tango/lib/compiler/gdc/typeinfo/ti_ubyte.d
tango/lib/compiler/gdc/typeinfo/ti_uint.d
tango/lib/compiler/gdc/typeinfo/ti_ulong.d
tango/lib/compiler/gdc/typeinfo/ti_ushort.d
tango/lib/compiler/gdc/typeinfo/ti_void.d
tango/lib/compiler/gdc/typeinfo/ti_wchar.d
tango/lib/compiler/gdc/util
tango/lib/compiler/gdc/util/console.d
tango/lib/compiler/gdc/util/ctype.d
tango/lib/compiler/gdc/util/string.d
tango/lib/compiler/gdc/util/utf.d
tango/lib/compiler/llvmdc
tango/lib/compiler/llvmdc/aApply.d
tango/lib/compiler/llvmdc/aApplyR.d
tango/lib/compiler/llvmdc/aaA.d
tango/lib/compiler/llvmdc/adi.d
tango/lib/compiler/llvmdc/arrays.d
tango/lib/compiler/llvmdc/build.sh
tango/lib/compiler/llvmdc/cast.d
tango/lib/compiler/llvmdc/contract.d
tango/lib/compiler/llvmdc/genobj.d
tango/lib/compiler/llvmdc/llvm
tango/lib/compiler/llvmdc/llvm/intrinsic.di
tango/lib/compiler/llvmdc/obj
tango/lib/compiler/llvmdc/qsort2.d
tango/lib/compiler/llvmdc/std
tango/lib/compiler/llvmdc/std/intrinsic.d
tango/lib/compiler/llvmdc/switch.d
tango/lib/compiler/llvmdc/typeinfo
tango/lib/compiler/llvmdc/typeinfo/ti_AC.d
tango/lib/compiler/llvmdc/typeinfo/ti_Acdouble.d
tango/lib/compiler/llvmdc/typeinfo/ti_Acfloat.d
tango/lib/compiler/llvmdc/typeinfo/ti_Acreal.d
tango/lib/compiler/llvmdc/typeinfo/ti_Adouble.d
tango/lib/compiler/llvmdc/typeinfo/ti_Afloat.d
tango/lib/compiler/llvmdc/typeinfo/ti_Ag.d
tango/lib/compiler/llvmdc/typeinfo/ti_Aint.d
tango/lib/compiler/llvmdc/typeinfo/ti_Along.d
tango/lib/compiler/llvmdc/typeinfo/ti_Areal.d
tango/lib/compiler/llvmdc/typeinfo/ti_Ashort.d
tango/lib/compiler/llvmdc/typeinfo/ti_C.d
tango/lib/compiler/llvmdc/typeinfo/ti_byte.d
tango/lib/compiler/llvmdc/typeinfo/ti_cdouble.d
tango/lib/compiler/llvmdc/typeinfo/ti_cfloat.d
tango/lib/compiler/llvmdc/typeinfo/ti_char.d
tango/lib/compiler/llvmdc/typeinfo/ti_creal.d
tango/lib/compiler/llvmdc/typeinfo/ti_dchar.d
tango/lib/compiler/llvmdc/typeinfo/ti_delegate.d
tango/lib/compiler/llvmdc/typeinfo/ti_double.d
tango/lib/compiler/llvmdc/typeinfo/ti_float.d
tango/lib/compiler/llvmdc/typeinfo/ti_idouble.d
tango/lib/compiler/llvmdc/typeinfo/ti_ifloat.d
tango/lib/compiler/llvmdc/typeinfo/ti_int.d
tango/lib/compiler/llvmdc/typeinfo/ti_ireal.d
tango/lib/compiler/llvmdc/typeinfo/ti_long.d
tango/lib/compiler/llvmdc/typeinfo/ti_ptr.d
tango/lib/compiler/llvmdc/typeinfo/ti_real.d
tango/lib/compiler/llvmdc/typeinfo/ti_short.d
tango/lib/compiler/llvmdc/typeinfo/ti_ubyte.d
tango/lib/compiler/llvmdc/typeinfo/ti_uint.d
tango/lib/compiler/llvmdc/typeinfo/ti_ulong.d
tango/lib/compiler/llvmdc/typeinfo/ti_ushort.d
tango/lib/compiler/llvmdc/typeinfo/ti_void.d
tango/lib/compiler/llvmdc/typeinfo/ti_wchar.d
tango/lib/compiler/llvmdc/util
tango/lib/compiler/llvmdc/util/console.d
tango/lib/compiler/llvmdc/util/ctype.d
tango/lib/compiler/llvmdc/util/string.d
tango/lib/compiler/llvmdc/util/utf.d
tango/lib/gc
tango/lib/gc/basic
tango/lib/gc/basic/gc.d
tango/lib/gc/basic/gcalloc.d
tango/lib/gc/basic/gcbits.d
tango/lib/gc/basic/gcstats.d
tango/lib/gc/basic/gcx.d
tango/lib/gc/stub
tango/lib/gc/stub/gc.d
tango/object.di
tango/std
tango/std/c
tango/std/c/stdarg.di
tango/std/intrinsic.di
tango/std/stdarg.di
tango/tango
tango/tango/core
tango/tango/core/Array.d
tango/tango/core/Atomic.d
tango/tango/core/BitArray.d
tango/tango/core/BitManip.di
tango/tango/core/ByteSwap.d
tango/tango/core/Exception.di
tango/tango/core/Memory.di
tango/tango/core/Runtime.di
tango/tango/core/Signal.d
tango/tango/core/Thread.di
tango/tango/core/Traits.d
tango/tango/core/Tuple.d
tango/tango/core/Vararg.d
tango/tango/core/Variant.d
tango/tango/core/Version.d
tango/tango/core/sync
tango/tango/core/sync/Barrier.d
tango/tango/core/sync/Condition.d
tango/tango/core/sync/Config.d
tango/tango/core/sync/Mutex.d
tango/tango/core/sync/ReadWriteMutex.d
tango/tango/core/sync/Semaphore.d
tango/tango/group
tango/tango/group/collection.d
tango/tango/group/convert.d
tango/tango/group/digest.d
tango/tango/group/file.d
tango/tango/group/http.d
tango/tango/group/log.d
tango/tango/group/math.d
tango/tango/group/net.d
tango/tango/group/stream.d
tango/tango/group/text.d
tango/tango/group/time.d
tango/tango/io
tango/tango/io/Buffer.d
tango/tango/io/Conduit.d
tango/tango/io/Console.d
tango/tango/io/DeviceConduit.d
tango/tango/io/File.d
tango/tango/io/FileConduit.d
tango/tango/io/FileConst.d
tango/tango/io/FilePath.d
tango/tango/io/FileRoots.d
tango/tango/io/FileScan.d
tango/tango/io/FileSystem.d
tango/tango/io/GrowBuffer.d
tango/tango/io/MappedBuffer.d
tango/tango/io/Print.d
tango/tango/io/Stdout.d
tango/tango/io/TempFile.d
tango/tango/io/UnicodeFile.d
tango/tango/io/archive
tango/tango/io/archive/Zip.d
tango/tango/io/compress
tango/tango/io/compress/BzipStream.d
tango/tango/io/compress/ZlibStream.d
tango/tango/io/compress/c
tango/tango/io/compress/c/bzlib.d
tango/tango/io/compress/c/zlib.d
tango/tango/io/digest
tango/tango/io/digest/Crc32.d
tango/tango/io/digest/Digest.d
tango/tango/io/digest/Md2.d
tango/tango/io/digest/Md4.d
tango/tango/io/digest/Md5.d
tango/tango/io/digest/MerkleDamgard.d
tango/tango/io/digest/Sha0.d
tango/tango/io/digest/Sha01.d
tango/tango/io/digest/Sha1.d
tango/tango/io/digest/Sha256.d
tango/tango/io/digest/Sha512.d
tango/tango/io/digest/Tiger.d
tango/tango/io/model
tango/tango/io/model/IBuffer.d
tango/tango/io/model/IConduit.d
tango/tango/io/model/IListener.d
tango/tango/io/protocol
tango/tango/io/protocol/Allocator.d
tango/tango/io/protocol/EndianProtocol.d
tango/tango/io/protocol/NativeProtocol.d
tango/tango/io/protocol/PickleProtocol.d
tango/tango/io/protocol/Reader.d
tango/tango/io/protocol/Writer.d
tango/tango/io/protocol/model
tango/tango/io/protocol/model/IProtocol.d
tango/tango/io/protocol/model/IReader.d
tango/tango/io/protocol/model/IWriter.d
tango/tango/io/selector
tango/tango/io/selector/AbstractSelector.d
tango/tango/io/selector/EpollSelector.d
tango/tango/io/selector/PollSelector.d
tango/tango/io/selector/SelectSelector.d
tango/tango/io/selector/Selector.d
tango/tango/io/selector/SelectorException.d
tango/tango/io/selector/model
tango/tango/io/selector/model/ISelector.d
tango/tango/io/stream
tango/tango/io/stream/BufferStream.d
tango/tango/io/stream/DataFileStream.d
tango/tango/io/stream/DataStream.d
tango/tango/io/stream/DigestStream.d
tango/tango/io/stream/EndianStream.d
tango/tango/io/stream/FileStream.d
tango/tango/io/stream/FormatStream.d
tango/tango/io/stream/GreedyStream.d
tango/tango/io/stream/LineStream.d
tango/tango/io/stream/MapStream.d
tango/tango/io/stream/SnoopStream.d
tango/tango/io/stream/TextFileStream.d
tango/tango/io/stream/TypedStream.d
tango/tango/io/stream/UtfStream.d
tango/tango/io/vfs
tango/tango/io/vfs/FileFolder.d
tango/tango/io/vfs/LinkedFolder.d
tango/tango/io/vfs/VirtualFolder.d
tango/tango/io/vfs/ZipArchive.d
tango/tango/io/vfs/model
tango/tango/io/vfs/model/Vfs.d
tango/tango/math
tango/tango/math/Bessel.d
tango/tango/math/Elliptic.d
tango/tango/math/ErrorFunction.d
tango/tango/math/GammaFunction.d
tango/tango/math/IEEE.d
tango/tango/math/Math.d
tango/tango/math/Probability.d
tango/tango/math/Random.d
tango/tango/net
tango/tango/net/DatagramConduit.d
tango/tango/net/InternetAddress.d
tango/tango/net/MulticastConduit.d
tango/tango/net/ServerSocket.d
tango/tango/net/Socket.d
tango/tango/net/SocketConduit.d
tango/tango/net/SocketListener.d
tango/tango/net/Uri.d
tango/tango/net/cluster
tango/tango/net/cluster/CacheInvalidatee.d
tango/tango/net/cluster/CacheInvalidator.d
tango/tango/net/cluster/NetworkAlert.d
tango/tango/net/cluster/NetworkCache.d
tango/tango/net/cluster/NetworkCall.d
tango/tango/net/cluster/NetworkClient.d
tango/tango/net/cluster/NetworkMessage.d
tango/tango/net/cluster/NetworkQueue.d
tango/tango/net/cluster/NetworkRegistry.d
tango/tango/net/cluster/NetworkTask.d
tango/tango/net/cluster/QueuedCache.d
tango/tango/net/cluster/model
tango/tango/net/cluster/model/ICache.d
tango/tango/net/cluster/model/IChannel.d
tango/tango/net/cluster/model/ICluster.d
tango/tango/net/cluster/model/IConsumer.d
tango/tango/net/cluster/model/IMessage.d
tango/tango/net/cluster/tina
tango/tango/net/cluster/tina/CacheServer.d
tango/tango/net/cluster/tina/CacheThread.d
tango/tango/net/cluster/tina/Cluster.d
tango/tango/net/cluster/tina/ClusterCache.d
tango/tango/net/cluster/tina/ClusterQueue.d
tango/tango/net/cluster/tina/ClusterServer.d
tango/tango/net/cluster/tina/ClusterTask.d
tango/tango/net/cluster/tina/ClusterThread.d
tango/tango/net/cluster/tina/ClusterTypes.d
tango/tango/net/cluster/tina/CmdParser.d
tango/tango/net/cluster/tina/ProtocolReader.d
tango/tango/net/cluster/tina/ProtocolWriter.d
tango/tango/net/cluster/tina/QueueFile.d
tango/tango/net/cluster/tina/QueueServer.d
tango/tango/net/cluster/tina/QueueThread.d
tango/tango/net/cluster/tina/RollCall.d
tango/tango/net/cluster/tina/TaskServer.d
tango/tango/net/cluster/tina/TaskThread.d
tango/tango/net/cluster/tina/util
tango/tango/net/cluster/tina/util/AbstractServer.d
tango/tango/net/cluster/tina/util/ServerThread.d
tango/tango/net/cluster/tina/util/model
tango/tango/net/cluster/tina/util/model/IServer.d
tango/tango/net/ftp
tango/tango/net/ftp/FtpClient.d
tango/tango/net/ftp/Telnet.d
tango/tango/net/http
tango/tango/net/http/ChunkStream.d
tango/tango/net/http/HttpClient.d
tango/tango/net/http/HttpConst.d
tango/tango/net/http/HttpCookies.d
tango/tango/net/http/HttpGet.d
tango/tango/net/http/HttpHeaders.d
tango/tango/net/http/HttpParams.d
tango/tango/net/http/HttpPost.d
tango/tango/net/http/HttpStack.d
tango/tango/net/http/HttpTokens.d
tango/tango/net/http/HttpTriplet.d
tango/tango/net/http/model
tango/tango/net/http/model/HttpParamsView.d
tango/tango/net/model
tango/tango/net/model/UriView.d
tango/tango/stdc
tango/tango/stdc/complex.d
tango/tango/stdc/config.d
tango/tango/stdc/ctype.d
tango/tango/stdc/errno.d
tango/tango/stdc/fenv.d
tango/tango/stdc/inttypes.d
tango/tango/stdc/limits.d
tango/tango/stdc/locale.d
tango/tango/stdc/math.d
tango/tango/stdc/posix
tango/tango/stdc/posix/arpa
tango/tango/stdc/posix/arpa/inet.d
tango/tango/stdc/posix/config.d
tango/tango/stdc/posix/dirent.d
tango/tango/stdc/posix/dlfcn.d
tango/tango/stdc/posix/fcntl.d
tango/tango/stdc/posix/inttypes.d
tango/tango/stdc/posix/net
tango/tango/stdc/posix/net/if_.d
tango/tango/stdc/posix/netinet
tango/tango/stdc/posix/netinet/in_.d
tango/tango/stdc/posix/netinet/tcp.d
tango/tango/stdc/posix/poll.d
tango/tango/stdc/posix/pthread.d
tango/tango/stdc/posix/pwd.d
tango/tango/stdc/posix/sched.d
tango/tango/stdc/posix/semaphore.d
tango/tango/stdc/posix/setjmp.d
tango/tango/stdc/posix/signal.d
tango/tango/stdc/posix/stdio.d
tango/tango/stdc/posix/stdlib.d
tango/tango/stdc/posix/sys
tango/tango/stdc/posix/sys/ipc.d
tango/tango/stdc/posix/sys/mman.d
tango/tango/stdc/posix/sys/select.d
tango/tango/stdc/posix/sys/shm.d
tango/tango/stdc/posix/sys/socket.d
tango/tango/stdc/posix/sys/stat.d
tango/tango/stdc/posix/sys/time.d
tango/tango/stdc/posix/sys/types.d
tango/tango/stdc/posix/sys/uio.d
tango/tango/stdc/posix/sys/wait.d
tango/tango/stdc/posix/time.d
tango/tango/stdc/posix/ucontext.d
tango/tango/stdc/posix/unistd.d
tango/tango/stdc/posix/utime.d
tango/tango/stdc/signal.d
tango/tango/stdc/stdarg.d
tango/tango/stdc/stddef.d
tango/tango/stdc/stdint.d
tango/tango/stdc/stdio.d
tango/tango/stdc/stdlib.d
tango/tango/stdc/string.d
tango/tango/stdc/stringz.d
tango/tango/stdc/tgmath.d
tango/tango/stdc/time.d
tango/tango/stdc/wctype.d
tango/tango/sys
tango/tango/sys/Common.d
tango/tango/sys/Environment.d
tango/tango/sys/Pipe.d
tango/tango/sys/Process.d
tango/tango/sys/SharedLib.d
tango/tango/sys/darwin
tango/tango/sys/darwin/darwin.d
tango/tango/sys/linux
tango/tango/sys/linux/epoll.d
tango/tango/sys/linux/linux.d
tango/tango/sys/linux/socket.d
tango/tango/sys/win32
tango/tango/sys/win32/CodePage.d
tango/tango/sys/win32/Macros.di
tango/tango/sys/win32/Process.di
tango/tango/sys/win32/Types.di
tango/tango/sys/win32/UserGdi.di
tango/tango/text
tango/tango/text/Ascii.d
tango/tango/text/Properties.d
tango/tango/text/Regex.d
tango/tango/text/Text.d
tango/tango/text/Unicode.d
tango/tango/text/UnicodeData.d
tango/tango/text/Util.d
tango/tango/text/convert
tango/tango/text/convert/Float.d
tango/tango/text/convert/Format.d
tango/tango/text/convert/Integer.d
tango/tango/text/convert/Layout.d
tango/tango/text/convert/Sprint.d
tango/tango/text/convert/TimeStamp.d
tango/tango/text/convert/UnicodeBom.d
tango/tango/text/convert/Utf.d
tango/tango/text/locale
tango/tango/text/locale/Collation.d
tango/tango/text/locale/Convert.d
tango/tango/text/locale/Core.d
tango/tango/text/locale/Data.d
tango/tango/text/locale/Locale.d
tango/tango/text/locale/Parse.d
tango/tango/text/locale/Posix.d
tango/tango/text/locale/Win32.d
tango/tango/text/stream
tango/tango/text/stream/LineIterator.d
tango/tango/text/stream/QuoteIterator.d
tango/tango/text/stream/RegexIterator.d
tango/tango/text/stream/SimpleIterator.d
tango/tango/text/stream/StreamIterator.d
tango/tango/time
tango/tango/time/Clock.d
tango/tango/time/ISO8601.d
tango/tango/time/StopWatch.d
tango/tango/time/Time.d
tango/tango/time/WallClock.d
tango/tango/time/chrono
tango/tango/time/chrono/Calendar.d
tango/tango/time/chrono/Gregorian.d
tango/tango/time/chrono/GregorianBased.d
tango/tango/time/chrono/Hebrew.d
tango/tango/time/chrono/Hijri.d
tango/tango/time/chrono/Japanese.d
tango/tango/time/chrono/Korean.d
tango/tango/time/chrono/Taiwan.d
tango/tango/time/chrono/ThaiBuddhist.d
tango/tango/util
tango/tango/util/ArgParser.d
tango/tango/util/Arguments.d
tango/tango/util/Convert.d
tango/tango/util/PathUtil.d
tango/tango/util/collection
tango/tango/util/collection/ArrayBag.d
tango/tango/util/collection/ArraySeq.d
tango/tango/util/collection/CircularSeq.d
tango/tango/util/collection/HashMap.d
tango/tango/util/collection/HashSet.d
tango/tango/util/collection/LinkMap.d
tango/tango/util/collection/LinkSeq.d
tango/tango/util/collection/TreeBag.d
tango/tango/util/collection/TreeMap.d
tango/tango/util/collection/impl
tango/tango/util/collection/impl/AbstractIterator.d
tango/tango/util/collection/impl/BagCollection.d
tango/tango/util/collection/impl/CLCell.d
tango/tango/util/collection/impl/Cell.d
tango/tango/util/collection/impl/Collection.d
tango/tango/util/collection/impl/DefaultComparator.d
tango/tango/util/collection/impl/LLCell.d
tango/tango/util/collection/impl/LLPair.d
tango/tango/util/collection/impl/MapCollection.d
tango/tango/util/collection/impl/RBCell.d
tango/tango/util/collection/impl/RBPair.d
tango/tango/util/collection/impl/SeqCollection.d
tango/tango/util/collection/impl/SetCollection.d
tango/tango/util/collection/iterator
tango/tango/util/collection/iterator/ArrayIterator.d
tango/tango/util/collection/iterator/FilteringIterator.d
tango/tango/util/collection/iterator/InterleavingIterator.d
tango/tango/util/collection/model
tango/tango/util/collection/model/Bag.d
tango/tango/util/collection/model/BagView.d
tango/tango/util/collection/model/Comparator.d
tango/tango/util/collection/model/Dispenser.d
tango/tango/util/collection/model/GuardIterator.d
tango/tango/util/collection/model/HashParams.d
tango/tango/util/collection/model/Iterator.d
tango/tango/util/collection/model/Map.d
tango/tango/util/collection/model/MapView.d
tango/tango/util/collection/model/Seq.d
tango/tango/util/collection/model/SeqView.d
tango/tango/util/collection/model/Set.d
tango/tango/util/collection/model/SetView.d
tango/tango/util/collection/model/Sortable.d
tango/tango/util/collection/model/SortedKeys.d
tango/tango/util/collection/model/SortedValues.d
tango/tango/util/collection/model/View.d
tango/tango/util/log
tango/tango/util/log/Appender.d
tango/tango/util/log/Configurator.d
tango/tango/util/log/ConsoleAppender.d
tango/tango/util/log/DateLayout.d
tango/tango/util/log/Event.d
tango/tango/util/log/EventLayout.d
tango/tango/util/log/FileAppender.d
tango/tango/util/log/Hierarchy.d
tango/tango/util/log/Log.d
tango/tango/util/log/Log4Layout.d
tango/tango/util/log/Logger.d
tango/tango/util/log/MailAppender.d
tango/tango/util/log/NullAppender.d
tango/tango/util/log/PropertyConfigurator.d
tango/tango/util/log/RollingFileAppender.d
tango/tango/util/log/SocketAppender.d
tango/tango/util/log/Trace.d
tango/tango/util/log/model
tango/tango/util/log/model/IHierarchy.d
tango/tango/util/log/model/ILevel.d
tangotests
tangotests/a.d
tangotests/b.d
tangotests/c.d
tangotests/d.d
tangotests/e.d
tangotests/f.d
tangotests/g.d
test
test/a.d
test/aa1.d
@@ -391,6 +1052,7 @@ test/funcptr.d
test/funcs.d
test/funcs2.d
test/g.d
test/gc1.d
test/globals1.d
test/globals2.d
test/goto1.d

24
tango/LICENSE Normal file
View 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
View 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
View 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
View 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
}

View 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);}
}

View 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);
}

View 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 ...");
}

View 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;
}

View 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);
}

View 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);
}
}

View 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);
}

View 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");
}

View 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;
}

View 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);
}

View 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));
}

View 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);
}
}

View 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;
}
}

View 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");
}

View 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 ();
}
}
}
}

View 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);
}

View 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;
}

View 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");
}

View 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;
}

View 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);
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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;
}

View 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);
}

View 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();
}

View 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;
}

View 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;
}

View 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;
}

View 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
View 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
View 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 );
}

View 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
View 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

View 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);
}
}

View 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");
}
}

View 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);
}
}

View 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");
}

View 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;
}

View 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;
}

View 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) ();
}

View 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;
}

View 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;
}

View 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;
}

View 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");
}
}
}

View 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(&notifyOneTestThread);
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(&notifyAllTestThread);
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());
}
}

View 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");
}
}
}

View 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");
}
}
}

View 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;
}

View 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;
}
}

View 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
);
}

View 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;
}

View 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());
}
}

View 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);
}

View 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");
}

View 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);
}

View 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;
}

View 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;
}

View 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;
}

View 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 );
}
}

View 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 );
}

View 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 );
}

View 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();
}

File diff suppressed because it is too large Load Diff

View 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

View 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)/{} \;

View 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)/{} \;

View 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;
}
}

View File

@@ -0,0 +1,14 @@
#include <errno.h>
int getErrno()
{
return errno;
}
int setErrno( int val )
{
errno = val;
return val;
}

View 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
}

View 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)\.

View 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;
}

View 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);
}

Some files were not shown because too many files have changed in this diff Show More