mirror of
https://github.com/xomboverlord/ldc.git
synced 2026-01-11 18:33:14 +01:00
[svn r136] MAJOR UNSTABLE UPDATE!!!
Initial commit after moving to Tango instead of Phobos. Lots of bugfixes... This build is not suitable for most things.
This commit is contained in:
@@ -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
4
bin/llvmdc.phobos
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
[Environment]
|
||||
|
||||
DFLAGS=-I%@P%/../lphobos -E%@P%/../lib -L-L=%@P%/../lib
|
||||
4
bin/llvmdc.tango
Normal file
4
bin/llvmdc.tango
Normal file
@@ -0,0 +1,4 @@
|
||||
|
||||
[Environment]
|
||||
|
||||
DFLAGS=-I%@P%/../tango -E%@P%/../lib -L-L=%@P%/../lib
|
||||
@@ -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());
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ Global::Global()
|
||||
memset(¶ms, 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");
|
||||
|
||||
@@ -242,7 +242,7 @@ struct Loc
|
||||
|
||||
Loc(Module *mod, unsigned linnum);
|
||||
|
||||
char *toChars();
|
||||
char *toChars() const;
|
||||
};
|
||||
|
||||
#ifndef GCC_SAFE_DMD
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
232
gen/classes.cpp
232
gen/classes.cpp
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
525
gen/runtime.cpp
525
gen/runtime.cpp
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
146
gen/toir.cpp
146
gen/toir.cpp
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
172
llvmdc.kdevelop
172
llvmdc.kdevelop
@@ -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>
|
||||
|
||||
@@ -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
24
tango/LICENSE
Normal file
@@ -0,0 +1,24 @@
|
||||
Tango is Open Source software, distributed by a group of developers which has been set up for the purpose of providing a vendor-neutral owner of Tango intellectual property. The goals of all Tango licensing decisions are to:
|
||||
|
||||
* Encourage adoption
|
||||
* Discourage political contention
|
||||
* Encourage collaboration and integration with other projects
|
||||
* Be transparent
|
||||
|
||||
Tango is dual-licensed:
|
||||
* Academic Free License v2.1 (http://opensource.org/licenses/afl-2.1.php)
|
||||
* BSD License (http://opensource.org/licenses/bsd-license.php) [1]
|
||||
|
||||
The preferred license is the Academic Free License v2.1. All Tango projects release their code under the terms of this license. Both licenses:
|
||||
|
||||
* Allow commercial use without encumbrance
|
||||
* Provide broad rights to make new products and derivative works
|
||||
* Place no requirement on users to contribute back (although we appreciate it if you do)
|
||||
|
||||
Users who wish to include Tango with software licensed under the (L)GPL will want to use Tango under the terms of the BSD License. [1] Tango projects may request a variance from the developers to release their projects under additional licenses in conjunction with the AFL.
|
||||
|
||||
If you have further questions regarding Tango licensing, please do not hesitate to contact us (http://dsource.org/projects/tango/wiki/Contact).
|
||||
|
||||
|
||||
[1] The advertising clause has not been a part of the BSD License since July 22, 1999. (ftp://ftp.cs.berkeley.edu/pub/4bsd/README.Impt.License.Change)
|
||||
|
||||
7
tango/README.txt
Normal file
7
tango/README.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
For a guide to install Tango see the online installation reference:
|
||||
|
||||
http://dsource.org/projects/tango/wiki/TopicInstallTango
|
||||
|
||||
The license can be found at
|
||||
|
||||
http://dsource.org/projects/tango/wiki/LibraryLicense
|
||||
10
tango/README_LLVMDC.txt
Normal file
10
tango/README_LLVMDC.txt
Normal file
@@ -0,0 +1,10 @@
|
||||
This version of Tango is modified to work with LLVMDC
|
||||
by Tomas Lindquist Olsen, 2008
|
||||
|
||||
Much has been removed as this is not intended to work with other compilers.
|
||||
Hopefully in time, this will go away and the required changes merged into the
|
||||
mainline Tango repository.
|
||||
|
||||
For more information on LLVMDC, check the site at:
|
||||
|
||||
http://www.dsource.org/projects/llvmdc
|
||||
83
tango/dsss.conf
Normal file
83
tango/dsss.conf
Normal file
@@ -0,0 +1,83 @@
|
||||
name = tango
|
||||
|
||||
[tango/core]
|
||||
postinstall=install tango/core/BitManip.di $INCLUDE_PREFIX/tango/core ; \
|
||||
install tango/core/Exception.di $INCLUDE_PREFIX/tango/core ; \
|
||||
install tango/core/Memory.di $INCLUDE_PREFIX/tango/core ; \
|
||||
install tango/core/Runtime.di $INCLUDE_PREFIX/tango/core ; \
|
||||
install tango/core/Thread.di $INCLUDE_PREFIX/tango/core
|
||||
version (GNU) {
|
||||
prebuild = $DSSS_BUILD -obj -explicit lib/common/tango/core/BitManip.d -fintfc-file=tango/core/BitManip.di ; \
|
||||
$DSSS_BUILD -obj -explicit lib/common/tango/core/Exception.d -fintfc-file=tango/core/Exception.di ; \
|
||||
$DSSS_BUILD -obj -explicit lib/common/tango/core/Memory.d -fintfc-file=tango/core/Memory.di ; \
|
||||
$DSSS_BUILD -obj -explicit lib/common/tango/core/Runtime.d -fintfc-file=tango/core/Runtime.di ; \
|
||||
$DSSS_BUILD -obj -explicit lib/common/tango/core/Thread.d -fintfc-file=tango/core/Thread.di ;
|
||||
} else version (DigitalMars) {
|
||||
prebuild = $DSSS_BUILD -obj -explicit lib/common/tango/core/BitManip.d -Hftango/core/BitManip.di ; \
|
||||
$DSSS_BUILD -obj -explicit lib/common/tango/core/Exception.d -Hftango/core/Exception.di ; \
|
||||
$DSSS_BUILD -obj -explicit lib/common/tango/core/Memory.d -Hftango/core/Memory.di ; \
|
||||
$DSSS_BUILD -obj -explicit lib/common/tango/core/Runtime.d -Hftango/core/Runtime.di ; \
|
||||
$DSSS_BUILD -obj -explicit lib/common/tango/core/Thread.d -Hftango/core/Thread.di ;
|
||||
}
|
||||
else version (LLVMDC) {
|
||||
prebuild = $DSSS_BUILD -obj -explicit lib/common/tango/core/BitManip.d -Hftango/core/BitManip.di ; \
|
||||
$DSSS_BUILD -obj -explicit lib/common/tango/core/Exception.d -Hftango/core/Exception.di ; \
|
||||
$DSSS_BUILD -obj -explicit lib/common/tango/core/Memory.d -Hftango/core/Memory.di ; \
|
||||
$DSSS_BUILD -obj -explicit lib/common/tango/core/Runtime.d -Hftango/core/Runtime.di ; \
|
||||
$DSSS_BUILD -obj -explicit lib/common/tango/core/Thread.d -Hftango/core/Thread.di ;
|
||||
}
|
||||
|
||||
version(LLVMDC) {
|
||||
[tango/stdc]
|
||||
} else {
|
||||
|
||||
[tango/io]
|
||||
|
||||
[tango/math]
|
||||
|
||||
[tango/net]
|
||||
|
||||
[tango/stdc]
|
||||
version (Windows) {
|
||||
exclude = tango/stdc/posix
|
||||
}
|
||||
|
||||
[tango/sys]
|
||||
exclude = tango/sys/linux/* tango/sys/darwin/* tango/sys/win32/*
|
||||
exclude += tango/sys/TimeConverter.d
|
||||
|
||||
version (linux) {
|
||||
[tango/sys/linux]
|
||||
}
|
||||
|
||||
version (darwin) {
|
||||
[tango/sys/darwin]
|
||||
}
|
||||
|
||||
version (Windows) {
|
||||
[+tango/sys/win32]
|
||||
preinstall = install tango/sys/win32/Macros.di $INCLUDE_PREFIX/tango/sys/win32 ; \
|
||||
install tango/sys/win32/Process.di $INCLUDE_PREFIX/tango/sys/win32 ; \
|
||||
install tango/sys/win32/Types.di $INCLUDE_PREFIX/tango/sys/win32 ; \
|
||||
install tango/sys/win32/UserGdi.di $INCLUDE_PREFIX/tango/sys/win32
|
||||
}
|
||||
|
||||
[tango/text]
|
||||
|
||||
[tango/text/locale]
|
||||
version (!linux) {
|
||||
exclude += tango/text/locale/Linux.d
|
||||
}
|
||||
version (!Windows) {
|
||||
exclude += tango/text/locale/Win32.d
|
||||
}
|
||||
|
||||
[tango/util]
|
||||
|
||||
[tango/time]
|
||||
|
||||
[tango/group]
|
||||
|
||||
[+std]
|
||||
preinstall = installdir std $INCLUDE_PREFIX/std
|
||||
}
|
||||
60
tango/example/cluster/Add.d
Normal file
60
tango/example/cluster/Add.d
Normal file
@@ -0,0 +1,60 @@
|
||||
/*******************************************************************************
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
public import tango.net.cluster.NetworkCall;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
a Task function
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
real add (real x, real y)
|
||||
{
|
||||
return x + y;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
a Task function
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
int divide (int x, int y)
|
||||
{
|
||||
return x / y;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
a verbose Task message
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
class Subtract : NetworkCall
|
||||
{
|
||||
double a,
|
||||
b,
|
||||
result;
|
||||
|
||||
double opCall (double a, double b, IChannel channel = null)
|
||||
{
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
send (channel);
|
||||
return result;
|
||||
}
|
||||
|
||||
override void execute ()
|
||||
{
|
||||
result = a - b;
|
||||
}
|
||||
|
||||
override void read (IReader input) {input (a)(b)(result);}
|
||||
|
||||
override void write (IWriter output) {output (a)(b)(result);}
|
||||
}
|
||||
36
tango/example/cluster/alert.d
Normal file
36
tango/example/cluster/alert.d
Normal file
@@ -0,0 +1,36 @@
|
||||
private import tango.core.Thread;
|
||||
|
||||
private import tango.util.log.Configurator;
|
||||
|
||||
private import tango.net.cluster.NetworkAlert;
|
||||
|
||||
private import tango.net.cluster.tina.Cluster;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
How to send and recieve Alert messages using tango.net.cluster
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main()
|
||||
{
|
||||
// hook into the cluster
|
||||
auto cluster = (new Cluster).join;
|
||||
|
||||
// hook into the Alert layer
|
||||
auto alert = new NetworkAlert (cluster, "my.kind.of.alert");
|
||||
|
||||
// listen for the broadcast (on this channel)
|
||||
alert.createConsumer (delegate void (IEvent event)
|
||||
{event.log.info ("Recieved alert on channel " ~ event.channel.name);}
|
||||
);
|
||||
|
||||
// say what's going on
|
||||
alert.log.info ("broadcasting alert");
|
||||
|
||||
// and send everyone an empty alert (on this channel)
|
||||
alert.broadcast;
|
||||
|
||||
// wait for it to arrive ...
|
||||
Thread.sleep(1);
|
||||
}
|
||||
48
tango/example/cluster/cclient.d
Normal file
48
tango/example/cluster/cclient.d
Normal file
@@ -0,0 +1,48 @@
|
||||
/*******************************************************************************
|
||||
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
import tango.io.Stdout;
|
||||
|
||||
import tango.time.StopWatch;
|
||||
|
||||
import tango.util.log.Configurator;
|
||||
|
||||
import tango.net.cluster.NetworkCache;
|
||||
|
||||
import tango.net.cluster.tina.Cluster;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main (char[][] args)
|
||||
{
|
||||
StopWatch w;
|
||||
|
||||
if (args.length > 1)
|
||||
{
|
||||
auto cluster = (new Cluster).join (args[1..$]);
|
||||
auto cache = new NetworkCache (cluster, "my.cache.channel");
|
||||
|
||||
while (true)
|
||||
{
|
||||
w.start;
|
||||
for (int i=10000; i--;)
|
||||
cache.put ("key", cache.EmptyMessage);
|
||||
|
||||
Stdout.formatln ("{} put/s", 10000/w.stop);
|
||||
|
||||
w.start;
|
||||
for (int i=10000; i--;)
|
||||
cache.get ("key");
|
||||
|
||||
Stdout.formatln ("{} get/s", 10000/w.stop);
|
||||
}
|
||||
}
|
||||
else
|
||||
Stdout.formatln ("usage: cache cachehost:port ...");
|
||||
}
|
||||
|
||||
30
tango/example/cluster/cserver.d
Normal file
30
tango/example/cluster/cserver.d
Normal file
@@ -0,0 +1,30 @@
|
||||
/*******************************************************************************
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
import tango.io.Console;
|
||||
|
||||
import tango.net.InternetAddress;
|
||||
|
||||
import tango.net.cluster.tina.CmdParser,
|
||||
tango.net.cluster.tina.CacheServer;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main (char[][] args)
|
||||
{
|
||||
auto arg = new CmdParser ("cache.server");
|
||||
|
||||
// default number of cache entries
|
||||
arg.size = 8192;
|
||||
|
||||
if (args.length > 1)
|
||||
arg.parse (args[1..$]);
|
||||
|
||||
if (arg.help)
|
||||
Cout ("usage: cacheserver -port=number -size=cachesize -log[=trace, info, warn, error, fatal, none]").newline;
|
||||
else
|
||||
(new CacheServer(new InternetAddress(arg.port), arg.log, arg.size)).start;
|
||||
}
|
||||
38
tango/example/cluster/invalidate.d
Normal file
38
tango/example/cluster/invalidate.d
Normal file
@@ -0,0 +1,38 @@
|
||||
private import tango.core.Thread;
|
||||
|
||||
private import tango.util.log.Configurator;
|
||||
|
||||
private import tango.net.cluster.tina.Cluster;
|
||||
|
||||
private import tango.net.cluster.QueuedCache,
|
||||
tango.net.cluster.CacheInvalidatee,
|
||||
tango.net.cluster.CacheInvalidator;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Demonstrates how to invalidate cache entries across a cluster
|
||||
via a channel
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main()
|
||||
{
|
||||
// access the cluster
|
||||
auto cluster = (new Cluster).join;
|
||||
|
||||
// wrap a cache instance with a network listener
|
||||
auto dst = new CacheInvalidatee (cluster, "my.cache.channel", new QueuedCache!(char[], IMessage)(101));
|
||||
|
||||
// connect an invalidator to that cache channel
|
||||
auto src = new CacheInvalidator (cluster, "my.cache.channel");
|
||||
|
||||
// stuff something in the local cache
|
||||
dst.cache.put ("key", dst.EmptyMessage);
|
||||
|
||||
// get it removed via a network broadcast
|
||||
src.log.info ("invalidating 'key' across the cluster");
|
||||
src.invalidate ("key");
|
||||
|
||||
// wait for it to arrive ...
|
||||
Thread.sleep (1);
|
||||
}
|
||||
44
tango/example/cluster/qclient.d
Normal file
44
tango/example/cluster/qclient.d
Normal file
@@ -0,0 +1,44 @@
|
||||
/*******************************************************************************
|
||||
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
import tango.io.Stdout;
|
||||
|
||||
import tango.time.StopWatch;
|
||||
|
||||
import tango.util.log.Configurator;
|
||||
|
||||
import tango.net.cluster.NetworkQueue;
|
||||
|
||||
import tango.net.cluster.tina.Cluster;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main (char[][] args)
|
||||
{
|
||||
StopWatch w;
|
||||
|
||||
auto cluster = (new Cluster).join;
|
||||
auto queue = new NetworkQueue (cluster, "my.queue.channel");
|
||||
|
||||
while (true)
|
||||
{
|
||||
w.start;
|
||||
for (int i=10000; i--;)
|
||||
queue.put (queue.EmptyMessage);
|
||||
|
||||
Stdout.formatln ("{} put/s", 10000/w.stop);
|
||||
|
||||
uint count;
|
||||
w.start;
|
||||
while (queue.get !is null)
|
||||
++count;
|
||||
|
||||
Stdout.formatln ("{} get/s", count/w.stop);
|
||||
}
|
||||
}
|
||||
|
||||
41
tango/example/cluster/qlisten.d
Normal file
41
tango/example/cluster/qlisten.d
Normal file
@@ -0,0 +1,41 @@
|
||||
private import tango.core.Thread;
|
||||
|
||||
private import tango.util.log.Configurator;
|
||||
|
||||
private import tango.net.cluster.NetworkQueue;
|
||||
|
||||
private import tango.net.cluster.tina.Cluster;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Illustrates how to setup and use a Queue in asynchronous mode
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main ()
|
||||
{
|
||||
void listen (IEvent event)
|
||||
{
|
||||
while (event.get)
|
||||
event.log.info ("received asynch msg on channel " ~ event.channel.name);
|
||||
}
|
||||
|
||||
|
||||
// join the cluster
|
||||
auto cluster = (new Cluster).join;
|
||||
|
||||
// access a queue of the specified name
|
||||
auto queue = new NetworkQueue (cluster, "my.queue.channel");
|
||||
|
||||
// listen for messages placed in my queue, via a delegate
|
||||
queue.createConsumer (&listen);
|
||||
|
||||
// stuff something into the queue
|
||||
queue.log.info ("sending three messages to the queue");
|
||||
queue.put (queue.EmptyMessage);
|
||||
queue.put (queue.EmptyMessage);
|
||||
queue.put (queue.EmptyMessage);
|
||||
|
||||
// wait for asynchronous msgs to arrive ...
|
||||
Thread.sleep (1);
|
||||
}
|
||||
30
tango/example/cluster/qrequest.d
Normal file
30
tango/example/cluster/qrequest.d
Normal file
@@ -0,0 +1,30 @@
|
||||
private import tango.util.log.Configurator;
|
||||
|
||||
private import tango.net.cluster.NetworkQueue;
|
||||
|
||||
private import tango.net.cluster.tina.Cluster;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Illustrates how to setup and use a Queue in synchronous mode
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main ()
|
||||
{
|
||||
// join the cluster
|
||||
auto cluster = (new Cluster).join;
|
||||
|
||||
// access a queue of the specified name
|
||||
auto queue = new NetworkQueue (cluster, "my.queue.channel");
|
||||
|
||||
// stuff something into the queue
|
||||
queue.log.info ("sending three messages to the queue");
|
||||
queue.put (queue.EmptyMessage);
|
||||
queue.put (queue.EmptyMessage);
|
||||
queue.put (queue.EmptyMessage);
|
||||
|
||||
// retreive synchronously
|
||||
while (queue.get)
|
||||
queue.log.info ("retrieved msg");
|
||||
}
|
||||
27
tango/example/cluster/qserver.d
Normal file
27
tango/example/cluster/qserver.d
Normal file
@@ -0,0 +1,27 @@
|
||||
/*******************************************************************************
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
import tango.io.Console;
|
||||
|
||||
import tango.net.InternetAddress;
|
||||
|
||||
import tango.net.cluster.tina.CmdParser,
|
||||
tango.net.cluster.tina.QueueServer;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main (char[][] args)
|
||||
{
|
||||
auto arg = new CmdParser ("queue.server");
|
||||
|
||||
if (args.length > 1)
|
||||
arg.parse (args[1..$]);
|
||||
|
||||
if (arg.help)
|
||||
Cout ("usage: queueserver -port=number -log[=trace, info, warn, error, fatal, none]").newline;
|
||||
else
|
||||
(new QueueServer(new InternetAddress(arg.port), arg.log)).start;
|
||||
}
|
||||
38
tango/example/cluster/reply.d
Normal file
38
tango/example/cluster/reply.d
Normal file
@@ -0,0 +1,38 @@
|
||||
private import tango.core.Thread;
|
||||
|
||||
private import tango.util.log.Configurator;
|
||||
|
||||
private import tango.net.cluster.tina.Cluster;
|
||||
|
||||
private import tango.net.cluster.NetworkQueue;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main()
|
||||
{
|
||||
// open the cluster and a queue channel. Note that the queue has
|
||||
// been configured with a reply listener ...
|
||||
auto cluster = (new Cluster).join;
|
||||
auto queue = new NetworkQueue (cluster, "message.channel",
|
||||
(IEvent event){event.log.info ("Received reply");}
|
||||
);
|
||||
|
||||
void recipient (IEvent event)
|
||||
{
|
||||
auto msg = event.get;
|
||||
|
||||
event.log.info ("Replying to message on channel "~msg.reply);
|
||||
event.reply (event.replyChannel(msg), queue.EmptyMessage);
|
||||
}
|
||||
|
||||
// setup a listener to recieve and reply
|
||||
queue.createConsumer (&recipient);
|
||||
|
||||
// toss a message out to the cluster
|
||||
queue.put (queue.EmptyMessage);
|
||||
|
||||
// wait for completion ...
|
||||
Thread.sleep (1);
|
||||
}
|
||||
15
tango/example/cluster/task.d
Normal file
15
tango/example/cluster/task.d
Normal file
@@ -0,0 +1,15 @@
|
||||
/*******************************************************************************
|
||||
|
||||
Illustrates usage of cluster tasks
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
import Add, tango.io.Stdout, tango.net.cluster.tina.ClusterTask;
|
||||
|
||||
void main (char[][] args)
|
||||
{
|
||||
scope add = new NetCall!(add);
|
||||
|
||||
Stdout.formatln ("cluster expression of 3.0 + 4.0 = {}", add(3, 4));
|
||||
}
|
||||
|
||||
42
tango/example/cluster/tclient.d
Normal file
42
tango/example/cluster/tclient.d
Normal file
@@ -0,0 +1,42 @@
|
||||
/*******************************************************************************
|
||||
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
import Add;
|
||||
|
||||
import tango.io.Stdout;
|
||||
|
||||
import tango.time.StopWatch;
|
||||
|
||||
import tango.util.log.Configurator;
|
||||
|
||||
import tango.net.cluster.tina.ClusterTask;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main (char[][] args)
|
||||
{
|
||||
// an implicit task instance
|
||||
auto add = new NetCall!(add);
|
||||
|
||||
// an explicit task instance
|
||||
auto sub = new Subtract;
|
||||
|
||||
StopWatch w;
|
||||
while (true)
|
||||
{
|
||||
w.start;
|
||||
for (int i=10000; i--;)
|
||||
{
|
||||
// both task types are used in the same manner
|
||||
add (1, 2);
|
||||
sub (3, 4);
|
||||
}
|
||||
Stdout.formatln ("{} calls/s", 20000/w.stop);
|
||||
}
|
||||
}
|
||||
|
||||
34
tango/example/cluster/tserver.d
Normal file
34
tango/example/cluster/tserver.d
Normal file
@@ -0,0 +1,34 @@
|
||||
/*******************************************************************************
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
import tango.io.Console;
|
||||
|
||||
import tango.net.InternetAddress;
|
||||
|
||||
import tango.net.cluster.tina.CmdParser,
|
||||
tango.net.cluster.tina.TaskServer;
|
||||
|
||||
import Add;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main (char[][] args)
|
||||
{
|
||||
auto arg = new CmdParser ("task.server");
|
||||
|
||||
if (args.length > 1)
|
||||
arg.parse (args[1..$]);
|
||||
|
||||
if (arg.help)
|
||||
Cout ("usage: taskserver -port=number -log[=trace, info, warn, error, fatal, none]").newline;
|
||||
else
|
||||
{
|
||||
auto server = new TaskServer (new InternetAddress(arg.port), arg.log);
|
||||
server.enroll (new NetCall!(add));
|
||||
server.enroll (new Subtract);
|
||||
server.start;
|
||||
}
|
||||
}
|
||||
806
tango/example/concurrency/fiber_test.d
Normal file
806
tango/example/concurrency/fiber_test.d
Normal file
@@ -0,0 +1,806 @@
|
||||
import tango.core.Thread;
|
||||
|
||||
extern (C) int printf(char * str, ...);
|
||||
|
||||
void main()
|
||||
{
|
||||
printf("Compile with -unittest");
|
||||
}
|
||||
|
||||
|
||||
unittest
|
||||
{
|
||||
printf("Testing context creation/deletion\n");
|
||||
int s0 = 0;
|
||||
static int s1 = 0;
|
||||
|
||||
Fiber a = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
s0++;
|
||||
});
|
||||
|
||||
static void fb() { s1++; }
|
||||
|
||||
Fiber b = new Fiber(&fb);
|
||||
|
||||
Fiber c = new Fiber(
|
||||
delegate void() { assert(false); });
|
||||
|
||||
assert(a);
|
||||
assert(b);
|
||||
assert(c);
|
||||
|
||||
assert(s0 == 0);
|
||||
assert(s1 == 0);
|
||||
assert(a.state == Fiber.State.HOLD);
|
||||
assert(b.state == Fiber.State.HOLD);
|
||||
assert(c.state == Fiber.State.HOLD);
|
||||
|
||||
delete c;
|
||||
|
||||
assert(s0 == 0);
|
||||
assert(s1 == 0);
|
||||
assert(a.state == Fiber.State.HOLD);
|
||||
assert(b.state == Fiber.State.HOLD);
|
||||
|
||||
printf("running a\n");
|
||||
a.call();
|
||||
printf("done a\n");
|
||||
|
||||
assert(a);
|
||||
|
||||
assert(s0 == 1);
|
||||
assert(s1 == 0);
|
||||
assert(a.state == Fiber.State.TERM);
|
||||
assert(b.state == Fiber.State.HOLD);
|
||||
|
||||
assert(b.state == Fiber.State.HOLD);
|
||||
|
||||
printf("Running b\n");
|
||||
b.call();
|
||||
printf("Done b\n");
|
||||
|
||||
assert(s0 == 1);
|
||||
assert(s1 == 1);
|
||||
assert(b.state == Fiber.State.TERM);
|
||||
|
||||
delete a;
|
||||
delete b;
|
||||
|
||||
printf("Context creation passed\n");
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
printf("Testing context switching\n");
|
||||
int s0 = 0;
|
||||
int s1 = 0;
|
||||
int s2 = 0;
|
||||
|
||||
Fiber a = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
debug printf(" ---A---\n");
|
||||
s0++;
|
||||
Fiber.yield();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Fiber b = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
debug printf(" ---B---\n");
|
||||
s1++;
|
||||
Fiber.yield();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
Fiber c = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
debug printf(" ---C---\n");
|
||||
s2++;
|
||||
Fiber.yield();
|
||||
}
|
||||
});
|
||||
|
||||
assert(a);
|
||||
assert(b);
|
||||
assert(c);
|
||||
assert(s0 == 0);
|
||||
assert(s1 == 0);
|
||||
assert(s2 == 0);
|
||||
|
||||
a.call();
|
||||
b.call();
|
||||
|
||||
assert(a);
|
||||
assert(b);
|
||||
assert(c);
|
||||
assert(s0 == 1);
|
||||
assert(s1 == 1);
|
||||
assert(s2 == 0);
|
||||
|
||||
for(int i=0; i<20; i++)
|
||||
{
|
||||
c.call();
|
||||
a.call();
|
||||
}
|
||||
|
||||
assert(a);
|
||||
assert(b);
|
||||
assert(c);
|
||||
assert(s0 == 21);
|
||||
assert(s1 == 1);
|
||||
assert(s2 == 20);
|
||||
|
||||
delete a;
|
||||
delete b;
|
||||
delete c;
|
||||
|
||||
printf("Context switching passed\n");
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
printf("Testing nested contexts\n");
|
||||
Fiber a, b, c;
|
||||
|
||||
int t0 = 0;
|
||||
int t1 = 0;
|
||||
int t2 = 0;
|
||||
|
||||
a = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
|
||||
t0++;
|
||||
b.call();
|
||||
|
||||
});
|
||||
|
||||
b = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
assert(t0 == 1);
|
||||
assert(t1 == 0);
|
||||
assert(t2 == 0);
|
||||
|
||||
t1++;
|
||||
c.call();
|
||||
|
||||
});
|
||||
|
||||
c = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
assert(t0 == 1);
|
||||
assert(t1 == 1);
|
||||
assert(t2 == 0);
|
||||
|
||||
t2++;
|
||||
});
|
||||
|
||||
assert(a);
|
||||
assert(b);
|
||||
assert(c);
|
||||
assert(t0 == 0);
|
||||
assert(t1 == 0);
|
||||
assert(t2 == 0);
|
||||
|
||||
a.call();
|
||||
|
||||
assert(t0 == 1);
|
||||
assert(t1 == 1);
|
||||
assert(t2 == 1);
|
||||
|
||||
assert(a);
|
||||
assert(b);
|
||||
assert(c);
|
||||
|
||||
delete a;
|
||||
delete b;
|
||||
delete c;
|
||||
|
||||
printf("Nesting contexts passed\n");
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
printf("Testing basic exceptions\n");
|
||||
|
||||
|
||||
int t0 = 0;
|
||||
int t1 = 0;
|
||||
int t2 = 0;
|
||||
|
||||
assert(t0 == 0);
|
||||
assert(t1 == 0);
|
||||
assert(t2 == 0);
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
try
|
||||
{
|
||||
throw new Exception("Testing\n");
|
||||
t2++;
|
||||
}
|
||||
catch(Exception fx)
|
||||
{
|
||||
t1++;
|
||||
throw fx;
|
||||
}
|
||||
|
||||
t2++;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
t0++;
|
||||
printf("%.*s\n", ex.toString);
|
||||
}
|
||||
|
||||
assert(t0 == 1);
|
||||
assert(t1 == 1);
|
||||
assert(t2 == 0);
|
||||
|
||||
printf("Basic exceptions are supported\n");
|
||||
}
|
||||
|
||||
|
||||
unittest
|
||||
{
|
||||
printf("Testing exceptions\n");
|
||||
Fiber a, b, c;
|
||||
|
||||
int t0 = 0;
|
||||
int t1 = 0;
|
||||
int t2 = 0;
|
||||
|
||||
printf("t0 = %d\nt1 = %d\nt2 = %d\n", t0, t1, t2);
|
||||
|
||||
a = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
t0++;
|
||||
throw new Exception("A exception\n");
|
||||
t0++;
|
||||
});
|
||||
|
||||
b = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
t1++;
|
||||
c.call();
|
||||
t1++;
|
||||
});
|
||||
|
||||
c = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
t2++;
|
||||
throw new Exception("C exception\n");
|
||||
t2++;
|
||||
});
|
||||
|
||||
assert(a);
|
||||
assert(b);
|
||||
assert(c);
|
||||
assert(t0 == 0);
|
||||
assert(t1 == 0);
|
||||
assert(t2 == 0);
|
||||
|
||||
try
|
||||
{
|
||||
a.call();
|
||||
assert(false);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
printf("%.*s\n", e.toString);
|
||||
}
|
||||
|
||||
assert(a);
|
||||
assert(a.state == Fiber.State.TERM);
|
||||
assert(b);
|
||||
assert(c);
|
||||
assert(t0 == 1);
|
||||
assert(t1 == 0);
|
||||
assert(t2 == 0);
|
||||
|
||||
try
|
||||
{
|
||||
b.call();
|
||||
assert(false);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
printf("%.*s\n", e.toString);
|
||||
}
|
||||
|
||||
printf("blah2\n");
|
||||
|
||||
assert(a);
|
||||
assert(b);
|
||||
assert(b.state == Fiber.State.TERM);
|
||||
assert(c);
|
||||
assert(c.state == Fiber.State.TERM);
|
||||
assert(t0 == 1);
|
||||
assert(t1 == 1);
|
||||
assert(t2 == 1);
|
||||
|
||||
delete a;
|
||||
delete b;
|
||||
delete c;
|
||||
|
||||
|
||||
Fiber t;
|
||||
int q0 = 0;
|
||||
int q1 = 0;
|
||||
|
||||
t = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
try
|
||||
{
|
||||
q0++;
|
||||
throw new Exception("T exception\n");
|
||||
q0++;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
q1++;
|
||||
printf("!!!!!!!!GOT EXCEPTION!!!!!!!!\n");
|
||||
printf("%.*s\n", ex.toString);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
assert(t);
|
||||
assert(q0 == 0);
|
||||
assert(q1 == 0);
|
||||
t.call();
|
||||
assert(t);
|
||||
assert(t.state == Fiber.State.TERM);
|
||||
assert(q0 == 1);
|
||||
assert(q1 == 1);
|
||||
|
||||
delete t;
|
||||
|
||||
Fiber d, e;
|
||||
int s0 = 0;
|
||||
int s1 = 0;
|
||||
|
||||
d = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
try
|
||||
{
|
||||
s0++;
|
||||
e.call();
|
||||
Fiber.yield();
|
||||
s0++;
|
||||
e.call();
|
||||
s0++;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
printf("%.*s\n", ex.toString);
|
||||
}
|
||||
});
|
||||
|
||||
e = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
s1++;
|
||||
Fiber.yield();
|
||||
throw new Exception("E exception\n");
|
||||
s1++;
|
||||
});
|
||||
|
||||
assert(d);
|
||||
assert(e);
|
||||
assert(s0 == 0);
|
||||
assert(s1 == 0);
|
||||
|
||||
d.call();
|
||||
|
||||
assert(d);
|
||||
assert(e);
|
||||
assert(s0 == 1);
|
||||
assert(s1 == 1);
|
||||
|
||||
d.call();
|
||||
|
||||
assert(d);
|
||||
assert(e);
|
||||
assert(s0 == 2);
|
||||
assert(s1 == 1);
|
||||
|
||||
assert(d.state == Fiber.State.TERM);
|
||||
assert(e.state == Fiber.State.TERM);
|
||||
|
||||
delete d;
|
||||
delete e;
|
||||
|
||||
printf("Exceptions passed\n");
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
printf("Testing standard exceptions\n");
|
||||
int t = 0;
|
||||
|
||||
Fiber a = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
throw new Exception("BLAHAHA");
|
||||
});
|
||||
|
||||
assert(a);
|
||||
assert(t == 0);
|
||||
|
||||
try
|
||||
{
|
||||
a.call();
|
||||
assert(false);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
printf("%.*s\n", e.toString);
|
||||
}
|
||||
|
||||
assert(a);
|
||||
assert(a.state == Fiber.State.TERM);
|
||||
assert(t == 0);
|
||||
|
||||
delete a;
|
||||
|
||||
|
||||
printf("Standard exceptions passed\n");
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
printf("Memory stress test\n");
|
||||
|
||||
const uint STRESS_SIZE = 5000;
|
||||
|
||||
Fiber ctx[];
|
||||
ctx.length = STRESS_SIZE;
|
||||
|
||||
int cnt0 = 0;
|
||||
int cnt1 = 0;
|
||||
|
||||
void threadFunc()
|
||||
{
|
||||
cnt0++;
|
||||
Fiber.yield;
|
||||
cnt1++;
|
||||
}
|
||||
|
||||
foreach(inout Fiber c; ctx)
|
||||
{
|
||||
c = new Fiber(&threadFunc, 1024);
|
||||
}
|
||||
|
||||
assert(cnt0 == 0);
|
||||
assert(cnt1 == 0);
|
||||
|
||||
foreach(inout Fiber c; ctx)
|
||||
{
|
||||
c.call;
|
||||
}
|
||||
|
||||
assert(cnt0 == STRESS_SIZE);
|
||||
assert(cnt1 == 0);
|
||||
|
||||
foreach(inout Fiber c; ctx)
|
||||
{
|
||||
c.call;
|
||||
}
|
||||
|
||||
assert(cnt0 == STRESS_SIZE);
|
||||
assert(cnt1 == STRESS_SIZE);
|
||||
|
||||
foreach(inout Fiber c; ctx)
|
||||
{
|
||||
delete c;
|
||||
}
|
||||
|
||||
assert(cnt0 == STRESS_SIZE);
|
||||
assert(cnt1 == STRESS_SIZE);
|
||||
|
||||
printf("Memory stress test passed\n");
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
printf("Testing floating point\n");
|
||||
|
||||
float f0 = 1.0;
|
||||
float f1 = 0.0;
|
||||
|
||||
double d0 = 2.0;
|
||||
double d1 = 0.0;
|
||||
|
||||
real r0 = 3.0;
|
||||
real r1 = 0.0;
|
||||
|
||||
assert(f0 == 1.0);
|
||||
assert(f1 == 0.0);
|
||||
assert(d0 == 2.0);
|
||||
assert(d1 == 0.0);
|
||||
assert(r0 == 3.0);
|
||||
assert(r1 == 0.0);
|
||||
|
||||
Fiber a, b, c;
|
||||
|
||||
a = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
f0 ++;
|
||||
d0 ++;
|
||||
r0 ++;
|
||||
|
||||
Fiber.yield();
|
||||
}
|
||||
});
|
||||
|
||||
b = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
f1 = d0 + r0;
|
||||
d1 = f0 + r0;
|
||||
r1 = f0 + d0;
|
||||
|
||||
Fiber.yield();
|
||||
}
|
||||
});
|
||||
|
||||
c = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
f0 *= d1;
|
||||
d0 *= r1;
|
||||
r0 *= f1;
|
||||
|
||||
Fiber.yield();
|
||||
}
|
||||
});
|
||||
|
||||
a.call();
|
||||
assert(f0 == 2.0);
|
||||
assert(f1 == 0.0);
|
||||
assert(d0 == 3.0);
|
||||
assert(d1 == 0.0);
|
||||
assert(r0 == 4.0);
|
||||
assert(r1 == 0.0);
|
||||
|
||||
b.call();
|
||||
assert(f0 == 2.0);
|
||||
assert(f1 == 7.0);
|
||||
assert(d0 == 3.0);
|
||||
assert(d1 == 6.0);
|
||||
assert(r0 == 4.0);
|
||||
assert(r1 == 5.0);
|
||||
|
||||
c.call();
|
||||
assert(f0 == 12.0);
|
||||
assert(f1 == 7.0);
|
||||
assert(d0 == 15.0);
|
||||
assert(d1 == 6.0);
|
||||
assert(r0 == 28.0);
|
||||
assert(r1 == 5.0);
|
||||
|
||||
a.call();
|
||||
assert(f0 == 13.0);
|
||||
assert(f1 == 7.0);
|
||||
assert(d0 == 16.0);
|
||||
assert(d1 == 6.0);
|
||||
assert(r0 == 29.0);
|
||||
assert(r1 == 5.0);
|
||||
|
||||
printf("Floating point passed\n");
|
||||
}
|
||||
|
||||
|
||||
version(x86) unittest
|
||||
{
|
||||
printf("Testing registers\n");
|
||||
|
||||
struct registers
|
||||
{
|
||||
int eax, ebx, ecx, edx;
|
||||
int esi, edi;
|
||||
int ebp, esp;
|
||||
|
||||
//TODO: Add fpu stuff
|
||||
}
|
||||
|
||||
static registers old;
|
||||
static registers next;
|
||||
static registers g_old;
|
||||
static registers g_next;
|
||||
|
||||
//I believe that D calling convention requires that
|
||||
//EBX, ESI and EDI be saved. In order to validate
|
||||
//this, we write to those registers and call the
|
||||
//stack thread.
|
||||
static StackThread reg_test = new StackThread(
|
||||
delegate void()
|
||||
{
|
||||
asm
|
||||
{
|
||||
naked;
|
||||
|
||||
pushad;
|
||||
|
||||
mov EBX, 1;
|
||||
mov ESI, 2;
|
||||
mov EDI, 3;
|
||||
|
||||
mov [old.ebx], EBX;
|
||||
mov [old.esi], ESI;
|
||||
mov [old.edi], EDI;
|
||||
mov [old.ebp], EBP;
|
||||
mov [old.esp], ESP;
|
||||
|
||||
call StackThread.yield;
|
||||
|
||||
mov [next.ebx], EBX;
|
||||
mov [next.esi], ESI;
|
||||
mov [next.edi], EDI;
|
||||
mov [next.ebp], EBP;
|
||||
mov [next.esp], ESP;
|
||||
|
||||
popad;
|
||||
}
|
||||
});
|
||||
|
||||
//Run the stack context
|
||||
asm
|
||||
{
|
||||
naked;
|
||||
|
||||
pushad;
|
||||
|
||||
mov EBX, 10;
|
||||
mov ESI, 11;
|
||||
mov EDI, 12;
|
||||
|
||||
mov [g_old.ebx], EBX;
|
||||
mov [g_old.esi], ESI;
|
||||
mov [g_old.edi], EDI;
|
||||
mov [g_old.ebp], EBP;
|
||||
mov [g_old.esp], ESP;
|
||||
|
||||
mov EAX, [reg_test];
|
||||
call StackThread.call;
|
||||
|
||||
mov [g_next.ebx], EBX;
|
||||
mov [g_next.esi], ESI;
|
||||
mov [g_next.edi], EDI;
|
||||
mov [g_next.ebp], EBP;
|
||||
mov [g_next.esp], ESP;
|
||||
|
||||
popad;
|
||||
}
|
||||
|
||||
|
||||
//Make sure the registers are byte for byte equal.
|
||||
assert(old.ebx = 1);
|
||||
assert(old.esi = 2);
|
||||
assert(old.edi = 3);
|
||||
assert(old == next);
|
||||
|
||||
assert(g_old.ebx = 10);
|
||||
assert(g_old.esi = 11);
|
||||
assert(g_old.edi = 12);
|
||||
assert(g_old == g_next);
|
||||
|
||||
printf("Registers passed!\n");
|
||||
}
|
||||
|
||||
|
||||
unittest
|
||||
{
|
||||
printf("Testing throwYield\n");
|
||||
|
||||
int q0 = 0;
|
||||
|
||||
Fiber st0 = new Fiber(
|
||||
delegate void()
|
||||
{
|
||||
q0++;
|
||||
Fiber.yieldAndThrow(new Exception("testing throw yield\n"));
|
||||
q0++;
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
st0.call();
|
||||
assert(false);
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
printf("%.*s\n", e.toString);
|
||||
}
|
||||
|
||||
assert(q0 == 1);
|
||||
assert(st0.state == Fiber.State.HOLD);
|
||||
|
||||
st0.call();
|
||||
assert(q0 == 2);
|
||||
assert(st0.state == Fiber.State.TERM);
|
||||
|
||||
printf("throwYield passed!\n");
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
printf("Testing thread safety\n");
|
||||
|
||||
int x = 0, y = 0;
|
||||
|
||||
Fiber sc0 = new Fiber(
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
x++;
|
||||
Fiber.yield;
|
||||
}
|
||||
});
|
||||
|
||||
Fiber sc1 = new Fiber(
|
||||
{
|
||||
while(true)
|
||||
{
|
||||
y++;
|
||||
Fiber.yield;
|
||||
}
|
||||
});
|
||||
|
||||
Thread t0 = new Thread(
|
||||
{
|
||||
for(int i=0; i<10000; i++)
|
||||
sc0.call();
|
||||
});
|
||||
|
||||
Thread t1 = new Thread(
|
||||
{
|
||||
for(int i=0; i<10000; i++)
|
||||
sc1.call();
|
||||
});
|
||||
|
||||
assert(sc0);
|
||||
assert(sc1);
|
||||
assert(t0);
|
||||
assert(t1);
|
||||
|
||||
t0.start;
|
||||
t1.start;
|
||||
t0.join;
|
||||
t1.join;
|
||||
|
||||
assert(x == 10000);
|
||||
assert(y == 10000);
|
||||
|
||||
printf("Thread safety passed!\n");
|
||||
}
|
||||
|
||||
319
tango/example/conduits/FileBucket.d
Normal file
319
tango/example/conduits/FileBucket.d
Normal file
@@ -0,0 +1,319 @@
|
||||
module FileBucket;
|
||||
|
||||
private import tango.io.FilePath,
|
||||
tango.io.FileConduit;
|
||||
|
||||
private import tango.core.Exception;
|
||||
|
||||
/******************************************************************************
|
||||
|
||||
FileBucket implements a simple mechanism to store and recover a
|
||||
large quantity of data for the duration of the hosting process.
|
||||
It is intended to act as a local-cache for a remote data-source,
|
||||
or as a spillover area for large in-memory cache instances.
|
||||
|
||||
Note that any and all stored data is rendered invalid the moment
|
||||
a FileBucket object is garbage-collected.
|
||||
|
||||
The implementation follows a fixed-capacity record scheme, where
|
||||
content can be rewritten in-place until said capacity is reached.
|
||||
At such time, the altered content is moved to a larger capacity
|
||||
record at end-of-file, and a hole remains at the prior location.
|
||||
These holes are not collected, since the lifespan of a FileBucket
|
||||
is limited to that of the host process.
|
||||
|
||||
All index keys must be unique. Writing to the FileBucket with an
|
||||
existing key will overwrite any previous content. What follows
|
||||
is a contrived example:
|
||||
|
||||
---
|
||||
char[] text = "this is a test";
|
||||
|
||||
auto bucket = new FileBucket (new FilePath("bucket.bin"), FileBucket.HalfK);
|
||||
|
||||
// insert some data, and retrieve it again
|
||||
bucket.put ("a key", text);
|
||||
char[] b = cast(char[]) bucket.get ("a key");
|
||||
|
||||
assert (b == text);
|
||||
bucket.close;
|
||||
---
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
class FileBucket
|
||||
{
|
||||
/**********************************************************************
|
||||
|
||||
Define the capacity (block-size) of each record
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
struct BlockSize
|
||||
{
|
||||
int capacity;
|
||||
}
|
||||
|
||||
// basic capacity for each record
|
||||
private FilePath path;
|
||||
|
||||
// basic capacity for each record
|
||||
private BlockSize block;
|
||||
|
||||
// where content is stored
|
||||
private FileConduit file;
|
||||
|
||||
// pointers to file records
|
||||
private Record[char[]] map;
|
||||
|
||||
// current file size
|
||||
private long fileSize;
|
||||
|
||||
// current file usage
|
||||
private long waterLine;
|
||||
|
||||
// supported block sizes
|
||||
public static const BlockSize EighthK = {128-1},
|
||||
HalfK = {512-1},
|
||||
OneK = {1024*1-1},
|
||||
TwoK = {1024*2-1},
|
||||
FourK = {1024*4-1},
|
||||
EightK = {1024*8-1},
|
||||
SixteenK = {1024*16-1},
|
||||
ThirtyTwoK = {1024*32-1},
|
||||
SixtyFourK = {1024*64-1};
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
|
||||
Construct a FileBucket with the provided path and record-
|
||||
size. Selecting a record size that roughly matches the
|
||||
serialized content will limit 'thrashing'.
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
this (char[] path, BlockSize block)
|
||||
{
|
||||
this (new FilePath(path), block);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
|
||||
Construct a FileBucket with the provided path, record-size,
|
||||
and inital record count. The latter causes records to be
|
||||
pre-allocated, saving a certain amount of growth activity.
|
||||
Selecting a record size that roughly matches the serialized
|
||||
content will limit 'thrashing'.
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
this (FilePath path, BlockSize block, uint initialRecords = 100)
|
||||
{
|
||||
this.path = path;
|
||||
this.block = block;
|
||||
|
||||
// open a storage file
|
||||
file = new FileConduit (path, FileConduit.ReadWriteCreate);
|
||||
|
||||
// set initial file size (can be zero)
|
||||
fileSize = initialRecords * block.capacity;
|
||||
file.seek (fileSize);
|
||||
file.truncate ();
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
|
||||
Return the block-size in use for this FileBucket
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
int getBufferSize ()
|
||||
{
|
||||
return block.capacity+1;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
|
||||
Return where the FileBucket is located
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
FilePath getFilePath ()
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
|
||||
Return the currently populated size of this FileBucket
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
synchronized long length ()
|
||||
{
|
||||
return waterLine;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
|
||||
Return the serialized data for the provided key. Returns
|
||||
null if the key was not found.
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
synchronized void[] get (char[] key)
|
||||
{
|
||||
Record r = null;
|
||||
|
||||
if (key in map)
|
||||
{
|
||||
r = map [key];
|
||||
return r.read (this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
|
||||
Remove the provided key from this FileBucket.
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
synchronized void remove (char[] key)
|
||||
{
|
||||
map.remove(key);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
|
||||
Write a serialized block of data, and associate it with
|
||||
the provided key. All keys must be unique, and it is the
|
||||
responsibility of the programmer to ensure this. Reusing
|
||||
an existing key will overwrite previous data.
|
||||
|
||||
Note that data is allowed to grow within the occupied
|
||||
bucket until it becomes larger than the allocated space.
|
||||
When this happens, the data is moved to a larger bucket
|
||||
at the file tail.
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
synchronized void put (char[] key, void[] data)
|
||||
{
|
||||
Record* r = key in map;
|
||||
|
||||
if (r is null)
|
||||
{
|
||||
auto rr = new Record;
|
||||
map [key] = rr;
|
||||
r = &rr;
|
||||
}
|
||||
r.write (this, data, block);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
|
||||
Close this FileBucket -- all content is lost.
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
synchronized void close ()
|
||||
{
|
||||
if (file)
|
||||
{
|
||||
file.detach;
|
||||
file = null;
|
||||
map = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
|
||||
Each Record takes up a number of 'pages' within the file.
|
||||
The size of these pages is determined by the BlockSize
|
||||
provided during FileBucket construction. Additional space
|
||||
at the end of each block is potentially wasted, but enables
|
||||
content to grow in size without creating a myriad of holes.
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
private static class Record
|
||||
{
|
||||
private long offset;
|
||||
private int length,
|
||||
capacity = -1;
|
||||
|
||||
/**************************************************************
|
||||
|
||||
**************************************************************/
|
||||
|
||||
private static void eof (FileBucket bucket)
|
||||
{
|
||||
throw new IOException ("Unexpected EOF in FileBucket '"~bucket.path.toString()~"'");
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
|
||||
This should be protected from thread-contention at
|
||||
a higher level.
|
||||
|
||||
**************************************************************/
|
||||
|
||||
void[] read (FileBucket bucket)
|
||||
{
|
||||
void[] data = new ubyte [length];
|
||||
|
||||
bucket.file.seek (offset);
|
||||
if (bucket.file.read (data) != length)
|
||||
eof (bucket);
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
|
||||
This should be protected from thread-contention at
|
||||
a higher level.
|
||||
|
||||
**************************************************************/
|
||||
|
||||
void write (FileBucket bucket, void[] data, BlockSize block)
|
||||
{
|
||||
length = data.length;
|
||||
|
||||
// create new slot if we exceed capacity
|
||||
if (length > capacity)
|
||||
createBucket (bucket, length, block);
|
||||
|
||||
// locate to start of content
|
||||
bucket.file.seek (offset);
|
||||
|
||||
// write content
|
||||
if (bucket.file.write (data) != length)
|
||||
eof (bucket);
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
|
||||
**************************************************************/
|
||||
|
||||
void createBucket (FileBucket bucket, int bytes, BlockSize block)
|
||||
{
|
||||
offset = bucket.waterLine;
|
||||
capacity = (bytes + block.capacity) & ~block.capacity;
|
||||
|
||||
bucket.waterLine += capacity;
|
||||
if (bucket.waterLine > bucket.fileSize)
|
||||
{
|
||||
// grow the filesize
|
||||
bucket.fileSize = bucket.waterLine * 2;
|
||||
|
||||
// expand the physical file size
|
||||
bucket.file.seek (bucket.fileSize);
|
||||
bucket.file.truncate ();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
85
tango/example/conduits/composite.d
Normal file
85
tango/example/conduits/composite.d
Normal file
@@ -0,0 +1,85 @@
|
||||
|
||||
private import tango.io.protocol.Reader,
|
||||
tango.io.protocol.Writer,
|
||||
tango.io.FileConduit;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Use cascading reads & writes to handle a composite class. There is
|
||||
just one primary call for output, and just one for input, but the
|
||||
classes propogate the request as appropriate.
|
||||
|
||||
Note that the class instances don't know how their content will be
|
||||
represented; that is dictated by the caller (via the reader/writer
|
||||
implementation).
|
||||
|
||||
Note also that this only serializes the content. To serialize the
|
||||
classes too, take a look at the Pickle.d example.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main()
|
||||
{
|
||||
// define a serializable class (via interfaces)
|
||||
class Wumpus : IReadable, IWritable
|
||||
{
|
||||
private int a = 11,
|
||||
b = 112,
|
||||
c = 1024;
|
||||
|
||||
void read (IReader input)
|
||||
{
|
||||
input (a) (b) (c);
|
||||
}
|
||||
|
||||
void write (IWriter output)
|
||||
{
|
||||
output (a) (b) (c);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// define a serializable class (via interfaces)
|
||||
class Wombat : IReadable, IWritable
|
||||
{
|
||||
private Wumpus wumpus;
|
||||
private char[] x = "xyz";
|
||||
private bool y = true;
|
||||
private float z = 3.14159;
|
||||
|
||||
this (Wumpus wumpus)
|
||||
{
|
||||
this.wumpus = wumpus;
|
||||
}
|
||||
|
||||
void read (IReader input)
|
||||
{
|
||||
input (x) (y) (z) (wumpus);
|
||||
}
|
||||
|
||||
void write (IWriter output)
|
||||
{
|
||||
output (x) (y) (z) (wumpus);
|
||||
}
|
||||
}
|
||||
|
||||
// construct a Wombat
|
||||
auto wombat = new Wombat (new Wumpus);
|
||||
|
||||
// open a file for IO
|
||||
auto file = new FileConduit ("random.bin", FileConduit.ReadWriteCreate);
|
||||
|
||||
// construct reader & writer upon the file, with binary IO
|
||||
auto output = new Writer (file);
|
||||
auto input = new Reader (file);
|
||||
|
||||
// write both Wombat & Wumpus (and flush them)
|
||||
output (wombat) ();
|
||||
|
||||
// rewind to file start
|
||||
file.seek (0);
|
||||
|
||||
// read both back again
|
||||
input (wombat);
|
||||
}
|
||||
|
||||
30
tango/example/conduits/filebubbler.d
Normal file
30
tango/example/conduits/filebubbler.d
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
private import tango.io.Console,
|
||||
tango.io.FileScan,
|
||||
tango.io.FileConst;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
This example sweeps a named sub-directory tree for html files,
|
||||
and moves them to the current directory. The existing directory
|
||||
hierarchy is flattened into a naming scheme where a '.' is used
|
||||
to replace the traditional path-separator
|
||||
|
||||
Used by the Tango project to help manage renderings of the source
|
||||
code.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main(char[][] args)
|
||||
{
|
||||
// sweep all html files in the specified subdir
|
||||
if (args.length is 2)
|
||||
foreach (proxy; (new FileScan).sweep(args[1], ".html").files)
|
||||
{
|
||||
auto other = new FilePath (proxy.toString);
|
||||
proxy.rename (other.replace (FileConst.PathSeparatorChar, '.'));
|
||||
}
|
||||
else
|
||||
Cout ("usage is filebubbler subdir").newline;
|
||||
}
|
||||
|
||||
26
tango/example/conduits/filecat.d
Normal file
26
tango/example/conduits/filecat.d
Normal file
@@ -0,0 +1,26 @@
|
||||
private import tango.io.Console,
|
||||
tango.io.FileConduit;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Concatenate a number of files onto a single destination
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main(char[][] args)
|
||||
{
|
||||
if (args.length > 2)
|
||||
{
|
||||
// open the file for writing
|
||||
auto dst = new FileConduit (args[1], FileConduit.WriteCreate);
|
||||
|
||||
// copy each file onto dst
|
||||
foreach (char[] arg; args[2..args.length])
|
||||
dst.copy (new FileConduit(arg));
|
||||
|
||||
// flush output and close
|
||||
dst.close;
|
||||
}
|
||||
else
|
||||
Cout ("usage: filecat target source1 ... sourceN");
|
||||
}
|
||||
23
tango/example/conduits/filecopy.d
Normal file
23
tango/example/conduits/filecopy.d
Normal file
@@ -0,0 +1,23 @@
|
||||
|
||||
private import tango.io.Console,
|
||||
tango.io.FileConduit;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
open a file, and stream directly to console
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main (char[][] args)
|
||||
{
|
||||
if (args.length is 2)
|
||||
{
|
||||
// open a file for reading
|
||||
auto fc = new FileConduit (args[1]);
|
||||
|
||||
// stream directly to console
|
||||
Cout.stream.copy (fc);
|
||||
}
|
||||
else
|
||||
Cout ("usage is: filecopy filename").newline;
|
||||
}
|
||||
26
tango/example/conduits/fileops.d
Normal file
26
tango/example/conduits/fileops.d
Normal file
@@ -0,0 +1,26 @@
|
||||
/*****************************************************
|
||||
|
||||
Example that shows some simple file operations
|
||||
|
||||
Put into public domain by Lars Ivar Igesund
|
||||
|
||||
*****************************************************/
|
||||
|
||||
import tango.io.Stdout;
|
||||
|
||||
import tango.io.FilePath;
|
||||
|
||||
void main (char[][] args)
|
||||
{
|
||||
auto src = args[0] ~ ".d";
|
||||
auto dst = new FilePath (args[0] ~ ".d.copy");
|
||||
|
||||
Stdout.formatln ("copy file {} to {}", src, dst);
|
||||
dst.copy (src);
|
||||
assert (dst.exists);
|
||||
|
||||
Stdout.formatln ("removing file {}", dst);
|
||||
dst.remove;
|
||||
|
||||
assert (dst.exists is false);
|
||||
}
|
||||
11
tango/example/conduits/filepathname.d
Normal file
11
tango/example/conduits/filepathname.d
Normal file
@@ -0,0 +1,11 @@
|
||||
import tango.io.Console;
|
||||
|
||||
import tango.io.FilePath;
|
||||
|
||||
void main(){
|
||||
Cout ((new FilePath(r"d:\path\foo.bat")).name).newline;
|
||||
Cout ((new FilePath(r"d:\path.two\bar")).name).newline;
|
||||
Cout ((new FilePath("/home/user.name/bar.")).name).newline;
|
||||
Cout ((new FilePath(r"d:\path.two\bar")).name).newline;
|
||||
Cout ((new FilePath("/home/user/.resource")).name).newline;
|
||||
}
|
||||
32
tango/example/conduits/filescan.d
Normal file
32
tango/example/conduits/filescan.d
Normal file
@@ -0,0 +1,32 @@
|
||||
private import tango.io.Stdout,
|
||||
tango.io.FileScan;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
List ".d" files and enclosing folders visible via a directory given
|
||||
as a command-line argument. In this example we're also postponing a
|
||||
flush on Stdout until output is complete. Stdout is usually flushed
|
||||
on each invocation of newline or formatln, but here we're using '\n'
|
||||
to illustrate how to avoid flushing many individual lines
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main(char[][] args)
|
||||
{
|
||||
char[] root = args.length < 2 ? "." : args[1];
|
||||
Stdout.formatln ("Scanning '{}'", root);
|
||||
|
||||
auto scan = (new FileScan)(root, ".d");
|
||||
|
||||
Stdout.format ("\n{} Folders\n", scan.folders.length);
|
||||
foreach (folder; scan.folders)
|
||||
Stdout.format ("{}\n", folder);
|
||||
|
||||
Stdout.format ("\n{0} Files\n", scan.files.length);
|
||||
foreach (file; scan.files)
|
||||
Stdout.format ("{}\n", file);
|
||||
|
||||
Stdout.formatln ("\n{} Errors", scan.errors.length);
|
||||
foreach (error; scan.errors)
|
||||
Stdout (error).newline;
|
||||
}
|
||||
40
tango/example/conduits/filescanregex.d
Normal file
40
tango/example/conduits/filescanregex.d
Normal file
@@ -0,0 +1,40 @@
|
||||
/**************************************************************
|
||||
|
||||
Example that use FileScan and Regex as a filter.
|
||||
|
||||
Put into public domain by Lars Ivar Igesund
|
||||
|
||||
**************************************************************/
|
||||
|
||||
import tango.io.File,
|
||||
tango.io.Stdout,
|
||||
tango.io.FileScan,
|
||||
tango.text.Regex;
|
||||
|
||||
void main(char[][] args) {
|
||||
uint total;
|
||||
|
||||
if (args.length < 2) {
|
||||
Stdout("Please pass a directory to search").newline;
|
||||
return;
|
||||
}
|
||||
|
||||
scope scan = new FileScan;
|
||||
scope regex = Regex(r"\.(d|obj)$");
|
||||
|
||||
scan(args[1], delegate bool (FilePath fp, bool isDir) {
|
||||
++total;
|
||||
return isDir || regex.test(fp.toString);
|
||||
});
|
||||
|
||||
|
||||
foreach (file; scan.files)
|
||||
Stdout(file).newline;
|
||||
|
||||
Stdout.formatln("Found {} matches in {} entries", scan.files.length, total);
|
||||
|
||||
Stdout.formatln ("\n{} Errors", scan.errors.length);
|
||||
foreach (error; scan.errors)
|
||||
Stdout (error).newline;
|
||||
}
|
||||
|
||||
29
tango/example/conduits/lineio.d
Normal file
29
tango/example/conduits/lineio.d
Normal file
@@ -0,0 +1,29 @@
|
||||
|
||||
private import tango.io.Console,
|
||||
tango.io.FileConduit;
|
||||
|
||||
private import tango.text.stream.LineIterator;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Read a file line-by-line, sending each one to the console. This
|
||||
illustrates how to bind a conduit to a stream iterator (iterators
|
||||
also support the binding of a buffer). Note that stream iterators
|
||||
are templated for char, wchar and dchar types.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main (char[][] args)
|
||||
{
|
||||
if (args.length is 2)
|
||||
{
|
||||
// open a file for reading
|
||||
scope file = new FileConduit (args[1]);
|
||||
|
||||
// process file one line at a time
|
||||
foreach (line; new LineIterator!(char)(file))
|
||||
Cout (line).newline;
|
||||
}
|
||||
else
|
||||
Cout ("usage: lineio filename").newline;
|
||||
}
|
||||
24
tango/example/conduits/mmap.d
Normal file
24
tango/example/conduits/mmap.d
Normal file
@@ -0,0 +1,24 @@
|
||||
|
||||
private import tango.io.Console,
|
||||
tango.io.FileConduit,
|
||||
tango.io.MappedBuffer;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
open a file, map it into memory, and copy to console
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main (char[][] args)
|
||||
{
|
||||
if (args.length is 2)
|
||||
{
|
||||
// open a file for reading
|
||||
auto mmap = new MappedBuffer (new FileConduit (args[1]));
|
||||
|
||||
// copy content to console
|
||||
Cout (cast(char[]) mmap.slice) ();
|
||||
}
|
||||
else
|
||||
Cout ("usage is: mmap filename").newline;
|
||||
}
|
||||
13
tango/example/conduits/paths.d
Normal file
13
tango/example/conduits/paths.d
Normal file
@@ -0,0 +1,13 @@
|
||||
/*****************************************************
|
||||
|
||||
How to create a path with all ancestors
|
||||
|
||||
*****************************************************/
|
||||
|
||||
import tango.io.FilePath;
|
||||
|
||||
void main (char[][] args)
|
||||
{
|
||||
auto path = new FilePath (r"d/tango/foo/bar/wumpus");
|
||||
assert (path.create.exists && path.isFolder);
|
||||
}
|
||||
38
tango/example/conduits/randomio.d
Normal file
38
tango/example/conduits/randomio.d
Normal file
@@ -0,0 +1,38 @@
|
||||
|
||||
private import tango.io.FileConduit;
|
||||
|
||||
private import tango.io.protocol.Reader,
|
||||
tango.io.protocol.Writer;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Create a file for random access. Write some stuff to it, rewind to
|
||||
file start and read back.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main()
|
||||
{
|
||||
// open a file for reading
|
||||
auto fc = new FileConduit ("random.bin", FileConduit.ReadWriteCreate);
|
||||
|
||||
// construct (binary) reader & writer upon this conduit
|
||||
auto read = new Reader (fc);
|
||||
auto write = new Writer (fc);
|
||||
|
||||
int x=10, y=20;
|
||||
|
||||
// write some data and flush output since IO is buffered
|
||||
write (x) (y) ();
|
||||
|
||||
// rewind to file start
|
||||
fc.seek (0);
|
||||
|
||||
// read data back again, but swap destinations
|
||||
read (y) (x);
|
||||
|
||||
assert (y is 10);
|
||||
assert (x is 20);
|
||||
|
||||
fc.close();
|
||||
}
|
||||
25
tango/example/conduits/unifile.d
Normal file
25
tango/example/conduits/unifile.d
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
private import tango.io.Console,
|
||||
tango.io.UnicodeFile;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Open a unicode file of an unknown encoding, and converts to UTF-8
|
||||
for console display. UnicodeFile is templated for char/wchar/dchar
|
||||
target encodings
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main (char[][] args)
|
||||
{
|
||||
if (args.length is 2)
|
||||
{
|
||||
// open a file for reading
|
||||
auto file = new UnicodeFile!(char) (args[1], Encoding.Unknown);
|
||||
|
||||
// display on console
|
||||
Cout (file.read).newline;
|
||||
}
|
||||
else
|
||||
Cout ("usage is: unifile filename").newline;
|
||||
}
|
||||
17
tango/example/console/buffered.d
Normal file
17
tango/example/console/buffered.d
Normal file
@@ -0,0 +1,17 @@
|
||||
private import tango.stdc.stdio;
|
||||
|
||||
private import tango.io.Console;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Demonstrates buffered output. Console output (and Stdout etc) is
|
||||
buffered, requiring a flush or newline to render on the console.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main (char[][] args)
|
||||
{
|
||||
Cout ("how now ");
|
||||
printf ("printf\n");
|
||||
Cout ("brown cow").newline;
|
||||
}
|
||||
21
tango/example/console/hello.d
Normal file
21
tango/example/console/hello.d
Normal file
@@ -0,0 +1,21 @@
|
||||
/*******************************************************************************
|
||||
|
||||
Hello World using tango.io
|
||||
|
||||
This illustrates bare console output, with no fancy formatting.
|
||||
|
||||
Console I/O in Tango is UTF-8 across both linux and Win32. The
|
||||
conversion between various unicode representations is handled
|
||||
by higher level constructs, such as Stdout and Stderr
|
||||
|
||||
Note that Cerr is tied to the console error output, and Cin is
|
||||
tied to the console input.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
import tango.io.Console;
|
||||
|
||||
void main()
|
||||
{
|
||||
Cout ("hello, sweetheart \u263a").newline;
|
||||
}
|
||||
14
tango/example/console/stdout.d
Normal file
14
tango/example/console/stdout.d
Normal file
@@ -0,0 +1,14 @@
|
||||
/*******************************************************************************
|
||||
|
||||
Illustrates the basic console formatting. This is different than
|
||||
the use of tango.io.Console, in that Stdout supports a variety of
|
||||
printf-style formatting, and has unicode-conversion support
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
private import tango.io.Stdout;
|
||||
|
||||
void main()
|
||||
{
|
||||
Stdout ("hello, sweetheart \u263a").newline;
|
||||
}
|
||||
35
tango/example/dsss.conf
Normal file
35
tango/example/dsss.conf
Normal file
@@ -0,0 +1,35 @@
|
||||
[concurrency/fiber_test.d]
|
||||
[conduits/composite.d]
|
||||
[conduits/filebubbler.d]
|
||||
[conduits/filecat.d]
|
||||
[conduits/filecopy.d]
|
||||
[conduits/fileops.d]
|
||||
[conduits/filepathname.d]
|
||||
[conduits/filescan.d]
|
||||
[conduits/filescanregex.d]
|
||||
[conduits/lineio.d]
|
||||
[conduits/mmap.d]
|
||||
[conduits/paths.d]
|
||||
[conduits/randomio.d]
|
||||
[conduits/unifile.d]
|
||||
[console/hello.d]
|
||||
[console/stdout.d]
|
||||
[logging/chainsaw.d]
|
||||
[logging/logging.d]
|
||||
[logging/multilog.d]
|
||||
[manual/chapterStorage.d]
|
||||
[networking/homepage.d]
|
||||
[networking/httpget.d]
|
||||
[networking/selector.d]
|
||||
[networking/sockethello.d]
|
||||
[networking/socketserver.d]
|
||||
[system/arguments.d]
|
||||
[system/localtime.d]
|
||||
[system/normpath.d]
|
||||
[system/process.d]
|
||||
[text/formatalign.d]
|
||||
[text/formatindex.d]
|
||||
[text/formatspec.d]
|
||||
[text/localetime.d]
|
||||
[text/properties.d]
|
||||
[text/token.d]
|
||||
42
tango/example/external/GlueFlectioned.d
vendored
Normal file
42
tango/example/external/GlueFlectioned.d
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
import tango.core.Exception;
|
||||
import cn.kuehne.flectioned;
|
||||
|
||||
|
||||
TracedExceptionInfo traceHandler( void* ptr = null )
|
||||
{
|
||||
class FlectionedTrace :
|
||||
TracedExceptionInfo
|
||||
{
|
||||
this( void* ptr = null )
|
||||
{
|
||||
if( ptr )
|
||||
m_trace = Trace.getTrace( cast(size_t) ptr );
|
||||
else
|
||||
m_trace = Trace.getTrace();
|
||||
}
|
||||
|
||||
int opApply( int delegate( inout char[] ) dg )
|
||||
{
|
||||
int ret = 0;
|
||||
foreach( t; m_trace )
|
||||
{
|
||||
char[] buf = t.toString;
|
||||
ret = dg( buf );
|
||||
if( ret != 0 )
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
private:
|
||||
Trace[] m_trace;
|
||||
}
|
||||
|
||||
return new FlectionedTrace( ptr );
|
||||
}
|
||||
|
||||
|
||||
static this()
|
||||
{
|
||||
setTraceHandler( &traceHandler );
|
||||
}
|
||||
76
tango/example/jake-all.bat
Normal file
76
tango/example/jake-all.bat
Normal file
@@ -0,0 +1,76 @@
|
||||
@rem ###########################################################################
|
||||
@rem # CONCURRENCY EXAMPLES
|
||||
@rem ###########################################################################
|
||||
|
||||
@jake concurrency\fiber_test.d -I.. -op -unittest
|
||||
|
||||
@rem ###########################################################################
|
||||
@rem # CONDUIT EXAMPLES
|
||||
@rem ###########################################################################
|
||||
|
||||
@jake conduits\composite.d -I.. -op
|
||||
@jake conduits\filebubbler.d -I.. -op
|
||||
@jake -c conduits\filebucket.d -I.. -op
|
||||
@jake conduits\filecat.d -I.. -op
|
||||
@jake conduits\filecopy.d -I.. -op
|
||||
@jake conduits\filepathname.d -I.. -op
|
||||
@jake conduits\filescan.d -I.. -op
|
||||
@jake conduits\filescanregex.d -I.. -op
|
||||
@jake conduits\lineio.d -I.. -op
|
||||
@jake conduits\mmap.d -I.. -op
|
||||
@jake conduits\randomio.d -I.. -op
|
||||
@jake conduits\unifile.d -I.. -op
|
||||
|
||||
@rem ###########################################################################
|
||||
@rem # CONSOLE EXAMPLES
|
||||
@rem ###########################################################################
|
||||
|
||||
@jake console\hello.d -I.. -op
|
||||
@jake console\stdout.d -I.. -op
|
||||
|
||||
@rem ###########################################################################
|
||||
@rem # LOGGING EXAMPLES
|
||||
@rem ###########################################################################
|
||||
|
||||
@jake logging\chainsaw.d -I.. -op
|
||||
@jake logging\logging.d -I.. -op
|
||||
|
||||
@rem ###########################################################################
|
||||
@rem # REFERENCE MANUAL EXAMPLES
|
||||
@rem ###########################################################################
|
||||
|
||||
@jake manual\chapterStorage.d -I.. -op
|
||||
|
||||
@rem ###########################################################################
|
||||
@rem # NETWORKING EXAMPLES
|
||||
@rem ###########################################################################
|
||||
|
||||
@jake networking\homepage.d -I.. -op
|
||||
@jake networking\httpget.d -I.. -op
|
||||
@jake networking\sockethello.d -I.. -op
|
||||
@jake networking\socketserver.d -I.. -op
|
||||
@jake networking\selector.d -I.. -op
|
||||
|
||||
@rem ###########################################################################
|
||||
@rem # SYSTEM EXAMPLES
|
||||
@rem ###########################################################################
|
||||
|
||||
@jake system\argparser.d -I.. -op
|
||||
@jake system\localtime.d -I.. -op
|
||||
@jake system\normpath.d -I.. -op
|
||||
@jake system\process.d -I.. -op
|
||||
|
||||
@rem ###########################################################################
|
||||
@rem # TEXT EXAMPLES
|
||||
@rem ###########################################################################
|
||||
|
||||
@jake text\formatalign.d -I.. -op
|
||||
@jake text\formatindex.d -I.. -op
|
||||
@jake text\formatspec.d -I.. -op
|
||||
@jake text\localetime.d -I.. -op
|
||||
@jake text\token.d -I.. -op
|
||||
|
||||
@rem FINI
|
||||
|
||||
@del *.map
|
||||
@dir *.exe
|
||||
89
tango/example/linux.mak
Normal file
89
tango/example/linux.mak
Normal file
@@ -0,0 +1,89 @@
|
||||
# Makefile to build the examples of tango for Linux
|
||||
# Designed to work with GNU make
|
||||
# Targets:
|
||||
# make
|
||||
# Same as make all
|
||||
# make all
|
||||
# Build all examples
|
||||
#
|
||||
# make <executable-name>
|
||||
# Build a specified example
|
||||
# make clean
|
||||
# remove all build examples
|
||||
#
|
||||
#
|
||||
|
||||
# Relative path to the tango include dir
|
||||
# This is where the tango tree is located
|
||||
TANGO_DIR = ..
|
||||
|
||||
# The build tool executable from dsource.org/projects/build
|
||||
BUILDTOOL = bud
|
||||
BUILDOPTS = -noautoimport -op -clean -full -g -debug -I$(TANGO_DIR)
|
||||
|
||||
.PHONY: all clean
|
||||
|
||||
# Standard target
|
||||
all :
|
||||
|
||||
# networking/httpserver \
|
||||
# networking/servlets \
|
||||
# networking/servletserver\
|
||||
|
||||
SIMPLE_EXAMPLES =\
|
||||
concurrency/fiber_test \
|
||||
conduits/FileBucket \
|
||||
conduits/composite \
|
||||
conduits/filebubbler \
|
||||
conduits/filecat \
|
||||
conduits/filecopy \
|
||||
conduits/fileops \
|
||||
conduits/filepathname \
|
||||
conduits/filescan \
|
||||
conduits/filescanregex \
|
||||
conduits/lineio \
|
||||
conduits/mmap \
|
||||
conduits/randomio \
|
||||
conduits/unifile \
|
||||
console/hello \
|
||||
console/stdout \
|
||||
logging/chainsaw \
|
||||
logging/logging \
|
||||
networking/homepage \
|
||||
networking/httpget \
|
||||
networking/sockethello \
|
||||
networking/socketserver \
|
||||
system/argparser \
|
||||
system/localtime \
|
||||
system/normpath \
|
||||
system/process \
|
||||
networking/selector \
|
||||
text/formatalign \
|
||||
text/formatindex \
|
||||
text/formatspec \
|
||||
text/localetime \
|
||||
text/properties \
|
||||
text/token
|
||||
|
||||
REFERENCE_EXAMPLES = \
|
||||
./reference/chapter4 \
|
||||
./reference/chapter11
|
||||
|
||||
$(SIMPLE_EXAMPLES) : % : %.d
|
||||
@echo "Building : " $@
|
||||
$(BUILDTOOL) $< $(BUILDOPTS) -T$@ -unittest
|
||||
|
||||
$(REFERENCE_EXAMPLES) : % : %.d
|
||||
@echo "Building : " $@
|
||||
$(BUILDTOOL) $< $(BUILDOPTS) -T$@
|
||||
|
||||
all : $(SIMPLE_EXAMPLES)
|
||||
|
||||
clean :
|
||||
@echo "Removing all examples"
|
||||
rm -f $(SIMPLE_EXAMPLES) $(REFERENCE_EXAMPLES)
|
||||
rm -f conduits/random.bin
|
||||
|
||||
|
||||
|
||||
|
||||
30
tango/example/logging/chainsaw.d
Normal file
30
tango/example/logging/chainsaw.d
Normal file
@@ -0,0 +1,30 @@
|
||||
import tango.core.Thread;
|
||||
|
||||
import tango.util.log.Log,
|
||||
tango.util.log.Log4Layout,
|
||||
tango.util.log.SocketAppender;
|
||||
|
||||
import tango.net.InternetAddress;
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Hooks up to Chainsaw for remote log capture. Chainsaw should be
|
||||
configured to listen with an XMLSocketReciever
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main()
|
||||
{
|
||||
// get a logger to represent this module
|
||||
auto logger = Log.getLogger ("example.chainsaw");
|
||||
|
||||
// hook up an appender for XML output
|
||||
logger.addAppender (new SocketAppender (new InternetAddress("127.0.0.1", 4448), new Log4Layout));
|
||||
|
||||
while (true)
|
||||
{
|
||||
logger.info ("Hello Chainsaw!");
|
||||
Thread.sleep (1.0);
|
||||
}
|
||||
}
|
||||
322
tango/example/logging/context.d
Normal file
322
tango/example/logging/context.d
Normal file
@@ -0,0 +1,322 @@
|
||||
/*******************************************************************************
|
||||
|
||||
copyright: Copyright (c) 2007 Stonecobra. All rights reserved
|
||||
|
||||
license: BSD style: $(LICENSE)
|
||||
|
||||
version: Initial release: December 2007
|
||||
|
||||
author: stonecobra
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
module context;
|
||||
|
||||
import tango.core.Thread,
|
||||
tango.util.log.Log,
|
||||
tango.util.log.Event,
|
||||
tango.util.log.EventLayout,
|
||||
tango.util.log.ConsoleAppender;
|
||||
|
||||
import tango.util.log.model.IHierarchy;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Allows the dynamic setting of log levels on a per-thread basis.
|
||||
Imagine that a user request comes into your production threaded
|
||||
server. You can't afford to turn logging up to trace for the sake
|
||||
of debugging this one users problem, but you also can't afford to
|
||||
find the problem and fix it. So now you just set the override log
|
||||
level to TRACE for the thread the user is on, and you get full trace
|
||||
output for only that user.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
class ThreadLocalDiagnosticContext : IHierarchy.Context
|
||||
{
|
||||
private ThreadLocal!(DCData) dcData;
|
||||
private char[128] tmp;
|
||||
|
||||
/***********************************************************************
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
public this()
|
||||
{
|
||||
dcData = new ThreadLocal!(DCData);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
||||
set the 'diagnostic' Level for logging. This overrides
|
||||
the Level in the current Logger. The default level starts
|
||||
at NONE, so as not to modify the behavior of existing clients
|
||||
of tango.util.log
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
void setLevel (ILevel.Level level)
|
||||
{
|
||||
auto data = dcData.val;
|
||||
data.level = level;
|
||||
dcData.val = data;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
||||
All log appends will be checked against this to see if a
|
||||
log level needs to be temporarily adjusted.
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
bool isEnabled (ILevel.Level setting, ILevel.Level level = ILevel.Level.Trace)
|
||||
{
|
||||
return level >= setting || level >= dcData.val.level;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
||||
Return the label to use for the current log message. Usually
|
||||
called by the Layout. This implementation returns "{}".
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
char[] label ()
|
||||
{
|
||||
return dcData.val.getLabel;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
||||
Push another string into the 'stack'. This strings will be
|
||||
appened together when getLabel is called.
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
void push (char[] label)
|
||||
{
|
||||
auto data = dcData.val;
|
||||
data.push(label);
|
||||
dcData.val = data;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
||||
pop the current label off the stack.
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
void pop ()
|
||||
{
|
||||
auto data = dcData.val;
|
||||
data.pop;
|
||||
dcData.val = data;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
|
||||
Clear the label stack.
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
void clear()
|
||||
{
|
||||
auto data = dcData.val;
|
||||
data.clear;
|
||||
dcData.val = data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
The thread locally stored struct to hold the logging level and
|
||||
the label stack.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
private struct DCData {
|
||||
|
||||
ILevel.Level level = ILevel.Level.None;
|
||||
char[][8] stack;
|
||||
bool shouldUpdate = true;
|
||||
int stackIndex = 0;
|
||||
uint labelLength;
|
||||
char[256] labelContent;
|
||||
|
||||
|
||||
char[] getLabel() {
|
||||
if (shouldUpdate) {
|
||||
labelLength = 0;
|
||||
append(" {");
|
||||
for (int i = 0; i < stackIndex; i++) {
|
||||
append(stack[i]);
|
||||
if (i < stackIndex - 1) {
|
||||
append(" ");
|
||||
}
|
||||
}
|
||||
append("}");
|
||||
shouldUpdate = false;
|
||||
}
|
||||
return labelContent[0..labelLength];
|
||||
}
|
||||
|
||||
void append(char[] x) {
|
||||
uint addition = x.length;
|
||||
uint newLength = labelLength + x.length;
|
||||
|
||||
if (newLength < labelContent.length)
|
||||
{
|
||||
labelContent [labelLength..newLength] = x[0..addition];
|
||||
labelLength = newLength;
|
||||
}
|
||||
}
|
||||
|
||||
void push(char[] label) {
|
||||
shouldUpdate = true;
|
||||
stack[stackIndex] = label.dup;
|
||||
stackIndex++;
|
||||
}
|
||||
|
||||
void pop() {
|
||||
shouldUpdate = true;
|
||||
if (stackIndex > 0) {
|
||||
stack[stackIndex] = null;
|
||||
stackIndex--;
|
||||
}
|
||||
}
|
||||
|
||||
void clear() {
|
||||
shouldUpdate = true;
|
||||
for (int i = 0; i < stack.length; i++) {
|
||||
stack[i] = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Simple console appender that counts the number of log lines it
|
||||
has written.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
class TestingConsoleAppender : ConsoleAppender {
|
||||
|
||||
int events = 0;
|
||||
|
||||
this (EventLayout layout = null)
|
||||
{
|
||||
super(layout);
|
||||
}
|
||||
|
||||
override void append (Event event)
|
||||
{
|
||||
events++;
|
||||
super.append(event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Testing harness for the DiagnosticContext functionality.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main(char[][] args)
|
||||
{
|
||||
//set up our appender that counts the log output. This is the configuration
|
||||
//equivalent of importing tango.util.log.Configurator.
|
||||
auto appender = new TestingConsoleAppender(new SimpleTimerLayout);
|
||||
Log.getRootLogger.addAppender(appender);
|
||||
|
||||
char[128] tmp = 0;
|
||||
auto log = Log.getLogger("context");
|
||||
log.setLevel(log.Level.Info);
|
||||
|
||||
//first test, use all defaults, validating it is working. None of the trace()
|
||||
//calls should count in the test.
|
||||
for (int i=0;i < 10; i++) {
|
||||
log.info(log.format(tmp, "test1 {}", i));
|
||||
log.trace(log.format(tmp, "test1 {}", i));
|
||||
}
|
||||
if (appender.events !is 10) {
|
||||
log.error(log.format(tmp, "events:{}", appender.events));
|
||||
throw new Exception("Incorrect Number of events in normal mode");
|
||||
}
|
||||
|
||||
appender.events = 0;
|
||||
|
||||
//test the thread local implementation without any threads, as a baseline.
|
||||
//should be same result as test1
|
||||
auto context = new ThreadLocalDiagnosticContext;
|
||||
Log.getHierarchy.context(context);
|
||||
for (int i=0;i < 10; i++) {
|
||||
log.info(log.format(tmp, "test2 {}", i));
|
||||
log.trace(log.format(tmp, "test2 {}", i));
|
||||
}
|
||||
if (appender.events !is 10) {
|
||||
log.error(log.format(tmp, "events:{}", appender.events));
|
||||
throw new Exception("Incorrect Number of events in TLS single thread mode");
|
||||
}
|
||||
|
||||
appender.events = 0;
|
||||
|
||||
//test the thread local implementation without any threads, as a baseline.
|
||||
//This should count all logging requests, because the DiagnosticContext has
|
||||
//'overridden' the logging level on ALL loggers up to TRACE.
|
||||
context.setLevel(log.Level.Trace);
|
||||
for (int i=0;i < 10; i++) {
|
||||
log.info(log.format(tmp, "test3 {}", i));
|
||||
log.trace(log.format(tmp, "test3 {}", i));
|
||||
}
|
||||
if (appender.events !is 20) {
|
||||
log.error(log.format(tmp, "events:{}", appender.events));
|
||||
throw new Exception("Incorrect Number of events in TLS single thread mode with level set");
|
||||
}
|
||||
|
||||
appender.events = 0;
|
||||
|
||||
//test the thread local implementation without any threads, as a baseline.
|
||||
context.setLevel(log.Level.None);
|
||||
for (int i=0;i < 10; i++) {
|
||||
log.info(log.format(tmp, "test4 {}", i));
|
||||
log.trace(log.format(tmp, "test4 {}", i));
|
||||
}
|
||||
if (appender.events !is 10) {
|
||||
log.error(log.format(tmp, "events:{}", appender.events));
|
||||
throw new Exception("Incorrect Number of events in TLS single thread mode after level reset");
|
||||
}
|
||||
|
||||
//Now test threading. set up a trace context in one thread, with a label, while
|
||||
//keeping the second thread at the normal configuration.
|
||||
appender.events = 0;
|
||||
ThreadGroup tg = new ThreadGroup();
|
||||
tg.create({
|
||||
char[128] tmp = 0;
|
||||
context.setLevel(log.Level.Trace);
|
||||
context.push("specialthread");
|
||||
context.push("2ndlevel");
|
||||
for (int i=0;i < 10; i++) {
|
||||
log.info(log.format(tmp, "test5 {}", i));
|
||||
log.trace(log.format(tmp, "test5 {}", i));
|
||||
}
|
||||
});
|
||||
tg.create({
|
||||
char[128] tmp = 0;
|
||||
context.setLevel(log.Level.None);
|
||||
for (int i=0;i < 10; i++) {
|
||||
log.info(log.format(tmp, "test6 {}", i));
|
||||
log.trace(log.format(tmp, "test6 {}", i));
|
||||
}
|
||||
});
|
||||
tg.joinAll();
|
||||
|
||||
if (appender.events !is 30) {
|
||||
log.error(log.format(tmp, "events:{}", appender.events));
|
||||
throw new Exception("Incorrect Number of events in TLS multi thread mode");
|
||||
}
|
||||
}
|
||||
|
||||
102
tango/example/logging/logging.d
Normal file
102
tango/example/logging/logging.d
Normal file
@@ -0,0 +1,102 @@
|
||||
/*******************************************************************************
|
||||
|
||||
Shows how the basic functionality of Logger operates.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
private import tango.util.log.Log,
|
||||
tango.util.log.Configurator;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Search for a set of prime numbers
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void compute (Logger log, uint max)
|
||||
{
|
||||
byte* feld;
|
||||
int teste=1,
|
||||
mom,
|
||||
hits=0,
|
||||
s=0,
|
||||
e = 1;
|
||||
int count;
|
||||
char tmp[128] = void;
|
||||
|
||||
void set (byte* f, uint x)
|
||||
{
|
||||
*(f+(x)/16) |= 1 << (((x)%16)/2);
|
||||
}
|
||||
|
||||
byte test (byte* f, uint x)
|
||||
{
|
||||
return cast(byte) (*(f+(x)/16) & (1 << (((x)%16)/2)));
|
||||
}
|
||||
|
||||
// information level
|
||||
log.info (log.format (tmp, "Searching prime numbers up to {}", max));
|
||||
|
||||
feld = (new byte[max / 16 + 1]).ptr;
|
||||
|
||||
// get milliseconds since application began
|
||||
auto begin = log.runtime;
|
||||
|
||||
while ((teste += 2) < max)
|
||||
if (! test (feld, teste))
|
||||
{
|
||||
if ((++hits & 0x0f) == 0)
|
||||
// more information level
|
||||
log.info (log.format (tmp, "found {}", hits));
|
||||
|
||||
for (mom=3*teste; mom < max; mom += teste<<1)
|
||||
set (feld, mom);
|
||||
}
|
||||
|
||||
// get number of milliseconds we took to compute
|
||||
auto period = log.runtime - begin;
|
||||
|
||||
if (hits)
|
||||
// more information
|
||||
log.info (log.format (tmp, "{} prime numbers found in {} millsecs", hits, period));
|
||||
else
|
||||
// a warning level
|
||||
log.warn ("no prime numbers found");
|
||||
|
||||
// check to see if we're enabled for
|
||||
// tracing before we expend a lot of effort
|
||||
if (log.isEnabled (log.Level.Trace))
|
||||
{
|
||||
e = max;
|
||||
count = 0 - 2;
|
||||
if (s % 2 is 0)
|
||||
count++;
|
||||
|
||||
while ((count+=2) < e)
|
||||
// log trace information
|
||||
if (! test (feld, count))
|
||||
log.trace (log.format (tmp, "prime found: {}", count));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Compute a bunch of prime numbers
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main()
|
||||
{
|
||||
// get a logger to represent this module. We could just as
|
||||
// easily share a name with some other module(s)
|
||||
auto log = Log.getLogger ("example.logging");
|
||||
try {
|
||||
compute (log, 1000);
|
||||
|
||||
} catch (Exception x)
|
||||
{
|
||||
// log the exception as an error
|
||||
log.error ("Exception: " ~ x.toString);
|
||||
}
|
||||
}
|
||||
31
tango/example/logging/multilog.d
Normal file
31
tango/example/logging/multilog.d
Normal file
@@ -0,0 +1,31 @@
|
||||
import tango.util.log.Log;
|
||||
import tango.util.log.Log4Layout;
|
||||
import tango.util.log.FileAppender;
|
||||
import tango.util.log.ConsoleAppender;
|
||||
import tango.util.log.RollingFileAppender;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Shows how to setup multiple appenders on logging tree
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main ()
|
||||
{
|
||||
// set default logging level at the root
|
||||
auto log = Log.getRootLogger;
|
||||
log.setLevel (log.Level.Trace);
|
||||
|
||||
// 10 logs, all with 10 mbs each
|
||||
log.addAppender (new RollingFileAppender("rolling.log", 9, 1024*1024*10));
|
||||
|
||||
// a single file appender, with an XML layout
|
||||
log.addAppender (new FileAppender ("single.log", new Log4Layout));
|
||||
|
||||
// console appender
|
||||
log.addAppender (new ConsoleAppender);
|
||||
|
||||
// log to all
|
||||
log.trace ("three-way logging");
|
||||
}
|
||||
|
||||
237
tango/example/manual/chapterStorage.d
Normal file
237
tango/example/manual/chapterStorage.d
Normal file
@@ -0,0 +1,237 @@
|
||||
module example.reference.chapter11;
|
||||
|
||||
import tango.util.collection.HashMap;
|
||||
import tango.util.collection.ArrayBag;
|
||||
import tango.util.collection.LinkSeq;
|
||||
import tango.util.collection.CircularSeq;
|
||||
import tango.util.collection.ArraySeq;
|
||||
import tango.util.collection.TreeBag;
|
||||
import tango.util.collection.iterator.FilteringIterator;
|
||||
import tango.util.collection.iterator.InterleavingIterator;
|
||||
|
||||
import tango.io.Stdout;
|
||||
import tango.core.Exception;
|
||||
|
||||
import tango.util.collection.model.Comparator;
|
||||
import tango.util.collection.impl.BagCollection;
|
||||
import tango.util.collection.impl.SeqCollection;
|
||||
import Ascii = tango.text.Ascii;
|
||||
|
||||
void linkedListExample(){
|
||||
Stdout.format( "linkedListExample" ).newline;
|
||||
alias LinkSeq!(char[]) StrList;
|
||||
StrList lst = new StrList();
|
||||
|
||||
lst.append( "value1" );
|
||||
lst.append( "value2" );
|
||||
lst.append( "value3" );
|
||||
|
||||
auto it = lst.elements();
|
||||
// The call to .more gives true, if there are more elements
|
||||
// and switches the iterator to the next one if available.
|
||||
while( it.more ){
|
||||
char[] item_value = it.get;
|
||||
Stdout.format( "Value:{0}", item_value ).newline;
|
||||
}
|
||||
}
|
||||
|
||||
void hashMapExample(){
|
||||
Stdout.format( "hashMapExample" ).newline;
|
||||
alias HashMap!(char[], char[]) StrStrMap;
|
||||
StrStrMap map = new StrStrMap();
|
||||
map.add( "key1", "value1" );
|
||||
char[] key = "key1";
|
||||
Stdout.format( "Key: {0}, Value:{1}", key, map.get( key )).newline;
|
||||
|
||||
|
||||
auto it = map.keys();
|
||||
// The call to .more gives true, if there are more elements
|
||||
// and switches the iterator to the next one if available.
|
||||
while( it.more ){
|
||||
char[] item_key = void;
|
||||
char[] item_value = it.get( item_key ); // only for maps, the key is returns via inout
|
||||
Stdout.format( "Key: {0}, Value:{1}", item_key, item_value ).newline;
|
||||
}
|
||||
}
|
||||
|
||||
void testComparator(){
|
||||
char[][] result;
|
||||
|
||||
// Create and fill the containers
|
||||
auto nameSet = new TreeBag!(char[])( null, new class() Comparator!(char[]){
|
||||
int compare( char[] first, char[] second ){
|
||||
return Ascii.icompare( first, second );
|
||||
}
|
||||
});
|
||||
|
||||
nameSet.addIf( "Alice" );
|
||||
nameSet.addIf( "Bob" );
|
||||
nameSet.addIf( "aliCe" );
|
||||
|
||||
// use foreach to iterate over the container
|
||||
foreach ( char[] i; nameSet )
|
||||
result ~= i;
|
||||
foreach( char[] i; result ) Stdout.format( "{0} ", i );
|
||||
Stdout.newline;
|
||||
|
||||
// test the result
|
||||
assert( result == [ "Alice", "Bob" ], "testIterator" );
|
||||
}
|
||||
|
||||
void testSreener(){
|
||||
int[] result;
|
||||
|
||||
// Create and fill the containers
|
||||
auto ratioSamples = new ArraySeq!(float)( (float v){
|
||||
return v >= 0.0f && v < 1.0f;
|
||||
});
|
||||
|
||||
ratioSamples.append( 0.0f );
|
||||
ratioSamples.append( 0.5f );
|
||||
ratioSamples.append( 0.99999f );
|
||||
// try to insert a value that is not allowed
|
||||
try{
|
||||
ratioSamples.append( 1.0f );
|
||||
// will never get here
|
||||
assert( false );
|
||||
} catch( IllegalElementException e ){
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void testForeach(){
|
||||
int[] result;
|
||||
|
||||
// Create and fill the containers
|
||||
auto l1 = new CircularSeq!(int);
|
||||
for( int i = 0; i < 6; i+=2 ){
|
||||
l1.append( i );
|
||||
}
|
||||
|
||||
// use foreach to iterate over the container
|
||||
foreach ( int i; l1 )
|
||||
result ~= i;
|
||||
// foreach_reverse ( int i; l1 )
|
||||
// result ~= i;
|
||||
|
||||
// test the result
|
||||
assert( result == [ 0, 2, 4 ], "testIterator" );
|
||||
}
|
||||
|
||||
void testIterator(){
|
||||
int[] result;
|
||||
|
||||
// Create and fill the containers
|
||||
auto l1 = new LinkSeq!(int);
|
||||
for( int i = 0; i < 6; i+=2 ){
|
||||
l1.append( i );
|
||||
}
|
||||
|
||||
// define the Iterator
|
||||
auto it = l1.elements();
|
||||
|
||||
// use the Iterator to iterate over the container
|
||||
while (it.more())
|
||||
result ~= it.get();
|
||||
|
||||
// test the result
|
||||
assert( result == [ 0, 2, 4 ], "testIterator" );
|
||||
}
|
||||
|
||||
void testFilteringIterator(){
|
||||
int[] result;
|
||||
alias ArrayBag!(int) IntBag;
|
||||
|
||||
// Create and fill the container
|
||||
auto ib = new IntBag;
|
||||
for( int i = 0; i < 20; i++ ){
|
||||
ib.add( i );
|
||||
}
|
||||
|
||||
// define the FilteringIterator with a function literal
|
||||
auto it = new FilteringIterator!(int)( ib.elements(), (int i){
|
||||
return i >= 3 && i < 7;
|
||||
});
|
||||
|
||||
// use the Iterator with the more()/get() pattern
|
||||
while (it.more())
|
||||
result ~= it.get();
|
||||
|
||||
// test the result
|
||||
assert( result == [ 3, 4, 5, 6 ], "testFilteringIterator" );
|
||||
|
||||
}
|
||||
|
||||
void testFilteringIteratorRemove(){
|
||||
int[] result;
|
||||
|
||||
// Create and fill the container
|
||||
auto container = new LinkSeq!(int);
|
||||
for( int i = 0; i < 10; i++ ){
|
||||
container.append( i );
|
||||
}
|
||||
|
||||
// 1. Build a list of elements to delete
|
||||
auto dellist = new LinkSeq!(int);
|
||||
foreach( int i; container ){
|
||||
if( i < 3 || i >= 7 ){
|
||||
// container.remove( i ); /* NOT POSSIBLE */
|
||||
dellist.append( i );
|
||||
}
|
||||
}
|
||||
// 2. Iterate over this deletion list and
|
||||
// delete the items in the original container.
|
||||
foreach( int i; dellist ){
|
||||
container.remove( i );
|
||||
}
|
||||
|
||||
foreach ( int i; container )
|
||||
result ~= i;
|
||||
|
||||
// test the result
|
||||
assert( result == [ 3, 4, 5, 6 ], "testFilteringIterator" );
|
||||
|
||||
}
|
||||
|
||||
void testInterleavingIterator(){
|
||||
int[] result;
|
||||
|
||||
// Create and fill the containers
|
||||
auto l1 = new LinkSeq!(int);
|
||||
auto l2 = new ArraySeq!(int);
|
||||
for( int i = 0; i < 6; i+=2 ){
|
||||
l1.append( i );
|
||||
l2.append( i+1 );
|
||||
}
|
||||
|
||||
// define the InterleavingIterator
|
||||
auto it = new InterleavingIterator!(int)( l1.elements(), l2.elements() );
|
||||
|
||||
// use the InterleavingIterator to iterate over the container
|
||||
while (it.more())
|
||||
result ~= it.get();
|
||||
|
||||
// test the result
|
||||
assert( result == [ 0, 1, 2, 3, 4, 5 ], "testInterleavingIterator" );
|
||||
}
|
||||
|
||||
// foreach( int i; result ) Stdout.format( "{0} ", i );
|
||||
// Stdout.newline;
|
||||
|
||||
void main(){
|
||||
Stdout.format( "reference - Chapter 11 Example" ).newline;
|
||||
hashMapExample();
|
||||
linkedListExample();
|
||||
|
||||
testSreener();
|
||||
testComparator();
|
||||
testForeach();
|
||||
testIterator();
|
||||
testFilteringIterator();
|
||||
testInterleavingIterator();
|
||||
testFilteringIteratorRemove();
|
||||
|
||||
Stdout.format( "=== End ===" ).newline;
|
||||
}
|
||||
|
||||
|
||||
30
tango/example/networking/homepage.d
Normal file
30
tango/example/networking/homepage.d
Normal file
@@ -0,0 +1,30 @@
|
||||
|
||||
private import tango.io.Console;
|
||||
|
||||
private import tango.net.http.HttpClient,
|
||||
tango.net.http.HttpHeaders;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Shows how to use HttpClient to retrieve content from the D website
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main()
|
||||
{
|
||||
auto client = new HttpClient (HttpClient.Get, "http://www.digitalmars.com/d/intro.html");
|
||||
|
||||
// open the client and get the input stream
|
||||
auto input = client.open;
|
||||
scope (exit)
|
||||
client.close;
|
||||
|
||||
// display returned content on console
|
||||
if (client.isResponseOK)
|
||||
Cout.stream.copy (input);
|
||||
else
|
||||
Cout ("failed to return the D home page");
|
||||
|
||||
// flush the console
|
||||
Cout.newline;
|
||||
}
|
||||
27
tango/example/networking/httpget.d
Normal file
27
tango/example/networking/httpget.d
Normal file
@@ -0,0 +1,27 @@
|
||||
private import tango.io.Console;
|
||||
|
||||
private import tango.net.http.HttpGet;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Read a page from a website, gathering the entire page before
|
||||
returning any content. This illustrates a high-level approach
|
||||
to retrieving web-content, whereas the homepage example shows
|
||||
a somewhat lower-level approach.
|
||||
|
||||
Note that this expects a fully qualified URL (with scheme),
|
||||
such as "http://www.digitalmars.com/d/intro.html"
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main (char[][] args)
|
||||
{
|
||||
char[] url = (args.length is 2) ? args[1] : "http://www.digitalmars.com/d/intro.html";
|
||||
|
||||
// open a web-page for reading (see HttpPost for writing)
|
||||
auto page = new HttpGet (url);
|
||||
|
||||
// retrieve and flush display content
|
||||
Cout (cast(char[]) page.read) ();
|
||||
}
|
||||
|
||||
399
tango/example/networking/selector.d
Normal file
399
tango/example/networking/selector.d
Normal file
@@ -0,0 +1,399 @@
|
||||
/*******************************************************************************
|
||||
copyright: Copyright (c) 2006 Juan Jose Comellas. All rights reserved
|
||||
license: BSD style: $(LICENSE)
|
||||
author: Juan Jose Comellas <juanjo@comellas.com.ar>
|
||||
*******************************************************************************/
|
||||
|
||||
private
|
||||
{
|
||||
version (Posix)
|
||||
{
|
||||
import tango.io.selector.PollSelector;
|
||||
}
|
||||
else version (linux)
|
||||
{
|
||||
import tango.io.selector.EpollSelector;
|
||||
import tango.sys.linux.linux;
|
||||
}
|
||||
|
||||
import tango.io.selector.model.ISelector;
|
||||
import tango.io.selector.Selector;
|
||||
import tango.io.selector.SelectSelector;
|
||||
import tango.io.selector.SelectorException;
|
||||
import tango.io.Conduit;
|
||||
import tango.net.Socket;
|
||||
import tango.net.SocketConduit;
|
||||
import tango.net.ServerSocket;
|
||||
import tango.time.Clock;
|
||||
import tango.util.log.Log;
|
||||
import tango.util.log.ConsoleAppender;
|
||||
import tango.util.log.DateLayout;
|
||||
import tango.text.convert.Sprint;
|
||||
import tango.core.Exception;
|
||||
import tango.core.Thread;
|
||||
import tango.sys.Common;
|
||||
import tango.stdc.errno;
|
||||
}
|
||||
|
||||
|
||||
const uint HANDLE_COUNT = 4;
|
||||
const uint EVENT_COUNT = 4;
|
||||
const uint LOOP_COUNT = 50000;
|
||||
const char[] SERVER_ADDR = "127.0.0.1";
|
||||
const ushort SERVER_PORT = 4000;
|
||||
const uint MAX_LENGTH = 16;
|
||||
|
||||
int main(char[][] args)
|
||||
{
|
||||
Logger log = Log.getLogger("selector");
|
||||
Sprint!(char) sprint = new Sprint!(char)(256);
|
||||
|
||||
log.addAppender(new ConsoleAppender(new DateLayout()));
|
||||
|
||||
ISelector selector;
|
||||
|
||||
for (int i = 0; i < 1; i++)
|
||||
{
|
||||
// Testing the SelectSelector
|
||||
log.info(sprint("Pass {0}: Testing the select-based selector", i + 1));
|
||||
selector = new SelectSelector();
|
||||
testSelector(selector);
|
||||
}
|
||||
|
||||
// Testing the PollSelector
|
||||
version (Posix)
|
||||
{
|
||||
for (int i = 0; i < 1; i++)
|
||||
{
|
||||
log.info(sprint("Pass {0}: Testing the poll-based selector", i + 1));
|
||||
selector = new PollSelector();
|
||||
testSelector(selector);
|
||||
}
|
||||
}
|
||||
|
||||
// Testing the EpollSelector
|
||||
version (linux)
|
||||
{
|
||||
for (int i = 0; i < 1; i++)
|
||||
{
|
||||
log.info(sprint("Pass {0}: Testing the epoll-based selector", i + 1));
|
||||
selector = new EpollSelector();
|
||||
testSelector(selector);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a server socket and run the Selector on it.
|
||||
*/
|
||||
void testSelector(ISelector selector)
|
||||
{
|
||||
Logger log = Log.getLogger("selector.server");
|
||||
Sprint!(char) sprint = new Sprint!(char)(512);
|
||||
|
||||
uint connectCount = 0;
|
||||
uint receiveCount = 0;
|
||||
uint sendCount = 0;
|
||||
uint failedConnectCount = 0;
|
||||
uint failedReceiveCount = 0;
|
||||
uint failedSendCount = 0;
|
||||
uint closeCount = 0;
|
||||
uint errorCount = 0;
|
||||
Time start = Clock.now;
|
||||
Thread clientThread;
|
||||
|
||||
selector.open(HANDLE_COUNT, EVENT_COUNT);
|
||||
|
||||
clientThread = new Thread(&clientThreadFunc);
|
||||
clientThread.start();
|
||||
|
||||
try
|
||||
{
|
||||
TimeSpan timeout = TimeSpan.seconds(1);
|
||||
InternetAddress addr = new InternetAddress(SERVER_ADDR, SERVER_PORT);
|
||||
ServerSocket serverSocket = new ServerSocket(addr, 5);
|
||||
SocketConduit clientSocket;
|
||||
char[MAX_LENGTH] buffer;
|
||||
int eventCount;
|
||||
uint count;
|
||||
int i = 0;
|
||||
|
||||
debug (selector)
|
||||
log.trace("Registering server socket to Selector");
|
||||
|
||||
selector.register(serverSocket, Event.Read);
|
||||
|
||||
while (true)
|
||||
{
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] Waiting for events from Selector", i));
|
||||
|
||||
eventCount = selector.select(timeout);
|
||||
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] {1} events received from Selector", i, eventCount));
|
||||
|
||||
if (eventCount > 0)
|
||||
{
|
||||
foreach (SelectionKey selectionKey; selector.selectedSet())
|
||||
{
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] Event mask for socket {1} is 0x{2:x4}",
|
||||
i, cast(int) selectionKey.conduit.fileHandle(),
|
||||
cast(uint) selectionKey.events));
|
||||
|
||||
if (selectionKey.isReadable())
|
||||
{
|
||||
if (selectionKey.conduit is serverSocket)
|
||||
{
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] New connection from client", i));
|
||||
|
||||
clientSocket = serverSocket.accept();
|
||||
if (clientSocket !is null)
|
||||
{
|
||||
selector.register(clientSocket, Event.Read);
|
||||
connectCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] New connection attempt failed", i));
|
||||
failedConnectCount++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Reading from a client socket
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] Receiving message from client", i));
|
||||
|
||||
count = (cast(SocketConduit) selectionKey.conduit).read(buffer);
|
||||
if (count != IConduit.Eof)
|
||||
{
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] Received {1} from client ({2} bytes)",
|
||||
i, buffer[0..count], count));
|
||||
selector.reregister(selectionKey.conduit, Event.Write);
|
||||
receiveCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] Handle {1} was closed; removing it from Selector",
|
||||
i, cast(int) selectionKey.conduit.fileHandle()));
|
||||
selector.unregister(selectionKey.conduit);
|
||||
(cast(SocketConduit) selectionKey.conduit).close();
|
||||
failedReceiveCount++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (selectionKey.isWritable())
|
||||
{
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] Sending PONG to client", i));
|
||||
|
||||
count = (cast(SocketConduit) selectionKey.conduit).write("PONG");
|
||||
if (count != IConduit.Eof)
|
||||
{
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] Sent PONG to client ({1} bytes)", i, count));
|
||||
|
||||
selector.reregister(selectionKey.conduit, Event.Read);
|
||||
sendCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] Handle {1} was closed; removing it from Selector",
|
||||
i, selectionKey.conduit.fileHandle()));
|
||||
selector.unregister(selectionKey.conduit);
|
||||
(cast(SocketConduit) selectionKey.conduit).close();
|
||||
failedSendCount++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (selectionKey.isError() || selectionKey.isHangup() || selectionKey.isInvalidHandle())
|
||||
{
|
||||
char[] status;
|
||||
|
||||
if (selectionKey.isHangup())
|
||||
{
|
||||
closeCount++;
|
||||
status = "Hangup";
|
||||
}
|
||||
else
|
||||
{
|
||||
errorCount++;
|
||||
if (selectionKey.isInvalidHandle())
|
||||
status = "Invalid request";
|
||||
else
|
||||
status = "Error";
|
||||
}
|
||||
|
||||
debug (selector)
|
||||
{
|
||||
log.trace(sprint("[{0}] {1} in handle {2} from Selector",
|
||||
i, status, cast(int) selectionKey.conduit.fileHandle()));
|
||||
|
||||
log.trace(sprint("[{0}] Unregistering handle {1} from Selector",
|
||||
i, cast(int) selectionKey.conduit.fileHandle()));
|
||||
}
|
||||
selector.unregister(selectionKey.conduit);
|
||||
(cast(Conduit) selectionKey.conduit).close();
|
||||
|
||||
if (selectionKey.conduit !is serverSocket)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] No more pending events in Selector; aborting", i));
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
|
||||
// Thread.sleep(1.0);
|
||||
/*
|
||||
if (i % 100 == 0)
|
||||
{
|
||||
fullCollect();
|
||||
getStats(gc)
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
serverSocket.socket().detach;
|
||||
}
|
||||
catch (SelectorException e)
|
||||
{
|
||||
log.error(sprint("Selector exception caught:\n{0}", e.toString()));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.error(sprint("Exception caught:\n{0}", e.toString()));
|
||||
}
|
||||
|
||||
log.info(sprint("Success: connect={0}; recv={1}; send={2}; close={3}",
|
||||
connectCount, receiveCount, sendCount, closeCount));
|
||||
log.info(sprint("Failure: connect={0}, recv={1}; send={2}; error={3}",
|
||||
failedConnectCount, failedReceiveCount, failedSendCount, errorCount));
|
||||
|
||||
log.info(sprint("Total time: {0} ms", cast(uint) (Clock.now - start).millis));
|
||||
|
||||
clientThread.join();
|
||||
|
||||
selector.close;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Thread that creates a client socket and sends messages to the server socket.
|
||||
*/
|
||||
void clientThreadFunc()
|
||||
{
|
||||
Logger log = Log.getLogger("selector.client");
|
||||
Sprint!(char) sprint = new Sprint!(char)(256);
|
||||
SocketConduit socket = new SocketConduit();
|
||||
|
||||
Thread.sleep(0.010); // 10 milliseconds
|
||||
|
||||
try
|
||||
{
|
||||
InternetAddress addr = new InternetAddress(SERVER_ADDR, SERVER_PORT);
|
||||
char[MAX_LENGTH] buffer;
|
||||
uint count;
|
||||
int i;
|
||||
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] Connecting to server", i));
|
||||
|
||||
socket.connect(addr);
|
||||
|
||||
for (i = 1; i <= LOOP_COUNT; i++)
|
||||
{
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] Sending PING to server", i));
|
||||
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
count = socket.write("PING");
|
||||
break;
|
||||
}
|
||||
catch (SocketException e)
|
||||
{
|
||||
if (errno != EINTR)
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
if (count != IConduit.Eof)
|
||||
{
|
||||
debug (selector)
|
||||
{
|
||||
log.trace(sprint("[{0}] Sent PING to server ({1} bytes)", i, count));
|
||||
|
||||
log.trace(sprint("[{0}] Receiving message from server", i));
|
||||
}
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
count = socket.read(buffer);
|
||||
break;
|
||||
}
|
||||
catch (SocketException e)
|
||||
{
|
||||
if (errno != EINTR)
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
if (count != IConduit.Eof)
|
||||
{
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] Received {1} from server ({2} bytes)",
|
||||
i, buffer[0..count], count));
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] Handle was closed; aborting",
|
||||
i, socket.fileHandle()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (selector)
|
||||
log.trace(sprint("[{0}] Handle {1} was closed; aborting",
|
||||
i, socket.fileHandle()));
|
||||
break;
|
||||
}
|
||||
}
|
||||
socket.shutdown();
|
||||
socket.close();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.error(sprint("Exception caught:\n{0}", e.toString()));
|
||||
}
|
||||
debug (selector)
|
||||
log.trace("Leaving thread");
|
||||
|
||||
return 0;
|
||||
}
|
||||
29
tango/example/networking/sockethello.d
Normal file
29
tango/example/networking/sockethello.d
Normal file
@@ -0,0 +1,29 @@
|
||||
/*******************************************************************************
|
||||
|
||||
Shows how to create a basic socket client, and how to converse with
|
||||
a remote server. The server must be running for this to succeed
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
private import tango.io.Console;
|
||||
|
||||
private import tango.net.SocketConduit,
|
||||
tango.net.InternetAddress;
|
||||
|
||||
void main()
|
||||
{
|
||||
// make a connection request to the server
|
||||
auto request = new SocketConduit;
|
||||
request.connect (new InternetAddress ("localhost", 8080));
|
||||
request.output.write ("hello\n");
|
||||
|
||||
// wait for response (there is an optional timeout supported)
|
||||
char[64] response;
|
||||
auto size = request.input.read (response);
|
||||
|
||||
// close socket
|
||||
request.close;
|
||||
|
||||
// display server response
|
||||
Cout (response[0..size]).newline;
|
||||
}
|
||||
53
tango/example/networking/socketserver.d
Normal file
53
tango/example/networking/socketserver.d
Normal file
@@ -0,0 +1,53 @@
|
||||
/*******************************************************************************
|
||||
|
||||
Shows how to create a basic socket server, and how to talk to
|
||||
it from a socket client. Note that both the server and client
|
||||
are entirely simplistic, and therefore this is for illustration
|
||||
purposes only. See HttpServer for something more robust.
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
private import tango.core.Thread;
|
||||
|
||||
private import tango.io.Console;
|
||||
|
||||
private import tango.net.ServerSocket,
|
||||
tango.net.SocketConduit;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Create a socket server, and have it respond to a request
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main()
|
||||
{
|
||||
const int port = 8080;
|
||||
|
||||
// thread body for socket-listener
|
||||
void run()
|
||||
{
|
||||
auto server = new ServerSocket (new InternetAddress(port));
|
||||
|
||||
// wait for requests
|
||||
auto request = server.accept;
|
||||
|
||||
// write a response
|
||||
request.output.write ("server replies 'hello'");
|
||||
}
|
||||
|
||||
// start server in a separate thread, and wait for it to start
|
||||
(new Thread (&run)).start;
|
||||
Thread.sleep (0.250);
|
||||
|
||||
// make a connection request to the server
|
||||
auto request = new SocketConduit;
|
||||
request.connect (new InternetAddress("localhost", port));
|
||||
|
||||
// wait for and display response (there is an optional timeout)
|
||||
char[64] response;
|
||||
auto len = request.input.read (response);
|
||||
Cout (response[0..len]).newline;
|
||||
|
||||
request.close;
|
||||
}
|
||||
138
tango/example/synchronization/barrier.d
Normal file
138
tango/example/synchronization/barrier.d
Normal file
@@ -0,0 +1,138 @@
|
||||
/*******************************************************************************
|
||||
copyright: Copyright (c) 2006 Juan Jose Comellas. All rights reserved
|
||||
license: BSD style: $(LICENSE)
|
||||
author: Juan Jose Comellas <juanjo@comellas.com.ar>
|
||||
Converted to use core.sync by Sean Kelly <sean@f4.ca>
|
||||
*******************************************************************************/
|
||||
|
||||
private import tango.core.sync.Barrier;
|
||||
private import tango.core.sync.Mutex;
|
||||
private import tango.core.Exception;
|
||||
private import tango.core.Thread;
|
||||
private import tango.io.Stdout;
|
||||
private import tango.text.convert.Integer;
|
||||
debug (barrier)
|
||||
{
|
||||
private import tango.util.log.Log;
|
||||
private import tango.util.log.ConsoleAppender;
|
||||
private import tango.util.log.DateLayout;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Example program for the tango.core.sync.Barrier module.
|
||||
*/
|
||||
void main(char[][] args)
|
||||
{
|
||||
const uint MaxThreadCount = 100;
|
||||
const uint LoopsPerThread = 10000;
|
||||
|
||||
debug (barrier)
|
||||
{
|
||||
Logger log = Log.getLogger("barrier");
|
||||
|
||||
log.addAppender(new ConsoleAppender(new DateLayout()));
|
||||
|
||||
log.info("Barrier test");
|
||||
}
|
||||
|
||||
Barrier barrier = new Barrier(MaxThreadCount);
|
||||
Mutex mutex = new Mutex();
|
||||
uint count = 0;
|
||||
uint correctCount = 0;
|
||||
|
||||
void barrierTestThread()
|
||||
{
|
||||
debug (barrier)
|
||||
{
|
||||
Logger log = Log.getLogger("barrier." ~ Thread.getThis().name());
|
||||
|
||||
log.trace("Starting thread");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
for (uint i; i < LoopsPerThread; ++i)
|
||||
{
|
||||
// 'count' is a resource shared by multiple threads, so we must
|
||||
// acquire the mutex before modifying it.
|
||||
synchronized (mutex)
|
||||
{
|
||||
// debug (barrier)
|
||||
// log.trace("Acquired mutex");
|
||||
count++;
|
||||
// debug (barrier)
|
||||
// log.trace("Releasing mutex");
|
||||
}
|
||||
}
|
||||
|
||||
// We wait for all the threads to finish counting.
|
||||
debug (barrier)
|
||||
log.trace("Waiting on barrier");
|
||||
barrier.wait();
|
||||
debug (barrier)
|
||||
log.trace("Barrier was opened");
|
||||
|
||||
// We make sure that all the threads exited the barrier after
|
||||
// *all* of them had finished counting.
|
||||
synchronized (mutex)
|
||||
{
|
||||
// debug (barrier)
|
||||
// log.trace("Acquired mutex");
|
||||
if (count == MaxThreadCount * LoopsPerThread)
|
||||
{
|
||||
++correctCount;
|
||||
}
|
||||
// debug (barrier)
|
||||
// log.trace("Releasing mutex");
|
||||
}
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Stderr.formatln("Sync exception caught in Barrier test thread {0}:\n{1}\n",
|
||||
Thread.getThis().name, e.toString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Stderr.formatln("Unexpected exception caught in Barrier test thread {0}:\n{1}\n",
|
||||
Thread.getThis().name, e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
ThreadGroup group = new ThreadGroup();
|
||||
Thread thread;
|
||||
char[10] tmp;
|
||||
|
||||
for (uint i = 0; i < MaxThreadCount; ++i)
|
||||
{
|
||||
thread = new Thread(&barrierTestThread);
|
||||
thread.name = "thread-" ~ format(tmp, i);
|
||||
|
||||
group.add(thread);
|
||||
debug (barrier)
|
||||
log.trace("Created thread " ~ thread.name);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
debug (barrier)
|
||||
log.trace("Waiting for threads to finish");
|
||||
group.joinAll();
|
||||
|
||||
if (count == MaxThreadCount * LoopsPerThread)
|
||||
{
|
||||
debug (barrier)
|
||||
log.info("The Barrier test was successful");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (barrier)
|
||||
{
|
||||
log.error("The Barrier is not working properly: the counter has an incorrect value");
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false, "The Barrier is not working properly: the counter has an incorrect value");
|
||||
}
|
||||
}
|
||||
}
|
||||
307
tango/example/synchronization/condition.d
Normal file
307
tango/example/synchronization/condition.d
Normal file
@@ -0,0 +1,307 @@
|
||||
/*******************************************************************************
|
||||
copyright: Copyright (c) 2006 Juan Jose Comellas. All rights reserved
|
||||
license: BSD style: $(LICENSE)
|
||||
author: Juan Jose Comellas <juanjo@comellas.com.ar>
|
||||
Converted to use core.sync by Sean Kelly <sean@f4.ca>
|
||||
*******************************************************************************/
|
||||
|
||||
private import tango.core.sync.Condition;
|
||||
private import tango.core.Exception;
|
||||
private import tango.core.Thread;
|
||||
private import tango.text.convert.Integer;
|
||||
private import tango.io.Stdout;
|
||||
debug (condition)
|
||||
{
|
||||
private import tango.util.log.Log;
|
||||
private import tango.util.log.ConsoleAppender;
|
||||
private import tango.util.log.DateLayout;
|
||||
}
|
||||
|
||||
|
||||
void main(char[][] args)
|
||||
{
|
||||
debug (condition)
|
||||
{
|
||||
Logger log = Log.getLogger("condition");
|
||||
|
||||
log.addAppender(new ConsoleAppender(new DateLayout()));
|
||||
|
||||
log.info("Condition test");
|
||||
}
|
||||
|
||||
testNotifyOne();
|
||||
testNotifyAll();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test for Condition.notify().
|
||||
*/
|
||||
void testNotifyOne()
|
||||
{
|
||||
debug (condition)
|
||||
{
|
||||
Logger log = Log.getLogger("condition.notify-one");
|
||||
}
|
||||
|
||||
scope Mutex mutex = new Mutex();
|
||||
scope Condition cond = new Condition(mutex);
|
||||
int waiting = 0;
|
||||
Thread thread;
|
||||
|
||||
void notifyOneTestThread()
|
||||
{
|
||||
debug (condition)
|
||||
{
|
||||
Logger log = Log.getLogger("condition.notify-one." ~ Thread.getThis().name());
|
||||
|
||||
log.trace("Starting thread");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
synchronized (mutex)
|
||||
{
|
||||
debug (condition)
|
||||
log.trace("Acquired mutex");
|
||||
|
||||
scope(exit)
|
||||
{
|
||||
debug (condition)
|
||||
log.trace("Releasing mutex");
|
||||
}
|
||||
|
||||
waiting++;
|
||||
|
||||
while (waiting != 2)
|
||||
{
|
||||
debug (condition)
|
||||
log.trace("Waiting on condition variable");
|
||||
cond.wait();
|
||||
}
|
||||
|
||||
debug (condition)
|
||||
log.trace("Condition variable was signaled");
|
||||
}
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Stderr.formatln("Sync exception caught in Condition test thread {0}:\n{1}",
|
||||
Thread.getThis().name(), e.toString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Stderr.formatln("Unexpected exception caught in Condition test thread {0}:\n{1}",
|
||||
Thread.getThis().name(), e.toString());
|
||||
}
|
||||
debug (condition)
|
||||
log.trace("Exiting thread");
|
||||
}
|
||||
|
||||
thread = new Thread(¬ifyOneTestThread);
|
||||
thread.name = "thread-1";
|
||||
|
||||
debug (condition)
|
||||
log.trace("Created thread " ~ thread.name);
|
||||
thread.start();
|
||||
|
||||
try
|
||||
{
|
||||
// Poor man's barrier: wait until the other thread is waiting.
|
||||
while (true)
|
||||
{
|
||||
synchronized (mutex)
|
||||
{
|
||||
if (waiting != 1)
|
||||
{
|
||||
Thread.yield();
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (mutex)
|
||||
{
|
||||
debug (condition)
|
||||
log.trace("Acquired mutex");
|
||||
|
||||
waiting++;
|
||||
|
||||
debug (condition)
|
||||
log.trace("Notifying test thread");
|
||||
cond.notify();
|
||||
|
||||
debug (condition)
|
||||
log.trace("Releasing mutex");
|
||||
}
|
||||
|
||||
thread.join();
|
||||
|
||||
if (waiting == 2)
|
||||
{
|
||||
debug (condition)
|
||||
log.info("The Condition notification test to one thread was successful");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (condition)
|
||||
{
|
||||
log.error("The condition variable notification to one thread is not working");
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false, "The condition variable notification to one thread is not working");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Stderr.formatln("Sync exception caught in main thread:\n{0}", e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test for Condition.notifyAll().
|
||||
*/
|
||||
void testNotifyAll()
|
||||
{
|
||||
const uint MaxThreadCount = 10;
|
||||
|
||||
debug (condition)
|
||||
{
|
||||
Logger log = Log.getLogger("condition.notify-all");
|
||||
}
|
||||
|
||||
scope Mutex mutex = new Mutex();
|
||||
scope Condition cond = new Condition(mutex);
|
||||
int waiting = 0;
|
||||
|
||||
/**
|
||||
* This thread waits for a notification from the main thread.
|
||||
*/
|
||||
void notifyAllTestThread()
|
||||
{
|
||||
debug (condition)
|
||||
{
|
||||
Logger log = Log.getLogger("condition.notify-all." ~ Thread.getThis().name());
|
||||
|
||||
log.trace("Starting thread");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
synchronized (mutex)
|
||||
{
|
||||
debug (condition)
|
||||
log.trace("Acquired mutex");
|
||||
|
||||
waiting++;
|
||||
|
||||
while (waiting != MaxThreadCount + 1)
|
||||
{
|
||||
debug (condition)
|
||||
log.trace("Waiting on condition variable");
|
||||
cond.wait();
|
||||
}
|
||||
|
||||
debug (condition)
|
||||
log.trace("Condition variable was signaled");
|
||||
|
||||
debug (condition)
|
||||
log.trace("Releasing mutex");
|
||||
}
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Stderr.formatln("Sync exception caught in Condition test thread {0}:\n{1}",
|
||||
Thread.getThis().name(), e.toString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Stderr.formatln("Unexpected exception caught in Condition test thread {0}:\n{1}",
|
||||
Thread.getThis().name(), e.toString());
|
||||
}
|
||||
debug (condition)
|
||||
log.trace("Exiting thread");
|
||||
}
|
||||
|
||||
ThreadGroup group = new ThreadGroup();
|
||||
Thread thread;
|
||||
char[10] tmp;
|
||||
|
||||
for (uint i = 0; i < MaxThreadCount; ++i)
|
||||
{
|
||||
thread = new Thread(¬ifyAllTestThread);
|
||||
thread.name = "thread-" ~ format(tmp, i);
|
||||
|
||||
group.add(thread);
|
||||
debug (condition)
|
||||
log.trace("Created thread " ~ thread.name);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// Poor man's barrier: wait until all the threads are waiting.
|
||||
while (true)
|
||||
{
|
||||
synchronized (mutex)
|
||||
{
|
||||
if (waiting != MaxThreadCount)
|
||||
{
|
||||
Thread.yield();
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (mutex)
|
||||
{
|
||||
debug (condition)
|
||||
log.trace("Acquired mutex");
|
||||
|
||||
waiting++;
|
||||
|
||||
debug (condition)
|
||||
log.trace("Notifying all threads");
|
||||
cond.notifyAll();
|
||||
|
||||
debug (condition)
|
||||
log.trace("Releasing mutex");
|
||||
}
|
||||
|
||||
debug (condition)
|
||||
log.trace("Waiting for threads to finish");
|
||||
group.joinAll();
|
||||
|
||||
if (waiting == MaxThreadCount + 1)
|
||||
{
|
||||
debug (condition)
|
||||
log.info("The Condition notification test to many threads was successful");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (condition)
|
||||
{
|
||||
log.error("The condition variable notification to many threads is not working");
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false, "The condition variable notification to many threads is not working");
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Stderr.formatln("Sync exception caught in main thread:\n{0}", e.toString());
|
||||
}
|
||||
}
|
||||
248
tango/example/synchronization/mutex.d
Normal file
248
tango/example/synchronization/mutex.d
Normal file
@@ -0,0 +1,248 @@
|
||||
/*******************************************************************************
|
||||
copyright: Copyright (c) 2006 Juan Jose Comellas. All rights reserved
|
||||
license: BSD style: $(LICENSE)
|
||||
author: Juan Jose Comellas <juanjo@comellas.com.ar>
|
||||
Converted to use core.sync by Sean Kelly <sean@f4.ca>
|
||||
*******************************************************************************/
|
||||
|
||||
private import tango.core.sync.Mutex;
|
||||
private import tango.core.Exception;
|
||||
private import tango.core.Thread;
|
||||
private import tango.io.Stdout;
|
||||
private import tango.text.convert.Integer;
|
||||
debug (mutex)
|
||||
{
|
||||
private import tango.util.log.Log;
|
||||
private import tango.util.log.ConsoleAppender;
|
||||
private import tango.util.log.DateLayout;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Example program for the tango.core.sync.Mutex module.
|
||||
*/
|
||||
void main(char[][] args)
|
||||
{
|
||||
debug (mutex)
|
||||
{
|
||||
Logger log = Log.getLogger("mutex");
|
||||
|
||||
log.addAppender(new ConsoleAppender(new DateLayout()));
|
||||
|
||||
log.info("Mutex test");
|
||||
}
|
||||
|
||||
testNonRecursive();
|
||||
testLocking();
|
||||
testRecursive();
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that non-recursive mutexes actually do what they're supposed to do.
|
||||
*
|
||||
* Remarks:
|
||||
* Windows only supports recursive mutexes.
|
||||
*/
|
||||
void testNonRecursive()
|
||||
{
|
||||
version (Posix)
|
||||
{
|
||||
debug (mutex)
|
||||
{
|
||||
Logger log = Log.getLogger("mutex.non-recursive");
|
||||
}
|
||||
|
||||
Mutex mutex = new Mutex(Mutex.Type.NonRecursive);
|
||||
bool couldLock;
|
||||
|
||||
try
|
||||
{
|
||||
mutex.lock();
|
||||
debug (mutex)
|
||||
log.trace("Acquired mutex");
|
||||
couldLock = mutex.tryLock();
|
||||
if (couldLock)
|
||||
{
|
||||
debug (mutex)
|
||||
{
|
||||
log.trace("Re-acquired mutex");
|
||||
log.trace("Releasing mutex");
|
||||
}
|
||||
mutex.unlock();
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (mutex)
|
||||
log.trace("Re-acquiring the mutex failed");
|
||||
}
|
||||
debug (mutex)
|
||||
log.trace("Releasing mutex");
|
||||
mutex.unlock();
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Stderr.formatln("Sync exception caught when testing non-recursive mutexes:\n{0}\n", e.toString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Stderr.formatln("Unexpected exception caught when testing non-recursive mutexes:\n{0}\n", e.toString());
|
||||
}
|
||||
|
||||
if (!couldLock)
|
||||
{
|
||||
debug (mutex)
|
||||
log.info("The non-recursive Mutex test was successful");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (mutex)
|
||||
{
|
||||
log.error("Non-recursive mutexes are not working: "
|
||||
"Mutex.tryAcquire() did not fail on an already acquired mutex");
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false, "Non-recursive mutexes are not working: "
|
||||
"Mutex.tryAcquire() did not fail on an already acquired mutex");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create several threads that acquire and release a mutex several times.
|
||||
*/
|
||||
void testLocking()
|
||||
{
|
||||
const uint MaxThreadCount = 10;
|
||||
const uint LoopsPerThread = 1000;
|
||||
|
||||
debug (mutex)
|
||||
{
|
||||
Logger log = Log.getLogger("mutex.locking");
|
||||
}
|
||||
|
||||
Mutex mutex = new Mutex();
|
||||
uint lockCount = 0;
|
||||
|
||||
void mutexLockingThread()
|
||||
{
|
||||
try
|
||||
{
|
||||
for (uint i; i < LoopsPerThread; i++)
|
||||
{
|
||||
synchronized (mutex)
|
||||
{
|
||||
lockCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Stderr.formatln("Sync exception caught inside mutex testing thread:\n{0}\n", e.toString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Stderr.formatln("Unexpected exception caught inside mutex testing thread:\n{0}\n", e.toString());
|
||||
}
|
||||
}
|
||||
|
||||
ThreadGroup group = new ThreadGroup();
|
||||
Thread thread;
|
||||
char[10] tmp;
|
||||
|
||||
for (uint i = 0; i < MaxThreadCount; i++)
|
||||
{
|
||||
thread = new Thread(&mutexLockingThread);
|
||||
thread.name = "thread-" ~ format(tmp, i);
|
||||
|
||||
debug (mutex)
|
||||
log.trace("Created thread " ~ thread.name);
|
||||
thread.start();
|
||||
|
||||
group.add(thread);
|
||||
}
|
||||
|
||||
debug (mutex)
|
||||
log.trace("Waiting for threads to finish");
|
||||
group.joinAll();
|
||||
|
||||
if (lockCount == MaxThreadCount * LoopsPerThread)
|
||||
{
|
||||
debug (mutex)
|
||||
log.info("The Mutex locking test was successful");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (mutex)
|
||||
{
|
||||
log.error("Mutex locking is not working properly: "
|
||||
"the number of times the mutex was acquired is incorrect");
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false,"Mutex locking is not working properly: "
|
||||
"the number of times the mutex was acquired is incorrect");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that recursive mutexes actually do what they're supposed to do.
|
||||
*/
|
||||
void testRecursive()
|
||||
{
|
||||
const uint LoopsPerThread = 1000;
|
||||
|
||||
debug (mutex)
|
||||
{
|
||||
Logger log = Log.getLogger("mutex.recursive");
|
||||
}
|
||||
|
||||
Mutex mutex = new Mutex;
|
||||
uint lockCount = 0;
|
||||
|
||||
try
|
||||
{
|
||||
for (uint i = 0; i < LoopsPerThread; i++)
|
||||
{
|
||||
mutex.lock();
|
||||
lockCount++;
|
||||
}
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Stderr.formatln("Sync exception caught in recursive mutex test:\n{0}\n", e.toString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Stderr.formatln("Unexpected exception caught in recursive mutex test:\n{0}\n", e.toString());
|
||||
}
|
||||
|
||||
for (uint i = 0; i < lockCount; i++)
|
||||
{
|
||||
mutex.unlock();
|
||||
}
|
||||
|
||||
if (lockCount == LoopsPerThread)
|
||||
{
|
||||
debug (mutex)
|
||||
log.info("The recursive Mutex test was successful");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (mutex)
|
||||
{
|
||||
log.error("Recursive mutexes are not working: "
|
||||
"the number of times the mutex was acquired is incorrect");
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false, "Recursive mutexes are not working: "
|
||||
"the number of times the mutex was acquired is incorrect");
|
||||
}
|
||||
}
|
||||
}
|
||||
145
tango/example/synchronization/readwritemutex.d
Normal file
145
tango/example/synchronization/readwritemutex.d
Normal file
@@ -0,0 +1,145 @@
|
||||
/*******************************************************************************
|
||||
copyright: Copyright (c) 2006 Juan Jose Comellas. All rights reserved
|
||||
license: BSD style: $(LICENSE)
|
||||
author: Juan Jose Comellas <juanjo@comellas.com.ar>
|
||||
Converted to use core.sync by Sean Kelly <sean@f4.ca>
|
||||
*******************************************************************************/
|
||||
|
||||
private import tango.core.sync.ReadWriteMutex;
|
||||
private import tango.core.sync.Mutex;
|
||||
private import tango.core.Thread;
|
||||
private import tango.text.convert.Integer;
|
||||
debug (readwritemutex)
|
||||
{
|
||||
private import tango.util.log.Log;
|
||||
private import tango.util.log.ConsoleAppender;
|
||||
private import tango.util.log.DateLayout;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Example program for the tango.core.sync.ReadWriteMutex module.
|
||||
*/
|
||||
void main(char[][] args)
|
||||
{
|
||||
const uint ReaderThreads = 100;
|
||||
const uint WriterThreads = 20;
|
||||
const uint LoopsPerReader = 10000;
|
||||
const uint LoopsPerWriter = 1000;
|
||||
const uint CounterIncrement = 3;
|
||||
|
||||
debug (readwritemutex)
|
||||
{
|
||||
Logger log = Log.getLogger("readwritemutex");
|
||||
|
||||
log.addAppender(new ConsoleAppender(new DateLayout()));
|
||||
|
||||
log.info("ReadWriteMutex test");
|
||||
}
|
||||
|
||||
ReadWriteMutex rwlock = new ReadWriteMutex();
|
||||
Mutex mutex = new Mutex();
|
||||
uint readCount = 0;
|
||||
uint passed = 0;
|
||||
uint failed = 0;
|
||||
|
||||
void mutexReaderThread()
|
||||
{
|
||||
debug (readwritemutex)
|
||||
{
|
||||
Logger log = Log.getLogger("readwritemutex." ~ Thread.getThis().name());
|
||||
|
||||
log.trace("Starting reader thread");
|
||||
}
|
||||
|
||||
for (uint i = 0; i < LoopsPerReader; ++i)
|
||||
{
|
||||
// All the reader threads acquire the mutex for reading and when they are
|
||||
// all done
|
||||
synchronized (rwlock.reader)
|
||||
{
|
||||
for (uint j = 0; j < CounterIncrement; ++j)
|
||||
{
|
||||
synchronized (mutex)
|
||||
{
|
||||
++readCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void mutexWriterThread()
|
||||
{
|
||||
debug (readwritemutex)
|
||||
{
|
||||
Logger log = Log.getLogger("readwritemutex." ~ Thread.getThis().name());
|
||||
|
||||
log.trace("Starting writer thread");
|
||||
}
|
||||
|
||||
for (uint i = 0; i < LoopsPerWriter; ++i)
|
||||
{
|
||||
synchronized (rwlock.writer)
|
||||
{
|
||||
synchronized (mutex)
|
||||
{
|
||||
if (readCount % 3 == 0)
|
||||
{
|
||||
++passed;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ThreadGroup group = new ThreadGroup();
|
||||
Thread thread;
|
||||
char[10] tmp;
|
||||
|
||||
for (uint i = 0; i < ReaderThreads; ++i)
|
||||
{
|
||||
thread = new Thread(&mutexReaderThread);
|
||||
thread.name = "reader-" ~ format(tmp, i);
|
||||
|
||||
debug (readwritemutex)
|
||||
log.trace("Created reader thread " ~ thread.name);
|
||||
thread.start();
|
||||
|
||||
group.add(thread);
|
||||
}
|
||||
|
||||
for (uint i = 0; i < WriterThreads; ++i)
|
||||
{
|
||||
thread = new Thread(&mutexWriterThread);
|
||||
thread.name = "writer-" ~ format(tmp, i);
|
||||
|
||||
debug (readwritemutex)
|
||||
log.trace("Created writer thread " ~ thread.name);
|
||||
thread.start();
|
||||
|
||||
group.add(thread);
|
||||
}
|
||||
|
||||
debug (readwritemutex)
|
||||
log.trace("Waiting for threads to finish");
|
||||
group.joinAll();
|
||||
|
||||
if (passed == WriterThreads * LoopsPerWriter)
|
||||
{
|
||||
debug (readwritemutex)
|
||||
log.info("The ReadWriteMutex test was successful");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (readwritemutex)
|
||||
{
|
||||
log.error("The ReadWriteMutex is not working properly: the counter has an incorrect value");
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false, "The ReadWriteMutex is not working properly: the counter has an incorrect value");
|
||||
}
|
||||
}
|
||||
}
|
||||
340
tango/example/synchronization/semaphore.d
Normal file
340
tango/example/synchronization/semaphore.d
Normal file
@@ -0,0 +1,340 @@
|
||||
/*******************************************************************************
|
||||
copyright: Copyright (c) 2007 Juan Jose Comellas. All rights reserved
|
||||
license: BSD style: $(LICENSE)
|
||||
author: Juan Jose Comellas <juanjo@comellas.com.ar>
|
||||
Converted to use core.sync by Sean Kelly <sean@f4.ca>
|
||||
*******************************************************************************/
|
||||
|
||||
module semaphore;
|
||||
|
||||
private import tango.core.sync.Semaphore;
|
||||
private import tango.core.sync.Mutex;
|
||||
private import tango.core.Exception;
|
||||
private import tango.core.Exception;
|
||||
private import tango.core.Thread;
|
||||
private import tango.io.Console;
|
||||
private import tango.text.stream.LineIterator;
|
||||
private import tango.text.convert.Integer;
|
||||
private import tango.sys.Process;
|
||||
|
||||
debug (semaphore)
|
||||
{
|
||||
private import tango.util.log.Log;
|
||||
private import tango.util.log.ConsoleAppender;
|
||||
private import tango.util.log.DateLayout;
|
||||
}
|
||||
|
||||
const char[] SemaphoreName = "TestProcessSemaphore";
|
||||
|
||||
|
||||
/**
|
||||
* Example program for the tango.core.sync.Barrier module.
|
||||
*/
|
||||
int main(char[][] args)
|
||||
{
|
||||
if (args.length == 1)
|
||||
{
|
||||
debug (semaphore)
|
||||
{
|
||||
Logger log = Log.getLogger("semaphore");
|
||||
|
||||
log.addAppender(new ConsoleAppender(new DateLayout()));
|
||||
|
||||
log.info("Semaphore test");
|
||||
}
|
||||
|
||||
testSemaphore();
|
||||
testProcessSemaphore(args[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return testSecondProcessSemaphore();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for single-process (multi-threaded) semaphores.
|
||||
*/
|
||||
void testSemaphore()
|
||||
{
|
||||
const uint MaxThreadCount = 10;
|
||||
|
||||
// Semaphore used in the tests. Start it "locked" (i.e., its initial
|
||||
// count is 0).
|
||||
Semaphore sem = new Semaphore(MaxThreadCount - 1);
|
||||
Mutex mutex = new Mutex();
|
||||
uint count = 0;
|
||||
bool passed = false;
|
||||
|
||||
void semaphoreTestThread()
|
||||
{
|
||||
debug (semaphore)
|
||||
{
|
||||
Logger log = Log.getLogger("semaphore.single." ~ Thread.getThis().name());
|
||||
|
||||
log.trace("Starting thread");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
uint threadNumber;
|
||||
|
||||
// 'count' is a resource shared by multiple threads, so we must
|
||||
// acquire the mutex before modifying it.
|
||||
synchronized (mutex)
|
||||
{
|
||||
// debug (semaphore)
|
||||
// log.trace("Acquired mutex");
|
||||
threadNumber = ++count;
|
||||
// debug (semaphore)
|
||||
// log.trace("Releasing mutex");
|
||||
}
|
||||
|
||||
// We wait for all the threads to finish counting.
|
||||
if (threadNumber < MaxThreadCount)
|
||||
{
|
||||
sem.wait();
|
||||
debug (semaphore)
|
||||
log.trace("Acquired semaphore");
|
||||
|
||||
while (true)
|
||||
{
|
||||
synchronized (mutex)
|
||||
{
|
||||
if (count >= MaxThreadCount + 1)
|
||||
break;
|
||||
}
|
||||
Thread.yield();
|
||||
}
|
||||
|
||||
debug (semaphore)
|
||||
log.trace("Releasing semaphore");
|
||||
sem.notify();
|
||||
}
|
||||
else
|
||||
{
|
||||
passed = !sem.tryWait();
|
||||
if (passed)
|
||||
{
|
||||
debug (semaphore)
|
||||
log.trace("Tried to acquire the semaphore too many times and failed: OK");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (semaphore)
|
||||
log.error("Tried to acquire the semaphore too may times and succeeded: FAILED");
|
||||
|
||||
debug (semaphore)
|
||||
log.trace("Releasing semaphore");
|
||||
sem.notify();
|
||||
}
|
||||
synchronized (mutex)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Cerr("Sync exception caught in Semaphore test thread " ~ Thread.getThis().name ~
|
||||
":\n" ~ e.toString()).newline;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Cerr("Unexpected exception caught in Semaphore test thread " ~ Thread.getThis().name ~
|
||||
":\n" ~ e.toString()).newline;
|
||||
}
|
||||
}
|
||||
|
||||
debug (semaphore)
|
||||
{
|
||||
Logger log = Log.getLogger("semaphore.single");
|
||||
}
|
||||
|
||||
ThreadGroup group = new ThreadGroup();
|
||||
Thread thread;
|
||||
char[10] tmp;
|
||||
|
||||
for (uint i = 0; i < MaxThreadCount; ++i)
|
||||
{
|
||||
thread = new Thread(&semaphoreTestThread);
|
||||
thread.name = "thread-" ~ tango.text.convert.Integer.format(tmp, i);
|
||||
|
||||
group.add(thread);
|
||||
debug (semaphore)
|
||||
log.trace("Created thread " ~ thread.name);
|
||||
thread.start();
|
||||
}
|
||||
|
||||
debug (semaphore)
|
||||
log.trace("Waiting for threads to finish");
|
||||
group.joinAll();
|
||||
|
||||
if (passed)
|
||||
{
|
||||
debug (semaphore)
|
||||
log.info("The Semaphore test was successful");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (semaphore)
|
||||
{
|
||||
log.error("The Semaphore is not working properly: it allowed "
|
||||
"to be acquired more than it should have done");
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false, "The Semaphore is not working properly: it allowed "
|
||||
"to be acquired more than it should have done");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for multi-process semaphores: this test works by creating a copy of
|
||||
* this process that tries to acquire the ProcessSemaphore that was created
|
||||
* in this function. If everything works as expected, the attempt should fail,
|
||||
* as the count of the semaphore is set to 1.
|
||||
*/
|
||||
void testProcessSemaphore(char[] programName)
|
||||
{
|
||||
/+
|
||||
bool success = false;
|
||||
|
||||
debug (semaphore)
|
||||
{
|
||||
Logger log = Log.getLogger("semaphore.multi");
|
||||
Logger childLog = Log.getLogger("semaphore.multi.child");
|
||||
|
||||
log.info("ProcessSemaphore test");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
scope ProcessSemaphore sem = new ProcessSemaphore(SemaphoreName, 1);
|
||||
Process proc = new Process(programName, "2");
|
||||
|
||||
debug (semaphore)
|
||||
log.trace("Created ProcessSemaphore('" ~ SemaphoreName ~ "')'");
|
||||
|
||||
sem.wait();
|
||||
debug (semaphore)
|
||||
log.trace("Acquired semaphore in main process");
|
||||
|
||||
debug (semaphore)
|
||||
log.trace("Executing child test process: " ~ proc.toString());
|
||||
proc.execute();
|
||||
|
||||
debug (semaphore)
|
||||
{
|
||||
foreach (line; new LineIterator!(char)(proc.stdout))
|
||||
{
|
||||
childLog.trace(line);
|
||||
}
|
||||
}
|
||||
foreach (line; new LineIterator!(char)(proc.stderr))
|
||||
{
|
||||
Cerr(line).newline;
|
||||
}
|
||||
|
||||
debug (semaphore)
|
||||
log.trace("Waiting for child process to finish");
|
||||
auto result = proc.wait();
|
||||
|
||||
success = (result.reason == Process.Result.Exit && result.status == 2);
|
||||
|
||||
debug (semaphore)
|
||||
log.trace("Releasing semaphore in main process");
|
||||
sem.notify();
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Cerr("Sync exception caught in ProcessSemaphore main test process:\n" ~ e.toString()).newline;
|
||||
}
|
||||
catch (ProcessException e)
|
||||
{
|
||||
Cerr("Process exception caught in ProcessSemaphore main test process:\n" ~ e.toString()).newline;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Cerr("Unexpected exception caught in ProcessSemaphore main test process:\n" ~ e.toString()).newline;
|
||||
}
|
||||
|
||||
if (success)
|
||||
{
|
||||
debug (semaphore)
|
||||
log.info("The ProcessSemaphore test was successful");
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (semaphore)
|
||||
{
|
||||
log.error("The multi-process semaphore is not working");
|
||||
assert(false);
|
||||
}
|
||||
else
|
||||
{
|
||||
assert(false, "The multi-process semaphore is not working");
|
||||
}
|
||||
}
|
||||
+/
|
||||
}
|
||||
|
||||
/**
|
||||
* Test for multi-process semaphores (second process).
|
||||
*/
|
||||
int testSecondProcessSemaphore()
|
||||
{
|
||||
int rc = 0;
|
||||
|
||||
/+
|
||||
debug (semaphore)
|
||||
{
|
||||
Cout("Starting child process\n");
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
scope ProcessSemaphore sem = new ProcessSemaphore(SemaphoreName);
|
||||
bool success;
|
||||
|
||||
success = !sem.tryAcquire();
|
||||
if (success)
|
||||
{
|
||||
debug (semaphore)
|
||||
Cout("Tried to acquire semaphore in child process and failed: OK\n");
|
||||
rc = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
debug (semaphore)
|
||||
{
|
||||
Cout("Acquired semaphore in child process: this should not have happened\n");
|
||||
Cout("Releasing semaphore in child process\n");
|
||||
}
|
||||
sem.notify();
|
||||
rc = 1;
|
||||
}
|
||||
}
|
||||
catch (SyncException e)
|
||||
{
|
||||
Cerr("Sync exception caught in ProcessSemaphore child test process:\n" ~ e.toString()).newline;
|
||||
}
|
||||
catch (ProcessException e)
|
||||
{
|
||||
Cerr("Process exception caught in ProcessSemaphore child test process:\n" ~ e.toString()).newline;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Cerr("Unexpected exception caught in ProcessSemaphore child test process:\n" ~ e.toString()).newline;
|
||||
}
|
||||
|
||||
debug (semaphore)
|
||||
Cout("Leaving child process\n");
|
||||
|
||||
+/
|
||||
return rc;
|
||||
}
|
||||
97
tango/example/system/arguments.d
Normal file
97
tango/example/system/arguments.d
Normal file
@@ -0,0 +1,97 @@
|
||||
/*******************************************************************************
|
||||
Illustrates use of the Arguments class.
|
||||
*******************************************************************************/
|
||||
|
||||
import tango.util.Arguments;
|
||||
import tango.io.Stdout;
|
||||
import tango.io.FileConduit;
|
||||
import tango.text.stream.LineIterator;
|
||||
|
||||
void usage()
|
||||
{
|
||||
Stdout("Usage: [OPTIONS]... FILES...").newline;
|
||||
Stdout("This is a program that does something.").newline;
|
||||
Stdout.newline;
|
||||
Stdout("OPTIONS: ").newline;
|
||||
Stdout("Output this help message: -?, --help").newline;
|
||||
Stdout("Do cool things to your files: -c, -C, --cool").newline;
|
||||
Stdout("Use filename as response file: -r, -R, --response").newline;
|
||||
}
|
||||
|
||||
void main(char[][] cmdlArgs)
|
||||
{
|
||||
char[][] implicitArguments = ["files"];
|
||||
|
||||
char[][][] argumentAliases;
|
||||
argumentAliases ~= ["help", "?"];
|
||||
argumentAliases ~= ["cool", "C", "c"];
|
||||
argumentAliases ~= ["response", "R", "r"];
|
||||
|
||||
auto args = new Arguments(cmdlArgs, implicitArguments, argumentAliases);
|
||||
|
||||
bool fileExistsValidation(char[] arg)
|
||||
{
|
||||
bool rtn;
|
||||
FilePath argFile = new FilePath(arg);
|
||||
rtn = argFile.exists;
|
||||
if (!rtn)
|
||||
Stdout.format("Specified path does not exist: {}", arg).newline;
|
||||
return rtn;
|
||||
}
|
||||
|
||||
bool singleFileValidation(char[][] args, inout char[] invalidArg)
|
||||
{
|
||||
if (args.length > 1)
|
||||
{
|
||||
Stdout("Cannot specify multiple paths for argument.").newline;
|
||||
invalidArg = args[1];
|
||||
}
|
||||
else
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
args.addValidation("response", &fileExistsValidation);
|
||||
args.addValidation("response", &singleFileValidation);
|
||||
args.addValidation("files", true, true);
|
||||
|
||||
bool argsValidated = true;
|
||||
try
|
||||
args.validate;
|
||||
catch (ArgumentException ex)
|
||||
{
|
||||
if (ex.reason == ArgumentException.ExceptionReason.MISSING_ARGUMENT)
|
||||
Stdout.format("Missing Argument: {} ({})", ex.name, ex.msg).newline;
|
||||
else if (ex.reason == ArgumentException.ExceptionReason.MISSING_PARAMETER)
|
||||
Stdout.format("Missing Parameter to Argument: {} ({})", ex.name, ex.msg).newline;
|
||||
else if (ex.reason == ArgumentException.ExceptionReason.INVALID_PARAMETER)
|
||||
Stdout.format("Invalid Parameter: {} ({})", ex.name, ex.msg).newline;
|
||||
Stdout.newline;
|
||||
argsValidated = false;
|
||||
}
|
||||
|
||||
if ((!argsValidated) || ("help" in args))
|
||||
usage();
|
||||
else
|
||||
{// ready to run
|
||||
if ("response" in args)
|
||||
{
|
||||
Stdout(args["response"][0]).newline;
|
||||
auto file = new FileConduit(args["response"][0]);
|
||||
auto lines = new LineIterator!(char)(file);
|
||||
char[][] arguments;
|
||||
foreach (line; lines)
|
||||
arguments ~= line.dup;
|
||||
args.parse(arguments, implicitArguments, argumentAliases);
|
||||
}
|
||||
if ("cool" in args)
|
||||
{
|
||||
Stdout ("Listing the files to be actioned in a cool way.").newline;
|
||||
foreach (char[] file; args["files"])
|
||||
Stdout.format("{}", file).newline;
|
||||
Stdout ("Cool and secret action performed.").newline;
|
||||
}
|
||||
if ("x" in args)
|
||||
Stdout.format("User set the X factor to '{}'", args["x"]).newline;
|
||||
}
|
||||
}
|
||||
54
tango/example/system/localtime.d
Normal file
54
tango/example/system/localtime.d
Normal file
@@ -0,0 +1,54 @@
|
||||
/*******************************************************************************
|
||||
|
||||
localtime.d
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
private import tango.io.Stdout;
|
||||
|
||||
private import tango.time.WallClock;
|
||||
|
||||
/******************************************************************************
|
||||
|
||||
Example code to format a local time in the following format:
|
||||
"Wed Dec 31 16:00:00 GMT-0800 1969". The day and month names
|
||||
would typically be extracted from a locale instance, but we
|
||||
convert them locally here for the sake of simplicity
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
void main ()
|
||||
{
|
||||
/// list of day names
|
||||
static char[][] days = ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"];
|
||||
|
||||
/// list of month names
|
||||
static char[][] months =
|
||||
[
|
||||
"Jan", "Feb", "Mar", "Apr", "May", "Jun",
|
||||
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
|
||||
];
|
||||
|
||||
// retreive local time
|
||||
auto dt = WallClock.toDate;
|
||||
|
||||
// get GMT difference in minutes
|
||||
auto tz = cast(int) WallClock.zone.minutes;
|
||||
char sign = '+';
|
||||
if (tz < 0)
|
||||
tz = -tz, sign = '-';
|
||||
|
||||
// format date
|
||||
Stdout.formatln ("{}, {} {:d2} {:d2}:{:d2}:{:d2} GMT{}{:d2}:{:d2} {}",
|
||||
days[dt.date.dow],
|
||||
months[dt.date.month-1],
|
||||
dt.date.day,
|
||||
dt.time.hours,
|
||||
dt.time.minutes,
|
||||
dt.time.seconds,
|
||||
sign,
|
||||
tz / 60,
|
||||
tz % 60,
|
||||
dt.date.year
|
||||
);
|
||||
}
|
||||
51
tango/example/system/normpath.d
Normal file
51
tango/example/system/normpath.d
Normal file
@@ -0,0 +1,51 @@
|
||||
/*****************************************************************
|
||||
|
||||
Simple example that shows possible inputs to normalize and the
|
||||
corresponding outputs.
|
||||
|
||||
Put into public domain by Lars Ivar Igesund.
|
||||
|
||||
*****************************************************************/
|
||||
|
||||
import tango.io.Stdout;
|
||||
|
||||
import tango.util.PathUtil;
|
||||
|
||||
int main()
|
||||
{
|
||||
version (Posix) {
|
||||
Stdout(normalize ( "/foo/../john")).newline;
|
||||
Stdout(normalize ( "foo/../john")).newline;
|
||||
Stdout(normalize ( "foo/bar/..")).newline;
|
||||
Stdout(normalize ( "foo/bar/../john")).newline;
|
||||
Stdout(normalize ( "foo/bar/doe/../../john")).newline;
|
||||
Stdout(normalize ( "foo/bar/doe/../../john/../bar")).newline;
|
||||
Stdout(normalize ( "./foo/bar/doe")).newline;
|
||||
Stdout(normalize ( "./foo/bar/doe/../../john/../bar")).newline;
|
||||
Stdout(normalize ( "./foo/bar/../../john/../bar")).newline;
|
||||
Stdout(normalize ( "foo/bar/./doe/../../john")).newline;
|
||||
Stdout(normalize ( "../../foo/bar/./doe/../../john")).newline;
|
||||
Stdout(normalize ( "../../../foo/bar")).newline;
|
||||
Stdout("** Should now throw exception as the following path is invalid for normalization.").newline;
|
||||
Stdout(normalize ( "/../../../foo/bar")).newline;
|
||||
}
|
||||
version (Windows) {
|
||||
Stdout(normalize ( "C:\\foo\\..\\john")).newline;
|
||||
Stdout(normalize ( "foo\\..\\john")).newline;
|
||||
Stdout(normalize ( "foo\\bar\\..")).newline;
|
||||
Stdout(normalize ( "foo\\bar\\..\\john")).newline;
|
||||
Stdout(normalize ( "foo\\bar\\doe\\..\\..\\john")).newline;
|
||||
Stdout(normalize ( "foo\\bar\\doe\\..\\..\\john\\..\\bar")).newline;
|
||||
Stdout(normalize ( ".\\foo\\bar\\doe")).newline;
|
||||
Stdout(normalize ( ".\\foo\\bar\\doe\\..\\..\\john\\..\\bar")).newline;
|
||||
Stdout(normalize ( ".\\foo\\bar\\..\\..\\john\\..\\bar")).newline;
|
||||
Stdout(normalize ( "foo\\bar\\.\\doe\\..\\..\\john")).newline;
|
||||
Stdout(normalize ( "..\\..\\foo\\bar\\.\\doe\\..\\..\\john")).newline;
|
||||
Stdout(normalize ( "..\\..\\..\\foo\\bar")).newline;
|
||||
Stdout("** Should now throw exception as the following path is invalid for normalization.").newline;
|
||||
Stdout(normalize ( "C:\\..\\..\\..\\foo\\bar")).newline;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
60
tango/example/system/process.d
Normal file
60
tango/example/system/process.d
Normal file
@@ -0,0 +1,60 @@
|
||||
/*******************************************************************************
|
||||
copyright: Copyright (c) 2006 Juan Jose Comellas. All rights reserved
|
||||
license: BSD style: $(LICENSE)
|
||||
author: Juan Jose Comellas <juanjo@comellas.com.ar>
|
||||
*******************************************************************************/
|
||||
|
||||
private import tango.io.Stdout;
|
||||
private import tango.sys.Process;
|
||||
private import tango.core.Exception;
|
||||
|
||||
private import tango.text.stream.LineIterator;
|
||||
|
||||
|
||||
/**
|
||||
* Example program for the tango.sys.Process class.
|
||||
*/
|
||||
void main()
|
||||
{
|
||||
version (Windows)
|
||||
char[] command = "ping -n 4 localhost";
|
||||
else version (Posix)
|
||||
char[] command = "ping -c 4 localhost";
|
||||
else
|
||||
assert(false, "Unsupported platform");
|
||||
|
||||
try
|
||||
{
|
||||
auto p = new Process(command, null);
|
||||
|
||||
Stdout.formatln("Executing {0}", p.toString());
|
||||
p.execute();
|
||||
|
||||
Stdout.formatln("Output from process: {0} (pid {1})\n---",
|
||||
p.programName, p.pid);
|
||||
|
||||
foreach (line; new LineIterator!(char)(p.stdout))
|
||||
{
|
||||
Stdout.formatln("{0}", line);
|
||||
}
|
||||
|
||||
Stdout.print("---\n");
|
||||
|
||||
auto result = p.wait();
|
||||
|
||||
Stdout.formatln("Process '{0}' ({1}) finished: {2}",
|
||||
p.programName, p.pid, result.toString());
|
||||
}
|
||||
catch (ProcessException e)
|
||||
{
|
||||
Stdout.formatln("Process execution failed: {0}", e.toString());
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
Stdout.formatln("Input/output exception caught: {0}", e.toString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Stdout.formatln("Unexpected exception caught: {0}", e.toString());
|
||||
}
|
||||
}
|
||||
20
tango/example/text/formatalign.d
Normal file
20
tango/example/text/formatalign.d
Normal file
@@ -0,0 +1,20 @@
|
||||
/**
|
||||
|
||||
Example showing how the alignment component in a format string argument works.
|
||||
|
||||
Put into public domain by Lars Ivar Igesund
|
||||
|
||||
*/
|
||||
|
||||
import tango.io.Stdout;
|
||||
|
||||
void main(){
|
||||
char[] myFName = "Johnny";
|
||||
Stdout.formatln("First Name = |{0,15}|", myFName);
|
||||
Stdout.formatln("Last Name = |{0,15}|", "Foo de Bar");
|
||||
|
||||
Stdout.formatln("First Name = |{0,-15}|", myFName);
|
||||
Stdout.formatln("Last Name = |{0,-15}|", "Foo de Bar");
|
||||
|
||||
Stdout.formatln("First name = |{0,5}|", myFName);
|
||||
}
|
||||
15
tango/example/text/formatindex.d
Normal file
15
tango/example/text/formatindex.d
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
|
||||
Example that shows how the format specifiers can be used to index into
|
||||
the argument list.
|
||||
|
||||
Put into public domain by Lars Ivar Igesund.
|
||||
|
||||
*/
|
||||
|
||||
import tango.io.Stdout;
|
||||
|
||||
void main(){
|
||||
Stdout.formatln("Many {1} can now be {0} around to make {2} easier,\n and {1} can also be repeated.",
|
||||
"switched", "arguments", "localization");
|
||||
}
|
||||
17
tango/example/text/formatspec.d
Normal file
17
tango/example/text/formatspec.d
Normal file
@@ -0,0 +1,17 @@
|
||||
/**
|
||||
|
||||
Example showing how to use format specifier components in a format string's
|
||||
argument.
|
||||
|
||||
Put into public domain by Lars Ivar Igesund
|
||||
|
||||
*/
|
||||
|
||||
import tango.io.Stdout;
|
||||
|
||||
void main(){
|
||||
double avogadros = 6.0221415e23;
|
||||
Stdout.formatln("I have {0:C} in cash.", 100);
|
||||
Stdout.formatln("Avogadro's number is {0:E}.", avogadros);
|
||||
Stdout.formatln("Avogadro's number (with alignment) is {0,4:E}.", avogadros);
|
||||
}
|
||||
21
tango/example/text/localetime.d
Normal file
21
tango/example/text/localetime.d
Normal file
@@ -0,0 +1,21 @@
|
||||
/******************************************************************************
|
||||
|
||||
Example to format a locale-based time. For a default locale of
|
||||
en-gb, this examples formats in the following manner:
|
||||
|
||||
"Thu, 27 April 2006 18:20:47 +1"
|
||||
|
||||
******************************************************************************/
|
||||
|
||||
private import tango.io.Console;
|
||||
|
||||
private import tango.time.Clock;
|
||||
|
||||
private import tango.text.locale.Locale;
|
||||
|
||||
void main ()
|
||||
{
|
||||
auto layout = new Locale;
|
||||
|
||||
Cout (layout ("{:ddd, dd MMMM yyyy HH:mm:ss z}", Clock.now)).newline;
|
||||
}
|
||||
32
tango/example/text/properties.d
Normal file
32
tango/example/text/properties.d
Normal file
@@ -0,0 +1,32 @@
|
||||
private import tango.io.Buffer,
|
||||
tango.io.Console;
|
||||
|
||||
private import tango.text.Properties;
|
||||
|
||||
/*******************************************************************************
|
||||
|
||||
Illustrates simple usage of tango.text.Properties
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
void main()
|
||||
{
|
||||
char[][char[]] aa;
|
||||
aa ["foo"] = "something";
|
||||
aa ["bar"] = "something else";
|
||||
aa ["wumpus"] = "";
|
||||
|
||||
// write associative-array to a buffer; could use a file
|
||||
auto props = new Properties!(char);
|
||||
auto buffer = new Buffer (256);
|
||||
props.save (buffer, aa);
|
||||
|
||||
// reset and repopulate AA from the buffer
|
||||
aa = null;
|
||||
props.load (buffer, (char[] name, char[] value){aa[name] = value;});
|
||||
|
||||
// display result
|
||||
foreach (name, value; aa)
|
||||
Cout (name) (" = ") (value).newline;
|
||||
}
|
||||
|
||||
25
tango/example/text/token.d
Normal file
25
tango/example/text/token.d
Normal file
@@ -0,0 +1,25 @@
|
||||
/*******************************************************************************
|
||||
|
||||
Tokenize input from the console. There are a variety of handy
|
||||
tokenizers in the tango.text package ~ this illustrates usage
|
||||
of an iterator that recognizes quoted-strings within an input
|
||||
array, and splits elements on a provided set of delimiters
|
||||
|
||||
*******************************************************************************/
|
||||
|
||||
import tango.io.Console;
|
||||
|
||||
import Text = tango.text.Util;
|
||||
|
||||
void main()
|
||||
{
|
||||
// flush the console output, since we have no newline present
|
||||
Cout ("Please enter some space-separated tokens: ") ();
|
||||
|
||||
// create quote-aware iterator for handling space-delimited
|
||||
// tokens from the console input
|
||||
foreach (element; Text.quotes (Text.trim(Cin.get), " \t"))
|
||||
Cout ("<") (element) ("> ");
|
||||
|
||||
Cout.newline;
|
||||
}
|
||||
286
tango/lib/common/tango/core/BitManip.d
Normal file
286
tango/lib/common/tango/core/BitManip.d
Normal file
@@ -0,0 +1,286 @@
|
||||
/**
|
||||
* This module contains a collection of bit-level operations.
|
||||
*
|
||||
* Copyright: Public Domain
|
||||
* License: Public Domain
|
||||
* Authors: Sean Kelly
|
||||
*/
|
||||
module tango.core.BitManip;
|
||||
|
||||
|
||||
version( DDoc )
|
||||
{
|
||||
/**
|
||||
* Scans the bits in v starting with bit 0, looking
|
||||
* for the first set bit.
|
||||
* Returns:
|
||||
* The bit number of the first bit set.
|
||||
* The return value is undefined if v is zero.
|
||||
*/
|
||||
int bsf( uint v );
|
||||
|
||||
|
||||
/**
|
||||
* Scans the bits in v from the most significant bit
|
||||
* to the least significant bit, looking
|
||||
* for the first set bit.
|
||||
* Returns:
|
||||
* The bit number of the first bit set.
|
||||
* The return value is undefined if v is zero.
|
||||
* Example:
|
||||
* ---
|
||||
* import std.intrinsic;
|
||||
*
|
||||
* int main()
|
||||
* {
|
||||
* uint v;
|
||||
* int x;
|
||||
*
|
||||
* v = 0x21;
|
||||
* x = bsf(v);
|
||||
* printf("bsf(x%x) = %d\n", v, x);
|
||||
* x = bsr(v);
|
||||
* printf("bsr(x%x) = %d\n", v, x);
|
||||
* return 0;
|
||||
* }
|
||||
* ---
|
||||
* Output:
|
||||
* bsf(x21) = 0<br>
|
||||
* bsr(x21) = 5
|
||||
*/
|
||||
int bsr( uint v );
|
||||
|
||||
|
||||
/**
|
||||
* Tests the bit.
|
||||
*/
|
||||
int bt( uint* p, uint bitnum );
|
||||
|
||||
|
||||
/**
|
||||
* Tests and complements the bit.
|
||||
*/
|
||||
int btc( uint* p, uint bitnum );
|
||||
|
||||
|
||||
/**
|
||||
* Tests and resets (sets to 0) the bit.
|
||||
*/
|
||||
int btr( uint* p, uint bitnum );
|
||||
|
||||
|
||||
/**
|
||||
* Tests and sets the bit.
|
||||
* Params:
|
||||
* p = a non-NULL pointer to an array of uints.
|
||||
* index = a bit number, starting with bit 0 of p[0],
|
||||
* and progressing. It addresses bits like the expression:
|
||||
---
|
||||
p[index / (uint.sizeof*8)] & (1 << (index & ((uint.sizeof*8) - 1)))
|
||||
---
|
||||
* Returns:
|
||||
* A non-zero value if the bit was set, and a zero
|
||||
* if it was clear.
|
||||
*
|
||||
* Example:
|
||||
* ---
|
||||
import std.intrinsic;
|
||||
|
||||
int main()
|
||||
{
|
||||
uint array[2];
|
||||
|
||||
array[0] = 2;
|
||||
array[1] = 0x100;
|
||||
|
||||
printf("btc(array, 35) = %d\n", <b>btc</b>(array, 35));
|
||||
printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
|
||||
|
||||
printf("btc(array, 35) = %d\n", <b>btc</b>(array, 35));
|
||||
printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
|
||||
|
||||
printf("bts(array, 35) = %d\n", <b>bts</b>(array, 35));
|
||||
printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
|
||||
|
||||
printf("btr(array, 35) = %d\n", <b>btr</b>(array, 35));
|
||||
printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
|
||||
|
||||
printf("bt(array, 1) = %d\n", <b>bt</b>(array, 1));
|
||||
printf("array = [0]:x%x, [1]:x%x\n", array[0], array[1]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
* ---
|
||||
* Output:
|
||||
<pre>
|
||||
btc(array, 35) = 0
|
||||
array = [0]:x2, [1]:x108
|
||||
btc(array, 35) = -1
|
||||
array = [0]:x2, [1]:x100
|
||||
bts(array, 35) = 0
|
||||
array = [0]:x2, [1]:x108
|
||||
btr(array, 35) = -1
|
||||
array = [0]:x2, [1]:x100
|
||||
bt(array, 1) = -1
|
||||
array = [0]:x2, [1]:x100
|
||||
</pre>
|
||||
*/
|
||||
int bts( uint* p, uint bitnum );
|
||||
|
||||
|
||||
/**
|
||||
* Swaps bytes in a 4 byte uint end-to-end, i.e. byte 0 becomes
|
||||
* byte 3, byte 1 becomes byte 2, byte 2 becomes byte 1, byte 3
|
||||
* becomes byte 0.
|
||||
*/
|
||||
uint bswap( uint v );
|
||||
|
||||
|
||||
/**
|
||||
* Reads I/O port at port_address.
|
||||
*/
|
||||
ubyte inp( uint port_address );
|
||||
|
||||
|
||||
/**
|
||||
* ditto
|
||||
*/
|
||||
ushort inpw( uint port_address );
|
||||
|
||||
|
||||
/**
|
||||
* ditto
|
||||
*/
|
||||
uint inpl( uint port_address );
|
||||
|
||||
|
||||
/**
|
||||
* Writes and returns value to I/O port at port_address.
|
||||
*/
|
||||
ubyte outp( uint port_address, ubyte value );
|
||||
|
||||
|
||||
/**
|
||||
* ditto
|
||||
*/
|
||||
ushort outpw( uint port_address, ushort value );
|
||||
|
||||
|
||||
/**
|
||||
* ditto
|
||||
*/
|
||||
uint outpl( uint port_address, uint value );
|
||||
}
|
||||
else
|
||||
{
|
||||
public import std.intrinsic;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates the number of set bits in a 32-bit integer.
|
||||
*/
|
||||
int popcnt( uint x )
|
||||
{
|
||||
// Avoid branches, and the potential for cache misses which
|
||||
// could be incurred with a table lookup.
|
||||
|
||||
// We need to mask alternate bits to prevent the
|
||||
// sum from overflowing.
|
||||
// add neighbouring bits. Each bit is 0 or 1.
|
||||
x = x - ((x>>1) & 0x5555_5555);
|
||||
// now each two bits of x is a number 00,01 or 10.
|
||||
// now add neighbouring pairs
|
||||
x = ((x&0xCCCC_CCCC)>>2) + (x&0x3333_3333);
|
||||
// now each nibble holds 0000-0100. Adding them won't
|
||||
// overflow any more, so we don't need to mask any more
|
||||
|
||||
// Now add the nibbles, then the bytes, then the words
|
||||
// We still need to mask to prevent double-counting.
|
||||
// Note that if we used a rotate instead of a shift, we
|
||||
// wouldn't need the masks, and could just divide the sum
|
||||
// by 8 to account for the double-counting.
|
||||
// On some CPUs, it may be faster to perform a multiply.
|
||||
|
||||
x += (x>>4);
|
||||
x &= 0x0F0F_0F0F;
|
||||
x += (x>>8);
|
||||
x &= 0x00FF_00FF;
|
||||
x += (x>>16);
|
||||
x &= 0xFFFF;
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
debug( UnitTest )
|
||||
{
|
||||
unittest
|
||||
{
|
||||
assert( popcnt( 0 ) == 0 );
|
||||
assert( popcnt( 7 ) == 3 );
|
||||
assert( popcnt( 0xAA )== 4 );
|
||||
assert( popcnt( 0x8421_1248 ) == 8 );
|
||||
assert( popcnt( 0xFFFF_FFFF ) == 32 );
|
||||
assert( popcnt( 0xCCCC_CCCC ) == 16 );
|
||||
assert( popcnt( 0x7777_7777 ) == 24 );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Reverses the order of bits in a 32-bit integer.
|
||||
*/
|
||||
uint bitswap( uint x )
|
||||
{
|
||||
|
||||
version( D_InlineAsm_X86 )
|
||||
{
|
||||
asm
|
||||
{
|
||||
// Author: Tiago Gasiba.
|
||||
mov EDX, EAX;
|
||||
shr EAX, 1;
|
||||
and EDX, 0x5555_5555;
|
||||
and EAX, 0x5555_5555;
|
||||
shl EDX, 1;
|
||||
or EAX, EDX;
|
||||
mov EDX, EAX;
|
||||
shr EAX, 2;
|
||||
and EDX, 0x3333_3333;
|
||||
and EAX, 0x3333_3333;
|
||||
shl EDX, 2;
|
||||
or EAX, EDX;
|
||||
mov EDX, EAX;
|
||||
shr EAX, 4;
|
||||
and EDX, 0x0f0f_0f0f;
|
||||
and EAX, 0x0f0f_0f0f;
|
||||
shl EDX, 4;
|
||||
or EAX, EDX;
|
||||
bswap EAX;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// swap odd and even bits
|
||||
x = ((x >> 1) & 0x5555_5555) | ((x & 0x5555_5555) << 1);
|
||||
// swap consecutive pairs
|
||||
x = ((x >> 2) & 0x3333_3333) | ((x & 0x3333_3333) << 2);
|
||||
// swap nibbles
|
||||
x = ((x >> 4) & 0x0F0F_0F0F) | ((x & 0x0F0F_0F0F) << 4);
|
||||
// swap bytes
|
||||
x = ((x >> 8) & 0x00FF_00FF) | ((x & 0x00FF_00FF) << 8);
|
||||
// swap 2-byte long pairs
|
||||
x = ( x >> 16 ) | ( x << 16);
|
||||
return x;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
debug( UnitTest )
|
||||
{
|
||||
unittest
|
||||
{
|
||||
assert( bitswap( 0x8000_0100 ) == 0x0080_0001 );
|
||||
}
|
||||
}
|
||||
622
tango/lib/common/tango/core/Exception.d
Normal file
622
tango/lib/common/tango/core/Exception.d
Normal file
@@ -0,0 +1,622 @@
|
||||
/**
|
||||
* The exception module defines all system-level exceptions and provides a
|
||||
* mechanism to alter system-level error handling.
|
||||
*
|
||||
* Copyright: Copyright (C) 2005-2006 Sean Kelly, Kris Bell. All rights reserved.
|
||||
* License: BSD style: $(LICENSE)
|
||||
* Authors: Sean Kelly, Kris Bell
|
||||
*/
|
||||
module tango.core.Exception;
|
||||
|
||||
|
||||
private
|
||||
{
|
||||
alias void function( char[] file, size_t line, char[] msg = null ) assertHandlerType;
|
||||
alias TracedExceptionInfo function( void* ptr = null ) traceHandlerType;
|
||||
|
||||
assertHandlerType assertHandler = null;
|
||||
traceHandlerType traceHandler = null;
|
||||
}
|
||||
|
||||
|
||||
interface TracedExceptionInfo
|
||||
{
|
||||
int opApply( int delegate( inout char[] ) );
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
/*
|
||||
- Exception
|
||||
- OutOfMemoryException
|
||||
|
||||
- TracedException
|
||||
- SwitchException
|
||||
- AssertException
|
||||
- ArrayBoundsException
|
||||
- FinalizeException
|
||||
|
||||
- PlatformException
|
||||
- ProcessException
|
||||
- ThreadException
|
||||
- FiberException
|
||||
- SyncException
|
||||
- IOException
|
||||
- SocketException
|
||||
- SocketAcceptException
|
||||
- AddressException
|
||||
- HostException
|
||||
- VfsException
|
||||
- ClusterException
|
||||
|
||||
- NoSuchElementException
|
||||
- CorruptedIteratorException
|
||||
|
||||
- IllegalArgumentException
|
||||
- IllegalElementException
|
||||
|
||||
- TextException
|
||||
- RegexException
|
||||
- LocaleException
|
||||
- UnicodeException
|
||||
|
||||
- PayloadException
|
||||
*/
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Thrown on an out of memory error.
|
||||
*/
|
||||
class OutOfMemoryException : Exception
|
||||
{
|
||||
this( char[] file, size_t line )
|
||||
{
|
||||
super( "Memory allocation failed", file, line );
|
||||
}
|
||||
|
||||
char[] toString()
|
||||
{
|
||||
return msg ? super.toString() : "Memory allocation failed";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Stores a stack trace when thrown.
|
||||
*/
|
||||
class TracedException : Exception
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
m_info = traceContext();
|
||||
}
|
||||
|
||||
this( char[] msg, Exception e )
|
||||
{
|
||||
super( msg, e );
|
||||
m_info = traceContext();
|
||||
}
|
||||
|
||||
this( char[] msg, char[] file, size_t line )
|
||||
{
|
||||
super( msg, file, line );
|
||||
m_info = traceContext();
|
||||
}
|
||||
|
||||
char[] toString()
|
||||
{
|
||||
if( m_info is null )
|
||||
return super.toString();
|
||||
char[] buf = super.toString();
|
||||
buf ~= "\n----------------";
|
||||
foreach( line; m_info )
|
||||
buf ~= "\n" ~ line;
|
||||
return buf;
|
||||
}
|
||||
|
||||
int opApply( int delegate( inout char[] buf ) dg )
|
||||
{
|
||||
if( m_info is null )
|
||||
return 0;
|
||||
return m_info.opApply( dg );
|
||||
}
|
||||
|
||||
private:
|
||||
TracedExceptionInfo m_info;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base class for operating system or library exceptions.
|
||||
*/
|
||||
class PlatformException : TracedException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown on an assert error.
|
||||
*/
|
||||
class AssertException : TracedException
|
||||
{
|
||||
this( char[] file, size_t line )
|
||||
{
|
||||
super( "Assertion failure", file, line );
|
||||
}
|
||||
|
||||
this( char[] msg, char[] file, size_t line )
|
||||
{
|
||||
super( msg, file, line );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Thrown on an array bounds error.
|
||||
*/
|
||||
class ArrayBoundsException : TracedException
|
||||
{
|
||||
this( char[] file, size_t line )
|
||||
{
|
||||
super( "Array index out of bounds", file, line );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Thrown on finalize error.
|
||||
*/
|
||||
class FinalizeException : TracedException
|
||||
{
|
||||
ClassInfo info;
|
||||
|
||||
this( ClassInfo c, Exception e = null )
|
||||
{
|
||||
super( "Finalization error", e );
|
||||
info = c;
|
||||
}
|
||||
|
||||
char[] toString()
|
||||
{
|
||||
//return "An exception was thrown while finalizing an instance of class " ~ info.name;
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Thrown on a switch error.
|
||||
*/
|
||||
class SwitchException : TracedException
|
||||
{
|
||||
this( char[] file, size_t line )
|
||||
{
|
||||
super( "No appropriate switch clause found", file, line );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Represents a text processing error.
|
||||
*/
|
||||
class TextException : TracedException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Thrown on a unicode conversion error.
|
||||
*/
|
||||
class UnicodeException : TextException
|
||||
{
|
||||
size_t idx;
|
||||
|
||||
this( char[] msg, size_t idx )
|
||||
{
|
||||
super( msg );
|
||||
this.idx = idx;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base class for thread exceptions.
|
||||
*/
|
||||
class ThreadException : PlatformException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base class for fiber exceptions.
|
||||
*/
|
||||
class FiberException : ThreadException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base class for synchronization exceptions.
|
||||
*/
|
||||
class SyncException : PlatformException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The basic exception thrown by the tango.io package. One should try to ensure
|
||||
* that all Tango exceptions related to IO are derived from this one.
|
||||
*/
|
||||
class IOException : PlatformException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The basic exception thrown by the tango.io.vfs package.
|
||||
*/
|
||||
private class VfsException : IOException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The basic exception thrown by the tango.io.cluster package.
|
||||
*/
|
||||
private class ClusterException : IOException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for socket exceptions.
|
||||
*/
|
||||
class SocketException : IOException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base class for exception thrown by an InternetHost.
|
||||
*/
|
||||
class HostException : IOException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base class for exceptiond thrown by an Address.
|
||||
*/
|
||||
class AddressException : IOException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Thrown when a socket failed to accept an incoming connection.
|
||||
*/
|
||||
class SocketAcceptException : SocketException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Thrown on a process error.
|
||||
*/
|
||||
class ProcessException : PlatformException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base class for regluar expression exceptions.
|
||||
*/
|
||||
class RegexException : TextException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Base class for locale exceptions.
|
||||
*/
|
||||
class LocaleException : TextException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* RegistryException is thrown when the NetworkRegistry encounters a
|
||||
* problem during proxy registration, or when it sees an unregistered
|
||||
* guid.
|
||||
*/
|
||||
class RegistryException : TracedException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Thrown when an illegal argument is encountered.
|
||||
*/
|
||||
class IllegalArgumentException : TracedException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* IllegalElementException is thrown by Collection methods
|
||||
* that add (or replace) elements (and/or keys) when their
|
||||
* arguments are null or do not pass screeners.
|
||||
*
|
||||
*/
|
||||
class IllegalElementException : IllegalArgumentException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Thrown on past-the-end errors by iterators and containers.
|
||||
*/
|
||||
class NoSuchElementException : TracedException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Thrown when a corrupt iterator is detected.
|
||||
*/
|
||||
class CorruptedIteratorException : NoSuchElementException
|
||||
{
|
||||
this( char[] msg )
|
||||
{
|
||||
super( msg );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Overrides
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Overrides the default assert hander with a user-supplied version.
|
||||
*
|
||||
* Params:
|
||||
* h = The new assert handler. Set to null to use the default handler.
|
||||
*/
|
||||
void setAssertHandler( assertHandlerType h )
|
||||
{
|
||||
assertHandler = h;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overrides the default trace hander with a user-supplied version.
|
||||
*
|
||||
* Params:
|
||||
* h = The new trace handler. Set to null to use the default handler.
|
||||
*/
|
||||
void setTraceHandler( traceHandlerType h )
|
||||
{
|
||||
traceHandler = h;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Overridable Callbacks
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* A callback for assert errors in D. The user-supplied assert handler will
|
||||
* be called if one has been supplied, otherwise an AssertException will be
|
||||
* thrown.
|
||||
*
|
||||
* Params:
|
||||
* file = The name of the file that signaled this error.
|
||||
* line = The line number on which this error occurred.
|
||||
*/
|
||||
extern (C) void onAssertError( char[] file, size_t line )
|
||||
{
|
||||
if( assertHandler is null )
|
||||
throw new AssertException( file, line );
|
||||
assertHandler( file, line );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A callback for assert errors in D. The user-supplied assert handler will
|
||||
* be called if one has been supplied, otherwise an AssertException will be
|
||||
* thrown.
|
||||
*
|
||||
* Params:
|
||||
* file = The name of the file that signaled this error.
|
||||
* line = The line number on which this error occurred.
|
||||
* msg = An error message supplied by the user.
|
||||
*/
|
||||
extern (C) void onAssertErrorMsg( char[] file, size_t line, char[] msg )
|
||||
{
|
||||
if( assertHandler is null )
|
||||
throw new AssertException( msg, file, line );
|
||||
assertHandler( file, line, msg );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function will be called when a TracedException is constructed. The
|
||||
* user-supplied trace handler will be called if one has been supplied,
|
||||
* otherwise no trace will be generated.
|
||||
*
|
||||
* Params:
|
||||
* ptr = A pointer to the location from which to generate the trace, or null
|
||||
* if the trace should be generated from within the trace handler
|
||||
* itself.
|
||||
*
|
||||
* Returns:
|
||||
* An object describing the current calling context or null if no handler is
|
||||
* supplied.
|
||||
*/
|
||||
TracedExceptionInfo traceContext( void* ptr = null )
|
||||
{
|
||||
if( traceHandler is null )
|
||||
return null;
|
||||
return traceHandler( ptr );
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Internal Error Callbacks
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* A callback for array bounds errors in D. An ArrayBoundsException will be
|
||||
* thrown.
|
||||
*
|
||||
* Params:
|
||||
* file = The name of the file that signaled this error.
|
||||
* line = The line number on which this error occurred.
|
||||
*
|
||||
* Throws:
|
||||
* ArrayBoundsException.
|
||||
*/
|
||||
extern (C) void onArrayBoundsError( char[] file, size_t line )
|
||||
{
|
||||
throw new ArrayBoundsException( file, line );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A callback for finalize errors in D. A FinalizeException will be thrown.
|
||||
*
|
||||
* Params:
|
||||
* e = The exception thrown during finalization.
|
||||
*
|
||||
* Throws:
|
||||
* FinalizeException.
|
||||
*/
|
||||
extern (C) void onFinalizeError( ClassInfo info, Exception ex )
|
||||
{
|
||||
throw new FinalizeException( info, ex );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A callback for out of memory errors in D. An OutOfMemoryException will be
|
||||
* thrown.
|
||||
*
|
||||
* Throws:
|
||||
* OutOfMemoryException.
|
||||
*/
|
||||
extern (C) void onOutOfMemoryError()
|
||||
{
|
||||
// NOTE: Since an out of memory condition exists, no allocation must occur
|
||||
// while generating this object.
|
||||
throw cast(OutOfMemoryException) cast(void*) OutOfMemoryException.classinfo.init;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A callback for switch errors in D. A SwitchException will be thrown.
|
||||
*
|
||||
* Params:
|
||||
* file = The name of the file that signaled this error.
|
||||
* line = The line number on which this error occurred.
|
||||
*
|
||||
* Throws:
|
||||
* SwitchException.
|
||||
*/
|
||||
extern (C) void onSwitchError( char[] file, size_t line )
|
||||
{
|
||||
throw new SwitchException( file, line );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A callback for unicode errors in D. A UnicodeException will be thrown.
|
||||
*
|
||||
* Params:
|
||||
* msg = Information about the error.
|
||||
* idx = String index where this error was detected.
|
||||
*
|
||||
* Throws:
|
||||
* UnicodeException.
|
||||
*/
|
||||
extern (C) void onUnicodeError( char[] msg, size_t idx )
|
||||
{
|
||||
throw new UnicodeException( msg, idx );
|
||||
}
|
||||
458
tango/lib/common/tango/core/Memory.d
Normal file
458
tango/lib/common/tango/core/Memory.d
Normal file
@@ -0,0 +1,458 @@
|
||||
/**
|
||||
* The memory module provides an interface to the garbage collector and to
|
||||
* any other OS or API-level memory management facilities.
|
||||
*
|
||||
* Copyright: Copyright (C) 2005-2006 Sean Kelly. All rights reserved.
|
||||
* License: BSD style: $(LICENSE)
|
||||
* Authors: Sean Kelly
|
||||
*/
|
||||
module tango.core.Memory;
|
||||
|
||||
|
||||
private
|
||||
{
|
||||
extern (C) void gc_init();
|
||||
extern (C) void gc_term();
|
||||
|
||||
extern (C) void gc_enable();
|
||||
extern (C) void gc_disable();
|
||||
extern (C) void gc_collect();
|
||||
|
||||
extern (C) uint gc_getAttr( void* p );
|
||||
extern (C) uint gc_setAttr( void* p, uint a );
|
||||
extern (C) uint gc_clrAttr( void* p, uint a );
|
||||
|
||||
extern (C) void* gc_malloc( size_t sz, uint ba = 0 );
|
||||
extern (C) void* gc_calloc( size_t sz, uint ba = 0 );
|
||||
extern (C) void* gc_realloc( void* p, size_t sz, uint ba = 0 );
|
||||
extern (C) size_t gc_extend( void* p, size_t mx, size_t sz );
|
||||
extern (C) void gc_free( void* p );
|
||||
|
||||
extern (C) void* gc_addrOf( void* p );
|
||||
extern (C) size_t gc_sizeOf( void* p );
|
||||
|
||||
struct BlkInfo_
|
||||
{
|
||||
void* base;
|
||||
size_t size;
|
||||
uint attr;
|
||||
}
|
||||
|
||||
extern (C) BlkInfo_ gc_query( void* p );
|
||||
|
||||
extern (C) void gc_addRoot( void* p );
|
||||
extern (C) void gc_addRange( void* p, size_t sz );
|
||||
|
||||
extern (C) void gc_removeRoot( void* p );
|
||||
extern (C) void gc_removeRange( void* p );
|
||||
|
||||
alias bool function( Object obj ) collectHandlerType;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This struct encapsulates all garbage collection functionality for the D
|
||||
* programming language.
|
||||
*/
|
||||
struct GC
|
||||
{
|
||||
/**
|
||||
* Enables the garbage collector if collections have previously been
|
||||
* suspended by a call to disable. This function is reentrant, and
|
||||
* must be called once for every call to disable before the garbage
|
||||
* collector is enabled.
|
||||
*/
|
||||
static void enable()
|
||||
{
|
||||
gc_enable();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Disables the garbage collector. This function is reentrant, but
|
||||
* enable must be called once for each call to disable.
|
||||
*/
|
||||
static void disable()
|
||||
{
|
||||
gc_disable();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Begins a full collection. While the meaning of this may change based
|
||||
* on the garbage collector implementation, typical behavior is to scan
|
||||
* all stack segments for roots, mark accessible memory blocks as alive,
|
||||
* and then to reclaim free space. This action may need to suspend all
|
||||
* running threads for at least part of the collection process.
|
||||
*/
|
||||
static void collect()
|
||||
{
|
||||
gc_collect();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Elements for a bit field representing memory block attributes. These
|
||||
* are manipulated via the getAttr, setAttr, clrAttr functions.
|
||||
*/
|
||||
enum BlkAttr : uint
|
||||
{
|
||||
FINALIZE = 0b0000_0001, /// Finalize the data in this block on collect.
|
||||
NO_SCAN = 0b0000_0010, /// Do not scan through this block on collect.
|
||||
NO_MOVE = 0b0000_0100 /// Do not move this memory block on collect.
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Contains aggregate information about a block of managed memory. The
|
||||
* purpose of this struct is to support a more efficient query style in
|
||||
* instances where detailed information is needed.
|
||||
*
|
||||
* base = A pointer to the base of the block in question.
|
||||
* size = The size of the block, calculated from base.
|
||||
* attr = Attribute bits set on the memory block.
|
||||
*/
|
||||
alias BlkInfo_ BlkInfo;
|
||||
|
||||
|
||||
/**
|
||||
* Returns a bit field representing all block attributes set for the memory
|
||||
* referenced by p. If p references memory not originally allocated by this
|
||||
* garbage collector, points to the interior of a memory block, or if p is
|
||||
* null, zero will be returned.
|
||||
*
|
||||
* Params:
|
||||
* p = A pointer to the root of a valid memory block or to null.
|
||||
*
|
||||
* Returns:
|
||||
* A bit field containing any bits set for the memory block referenced by
|
||||
* p or zero on error.
|
||||
*/
|
||||
static uint getAttr( void* p )
|
||||
{
|
||||
return gc_getAttr( p );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sets the specified bits for the memory references by p. If p references
|
||||
* memory not originally allocated by this garbage collector, points to the
|
||||
* interior of a memory block, or if p is null, no action will be performed.
|
||||
*
|
||||
* Params:
|
||||
* p = A pointer to the root of a valid memory block or to null.
|
||||
* a = A bit field containing any bits to set for this memory block.
|
||||
*
|
||||
* The result of a call to getAttr after the specified bits have been
|
||||
* set.
|
||||
*/
|
||||
static uint setAttr( void* p, uint a )
|
||||
{
|
||||
return gc_setAttr( p, a );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Clears the specified bits for the memory references by p. If p
|
||||
* references memory not originally allocated by this garbage collector,
|
||||
* points to the interior of a memory block, or if p is null, no action
|
||||
* will be performed.
|
||||
*
|
||||
* Params:
|
||||
* p = A pointer to the root of a valid memory block or to null.
|
||||
* a = A bit field containing any bits to clear for this memory block.
|
||||
*
|
||||
* Returns:
|
||||
* The result of a call to getAttr after the specified bits have been
|
||||
* cleared.
|
||||
*/
|
||||
static uint clrAttr( void* p, uint a )
|
||||
{
|
||||
return gc_clrAttr( p, a );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Requests an aligned block of managed memory from the garbage collector.
|
||||
* This memory may be deleted at will with a call to free, or it may be
|
||||
* discarded and cleaned up automatically during a collection run. If
|
||||
* allocation fails, this function will call onOutOfMemory which is
|
||||
* expected to throw an OutOfMemoryException.
|
||||
*
|
||||
* Params:
|
||||
* sz = The desired allocation size in bytes.
|
||||
* ba = A bitmask of the attributes to set on this block.
|
||||
*
|
||||
* Returns:
|
||||
* A reference to the allocated memory or null if insufficient memory
|
||||
* is available.
|
||||
*
|
||||
* Throws:
|
||||
* OutOfMemoryException on allocation failure.
|
||||
*/
|
||||
static void* malloc( size_t sz, uint ba = 0 )
|
||||
{
|
||||
return gc_malloc( sz, ba );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Requests an aligned block of managed memory from the garbage collector,
|
||||
* which is initialized with all bits set to zero. This memory may be
|
||||
* deleted at will with a call to free, or it may be discarded and cleaned
|
||||
* up automatically during a collection run. If allocation fails, this
|
||||
* function will call onOutOfMemory which is expected to throw an
|
||||
* OutOfMemoryException.
|
||||
*
|
||||
* Params:
|
||||
* sz = The desired allocation size in bytes.
|
||||
* ba = A bitmask of the attributes to set on this block.
|
||||
*
|
||||
* Returns:
|
||||
* A reference to the allocated memory or null if insufficient memory
|
||||
* is available.
|
||||
*
|
||||
* Throws:
|
||||
* OutOfMemoryException on allocation failure.
|
||||
*/
|
||||
static void* calloc( size_t sz, uint ba = 0 )
|
||||
{
|
||||
return gc_calloc( sz, ba );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If sz is zero, the memory referenced by p will be deallocated as if
|
||||
* by a call to free. A new memory block of size sz will then be
|
||||
* allocated as if by a call to malloc, or the implementation may instead
|
||||
* resize the memory block in place. The contents of the new memory block
|
||||
* will be the same as the contents of the old memory block, up to the
|
||||
* lesser of the new and old sizes. Note that existing memory will only
|
||||
* be freed by realloc if sz is equal to zero. The garbage collector is
|
||||
* otherwise expected to later reclaim the memory block if it is unused.
|
||||
* If allocation fails, this function will call onOutOfMemory which is
|
||||
* expected to throw an OutOfMemoryException. If p references memory not
|
||||
* originally allocated by this garbage collector, or if it points to the
|
||||
* interior of a memory block, no action will be taken. If ba is zero
|
||||
* (the default) and p references the head of a valid, known memory block
|
||||
* then any bits set on the current block will be set on the new block if a
|
||||
* reallocation is required. If ba is not zero and p references the head
|
||||
* of a valid, known memory block then the bits in ba will replace those on
|
||||
* the current memory block and will also be set on the new block if a
|
||||
* reallocation is required.
|
||||
*
|
||||
* Params:
|
||||
* p = A pointer to the root of a valid memory block or to null.
|
||||
* sz = The desired allocation size in bytes.
|
||||
* ba = A bitmask of the attributes to set on this block.
|
||||
*
|
||||
* Returns:
|
||||
* A reference to the allocated memory on success or null if sz is
|
||||
* zero. On failure, the original value of p is returned.
|
||||
*
|
||||
* Throws:
|
||||
* OutOfMemoryException on allocation failure.
|
||||
*/
|
||||
static void* realloc( void* p, size_t sz, uint ba = 0 )
|
||||
{
|
||||
return gc_realloc( p, sz, ba );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Requests that the managed memory block referenced by p be extended in
|
||||
* place by at least mx bytes, with a desired extension of sz bytes. If an
|
||||
* extension of the required size is not possible, if p references memory
|
||||
* not originally allocated by this garbage collector, or if p points to
|
||||
* the interior of a memory block, no action will be taken.
|
||||
*
|
||||
* Params:
|
||||
* mx = The minimum extension size in bytes.
|
||||
* sz = The desired extension size in bytes.
|
||||
*
|
||||
* Returns:
|
||||
* The size in bytes of the extended memory block referenced by p or zero
|
||||
* if no extension occurred.
|
||||
*/
|
||||
static size_t extend( void* p, size_t mx, size_t sz )
|
||||
{
|
||||
return gc_extend( p, mx, sz );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Deallocates the memory referenced by p. If p is null, no action
|
||||
* occurs. If p references memory not originally allocated by this
|
||||
* garbage collector, or if it points to the interior of a memory block,
|
||||
* no action will be taken. The block will not be finalized regardless
|
||||
* of whether the FINALIZE attribute is set. If finalization is desired,
|
||||
* use delete instead.
|
||||
*
|
||||
* Params:
|
||||
* p = A pointer to the root of a valid memory block or to null.
|
||||
*/
|
||||
static void free( void* p )
|
||||
{
|
||||
gc_free( p );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the base address of the memory block containing p. This value
|
||||
* is useful to determine whether p is an interior pointer, and the result
|
||||
* may be passed to routines such as sizeOf which may otherwise fail. If p
|
||||
* references memory not originally allocated by this garbage collector, if
|
||||
* p is null, or if the garbage collector does not support this operation,
|
||||
* null will be returned.
|
||||
*
|
||||
* Params:
|
||||
* p = A pointer to the root or the interior of a valid memory block or to
|
||||
* null.
|
||||
*
|
||||
* Returns:
|
||||
* The base address of the memory block referenced by p or null on error.
|
||||
*/
|
||||
static void* addrOf( void* p )
|
||||
{
|
||||
return gc_addrOf( p );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the true size of the memory block referenced by p. This value
|
||||
* represents the maximum number of bytes for which a call to realloc may
|
||||
* resize the existing block in place. If p references memory not
|
||||
* originally allocated by this garbage collector, points to the interior
|
||||
* of a memory block, or if p is null, zero will be returned.
|
||||
*
|
||||
* Params:
|
||||
* p = A pointer to the root of a valid memory block or to null.
|
||||
*
|
||||
* Returns:
|
||||
* The size in bytes of the memory block referenced by p or zero on error.
|
||||
*/
|
||||
static size_t sizeOf( void* p )
|
||||
{
|
||||
return gc_sizeOf( p );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns aggregate information about the memory block containing p. If p
|
||||
* references memory not originally allocated by this garbage collector, if
|
||||
* p is null, or if the garbage collector does not support this operation,
|
||||
* BlkInfo.init will be returned. Typically, support for this operation
|
||||
* is dependent on support for addrOf.
|
||||
*
|
||||
* Params:
|
||||
* p = A pointer to the root or the interior of a valid memory block or to
|
||||
* null.
|
||||
*
|
||||
* Returns:
|
||||
* Information regarding the memory block referenced by p or BlkInfo.init
|
||||
* on error.
|
||||
*/
|
||||
static BlkInfo query( void* p )
|
||||
{
|
||||
return gc_query( p );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds the memory address referenced by p to an internal list of roots to
|
||||
* be scanned during a collection. If p is null, no operation is
|
||||
* performed.
|
||||
*
|
||||
* Params:
|
||||
* p = A pointer to a valid memory address or to null.
|
||||
*/
|
||||
static void addRoot( void* p )
|
||||
{
|
||||
gc_addRoot( p );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds the memory block referenced by p and of size sz to an internal list
|
||||
* of ranges to be scanned during a collection. If p is null, no operation
|
||||
* is performed.
|
||||
*
|
||||
* Params:
|
||||
* p = A pointer to a valid memory address or to null.
|
||||
* sz = The size in bytes of the block to add. If sz is zero then the
|
||||
* no operation will occur. If p is null then sz must be zero.
|
||||
*/
|
||||
static void addRange( void* p, size_t sz )
|
||||
{
|
||||
gc_addRange( p, sz );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes the memory block referenced by p from an internal list of roots
|
||||
* to be scanned during a collection. If p is null or does not represent
|
||||
* a value previously passed to add(void*) then no operation is performed.
|
||||
*
|
||||
* p = A pointer to a valid memory address or to null.
|
||||
*/
|
||||
static void removeRoot( void* p )
|
||||
{
|
||||
gc_removeRoot( p );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes the memory block referenced by p from an internal list of ranges
|
||||
* to be scanned during a collection. If p is null or does not represent
|
||||
* a value previously passed to add(void*, size_t) then no operation is
|
||||
* performed.
|
||||
*
|
||||
* Params:
|
||||
* p = A pointer to a valid memory address or to null.
|
||||
*/
|
||||
static void removeRange( void* p )
|
||||
{
|
||||
gc_removeRange( p );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overrides the default collect hander with a user-supplied version.
|
||||
*
|
||||
* Params:
|
||||
* h = The new collect handler. Set to null to use the default handler.
|
||||
*/
|
||||
static void collectHandler( collectHandlerType h )
|
||||
{
|
||||
sm_collectHandler = h;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
static collectHandlerType sm_collectHandler = null;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Overridable Callbacks
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* This function will be called when resource objects (ie. objects with a dtor)
|
||||
* are finalized by the garbage collector. The user-supplied collect handler
|
||||
* will be called if one has been supplied, otherwise no action will be taken.
|
||||
*
|
||||
* Params:
|
||||
* obj = The object being collected.
|
||||
*
|
||||
* Returns:
|
||||
* true if the runtime should call this object's dtor and false if not.
|
||||
* Default behavior is to return true.
|
||||
*/
|
||||
extern (C) bool onCollectResource( Object obj )
|
||||
{
|
||||
if( GC.sm_collectHandler is null )
|
||||
return true;
|
||||
return GC.sm_collectHandler( obj );
|
||||
}
|
||||
87
tango/lib/common/tango/core/Runtime.d
Normal file
87
tango/lib/common/tango/core/Runtime.d
Normal file
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* The runtime module exposes information specific to the D runtime code.
|
||||
*
|
||||
* Copyright: Copyright (C) 2005-2006 Sean Kelly. All rights reserved.
|
||||
* License: BSD style: $(LICENSE)
|
||||
* Authors: Sean Kelly
|
||||
*/
|
||||
module tango.core.Runtime;
|
||||
|
||||
|
||||
private
|
||||
{
|
||||
extern (C) bool rt_isHalting();
|
||||
|
||||
alias bool function() moduleUnitTesterType;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Runtime
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* This struct encapsulates all functionality related to the underlying runtime
|
||||
* module for the calling context.
|
||||
*/
|
||||
struct Runtime
|
||||
{
|
||||
/**
|
||||
* Returns true if the runtime is halting. Under normal circumstances,
|
||||
* this will be set between the time that normal application code has
|
||||
* exited and before module dtors are called.
|
||||
*
|
||||
* Returns:
|
||||
* true if the runtime is halting.
|
||||
*/
|
||||
static bool isHalting()
|
||||
{
|
||||
return rt_isHalting();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Overrides the default module unit tester with a user-supplied version.
|
||||
*
|
||||
* Params:
|
||||
* h = The new unit tester. Set to null to use the default unit tester.
|
||||
*/
|
||||
static void moduleUnitTester( moduleUnitTesterType h )
|
||||
{
|
||||
sm_moduleUnitTester = h;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
static moduleUnitTesterType sm_moduleUnitTester = null;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Overridable Callbacks
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* This routine is called by the runtime to run module unit tests on startup.
|
||||
* The user-supplied unit tester will be called if one has been supplied,
|
||||
* otherwise all unit tests will be run in sequence.
|
||||
*
|
||||
* Returns:
|
||||
* true if execution should continue after testing is complete and false if
|
||||
* not. Default behavior is to return true.
|
||||
*/
|
||||
extern (C) bool runModuleUnitTests()
|
||||
{
|
||||
if( Runtime.sm_moduleUnitTester is null )
|
||||
{
|
||||
foreach( m; ModuleInfo )
|
||||
{
|
||||
if( m.unitTest )
|
||||
m.unitTest();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return Runtime.sm_moduleUnitTester();
|
||||
}
|
||||
3256
tango/lib/common/tango/core/Thread.d
Normal file
3256
tango/lib/common/tango/core/Thread.d
Normal file
File diff suppressed because it is too large
Load Diff
136
tango/lib/common/tango/core/ThreadASM.S
Normal file
136
tango/lib/common/tango/core/ThreadASM.S
Normal file
@@ -0,0 +1,136 @@
|
||||
/**
|
||||
* Tango Fiber switching assembler code.
|
||||
*
|
||||
* Author: Mikola Lysenko
|
||||
*/
|
||||
|
||||
/************************************************************************************
|
||||
* POWER PC ASM BITS
|
||||
************************************************************************************/
|
||||
#if defined( __ppc__ ) || defined( __PPC__ ) || defined( __powerpc__ )
|
||||
|
||||
|
||||
/**
|
||||
* Performs a context switch.
|
||||
*
|
||||
* r3 - old context pointer
|
||||
* r4 - new context pointer
|
||||
*
|
||||
*/
|
||||
.text
|
||||
.align 2
|
||||
.globl _fiber_switchContext
|
||||
_fiber_switchContext:
|
||||
|
||||
/* Save linkage area */
|
||||
mflr r0
|
||||
mfcr r5
|
||||
stw r0, 8(r1)
|
||||
stw r5, 4(r1)
|
||||
|
||||
/* Save GPRs */
|
||||
stw r11, (-1 * 4)(r1)
|
||||
stw r13, (-2 * 4)(r1)
|
||||
stw r14, (-3 * 4)(r1)
|
||||
stw r15, (-4 * 4)(r1)
|
||||
stw r16, (-5 * 4)(r1)
|
||||
stw r17, (-6 * 4)(r1)
|
||||
stw r18, (-7 * 4)(r1)
|
||||
stw r19, (-8 * 4)(r1)
|
||||
stw r20, (-9 * 4)(r1)
|
||||
stw r21, (-10 * 4)(r1)
|
||||
stw r22, (-11 * 4)(r1)
|
||||
stw r23, (-12 * 4)(r1)
|
||||
stw r24, (-13 * 4)(r1)
|
||||
stw r25, (-14 * 4)(r1)
|
||||
stw r26, (-15 * 4)(r1)
|
||||
stw r27, (-16 * 4)(r1)
|
||||
stw r28, (-17 * 4)(r1)
|
||||
stw r29, (-18 * 4)(r1)
|
||||
stw r30, (-19 * 4)(r1)
|
||||
stwu r31, (-20 * 4)(r1)
|
||||
|
||||
/* We update the stack pointer here, since we do not want the GC to
|
||||
scan the floating point registers. */
|
||||
|
||||
/* Save FPRs */
|
||||
stfd f14, (-1 * 8)(r1)
|
||||
stfd f15, (-2 * 8)(r1)
|
||||
stfd f16, (-3 * 8)(r1)
|
||||
stfd f17, (-4 * 8)(r1)
|
||||
stfd f18, (-5 * 8)(r1)
|
||||
stfd f19, (-6 * 8)(r1)
|
||||
stfd f20, (-7 * 8)(r1)
|
||||
stfd f21, (-8 * 8)(r1)
|
||||
stfd f22, (-9 * 8)(r1)
|
||||
stfd f23, (-10 * 8)(r1)
|
||||
stfd f24, (-11 * 8)(r1)
|
||||
stfd f25, (-12 * 8)(r1)
|
||||
stfd f26, (-13 * 8)(r1)
|
||||
stfd f27, (-14 * 8)(r1)
|
||||
stfd f28, (-15 * 8)(r1)
|
||||
stfd f29, (-16 * 8)(r1)
|
||||
stfd f30, (-17 * 8)(r1)
|
||||
stfd f31, (-18 * 8)(r1)
|
||||
|
||||
/* Update the old stack pointer */
|
||||
stw r1, 0(r3)
|
||||
|
||||
/* Set new stack pointer */
|
||||
addi r1, r4, 20 * 4
|
||||
|
||||
/* Restore linkage area */
|
||||
lwz r0, 8(r1)
|
||||
lwz r5, 4(r1)
|
||||
|
||||
/* Restore GPRs */
|
||||
lwz r11, (-1 * 4)(r1)
|
||||
lwz r13, (-2 * 4)(r1)
|
||||
lwz r14, (-3 * 4)(r1)
|
||||
lwz r15, (-4 * 4)(r1)
|
||||
lwz r16, (-5 * 4)(r1)
|
||||
lwz r17, (-6 * 4)(r1)
|
||||
lwz r18, (-7 * 4)(r1)
|
||||
lwz r19, (-8 * 4)(r1)
|
||||
lwz r20, (-9 * 4)(r1)
|
||||
lwz r21, (-10 * 4)(r1)
|
||||
lwz r22, (-11 * 4)(r1)
|
||||
lwz r23, (-12 * 4)(r1)
|
||||
lwz r24, (-13 * 4)(r1)
|
||||
lwz r25, (-14 * 4)(r1)
|
||||
lwz r26, (-15 * 4)(r1)
|
||||
lwz r27, (-16 * 4)(r1)
|
||||
lwz r28, (-17 * 4)(r1)
|
||||
lwz r29, (-18 * 4)(r1)
|
||||
lwz r30, (-19 * 4)(r1)
|
||||
lwz r31, (-20 * 4)(r1)
|
||||
|
||||
|
||||
/* Restore FPRs */
|
||||
lfd f14, (-1 * 8)(r4)
|
||||
lfd f15, (-2 * 8)(r4)
|
||||
lfd f16, (-3 * 8)(r4)
|
||||
lfd f17, (-4 * 8)(r4)
|
||||
lfd f18, (-5 * 8)(r4)
|
||||
lfd f19, (-6 * 8)(r4)
|
||||
lfd f20, (-7 * 8)(r4)
|
||||
lfd f21, (-8 * 8)(r4)
|
||||
lfd f22, (-9 * 8)(r4)
|
||||
lfd f23, (-10 * 8)(r4)
|
||||
lfd f24, (-11 * 8)(r4)
|
||||
lfd f25, (-12 * 8)(r4)
|
||||
lfd f26, (-13 * 8)(r4)
|
||||
lfd f27, (-14 * 8)(r4)
|
||||
lfd f28, (-15 * 8)(r4)
|
||||
lfd f29, (-16 * 8)(r4)
|
||||
lfd f30, (-17 * 8)(r4)
|
||||
lfd f31, (-18 * 8)(r4)
|
||||
|
||||
/* Set condition and link register */
|
||||
mtcr r5
|
||||
mtlr r0
|
||||
|
||||
/* Return and switch context */
|
||||
blr
|
||||
|
||||
#endif
|
||||
139
tango/lib/common/tango/llvmdc.mak
Normal file
139
tango/lib/common/tango/llvmdc.mak
Normal file
@@ -0,0 +1,139 @@
|
||||
# Makefile to build the common D runtime library for LLVM
|
||||
# Designed to work with GNU make
|
||||
# Targets:
|
||||
# make
|
||||
# Same as make all
|
||||
# make lib
|
||||
# Build the common library
|
||||
# make doc
|
||||
# Generate documentation
|
||||
# make clean
|
||||
# Delete unneeded files created by build process
|
||||
|
||||
LIB_TARGET=libtango-cc-tango.a
|
||||
LIB_MASK=libtango-cc-tango*.a
|
||||
|
||||
CP=cp -f
|
||||
RM=rm -f
|
||||
MD=mkdir -p
|
||||
|
||||
ADD_CFLAGS=
|
||||
ADD_DFLAGS=
|
||||
|
||||
CFLAGS=-O $(ADD_CFLAGS)
|
||||
#CFLAGS=-g $(ADD_CFLAGS)
|
||||
|
||||
DFLAGS=-release -O -inline -w -nofloat $(ADD_DFLAGS)
|
||||
#DFLAGS=-g -w -nofloat $(ADD_DFLAGS)
|
||||
|
||||
TFLAGS=-O -inline -w -nofloat $(ADD_DFLAGS)
|
||||
#TFLAGS=-g -w -nofloat $(ADD_DFLAGS)
|
||||
|
||||
DOCFLAGS=-version=DDoc
|
||||
|
||||
CC=gcc
|
||||
LC=llvm-ar rsv
|
||||
DC=llvmdc
|
||||
LLC=llvm-as
|
||||
|
||||
INC_DEST=../../../tango
|
||||
LIB_DEST=..
|
||||
DOC_DEST=../../../doc/tango
|
||||
|
||||
.SUFFIXES: .s .S .c .cpp .d .ll .html .o .bc
|
||||
|
||||
.s.o:
|
||||
$(CC) -c $(CFLAGS) $< -o$@
|
||||
|
||||
.S.o:
|
||||
$(CC) -c $(CFLAGS) $< -o$@
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(CFLAGS) $< -o$@
|
||||
|
||||
.cpp.o:
|
||||
g++ -c $(CFLAGS) $< -o$@
|
||||
|
||||
.d.bc:
|
||||
$(DC) -c $(DFLAGS) -Hf$*.di $< -of$@
|
||||
# $(DC) -c $(DFLAGS) $< -of$@
|
||||
|
||||
.ll.bc:
|
||||
$(LLC) -f -o=$@ $<
|
||||
|
||||
.d.html:
|
||||
$(DC) -c -o- $(DOCFLAGS) -Df$*.html $<
|
||||
# $(DC) -c -o- $(DOCFLAGS) -Df$*.html tango.ddoc $<
|
||||
|
||||
targets : lib doc
|
||||
all : lib doc
|
||||
tango : lib
|
||||
lib : tango.lib
|
||||
doc : tango.doc
|
||||
|
||||
######################################################
|
||||
|
||||
OBJ_CORE= \
|
||||
core/BitManip.bc \
|
||||
core/Exception.bc \
|
||||
core/Memory.bc \
|
||||
core/Runtime.bc \
|
||||
core/Thread.bc
|
||||
# core/ThreadASM.o
|
||||
|
||||
OBJ_STDC= \
|
||||
stdc/wrap.bc
|
||||
|
||||
OBJ_STDC_POSIX= \
|
||||
stdc/posix/pthread_darwin.o
|
||||
|
||||
ALL_OBJS= \
|
||||
$(OBJ_CORE) \
|
||||
$(OBJ_STDC)
|
||||
# $(OBJ_STDC_POSIX)
|
||||
|
||||
######################################################
|
||||
|
||||
DOC_CORE= \
|
||||
core/BitManip.html \
|
||||
core/Exception.html \
|
||||
core/Memory.html \
|
||||
core/Runtime.html \
|
||||
core/Thread.html
|
||||
|
||||
|
||||
ALL_DOCS=
|
||||
|
||||
######################################################
|
||||
|
||||
tango.lib : $(LIB_TARGET)
|
||||
|
||||
$(LIB_TARGET) : $(ALL_OBJS)
|
||||
$(RM) $@
|
||||
$(LC) $@ $(ALL_OBJS)
|
||||
|
||||
tango.doc : $(ALL_DOCS)
|
||||
echo Documentation generated.
|
||||
|
||||
######################################################
|
||||
|
||||
### stdc/posix
|
||||
|
||||
#stdc/posix/pthread_darwin.o : stdc/posix/pthread_darwin.d
|
||||
# $(DC) -c $(DFLAGS) stdc/posix/pthread_darwin.d -of$@
|
||||
|
||||
######################################################
|
||||
|
||||
clean :
|
||||
find . -name "*.di" | xargs $(RM)
|
||||
$(RM) $(ALL_OBJS)
|
||||
$(RM) $(ALL_DOCS)
|
||||
find . -name "$(LIB_MASK)" | xargs $(RM)
|
||||
|
||||
install :
|
||||
$(MD) $(INC_DEST)
|
||||
find . -name "*.di" -exec cp -f {} $(INC_DEST)/{} \;
|
||||
$(MD) $(DOC_DEST)
|
||||
find . -name "*.html" -exec cp -f {} $(DOC_DEST)/{} \;
|
||||
$(MD) $(LIB_DEST)
|
||||
find . -name "$(LIB_MASK)" -exec cp -f {} $(LIB_DEST)/{} \;
|
||||
135
tango/lib/common/tango/posix.mak
Normal file
135
tango/lib/common/tango/posix.mak
Normal file
@@ -0,0 +1,135 @@
|
||||
# Makefile to build the common D runtime library for Linux
|
||||
# Designed to work with GNU make
|
||||
# Targets:
|
||||
# make
|
||||
# Same as make all
|
||||
# make lib
|
||||
# Build the common library
|
||||
# make doc
|
||||
# Generate documentation
|
||||
# make clean
|
||||
# Delete unneeded files created by build process
|
||||
|
||||
LIB_TARGET=libtango-cc-tango.a
|
||||
LIB_MASK=libtango-cc-tango*.a
|
||||
|
||||
CP=cp -f
|
||||
RM=rm -f
|
||||
MD=mkdir -p
|
||||
|
||||
ADD_CFLAGS=
|
||||
ADD_DFLAGS=
|
||||
|
||||
CFLAGS=-O -m32 $(ADD_CFLAGS)
|
||||
#CFLAGS=-g -m32 $(ADD_CFLAGS)
|
||||
|
||||
DFLAGS=-release -O -inline -w -nofloat -version=Posix $(ADD_DFLAGS)
|
||||
#DFLAGS=-g -w -nofloat -version=Posix $(ADD_DFLAGS)
|
||||
|
||||
TFLAGS=-O -inline -w -nofloat -version=Posix $(ADD_DFLAGS)
|
||||
#TFLAGS=-g -w -nofloat -version=Posix $(ADD_DFLAGS)
|
||||
|
||||
DOCFLAGS=-version=DDoc -version=Posix
|
||||
|
||||
CC=gcc
|
||||
LC=$(AR) -qsv
|
||||
DC=dmd
|
||||
|
||||
INC_DEST=../../../tango
|
||||
LIB_DEST=..
|
||||
DOC_DEST=../../../doc/tango
|
||||
|
||||
.SUFFIXES: .s .S .c .cpp .d .html .o
|
||||
|
||||
.s.o:
|
||||
$(CC) -c $(CFLAGS) $< -o$@
|
||||
|
||||
.S.o:
|
||||
$(CC) -c $(CFLAGS) $< -o$@
|
||||
|
||||
.c.o:
|
||||
$(CC) -c $(CFLAGS) $< -o$@
|
||||
|
||||
.cpp.o:
|
||||
g++ -c $(CFLAGS) $< -o$@
|
||||
|
||||
.d.o:
|
||||
$(DC) -c $(DFLAGS) -Hf$*.di $< -of$@
|
||||
# $(DC) -c $(DFLAGS) $< -of$@
|
||||
|
||||
.d.html:
|
||||
$(DC) -c -o- $(DOCFLAGS) -Df$*.html $<
|
||||
# $(DC) -c -o- $(DOCFLAGS) -Df$*.html tango.ddoc $<
|
||||
|
||||
targets : lib doc
|
||||
all : lib doc
|
||||
tango : lib
|
||||
lib : tango.lib
|
||||
doc : tango.doc
|
||||
|
||||
######################################################
|
||||
|
||||
OBJ_CORE= \
|
||||
core/BitManip.o \
|
||||
core/Exception.o \
|
||||
core/Memory.o \
|
||||
core/Runtime.o \
|
||||
core/Thread.o \
|
||||
core/ThreadASM.o
|
||||
|
||||
OBJ_STDC= \
|
||||
stdc/wrap.o
|
||||
|
||||
OBJ_STDC_POSIX= \
|
||||
stdc/posix/pthread_darwin.o
|
||||
|
||||
ALL_OBJS= \
|
||||
$(OBJ_CORE) \
|
||||
$(OBJ_STDC) \
|
||||
$(OBJ_STDC_POSIX)
|
||||
|
||||
######################################################
|
||||
|
||||
DOC_CORE= \
|
||||
core/BitManip.html \
|
||||
core/Exception.html \
|
||||
core/Memory.html \
|
||||
core/Runtime.html \
|
||||
core/Thread.html
|
||||
|
||||
|
||||
ALL_DOCS=
|
||||
|
||||
######################################################
|
||||
|
||||
tango.lib : $(LIB_TARGET)
|
||||
|
||||
$(LIB_TARGET) : $(ALL_OBJS)
|
||||
$(RM) $@
|
||||
$(LC) $@ $(ALL_OBJS)
|
||||
|
||||
tango.doc : $(ALL_DOCS)
|
||||
echo Documentation generated.
|
||||
|
||||
######################################################
|
||||
|
||||
### stdc/posix
|
||||
|
||||
stdc/posix/pthread_darwin.o : stdc/posix/pthread_darwin.d
|
||||
$(DC) -c $(DFLAGS) stdc/posix/pthread_darwin.d -of$@
|
||||
|
||||
######################################################
|
||||
|
||||
clean :
|
||||
find . -name "*.di" | xargs $(RM)
|
||||
$(RM) $(ALL_OBJS)
|
||||
$(RM) $(ALL_DOCS)
|
||||
find . -name "$(LIB_MASK)" | xargs $(RM)
|
||||
|
||||
install :
|
||||
$(MD) $(INC_DEST)
|
||||
find . -name "*.di" -exec cp -f {} $(INC_DEST)/{} \;
|
||||
$(MD) $(DOC_DEST)
|
||||
find . -name "*.html" -exec cp -f {} $(DOC_DEST)/{} \;
|
||||
$(MD) $(LIB_DEST)
|
||||
find . -name "$(LIB_MASK)" -exec cp -f {} $(LIB_DEST)/{} \;
|
||||
334
tango/lib/common/tango/stdc/posix/pthread_darwin.d
Normal file
334
tango/lib/common/tango/stdc/posix/pthread_darwin.d
Normal file
@@ -0,0 +1,334 @@
|
||||
/**
|
||||
* D header file for POSIX.
|
||||
*
|
||||
* Copyright: Public Domain
|
||||
* License: Public Domain
|
||||
* Authors: Sean Kelly
|
||||
* Standards: The Open Group Base Specifications Issue 6, IEEE Std 1003.1, 2004 Edition
|
||||
*/
|
||||
module tango.stdc.posix.pthread;
|
||||
|
||||
public import tango.stdc.posix.sys.types;
|
||||
public import tango.stdc.posix.sched;
|
||||
public import tango.stdc.posix.time;
|
||||
private import tango.stdc.stdlib;
|
||||
|
||||
extern (C):
|
||||
|
||||
//
|
||||
// Required
|
||||
//
|
||||
|
||||
version( darwin )
|
||||
{
|
||||
int pthread_cond_broadcast(pthread_cond_t*);
|
||||
int pthread_cond_destroy(pthread_cond_t*);
|
||||
int pthread_cond_init(pthread_cond_t*, pthread_condattr_t*);
|
||||
//int pthread_cond_signal(pthread_cond_t*);
|
||||
//int pthread_cond_timedwait(pthread_cond_t*, pthread_mutex_t*, timespec*);
|
||||
int pthread_cond_wait(pthread_cond_t*, pthread_mutex_t*);
|
||||
|
||||
int pthread_mutex_destroy(pthread_mutex_t*);
|
||||
int pthread_mutex_init(pthread_mutex_t*, pthread_mutexattr_t*);
|
||||
int pthread_mutex_lock(pthread_mutex_t*);
|
||||
int pthread_mutex_trylock(pthread_mutex_t*);
|
||||
int pthread_mutex_unlock(pthread_mutex_t*);
|
||||
|
||||
//int pthread_rwlock_destroy(pthread_rwlock_t*);
|
||||
//int pthread_rwlock_init(pthread_rwlock_t*, pthread_rwlockattr_t*);
|
||||
//int pthread_rwlock_rdlock(pthread_rwlock_t*);
|
||||
int pthread_rwlock_tryrdlock(pthread_rwlock_t*);
|
||||
int pthread_rwlock_trywrlock(pthread_rwlock_t*);
|
||||
//int pthread_rwlock_unlock(pthread_rwlock_t*);
|
||||
//int pthread_rwlock_wrlock(pthread_rwlock_t*);
|
||||
}
|
||||
|
||||
//
|
||||
// Barrier (BAR)
|
||||
//
|
||||
/*
|
||||
PTHREAD_BARRIER_SERIAL_THREAD
|
||||
|
||||
int pthread_barrier_destroy(pthread_barrier_t*);
|
||||
int pthread_barrier_init(pthread_barrier_t*, pthread_barrierattr_t*, uint);
|
||||
int pthread_barrier_wait(pthread_barrier_t*);
|
||||
int pthread_barrierattr_destroy(pthread_barrierattr_t*);
|
||||
int pthread_barrierattr_getpshared(pthread_barrierattr_t*, int*); (BAR|TSH)
|
||||
int pthread_barrierattr_init(pthread_barrierattr_t*);
|
||||
int pthread_barrierattr_setpshared(pthread_barrierattr_t*, int); (BAR|TSH)
|
||||
*/
|
||||
|
||||
version( darwin )
|
||||
{
|
||||
const PTHREAD_BARRIER_SERIAL_THREAD = -1;
|
||||
|
||||
// defined in tango.stdc.posix.pthread and redefined here
|
||||
enum
|
||||
{
|
||||
PTHREAD_PROCESS_PRIVATE,
|
||||
PTHREAD_PROCESS_SHARED
|
||||
}
|
||||
|
||||
int pthread_barrier_destroy( pthread_barrier_t* barrier )
|
||||
{
|
||||
if( barrier is null )
|
||||
return EINVAL;
|
||||
if( barrier.b_waiters > 0 )
|
||||
return EBUSY;
|
||||
int mret = pthread_mutex_destroy( &barrier.b_lock );
|
||||
int cret = pthread_cond_destroy( &barrier.b_cond );
|
||||
free( barrier );
|
||||
return mret ? mret : cret;
|
||||
}
|
||||
|
||||
int pthread_barrier_init( pthread_barrier_t* barrier,
|
||||
pthread_barrierattr_t* attr,
|
||||
uint count )
|
||||
{
|
||||
if( barrier is null || count <= 0 )
|
||||
return EINVAL;
|
||||
|
||||
pthread_barrier_t* newbarrier = cast(pthread_barrier_t*)
|
||||
malloc( pthread_barrier_t.sizeof );
|
||||
if( newbarrier is null )
|
||||
return ENOMEM;
|
||||
|
||||
int ret;
|
||||
if( ( ret = pthread_mutex_init( &newbarrier.b_lock, null ) ) != 0 )
|
||||
{
|
||||
free( newbarrier );
|
||||
return ret;
|
||||
}
|
||||
if( ( ret = pthread_cond_init( &newbarrier.b_cond, null ) ) != 0 )
|
||||
{
|
||||
pthread_mutex_destroy( &newbarrier.b_lock );
|
||||
free( newbarrier );
|
||||
return ret;
|
||||
}
|
||||
newbarrier.b_waiters = 0;
|
||||
newbarrier.b_count = count;
|
||||
newbarrier.b_generation = 0;
|
||||
*barrier = *newbarrier;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_barrier_wait( pthread_barrier_t* barrier )
|
||||
{
|
||||
if( barrier is null )
|
||||
return EINVAL;
|
||||
|
||||
int ret;
|
||||
if( ( ret = pthread_mutex_lock( &barrier.b_lock ) ) != 0 )
|
||||
return ret;
|
||||
|
||||
if( ++barrier.b_waiters == barrier.b_count )
|
||||
{
|
||||
// current thread is lastest thread
|
||||
barrier.b_generation++;
|
||||
barrier.b_waiters = 0;
|
||||
if( ( ret = pthread_cond_broadcast( &barrier.b_cond ) ) == 0 )
|
||||
ret = PTHREAD_BARRIER_SERIAL_THREAD;
|
||||
}
|
||||
else
|
||||
{
|
||||
int gen = barrier.b_generation;
|
||||
do
|
||||
{
|
||||
ret = pthread_cond_wait( &barrier.b_cond, &barrier.b_lock );
|
||||
// test generation to avoid bogus wakeup
|
||||
} while( ret == 0 && gen == barrier.b_generation );
|
||||
}
|
||||
pthread_mutex_unlock( &barrier.b_lock );
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pthread_barrierattr_destroy( pthread_barrierattr_t* attr )
|
||||
{
|
||||
if( attr is null )
|
||||
return EINVAL;
|
||||
free( attr );
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_barrierattr_getpshared( pthread_barrierattr_t* attr, int* pshared )
|
||||
{
|
||||
if( attr is null )
|
||||
return EINVAL;
|
||||
*pshared = attr.pshared;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_barrierattr_init( pthread_barrierattr_t* attr )
|
||||
{
|
||||
if( attr is null )
|
||||
return EINVAL;
|
||||
if( ( attr = cast(pthread_barrierattr_t*)
|
||||
malloc( pthread_barrierattr_t.sizeof ) ) is null )
|
||||
return ENOMEM;
|
||||
attr.pshared = PTHREAD_PROCESS_PRIVATE;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_barrierattr_setpshared( pthread_barrierattr_t* attr, int pshared )
|
||||
{
|
||||
if( attr is null )
|
||||
return EINVAL;
|
||||
// only PTHREAD_PROCESS_PRIVATE is supported
|
||||
if( pshared != PTHREAD_PROCESS_PRIVATE )
|
||||
return EINVAL;
|
||||
attr.pshared = pshared;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Timeouts (TMO)
|
||||
//
|
||||
/*
|
||||
int pthread_mutex_timedlock(pthread_mutex_t*, timespec*);
|
||||
int pthread_rwlock_timedrdlock(pthread_rwlock_t*, timespec*);
|
||||
int pthread_rwlock_timedwrlock(pthread_rwlock_t*, timespec*);
|
||||
*/
|
||||
|
||||
version( darwin )
|
||||
{
|
||||
private
|
||||
{
|
||||
import tango.stdc.errno;
|
||||
import tango.stdc.posix.unistd;
|
||||
import tango.stdc.posix.sys.time;
|
||||
|
||||
extern (D)
|
||||
{
|
||||
void timerclear( timeval* tvp )
|
||||
{
|
||||
tvp.tv_sec = tvp.tv_usec = 0;
|
||||
}
|
||||
|
||||
bool timerisset( timeval* tvp )
|
||||
{
|
||||
return tvp.tv_sec || tvp.tv_usec;
|
||||
}
|
||||
|
||||
bool timer_cmp_leq( timeval* tvp, timeval* uvp )
|
||||
{
|
||||
return tvp.tv_sec == uvp.tv_sec ?
|
||||
tvp.tv_usec <= uvp.tv_usec :
|
||||
tvp.tv_sec <= uvp.tv_sec;
|
||||
}
|
||||
|
||||
void timeradd( timeval* tvp, timeval* uvp, timeval* vvp )
|
||||
{
|
||||
vvp.tv_sec = tvp.tv_sec + uvp.tv_sec;
|
||||
vvp.tv_usec = tvp.tv_usec + uvp.tv_usec;
|
||||
if( vvp.tv_usec >= 1000000 )
|
||||
{
|
||||
vvp.tv_sec++;
|
||||
vvp.tv_usec -= 1000000;
|
||||
}
|
||||
}
|
||||
|
||||
void timersub( timeval* tvp, timeval* uvp, timeval* vvp )
|
||||
{
|
||||
vvp.tv_sec = tvp.tv_sec - uvp.tv_sec;
|
||||
vvp.tv_usec = tvp.tv_usec - uvp.tv_usec;
|
||||
if( vvp.tv_usec < 0 )
|
||||
{
|
||||
vvp.tv_sec--;
|
||||
vvp.tv_usec += 1000000;
|
||||
}
|
||||
}
|
||||
|
||||
void TIMEVAL_TO_TIMESPEC( timeval* tv, timespec* ts )
|
||||
{
|
||||
ts.tv_sec = tv.tv_sec;
|
||||
ts.tv_nsec = tv.tv_usec * 1000;
|
||||
}
|
||||
|
||||
void TIMESPEC_TO_TIMEVAL( timeval* tv, timespec* ts )
|
||||
{
|
||||
tv.tv_sec = ts.tv_sec;
|
||||
tv.tv_usec = ts.tv_nsec / 1000;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int pthread_mutex_timedlock( pthread_mutex_t* m, timespec* t )
|
||||
{
|
||||
timeval currtime;
|
||||
timeval maxwait;
|
||||
TIMESPEC_TO_TIMEVAL( &maxwait, t );
|
||||
timeval waittime;
|
||||
waittime.tv_usec = 100;
|
||||
|
||||
while( timer_cmp_leq( &currtime, &maxwait ) )
|
||||
{
|
||||
int ret = pthread_mutex_trylock( m );
|
||||
switch( ret )
|
||||
{
|
||||
case 0: // locked successfully
|
||||
return ret;
|
||||
case EBUSY: // waiting
|
||||
timeradd( &currtime, &waittime, &currtime );
|
||||
break;
|
||||
default:
|
||||
return ret;
|
||||
}
|
||||
usleep( waittime.tv_usec );
|
||||
}
|
||||
return ETIMEDOUT;
|
||||
}
|
||||
|
||||
int pthread_rwlock_timedrdlock( pthread_rwlock_t *rwlock, timespec* t )
|
||||
{
|
||||
timeval currtime;
|
||||
timeval maxwait;
|
||||
TIMESPEC_TO_TIMEVAL( &maxwait, t );
|
||||
timeval waittime;
|
||||
waittime.tv_usec = 100;
|
||||
|
||||
while( timer_cmp_leq( &currtime, &maxwait ) )
|
||||
{
|
||||
int ret = pthread_rwlock_tryrdlock( rwlock );
|
||||
switch( ret )
|
||||
{
|
||||
case 0: // locked successfully
|
||||
return ret;
|
||||
case EBUSY: // waiting
|
||||
timeradd( &currtime, &waittime, &currtime );
|
||||
break;
|
||||
default:
|
||||
return ret;
|
||||
}
|
||||
usleep( waittime.tv_usec );
|
||||
}
|
||||
return ETIMEDOUT;
|
||||
}
|
||||
|
||||
int pthread_rwlock_timedwrlock( pthread_rwlock_t* l, timespec* t )
|
||||
{
|
||||
timeval currtime;
|
||||
timeval maxwait;
|
||||
TIMESPEC_TO_TIMEVAL( &maxwait, t );
|
||||
timeval waittime;
|
||||
waittime.tv_usec = 100;
|
||||
|
||||
while( timer_cmp_leq( &currtime, &maxwait ) )
|
||||
{
|
||||
int ret = pthread_rwlock_trywrlock( l );
|
||||
switch( ret )
|
||||
{
|
||||
case 0: // locked successfully
|
||||
return ret;
|
||||
case EBUSY: // waiting
|
||||
timeradd( &currtime, &waittime, &currtime );
|
||||
break;
|
||||
default:
|
||||
return ret;
|
||||
}
|
||||
usleep( waittime.tv_usec );
|
||||
}
|
||||
return ETIMEDOUT;
|
||||
}
|
||||
}
|
||||
14
tango/lib/common/tango/stdc/wrap.c
Normal file
14
tango/lib/common/tango/stdc/wrap.c
Normal file
@@ -0,0 +1,14 @@
|
||||
#include <errno.h>
|
||||
|
||||
|
||||
int getErrno()
|
||||
{
|
||||
return errno;
|
||||
}
|
||||
|
||||
|
||||
int setErrno( int val )
|
||||
{
|
||||
errno = val;
|
||||
return val;
|
||||
}
|
||||
14
tango/lib/common/tango/stdc/wrap.ll
Normal file
14
tango/lib/common/tango/stdc/wrap.ll
Normal file
@@ -0,0 +1,14 @@
|
||||
; ModuleID = 'wrap.bc'
|
||||
@errno = external global i32 ; <i32*> [#uses=2]
|
||||
|
||||
define i32 @getErrno() {
|
||||
entry:
|
||||
%tmp = load i32* @errno ; <i32> [#uses=1]
|
||||
ret i32 %tmp
|
||||
}
|
||||
|
||||
define i32 @setErrno(i32 %val) {
|
||||
entry:
|
||||
store i32 %val, i32* @errno
|
||||
ret i32 %val
|
||||
}
|
||||
126
tango/lib/common/tango/win32.mak
Normal file
126
tango/lib/common/tango/win32.mak
Normal file
@@ -0,0 +1,126 @@
|
||||
# Makefile to build the common D runtime library for Win32
|
||||
# Designed to work with DigitalMars make
|
||||
# Targets:
|
||||
# make
|
||||
# Same as make all
|
||||
# make lib
|
||||
# Build the common library
|
||||
# make doc
|
||||
# Generate documentation
|
||||
# make clean
|
||||
# Delete unneeded files created by build process
|
||||
|
||||
LIB_TARGET=tango-cc-tango.lib
|
||||
LIB_MASK=tango-cc-tango*.lib
|
||||
|
||||
CP=xcopy /y
|
||||
RM=del /f
|
||||
MD=mkdir
|
||||
|
||||
ADD_CFLAGS=
|
||||
ADD_DFLAGS=
|
||||
|
||||
CFLAGS=-mn -6 -r $(ADD_CFLAGS)
|
||||
#CFLAGS=-g -mn -6 -r $(ADD_CFLAGS)
|
||||
|
||||
DFLAGS=-release -O -inline -w -nofloat $(ADD_DFLAGS)
|
||||
#DFLAGS=-g -w -nofloat $(ADD_DFLAGS)
|
||||
|
||||
TFLAGS=-O -inline -w -nofloat $(ADD_DFLAGS)
|
||||
#TFLAGS=-g -w -nofloat $(ADD_DFLAGS)
|
||||
|
||||
DOCFLAGS=-version=DDoc
|
||||
|
||||
CC=dmc
|
||||
LC=lib
|
||||
DC=dmd
|
||||
|
||||
INC_DEST=..\..\..\tango
|
||||
LIB_DEST=..
|
||||
DOC_DEST=..\..\..\doc\tango
|
||||
|
||||
.DEFAULT: .asm .c .cpp .d .html .obj
|
||||
|
||||
.asm.obj:
|
||||
$(CC) -c $<
|
||||
|
||||
.c.obj:
|
||||
$(CC) -c $(CFLAGS) $< -o$@
|
||||
|
||||
.cpp.obj:
|
||||
$(CC) -c $(CFLAGS) $< -o$@
|
||||
|
||||
.d.obj:
|
||||
$(DC) -c $(DFLAGS) -Hf$*.di $< -of$@
|
||||
# $(DC) -c $(DFLAGS) $< -of$@
|
||||
|
||||
.d.html:
|
||||
$(DC) -c -o- $(DOCFLAGS) -Df$*.html $<
|
||||
# $(DC) -c -o- $(DOCFLAGS) -Df$*.html tango.ddoc $<
|
||||
|
||||
targets : lib doc
|
||||
all : lib doc
|
||||
tango : lib
|
||||
lib : tango.lib
|
||||
doc : tango.doc
|
||||
|
||||
######################################################
|
||||
|
||||
OBJ_CORE= \
|
||||
core\BitManip.obj \
|
||||
core\Exception.obj \
|
||||
core\Memory.obj \
|
||||
core\Runtime.obj \
|
||||
core\Thread.obj
|
||||
|
||||
OBJ_STDC= \
|
||||
stdc\wrap.obj
|
||||
|
||||
ALL_OBJS= \
|
||||
$(OBJ_CORE) \
|
||||
$(OBJ_STDC)
|
||||
|
||||
######################################################
|
||||
|
||||
DOC_CORE= \
|
||||
core\BitManip.html \
|
||||
core\Exception.html \
|
||||
core\Memory.html \
|
||||
core\Runtime.html \
|
||||
core\Thread.html
|
||||
|
||||
ALL_DOCS=
|
||||
|
||||
######################################################
|
||||
|
||||
tango.lib : $(LIB_TARGET)
|
||||
|
||||
$(LIB_TARGET) : $(ALL_OBJS)
|
||||
$(RM) $@
|
||||
$(LC) -c -n $@ $(ALL_OBJS)
|
||||
|
||||
tango.doc : $(ALL_DOCS)
|
||||
@echo Documentation generated.
|
||||
|
||||
######################################################
|
||||
|
||||
### config
|
||||
|
||||
# config.obj : config.d
|
||||
# $(DC) -c $(DFLAGS) config.d -of$@
|
||||
|
||||
######################################################
|
||||
|
||||
clean :
|
||||
$(RM) /s .\*.di
|
||||
$(RM) $(ALL_OBJS)
|
||||
$(RM) $(ALL_DOCS)
|
||||
$(RM) $(LIB_MASK)
|
||||
|
||||
install :
|
||||
$(MD) $(INC_DEST)
|
||||
$(CP) /s *.di $(INC_DEST)\.
|
||||
$(MD) $(DOC_DEST)
|
||||
$(CP) /s *.html $(DOC_DEST)\.
|
||||
$(MD) $(LIB_DEST)
|
||||
$(CP) $(LIB_MASK) $(LIB_DEST)\.
|
||||
406
tango/lib/compiler/llvmdc/aApply.d
Normal file
406
tango/lib/compiler/llvmdc/aApply.d
Normal file
@@ -0,0 +1,406 @@
|
||||
/**
|
||||
* Part of the D programming language runtime library.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
|
||||
* Written by Walter Bright
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, in both source and binary form, subject to the following
|
||||
* restrictions:
|
||||
*
|
||||
* o The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* o Altered source versions must be plainly marked as such, and must not
|
||||
* be misrepresented as being the original software.
|
||||
* o This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by Sean Kelly <sean@f4.ca> for use with Tango.
|
||||
*/
|
||||
|
||||
/* This code handles decoding UTF strings for foreach loops.
|
||||
* There are 6 combinations of conversions between char, wchar,
|
||||
* and dchar, and 2 of each of those.
|
||||
*/
|
||||
|
||||
private import util.utf;
|
||||
|
||||
/**********************************************
|
||||
*/
|
||||
|
||||
// dg is D, but _aApplycd() is C
|
||||
extern (D) typedef int delegate(void *) dg_t;
|
||||
|
||||
extern (C) int _aApplycd1(char[] aa, dg_t dg)
|
||||
{ int result;
|
||||
size_t i;
|
||||
size_t len = aa.length;
|
||||
|
||||
debug(apply) printf("_aApplycd1(), len = %d\n", len);
|
||||
for (i = 0; i < len; )
|
||||
{ dchar d;
|
||||
|
||||
d = aa[i];
|
||||
if (d & 0x80)
|
||||
d = decode(aa, i);
|
||||
else
|
||||
i++;
|
||||
result = dg(cast(void *)&d);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C) int _aApplywd1(wchar[] aa, dg_t dg)
|
||||
{ int result;
|
||||
size_t i;
|
||||
size_t len = aa.length;
|
||||
|
||||
debug(apply) printf("_aApplywd1(), len = %d\n", len);
|
||||
for (i = 0; i < len; )
|
||||
{ dchar d;
|
||||
|
||||
d = aa[i];
|
||||
if (d & ~0x7F)
|
||||
d = decode(aa, i);
|
||||
else
|
||||
i++;
|
||||
result = dg(cast(void *)&d);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C) int _aApplycw1(char[] aa, dg_t dg)
|
||||
{ int result;
|
||||
size_t i;
|
||||
size_t len = aa.length;
|
||||
|
||||
debug(apply) printf("_aApplycw1(), len = %d\n", len);
|
||||
for (i = 0; i < len; )
|
||||
{ dchar d;
|
||||
wchar w;
|
||||
|
||||
w = aa[i];
|
||||
if (w & 0x80)
|
||||
{ d = decode(aa, i);
|
||||
if (d <= 0xFFFF)
|
||||
w = cast(wchar) d;
|
||||
else
|
||||
{
|
||||
w = cast(wchar)((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||
result = dg(cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
w = cast(wchar)(((d - 0x10000) & 0x3FF) + 0xDC00);
|
||||
}
|
||||
}
|
||||
else
|
||||
i++;
|
||||
result = dg(cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C) int _aApplywc1(wchar[] aa, dg_t dg)
|
||||
{ int result;
|
||||
size_t i;
|
||||
size_t len = aa.length;
|
||||
|
||||
debug(apply) printf("_aApplywc1(), len = %d\n", len);
|
||||
for (i = 0; i < len; )
|
||||
{ dchar d;
|
||||
wchar w;
|
||||
char c;
|
||||
|
||||
w = aa[i];
|
||||
if (w & ~0x7F)
|
||||
{
|
||||
char[4] buf;
|
||||
|
||||
d = decode(aa, i);
|
||||
auto b = toUTF8(buf, d);
|
||||
foreach (char c2; b)
|
||||
{
|
||||
result = dg(cast(void *)&c2);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{ c = cast(char)w;
|
||||
i++;
|
||||
}
|
||||
result = dg(cast(void *)&c);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C) int _aApplydc1(dchar[] aa, dg_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplydc1(), len = %d\n", aa.length);
|
||||
foreach (dchar d; aa)
|
||||
{
|
||||
char c;
|
||||
|
||||
if (d & ~0x7F)
|
||||
{
|
||||
char[4] buf;
|
||||
|
||||
auto b = toUTF8(buf, d);
|
||||
foreach (char c2; b)
|
||||
{
|
||||
result = dg(cast(void *)&c2);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
c = cast(char)d;
|
||||
}
|
||||
result = dg(cast(void *)&c);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C) int _aApplydw1(dchar[] aa, dg_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplydw1(), len = %d\n", aa.length);
|
||||
foreach (dchar d; aa)
|
||||
{
|
||||
wchar w;
|
||||
|
||||
if (d <= 0xFFFF)
|
||||
w = cast(wchar) d;
|
||||
else
|
||||
{
|
||||
w = cast(wchar)((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||
result = dg(cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
w = cast(wchar)(((d - 0x10000) & 0x3FF) + 0xDC00);
|
||||
}
|
||||
result = dg(cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
|
||||
// dg is D, but _aApplycd2() is C
|
||||
extern (D) typedef int delegate(void *, void *) dg2_t;
|
||||
|
||||
extern (C) int _aApplycd2(char[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
size_t i;
|
||||
size_t n;
|
||||
size_t len = aa.length;
|
||||
|
||||
debug(apply) printf("_aApplycd2(), len = %d\n", len);
|
||||
for (i = 0; i < len; i += n)
|
||||
{ dchar d;
|
||||
|
||||
d = aa[i];
|
||||
if (d & 0x80)
|
||||
{
|
||||
n = i;
|
||||
d = decode(aa, n);
|
||||
n -= i;
|
||||
}
|
||||
else
|
||||
n = 1;
|
||||
result = dg(&i, cast(void *)&d);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C) int _aApplywd2(wchar[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
size_t i;
|
||||
size_t n;
|
||||
size_t len = aa.length;
|
||||
|
||||
debug(apply) printf("_aApplywd2(), len = %d\n", len);
|
||||
for (i = 0; i < len; i += n)
|
||||
{ dchar d;
|
||||
|
||||
d = aa[i];
|
||||
if (d & ~0x7F)
|
||||
{
|
||||
n = i;
|
||||
d = decode(aa, n);
|
||||
n -= i;
|
||||
}
|
||||
else
|
||||
n = 1;
|
||||
result = dg(&i, cast(void *)&d);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C) int _aApplycw2(char[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
size_t i;
|
||||
size_t n;
|
||||
size_t len = aa.length;
|
||||
|
||||
debug(apply) printf("_aApplycw2(), len = %d\n", len);
|
||||
for (i = 0; i < len; i += n)
|
||||
{ dchar d;
|
||||
wchar w;
|
||||
|
||||
w = aa[i];
|
||||
if (w & 0x80)
|
||||
{ n = i;
|
||||
d = decode(aa, n);
|
||||
n -= i;
|
||||
if (d <= 0xFFFF)
|
||||
w = cast(wchar) d;
|
||||
else
|
||||
{
|
||||
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||
result = dg(&i, cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
|
||||
}
|
||||
}
|
||||
else
|
||||
n = 1;
|
||||
result = dg(&i, cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C) int _aApplywc2(wchar[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
size_t i;
|
||||
size_t n;
|
||||
size_t len = aa.length;
|
||||
|
||||
debug(apply) printf("_aApplywc2(), len = %d\n", len);
|
||||
for (i = 0; i < len; i += n)
|
||||
{ dchar d;
|
||||
wchar w;
|
||||
char c;
|
||||
|
||||
w = aa[i];
|
||||
if (w & ~0x7F)
|
||||
{
|
||||
char[4] buf;
|
||||
|
||||
n = i;
|
||||
d = decode(aa, n);
|
||||
n -= i;
|
||||
auto b = toUTF8(buf, d);
|
||||
foreach (char c2; b)
|
||||
{
|
||||
result = dg(&i, cast(void *)&c2);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{ c = cast(char)w;
|
||||
n = 1;
|
||||
}
|
||||
result = dg(&i, cast(void *)&c);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C) int _aApplydc2(dchar[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
size_t i;
|
||||
size_t len = aa.length;
|
||||
|
||||
debug(apply) printf("_aApplydc2(), len = %d\n", len);
|
||||
for (i = 0; i < len; i++)
|
||||
{ dchar d;
|
||||
char c;
|
||||
|
||||
d = aa[i];
|
||||
if (d & ~0x7F)
|
||||
{
|
||||
char[4] buf;
|
||||
|
||||
auto b = toUTF8(buf, d);
|
||||
foreach (char c2; b)
|
||||
{
|
||||
result = dg(&i, cast(void *)&c2);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{ c = cast(char)d;
|
||||
}
|
||||
result = dg(&i, cast(void *)&c);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
extern (C) int _aApplydw2(dchar[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplydw2(), len = %d\n", aa.length);
|
||||
foreach (size_t i, dchar d; aa)
|
||||
{
|
||||
wchar w;
|
||||
auto j = i;
|
||||
|
||||
if (d <= 0xFFFF)
|
||||
w = cast(wchar) d;
|
||||
else
|
||||
{
|
||||
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||
result = dg(&j, cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
|
||||
}
|
||||
result = dg(&j, cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
975
tango/lib/compiler/llvmdc/aApplyR.d
Normal file
975
tango/lib/compiler/llvmdc/aApplyR.d
Normal file
@@ -0,0 +1,975 @@
|
||||
|
||||
/**
|
||||
* Part of the D programming language runtime library.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright (C) 2004-2006 by Digital Mars, www.digitalmars.com
|
||||
* Written by Walter Bright
|
||||
*
|
||||
* This software is provided 'as-is', without any express or implied
|
||||
* warranty. In no event will the authors be held liable for any damages
|
||||
* arising from the use of this software.
|
||||
*
|
||||
* Permission is granted to anyone to use this software for any purpose,
|
||||
* including commercial applications, and to alter it and redistribute it
|
||||
* freely, in both source and binary form, subject to the following
|
||||
* restrictions:
|
||||
*
|
||||
* o The origin of this software must not be misrepresented; you must not
|
||||
* claim that you wrote the original software. If you use this software
|
||||
* in a product, an acknowledgment in the product documentation would be
|
||||
* appreciated but is not required.
|
||||
* o Altered source versions must be plainly marked as such, and must not
|
||||
* be misrepresented as being the original software.
|
||||
* o This notice may not be removed or altered from any source
|
||||
* distribution.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Modified by Sean Kelly <sean@f4.ca> for use with Tango.
|
||||
*/
|
||||
|
||||
/* This code handles decoding UTF strings for foreach_reverse loops.
|
||||
* There are 6 combinations of conversions between char, wchar,
|
||||
* and dchar, and 2 of each of those.
|
||||
*/
|
||||
|
||||
private import util.utf;
|
||||
|
||||
/**********************************************/
|
||||
/* 1 argument versions */
|
||||
|
||||
// dg is D, but _aApplyRcd() is C
|
||||
extern (D) typedef int delegate(void *) dg_t;
|
||||
|
||||
extern (C) int _aApplyRcd1(in char[] aa, dg_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRcd1(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0; )
|
||||
{ dchar d;
|
||||
|
||||
i--;
|
||||
d = aa[i];
|
||||
if (d & 0x80)
|
||||
{ char c = cast(char)d;
|
||||
uint j;
|
||||
uint m = 0x3F;
|
||||
d = 0;
|
||||
while ((c & 0xC0) != 0xC0)
|
||||
{ if (i == 0)
|
||||
onUnicodeError("Invalid UTF-8 sequence", 0);
|
||||
i--;
|
||||
d |= (c & 0x3F) << j;
|
||||
j += 6;
|
||||
m >>= 1;
|
||||
c = aa[i];
|
||||
}
|
||||
d |= (c & m) << j;
|
||||
}
|
||||
result = dg(cast(void *)&d);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRcd1.unittest\n");
|
||||
|
||||
auto s = "hello"c;
|
||||
int i;
|
||||
|
||||
foreach_reverse(dchar d; s)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(dchar d; s)
|
||||
{
|
||||
//printf("i = %d, d = %x\n", i, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'b'); break;
|
||||
case 1: assert(d == '\U00100456'); break;
|
||||
case 2: assert(d == '\u1234'); break;
|
||||
case 3: assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 4);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
||||
extern (C) int _aApplyRwd1(in wchar[] aa, dg_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRwd1(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0; )
|
||||
{ dchar d;
|
||||
|
||||
i--;
|
||||
d = aa[i];
|
||||
if (d >= 0xDC00 && d <= 0xDFFF)
|
||||
{ if (i == 0)
|
||||
onUnicodeError("Invalid UTF-16 sequence", 0);
|
||||
i--;
|
||||
d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
|
||||
}
|
||||
result = dg(cast(void *)&d);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRwd1.unittest\n");
|
||||
|
||||
auto s = "hello"w;
|
||||
int i;
|
||||
|
||||
foreach_reverse(dchar d; s)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(dchar d; s)
|
||||
{
|
||||
//printf("i = %d, d = %x\n", i, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'b'); break;
|
||||
case 1: assert(d == '\U00100456'); break;
|
||||
case 2: assert(d == '\u1234'); break;
|
||||
case 3: assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 4);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
||||
extern (C) int _aApplyRcw1(in char[] aa, dg_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRcw1(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0; )
|
||||
{ dchar d;
|
||||
wchar w;
|
||||
|
||||
i--;
|
||||
w = aa[i];
|
||||
if (w & 0x80)
|
||||
{ char c = cast(char)w;
|
||||
uint j;
|
||||
uint m = 0x3F;
|
||||
d = 0;
|
||||
while ((c & 0xC0) != 0xC0)
|
||||
{ if (i == 0)
|
||||
onUnicodeError("Invalid UTF-8 sequence", 0);
|
||||
i--;
|
||||
d |= (c & 0x3F) << j;
|
||||
j += 6;
|
||||
m >>= 1;
|
||||
c = aa[i];
|
||||
}
|
||||
d |= (c & m) << j;
|
||||
|
||||
if (d <= 0xFFFF)
|
||||
w = cast(wchar) d;
|
||||
else
|
||||
{
|
||||
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||
result = dg(cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
|
||||
}
|
||||
}
|
||||
result = dg(cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRcw1.unittest\n");
|
||||
|
||||
auto s = "hello"c;
|
||||
int i;
|
||||
|
||||
foreach_reverse(wchar d; s)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(wchar d; s)
|
||||
{
|
||||
//printf("i = %d, d = %x\n", i, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'b'); break;
|
||||
case 1: assert(d == 0xDBC1); break;
|
||||
case 2: assert(d == 0xDC56); break;
|
||||
case 3: assert(d == 0x1234); break;
|
||||
case 4: assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
||||
extern (C) int _aApplyRwc1(in wchar[] aa, dg_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRwc1(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0; )
|
||||
{ dchar d;
|
||||
char c;
|
||||
|
||||
i--;
|
||||
d = aa[i];
|
||||
if (d >= 0xDC00 && d <= 0xDFFF)
|
||||
{ if (i == 0)
|
||||
onUnicodeError("Invalid UTF-16 sequence", 0);
|
||||
i--;
|
||||
d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
|
||||
}
|
||||
|
||||
if (d & ~0x7F)
|
||||
{
|
||||
char[4] buf;
|
||||
|
||||
auto b = toUTF8(buf, d);
|
||||
foreach (char c2; b)
|
||||
{
|
||||
result = dg(cast(void *)&c2);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
c = cast(char)d;
|
||||
result = dg(cast(void *)&c);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRwc1.unittest\n");
|
||||
|
||||
auto s = "hello"w;
|
||||
int i;
|
||||
|
||||
foreach_reverse(char d; s)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(char d; s)
|
||||
{
|
||||
//printf("i = %d, d = %x\n", i, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'b'); break;
|
||||
case 1: assert(d == 0xF4); break;
|
||||
case 2: assert(d == 0x80); break;
|
||||
case 3: assert(d == 0x91); break;
|
||||
case 4: assert(d == 0x96); break;
|
||||
case 5: assert(d == 0xE1); break;
|
||||
case 6: assert(d == 0x88); break;
|
||||
case 7: assert(d == 0xB4); break;
|
||||
case 8: assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 9);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
||||
extern (C) int _aApplyRdc1(in dchar[] aa, dg_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRdc1(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0;)
|
||||
{ dchar d = aa[--i];
|
||||
char c;
|
||||
|
||||
if (d & ~0x7F)
|
||||
{
|
||||
char[4] buf;
|
||||
|
||||
auto b = toUTF8(buf, d);
|
||||
foreach (char c2; b)
|
||||
{
|
||||
result = dg(cast(void *)&c2);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
c = cast(char)d;
|
||||
}
|
||||
result = dg(cast(void *)&c);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRdc1.unittest\n");
|
||||
|
||||
auto s = "hello"d;
|
||||
int i;
|
||||
|
||||
foreach_reverse(char d; s)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(char d; s)
|
||||
{
|
||||
//printf("i = %d, d = %x\n", i, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'b'); break;
|
||||
case 1: assert(d == 0xF4); break;
|
||||
case 2: assert(d == 0x80); break;
|
||||
case 3: assert(d == 0x91); break;
|
||||
case 4: assert(d == 0x96); break;
|
||||
case 5: assert(d == 0xE1); break;
|
||||
case 6: assert(d == 0x88); break;
|
||||
case 7: assert(d == 0xB4); break;
|
||||
case 8: assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 9);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
||||
extern (C) int _aApplyRdw1(in dchar[] aa, dg_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRdw1(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0; )
|
||||
{ dchar d = aa[--i];
|
||||
wchar w;
|
||||
|
||||
if (d <= 0xFFFF)
|
||||
w = cast(wchar) d;
|
||||
else
|
||||
{
|
||||
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||
result = dg(cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
|
||||
}
|
||||
result = dg(cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRdw1.unittest\n");
|
||||
|
||||
auto s = "hello"d;
|
||||
int i;
|
||||
|
||||
foreach_reverse(wchar d; s)
|
||||
{
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(wchar d; s)
|
||||
{
|
||||
//printf("i = %d, d = %x\n", i, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'b'); break;
|
||||
case 1: assert(d == 0xDBC1); break;
|
||||
case 2: assert(d == 0xDC56); break;
|
||||
case 3: assert(d == 0x1234); break;
|
||||
case 4: assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************/
|
||||
/* 2 argument versions */
|
||||
|
||||
// dg is D, but _aApplyRcd2() is C
|
||||
extern (D) typedef int delegate(void *, void *) dg2_t;
|
||||
|
||||
extern (C) int _aApplyRcd2(in char[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
size_t i;
|
||||
size_t len = aa.length;
|
||||
|
||||
debug(apply) printf("_aApplyRcd2(), len = %d\n", len);
|
||||
for (i = len; i != 0; )
|
||||
{ dchar d;
|
||||
|
||||
i--;
|
||||
d = aa[i];
|
||||
if (d & 0x80)
|
||||
{ char c = cast(char)d;
|
||||
uint j;
|
||||
uint m = 0x3F;
|
||||
d = 0;
|
||||
while ((c & 0xC0) != 0xC0)
|
||||
{ if (i == 0)
|
||||
onUnicodeError("Invalid UTF-8 sequence", 0);
|
||||
i--;
|
||||
d |= (c & 0x3F) << j;
|
||||
j += 6;
|
||||
m >>= 1;
|
||||
c = aa[i];
|
||||
}
|
||||
d |= (c & m) << j;
|
||||
}
|
||||
result = dg(&i, cast(void *)&d);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRcd2.unittest\n");
|
||||
|
||||
auto s = "hello"c;
|
||||
int i;
|
||||
|
||||
foreach_reverse(k, dchar d; s)
|
||||
{
|
||||
assert(k == 4 - i);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(k, dchar d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'b'); assert(k == 8); break;
|
||||
case 1: assert(d == '\U00100456'); assert(k == 4); break;
|
||||
case 2: assert(d == '\u1234'); assert(k == 1); break;
|
||||
case 3: assert(d == 'a'); assert(k == 0); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 4);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
||||
extern (C) int _aApplyRwd2(in wchar[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRwd2(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0; )
|
||||
{ dchar d;
|
||||
|
||||
i--;
|
||||
d = aa[i];
|
||||
if (d >= 0xDC00 && d <= 0xDFFF)
|
||||
{ if (i == 0)
|
||||
onUnicodeError("Invalid UTF-16 sequence", 0);
|
||||
i--;
|
||||
d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
|
||||
}
|
||||
result = dg(&i, cast(void *)&d);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRwd2.unittest\n");
|
||||
|
||||
auto s = "hello"w;
|
||||
int i;
|
||||
|
||||
foreach_reverse(k, dchar d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
assert(k == 4 - i);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(k, dchar d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(k == 4); assert(d == 'b'); break;
|
||||
case 1: assert(k == 2); assert(d == '\U00100456'); break;
|
||||
case 2: assert(k == 1); assert(d == '\u1234'); break;
|
||||
case 3: assert(k == 0); assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 4);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
||||
extern (C) int _aApplyRcw2(in char[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRcw2(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0; )
|
||||
{ dchar d;
|
||||
wchar w;
|
||||
|
||||
i--;
|
||||
w = aa[i];
|
||||
if (w & 0x80)
|
||||
{ char c = cast(char)w;
|
||||
uint j;
|
||||
uint m = 0x3F;
|
||||
d = 0;
|
||||
while ((c & 0xC0) != 0xC0)
|
||||
{ if (i == 0)
|
||||
onUnicodeError("Invalid UTF-8 sequence", 0);
|
||||
i--;
|
||||
d |= (c & 0x3F) << j;
|
||||
j += 6;
|
||||
m >>= 1;
|
||||
c = aa[i];
|
||||
}
|
||||
d |= (c & m) << j;
|
||||
|
||||
if (d <= 0xFFFF)
|
||||
w = cast(wchar) d;
|
||||
else
|
||||
{
|
||||
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||
result = dg(&i, cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
|
||||
}
|
||||
}
|
||||
result = dg(&i, cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRcw2.unittest\n");
|
||||
|
||||
auto s = "hello"c;
|
||||
int i;
|
||||
|
||||
foreach_reverse(k, wchar d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
assert(k == 4 - i);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(k, wchar d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(k == 8); assert(d == 'b'); break;
|
||||
case 1: assert(k == 4); assert(d == 0xDBC1); break;
|
||||
case 2: assert(k == 4); assert(d == 0xDC56); break;
|
||||
case 3: assert(k == 1); assert(d == 0x1234); break;
|
||||
case 4: assert(k == 0); assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
||||
extern (C) int _aApplyRwc2(in wchar[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRwc2(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0; )
|
||||
{ dchar d;
|
||||
char c;
|
||||
|
||||
i--;
|
||||
d = aa[i];
|
||||
if (d >= 0xDC00 && d <= 0xDFFF)
|
||||
{ if (i == 0)
|
||||
onUnicodeError("Invalid UTF-16 sequence", 0);
|
||||
i--;
|
||||
d = ((aa[i] - 0xD7C0) << 10) + (d - 0xDC00);
|
||||
}
|
||||
|
||||
if (d & ~0x7F)
|
||||
{
|
||||
char[4] buf;
|
||||
|
||||
auto b = toUTF8(buf, d);
|
||||
foreach (char c2; b)
|
||||
{
|
||||
result = dg(&i, cast(void *)&c2);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
c = cast(char)d;
|
||||
result = dg(&i, cast(void *)&c);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRwc2.unittest\n");
|
||||
|
||||
auto s = "hello"w;
|
||||
int i;
|
||||
|
||||
foreach_reverse(k, char d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
assert(k == 4 - i);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(k, char d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(k == 4); assert(d == 'b'); break;
|
||||
case 1: assert(k == 2); assert(d == 0xF4); break;
|
||||
case 2: assert(k == 2); assert(d == 0x80); break;
|
||||
case 3: assert(k == 2); assert(d == 0x91); break;
|
||||
case 4: assert(k == 2); assert(d == 0x96); break;
|
||||
case 5: assert(k == 1); assert(d == 0xE1); break;
|
||||
case 6: assert(k == 1); assert(d == 0x88); break;
|
||||
case 7: assert(k == 1); assert(d == 0xB4); break;
|
||||
case 8: assert(k == 0); assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 9);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
||||
extern (C) int _aApplyRdc2(in dchar[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRdc2(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0; )
|
||||
{ dchar d = aa[--i];
|
||||
char c;
|
||||
|
||||
if (d & ~0x7F)
|
||||
{
|
||||
char[4] buf;
|
||||
|
||||
auto b = toUTF8(buf, d);
|
||||
foreach (char c2; b)
|
||||
{
|
||||
result = dg(&i, cast(void *)&c2);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{ c = cast(char)d;
|
||||
}
|
||||
result = dg(&i, cast(void *)&c);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRdc2.unittest\n");
|
||||
|
||||
auto s = "hello"d;
|
||||
int i;
|
||||
|
||||
foreach_reverse(k, char d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
assert(k == 4 - i);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(k, char d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(k == 3); assert(d == 'b'); break;
|
||||
case 1: assert(k == 2); assert(d == 0xF4); break;
|
||||
case 2: assert(k == 2); assert(d == 0x80); break;
|
||||
case 3: assert(k == 2); assert(d == 0x91); break;
|
||||
case 4: assert(k == 2); assert(d == 0x96); break;
|
||||
case 5: assert(k == 1); assert(d == 0xE1); break;
|
||||
case 6: assert(k == 1); assert(d == 0x88); break;
|
||||
case 7: assert(k == 1); assert(d == 0xB4); break;
|
||||
case 8: assert(k == 0); assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 9);
|
||||
}
|
||||
|
||||
/*****************************/
|
||||
|
||||
extern (C) int _aApplyRdw2(in dchar[] aa, dg2_t dg)
|
||||
{ int result;
|
||||
|
||||
debug(apply) printf("_aApplyRdw2(), len = %d\n", aa.length);
|
||||
for (size_t i = aa.length; i != 0; )
|
||||
{ dchar d = aa[--i];
|
||||
wchar w;
|
||||
|
||||
if (d <= 0xFFFF)
|
||||
w = cast(wchar) d;
|
||||
else
|
||||
{
|
||||
w = cast(wchar) ((((d - 0x10000) >> 10) & 0x3FF) + 0xD800);
|
||||
result = dg(&i, cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
w = cast(wchar) (((d - 0x10000) & 0x3FF) + 0xDC00);
|
||||
}
|
||||
result = dg(&i, cast(void *)&w);
|
||||
if (result)
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
unittest
|
||||
{
|
||||
debug(apply) printf("_aApplyRdw2.unittest\n");
|
||||
|
||||
auto s = "hello"d;
|
||||
int i;
|
||||
|
||||
foreach_reverse(k, wchar d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
assert(k == 4 - i);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(d == 'o'); break;
|
||||
case 1: assert(d == 'l'); break;
|
||||
case 2: assert(d == 'l'); break;
|
||||
case 3: assert(d == 'e'); break;
|
||||
case 4: assert(d == 'h'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
|
||||
s = "a\u1234\U00100456b";
|
||||
i = 0;
|
||||
foreach_reverse(k, wchar d; s)
|
||||
{
|
||||
//printf("i = %d, k = %d, d = %x\n", i, k, d);
|
||||
switch (i)
|
||||
{
|
||||
case 0: assert(k == 3); assert(d == 'b'); break;
|
||||
case 1: assert(k == 2); assert(d == 0xDBC1); break;
|
||||
case 2: assert(k == 2); assert(d == 0xDC56); break;
|
||||
case 3: assert(k == 1); assert(d == 0x1234); break;
|
||||
case 4: assert(k == 0); assert(d == 'a'); break;
|
||||
default: assert(0);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
assert(i == 5);
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user